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