blob: 719bb1d4416c03c9e86ad4447ffec6877039bef6 [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 Wangdd29c5d2023-12-07 09:56:23 +000020use crate::util::{check_int_result, to_call_failed_error};
Alice Wang600ea5b2023-11-17 15:12:16 +000021use alloc::vec::Vec;
Alice Wangbe7a4b12023-12-01 11:53:36 +000022use bssl_avf_error::{ApiName, Error, Result};
Maurice Lam0322b8c2023-12-18 22:13:48 +000023use bssl_sys::{
Alice Wang7468ae42023-11-30 10:20:36 +000024 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,
Alice Wang600ea5b2023-11-17 15:12:16 +000027};
Alice Wangdd29c5d2023-12-07 09:56:23 +000028use cbor_util::{get_label_value, get_label_value_as_bytes};
Alice Wangbe7a4b12023-12-01 11:53:36 +000029use ciborium::Value;
Alice Wang7468ae42023-11-30 10:20:36 +000030use core::ptr::{self, NonNull};
Alice Wangbe7a4b12023-12-01 11:53:36 +000031use coset::{
32 iana::{self, EnumI64},
33 CoseKey, KeyType, Label,
34};
35use log::error;
Alice Wang600ea5b2023-11-17 15:12:16 +000036
37/// Wrapper of an `EVP_PKEY` object, representing a public or private key.
Alice Wangeb77f7d2023-12-01 09:13:58 +000038pub struct PKey {
Alice Wang600ea5b2023-11-17 15:12:16 +000039 pkey: NonNull<EVP_PKEY>,
Alice Wang7468ae42023-11-30 10:20:36 +000040 /// If this struct owns the inner EC key, the inner EC key should remain valid as
Alice Wang600ea5b2023-11-17 15:12:16 +000041 /// long as the pointer to `EVP_PKEY` is valid.
Alice Wang7468ae42023-11-30 10:20:36 +000042 _inner_ec_key: Option<EcKey>,
Alice Wang600ea5b2023-11-17 15:12:16 +000043}
44
Alice Wangeb77f7d2023-12-01 09:13:58 +000045impl Drop for PKey {
Alice Wang600ea5b2023-11-17 15:12:16 +000046 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`.
54fn new_pkey() -> Result<NonNull<EVP_PKEY>> {
55 // SAFETY: The returned pointer is checked below.
56 let key = unsafe { EVP_PKEY_new() };
Alice Wangf6e02272024-03-20 10:11:30 +000057 NonNull::new(key).ok_or_else(|| to_call_failed_error(ApiName::EVP_PKEY_new))
Alice Wang600ea5b2023-11-17 15:12:16 +000058}
59
Alice Wangeb77f7d2023-12-01 09:13:58 +000060impl TryFrom<EcKey> for PKey {
Alice Wang600ea5b2023-11-17 15:12:16 +000061 type Error = bssl_avf_error::Error;
62
63 fn try_from(key: EcKey) -> Result<Self> {
64 let pkey = new_pkey()?;
Alice Wang7468ae42023-11-30 10:20:36 +000065 // SAFETY: The function only sets the inner EC key of the initialized and
Alice Wang600ea5b2023-11-17 15:12:16 +000066 // 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)?;
Alice Wang7468ae42023-11-30 10:20:36 +000072 Ok(Self { pkey, _inner_ec_key: Some(key) })
Alice Wang600ea5b2023-11-17 15:12:16 +000073 }
74}
75
Alice Wangeb77f7d2023-12-01 09:13:58 +000076impl PKey {
Alice Wang600ea5b2023-11-17 15:12:16 +000077 /// 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
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()) };
Alice Wangf6e02272024-03-20 10:11:30 +000097 Ok(buf.get(0..len).ok_or_else(|| to_call_failed_error(ApiName::CBB_len))?.to_vec())
Alice Wang600ea5b2023-11-17 15:12:16 +000098 }
Alice Wang7468ae42023-11-30 10:20:36 +000099
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.
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 };
Alice Wangf6e02272024-03-20 10:11:30 +0000121 let pkey = NonNull::new(pkey)
122 .ok_or_else(|| to_call_failed_error(ApiName::EVP_PKEY_new_raw_public_key))?;
Alice Wang7468ae42023-11-30 10:20:36 +0000123 Ok(Self { pkey, _inner_ec_key: None })
124 }
125
Alice Wangbe7a4b12023-12-01 11:53:36 +0000126 /// 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.
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
Alice Wang7468ae42023-11-30 10:20:36 +0000163 /// 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`.
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)]
214pub struct PKeyType(i32);
215
216impl 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);
Alice Wang600ea5b2023-11-17 15:12:16 +0000221}