1 // 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
17 use crate::cbb::CbbFixed;
18 use crate::digest::{Digester, DigesterContext};
19 use crate::ec_key::EcKey;
20 use crate::util::{check_int_result, to_call_failed_error};
21 use alloc::vec::Vec;
22 use bssl_avf_error::{ApiName, Error, Result};
23 use bssl_sys::{
24 CBB_flush, CBB_len, EVP_DigestVerify, EVP_DigestVerifyInit, EVP_PKEY_free, EVP_PKEY_new,
25 EVP_PKEY_new_raw_public_key, EVP_PKEY_set1_EC_KEY, EVP_marshal_public_key, EVP_PKEY,
26 EVP_PKEY_ED25519, EVP_PKEY_X25519,
27 };
28 use cbor_util::{get_label_value, get_label_value_as_bytes};
29 use ciborium::Value;
30 use core::ptr::{self, NonNull};
31 use coset::{
32 iana::{self, EnumI64},
33 CoseKey, KeyType, Label,
34 };
35 use log::error;
36
37 /// Wrapper of an `EVP_PKEY` object, representing a public or private key.
38 pub struct PKey {
39 pkey: NonNull<EVP_PKEY>,
40 /// If this struct owns the inner EC key, the inner EC key should remain valid as
41 /// long as the pointer to `EVP_PKEY` is valid.
42 _inner_ec_key: Option<EcKey>,
43 }
44
45 impl Drop for PKey {
drop(&mut self)46 fn drop(&mut self) {
47 // SAFETY: It is safe because `EVP_PKEY` has been allocated by BoringSSL and isn't
48 // used after this.
49 unsafe { EVP_PKEY_free(self.pkey.as_ptr()) }
50 }
51 }
52
53 /// Creates a new empty `EVP_PKEY`.
new_pkey() -> Result<NonNull<EVP_PKEY>>54 fn new_pkey() -> Result<NonNull<EVP_PKEY>> {
55 // SAFETY: The returned pointer is checked below.
56 let key = unsafe { EVP_PKEY_new() };
57 NonNull::new(key).ok_or_else(|| to_call_failed_error(ApiName::EVP_PKEY_new))
58 }
59
60 impl TryFrom<EcKey> for PKey {
61 type Error = bssl_avf_error::Error;
62
try_from(key: EcKey) -> Result<Self>63 fn try_from(key: EcKey) -> Result<Self> {
64 let pkey = new_pkey()?;
65 // SAFETY: The function only sets the inner EC key of the initialized and
66 // non-null `EVP_PKEY` to point to the given `EC_KEY`. It only reads from
67 // and writes to the initialized `EVP_PKEY`.
68 // Since this struct owns the inner key, the inner key remains valid as
69 // long as `EVP_PKEY` is valid.
70 let ret = unsafe { EVP_PKEY_set1_EC_KEY(pkey.as_ptr(), key.0.as_ptr()) };
71 check_int_result(ret, ApiName::EVP_PKEY_set1_EC_KEY)?;
72 Ok(Self { pkey, _inner_ec_key: Some(key) })
73 }
74 }
75
76 impl PKey {
77 /// Returns a DER-encoded SubjectPublicKeyInfo structure as specified
78 /// in RFC 5280 s4.1.2.7:
79 ///
80 /// https://www.rfc-editor.org/rfc/rfc5280.html#section-4.1.2.7
subject_public_key_info(&self) -> Result<Vec<u8>>81 pub fn subject_public_key_info(&self) -> Result<Vec<u8>> {
82 const CAPACITY: usize = 256;
83 let mut buf = [0u8; CAPACITY];
84 let mut cbb = CbbFixed::new(buf.as_mut());
85 // SAFETY: The function only write bytes to the buffer managed by the valid `CBB`.
86 // The inner key in `EVP_PKEY` was set to a valid key when the object was created.
87 // As this struct owns the inner key, the inner key is guaranteed to be valid
88 // throughout the execution of the function.
89 let ret = unsafe { EVP_marshal_public_key(cbb.as_mut(), self.pkey.as_ptr()) };
90 check_int_result(ret, ApiName::EVP_marshal_public_key)?;
91 // SAFETY: This is safe because the CBB pointer is a valid pointer initialized with
92 // `CBB_init_fixed()`.
93 check_int_result(unsafe { CBB_flush(cbb.as_mut()) }, ApiName::CBB_flush)?;
94 // SAFETY: This is safe because the CBB pointer is initialized with `CBB_init_fixed()`,
95 // and it has been flushed, thus it has no active children.
96 let len = unsafe { CBB_len(cbb.as_ref()) };
97 Ok(buf.get(0..len).ok_or_else(|| to_call_failed_error(ApiName::CBB_len))?.to_vec())
98 }
99
100 /// This function takes a raw public key data slice and creates a `PKey` instance wrapping
101 /// a freshly allocated `EVP_PKEY` object from it.
102 ///
103 /// The lifetime of the returned instance is not tied to the lifetime of the raw public
104 /// key slice because the raw data is copied into the `EVP_PKEY` object.
105 ///
106 /// Currently the only supported raw formats are X25519 and Ed25519, where the formats
107 /// are specified in RFC 7748 and RFC 8032 respectively.
new_raw_public_key(raw_public_key: &[u8], type_: PKeyType) -> Result<Self>108 pub fn new_raw_public_key(raw_public_key: &[u8], type_: PKeyType) -> Result<Self> {
109 let engine = ptr::null_mut(); // Engine is not used.
110 let pkey =
111 // SAFETY: The function only reads from the given raw public key within its bounds.
112 // The returned pointer is checked below.
113 unsafe {
114 EVP_PKEY_new_raw_public_key(
115 type_.0,
116 engine,
117 raw_public_key.as_ptr(),
118 raw_public_key.len(),
119 )
120 };
121 let pkey = NonNull::new(pkey)
122 .ok_or_else(|| to_call_failed_error(ApiName::EVP_PKEY_new_raw_public_key))?;
123 Ok(Self { pkey, _inner_ec_key: None })
124 }
125
126 /// Creates a `PKey` from the given `cose_key`.
127 ///
128 /// The lifetime of the returned instance is not tied to the lifetime of the `cose_key` as the
129 /// data of `cose_key` is copied into the `EVP_PKEY` or `EC_KEY` object.
from_cose_public_key(cose_key: &CoseKey) -> Result<Self>130 pub fn from_cose_public_key(cose_key: &CoseKey) -> Result<Self> {
131 match &cose_key.kty {
132 KeyType::Assigned(iana::KeyType::EC2) => {
133 EcKey::from_cose_public_key(cose_key)?.try_into()
134 }
135 KeyType::Assigned(iana::KeyType::OKP) => {
136 let curve_type =
137 get_label_value(cose_key, Label::Int(iana::OkpKeyParameter::Crv.to_i64()))?;
138 let curve_type = match curve_type {
139 crv if crv == &Value::from(iana::EllipticCurve::Ed25519.to_i64()) => {
140 PKeyType::ED25519
141 }
142 crv if crv == &Value::from(iana::EllipticCurve::X25519.to_i64()) => {
143 PKeyType::X25519
144 }
145 crv => {
146 error!("Unsupported curve type in OKP COSE key: {:?}", crv);
147 return Err(Error::Unimplemented);
148 }
149 };
150 let x = get_label_value_as_bytes(
151 cose_key,
152 Label::Int(iana::OkpKeyParameter::X.to_i64()),
153 )?;
154 Self::new_raw_public_key(x, curve_type)
155 }
156 kty => {
157 error!("Unsupported key type in COSE key: {:?}", kty);
158 Err(Error::Unimplemented)
159 }
160 }
161 }
162
163 /// Verifies the given `signature` of the `message` using the current public key.
164 ///
165 /// The `message` will be hashed using the given `digester` before verification.
166 ///
167 /// For algorithms like Ed25519 that do not use pre-hashed inputs, the `digester` should
168 /// be `None`.
verify( &self, signature: &[u8], message: &[u8], digester: Option<Digester>, ) -> Result<()>169 pub fn verify(
170 &self,
171 signature: &[u8],
172 message: &[u8],
173 digester: Option<Digester>,
174 ) -> Result<()> {
175 let mut digester_context = DigesterContext::new()?;
176 // The `EVP_PKEY_CTX` is set to null as this function does not collect the context
177 // during the verification.
178 let pkey_context = ptr::null_mut();
179 let engine = ptr::null_mut(); // Use the default engine.
180 let ret =
181 // SAFETY: All the non-null parameters passed to this function have been properly
182 // initialized as required in the BoringSSL spec.
183 unsafe {
184 EVP_DigestVerifyInit(
185 digester_context.as_mut_ptr(),
186 pkey_context,
187 digester.map_or(ptr::null(), |d| d.0),
188 engine,
189 self.pkey.as_ptr(),
190 )
191 };
192 check_int_result(ret, ApiName::EVP_DigestVerifyInit)?;
193
194 // SAFETY: The function only reads from the given slices within their bounds.
195 // The `EVP_MD_CTX` is successfully initialized before this call.
196 let ret = unsafe {
197 EVP_DigestVerify(
198 digester_context.as_mut_ptr(),
199 signature.as_ptr(),
200 signature.len(),
201 message.as_ptr(),
202 message.len(),
203 )
204 };
205 check_int_result(ret, ApiName::EVP_DigestVerify)
206 }
207 }
208
209 /// Type of the keys supported by `PKey`.
210 ///
211 /// It is a wrapper of the `EVP_PKEY_*` macros defined BoringSSL evp.h, which are the
212 /// NID values of the corresponding keys.
213 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
214 pub struct PKeyType(i32);
215
216 impl PKeyType {
217 /// EVP_PKEY_X25519 / NID_X25519
218 pub const X25519: PKeyType = PKeyType(EVP_PKEY_X25519);
219 /// EVP_PKEY_ED25519 / NID_ED25519
220 pub const ED25519: PKeyType = PKeyType(EVP_PKEY_ED25519);
221 }
222