blob: 86f99a8bb0eb6bf396751bb9c7ea3d0e6d310fd0 [file] [log] [blame]
Alice Wang600ea5b2023-11-17 15:12:16 +00001// Copyright 2023, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Wrappers of the EVP functions in BoringSSL evp.h.
16
17use crate::cbb::CbbFixed;
Alice Wang7468ae42023-11-30 10:20:36 +000018use crate::digest::{Digester, DigesterContext};
Alice Wang600ea5b2023-11-17 15:12:16 +000019use crate::ec_key::EcKey;
Alice Wangbe7a4b12023-12-01 11:53:36 +000020use crate::util::{
21 check_int_result, get_label_value, get_label_value_as_bytes, to_call_failed_error,
22};
Alice Wang600ea5b2023-11-17 15:12:16 +000023use alloc::vec::Vec;
Alice Wangbe7a4b12023-12-01 11:53:36 +000024use bssl_avf_error::{ApiName, Error, Result};
Alice Wang600ea5b2023-11-17 15:12:16 +000025use bssl_ffi::{
Alice Wang7468ae42023-11-30 10:20:36 +000026 CBB_flush, CBB_len, EVP_DigestVerify, EVP_DigestVerifyInit, EVP_PKEY_free, EVP_PKEY_new,
27 EVP_PKEY_new_raw_public_key, EVP_PKEY_set1_EC_KEY, EVP_marshal_public_key, EVP_PKEY,
28 EVP_PKEY_ED25519, EVP_PKEY_X25519,
Alice Wang600ea5b2023-11-17 15:12:16 +000029};
Alice Wangbe7a4b12023-12-01 11:53:36 +000030use ciborium::Value;
Alice Wang7468ae42023-11-30 10:20:36 +000031use core::ptr::{self, NonNull};
Alice Wangbe7a4b12023-12-01 11:53:36 +000032use coset::{
33 iana::{self, EnumI64},
34 CoseKey, KeyType, Label,
35};
36use log::error;
Alice Wang600ea5b2023-11-17 15:12:16 +000037
38/// Wrapper of an `EVP_PKEY` object, representing a public or private key.
Alice Wangeb77f7d2023-12-01 09:13:58 +000039pub struct PKey {
Alice Wang600ea5b2023-11-17 15:12:16 +000040 pkey: NonNull<EVP_PKEY>,
Alice Wang7468ae42023-11-30 10:20:36 +000041 /// If this struct owns the inner EC key, the inner EC key should remain valid as
Alice Wang600ea5b2023-11-17 15:12:16 +000042 /// long as the pointer to `EVP_PKEY` is valid.
Alice Wang7468ae42023-11-30 10:20:36 +000043 _inner_ec_key: Option<EcKey>,
Alice Wang600ea5b2023-11-17 15:12:16 +000044}
45
Alice Wangeb77f7d2023-12-01 09:13:58 +000046impl Drop for PKey {
Alice Wang600ea5b2023-11-17 15:12:16 +000047 fn drop(&mut self) {
48 // SAFETY: It is safe because `EVP_PKEY` has been allocated by BoringSSL and isn't
49 // used after this.
50 unsafe { EVP_PKEY_free(self.pkey.as_ptr()) }
51 }
52}
53
54/// Creates a new empty `EVP_PKEY`.
55fn new_pkey() -> Result<NonNull<EVP_PKEY>> {
56 // SAFETY: The returned pointer is checked below.
57 let key = unsafe { EVP_PKEY_new() };
58 NonNull::new(key).ok_or(to_call_failed_error(ApiName::EVP_PKEY_new))
59}
60
Alice Wangeb77f7d2023-12-01 09:13:58 +000061impl TryFrom<EcKey> for PKey {
Alice Wang600ea5b2023-11-17 15:12:16 +000062 type Error = bssl_avf_error::Error;
63
64 fn try_from(key: EcKey) -> Result<Self> {
65 let pkey = new_pkey()?;
Alice Wang7468ae42023-11-30 10:20:36 +000066 // SAFETY: The function only sets the inner EC key of the initialized and
Alice Wang600ea5b2023-11-17 15:12:16 +000067 // non-null `EVP_PKEY` to point to the given `EC_KEY`. It only reads from
68 // and writes to the initialized `EVP_PKEY`.
69 // Since this struct owns the inner key, the inner key remains valid as
70 // long as `EVP_PKEY` is valid.
71 let ret = unsafe { EVP_PKEY_set1_EC_KEY(pkey.as_ptr(), key.0.as_ptr()) };
72 check_int_result(ret, ApiName::EVP_PKEY_set1_EC_KEY)?;
Alice Wang7468ae42023-11-30 10:20:36 +000073 Ok(Self { pkey, _inner_ec_key: Some(key) })
Alice Wang600ea5b2023-11-17 15:12:16 +000074 }
75}
76
Alice Wangeb77f7d2023-12-01 09:13:58 +000077impl PKey {
Alice Wang600ea5b2023-11-17 15:12:16 +000078 /// Returns a DER-encoded SubjectPublicKeyInfo structure as specified
79 /// in RFC 5280 s4.1.2.7:
80 ///
81 /// https://www.rfc-editor.org/rfc/rfc5280.html#section-4.1.2.7
82 pub fn subject_public_key_info(&self) -> Result<Vec<u8>> {
83 const CAPACITY: usize = 256;
84 let mut buf = [0u8; CAPACITY];
85 let mut cbb = CbbFixed::new(buf.as_mut());
86 // SAFETY: The function only write bytes to the buffer managed by the valid `CBB`.
87 // The inner key in `EVP_PKEY` was set to a valid key when the object was created.
88 // As this struct owns the inner key, the inner key is guaranteed to be valid
89 // throughout the execution of the function.
90 let ret = unsafe { EVP_marshal_public_key(cbb.as_mut(), self.pkey.as_ptr()) };
91 check_int_result(ret, ApiName::EVP_marshal_public_key)?;
92 // SAFETY: This is safe because the CBB pointer is a valid pointer initialized with
93 // `CBB_init_fixed()`.
94 check_int_result(unsafe { CBB_flush(cbb.as_mut()) }, ApiName::CBB_flush)?;
95 // SAFETY: This is safe because the CBB pointer is initialized with `CBB_init_fixed()`,
96 // and it has been flushed, thus it has no active children.
97 let len = unsafe { CBB_len(cbb.as_ref()) };
98 Ok(buf.get(0..len).ok_or(to_call_failed_error(ApiName::CBB_len))?.to_vec())
99 }
Alice Wang7468ae42023-11-30 10:20:36 +0000100
101 /// This function takes a raw public key data slice and creates a `PKey` instance wrapping
102 /// a freshly allocated `EVP_PKEY` object from it.
103 ///
104 /// The lifetime of the returned instance is not tied to the lifetime of the raw public
105 /// key slice because the raw data is copied into the `EVP_PKEY` object.
106 ///
107 /// Currently the only supported raw formats are X25519 and Ed25519, where the formats
108 /// are specified in RFC 7748 and RFC 8032 respectively.
109 pub fn new_raw_public_key(raw_public_key: &[u8], type_: PKeyType) -> Result<Self> {
110 let engine = ptr::null_mut(); // Engine is not used.
111 let pkey =
112 // SAFETY: The function only reads from the given raw public key within its bounds.
113 // The returned pointer is checked below.
114 unsafe {
115 EVP_PKEY_new_raw_public_key(
116 type_.0,
117 engine,
118 raw_public_key.as_ptr(),
119 raw_public_key.len(),
120 )
121 };
122 let pkey =
123 NonNull::new(pkey).ok_or(to_call_failed_error(ApiName::EVP_PKEY_new_raw_public_key))?;
124 Ok(Self { pkey, _inner_ec_key: None })
125 }
126
Alice Wangbe7a4b12023-12-01 11:53:36 +0000127 /// Creates a `PKey` from the given `cose_key`.
128 ///
129 /// The lifetime of the returned instance is not tied to the lifetime of the `cose_key` as the
130 /// data of `cose_key` is copied into the `EVP_PKEY` or `EC_KEY` object.
131 pub fn from_cose_public_key(cose_key: &CoseKey) -> Result<Self> {
132 match &cose_key.kty {
133 KeyType::Assigned(iana::KeyType::EC2) => {
134 EcKey::from_cose_public_key(cose_key)?.try_into()
135 }
136 KeyType::Assigned(iana::KeyType::OKP) => {
137 let curve_type =
138 get_label_value(cose_key, Label::Int(iana::OkpKeyParameter::Crv.to_i64()))?;
139 let curve_type = match curve_type {
140 crv if crv == &Value::from(iana::EllipticCurve::Ed25519.to_i64()) => {
141 PKeyType::ED25519
142 }
143 crv if crv == &Value::from(iana::EllipticCurve::X25519.to_i64()) => {
144 PKeyType::X25519
145 }
146 crv => {
147 error!("Unsupported curve type in OKP COSE key: {:?}", crv);
148 return Err(Error::Unimplemented);
149 }
150 };
151 let x = get_label_value_as_bytes(
152 cose_key,
153 Label::Int(iana::OkpKeyParameter::X.to_i64()),
154 )?;
155 Self::new_raw_public_key(x, curve_type)
156 }
157 kty => {
158 error!("Unsupported key type in COSE key: {:?}", kty);
159 Err(Error::Unimplemented)
160 }
161 }
162 }
163
Alice Wang7468ae42023-11-30 10:20:36 +0000164 /// Verifies the given `signature` of the `message` using the current public key.
165 ///
166 /// The `message` will be hashed using the given `digester` before verification.
167 ///
168 /// For algorithms like Ed25519 that do not use pre-hashed inputs, the `digester` should
169 /// be `None`.
170 pub fn verify(
171 &self,
172 signature: &[u8],
173 message: &[u8],
174 digester: Option<Digester>,
175 ) -> Result<()> {
176 let mut digester_context = DigesterContext::new()?;
177 // The `EVP_PKEY_CTX` is set to null as this function does not collect the context
178 // during the verification.
179 let pkey_context = ptr::null_mut();
180 let engine = ptr::null_mut(); // Use the default engine.
181 let ret =
182 // SAFETY: All the non-null parameters passed to this function have been properly
183 // initialized as required in the BoringSSL spec.
184 unsafe {
185 EVP_DigestVerifyInit(
186 digester_context.as_mut_ptr(),
187 pkey_context,
188 digester.map_or(ptr::null(), |d| d.0),
189 engine,
190 self.pkey.as_ptr(),
191 )
192 };
193 check_int_result(ret, ApiName::EVP_DigestVerifyInit)?;
194
195 // SAFETY: The function only reads from the given slices within their bounds.
196 // The `EVP_MD_CTX` is successfully initialized before this call.
197 let ret = unsafe {
198 EVP_DigestVerify(
199 digester_context.as_mut_ptr(),
200 signature.as_ptr(),
201 signature.len(),
202 message.as_ptr(),
203 message.len(),
204 )
205 };
206 check_int_result(ret, ApiName::EVP_DigestVerify)
207 }
208}
209
210/// Type of the keys supported by `PKey`.
211///
212/// It is a wrapper of the `EVP_PKEY_*` macros defined BoringSSL evp.h, which are the
213/// NID values of the corresponding keys.
214#[derive(Debug, Copy, Clone, PartialEq, Eq)]
215pub struct PKeyType(i32);
216
217impl PKeyType {
218 /// EVP_PKEY_X25519 / NID_X25519
219 pub const X25519: PKeyType = PKeyType(EVP_PKEY_X25519);
220 /// EVP_PKEY_ED25519 / NID_ED25519
221 pub const ED25519: PKeyType = PKeyType(EVP_PKEY_ED25519);
Alice Wang600ea5b2023-11-17 15:12:16 +0000222}