xref: /aosp_15_r20/system/keymint/boringssl/src/lib.rs (revision 9860b7637a5f185913c70aa0caabe3ecb78441e4)
1 // Copyright 2022, 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 //! Implementations of [`kmr_common::crypto`] traits based on BoringSSL.
16 #![no_std]
17 
18 extern crate alloc;
19 
20 use alloc::string::ToString;
21 use kmr_common::Error;
22 use kmr_wire::keymint::{Digest, ErrorCode};
23 use log::error;
24 use openssl::hash::MessageDigest;
25 
26 #[cfg(soong)]
27 // There is no OpenSSL CMAC API that is available in both BoringSSL for Android (which has `cmac.h`
28 // functions but not `EVP_PKEY_CMAC` functionality) and in tip OpenSSL (which has `EVP_PKEY_CMAC`
29 // functionality but which has removed `cmac.h`).  So only build AES-CMAC for Android.
30 pub mod aes_cmac;
31 
32 pub mod aes;
33 pub mod des;
34 pub mod ec;
35 pub mod eq;
36 pub mod hmac;
37 pub mod rng;
38 pub mod rsa;
39 pub mod sha256;
40 
41 #[cfg(soong)]
42 mod err;
43 #[cfg(soong)]
44 use err::*;
45 
46 #[cfg(test)]
47 mod tests;
48 
49 mod types;
50 
51 /// Map an OpenSSL `ErrorStack` into a KeyMint [`ErrorCode`] value.
map_openssl_errstack(errs: &openssl::error::ErrorStack) -> ErrorCode52 pub(crate) fn map_openssl_errstack(errs: &openssl::error::ErrorStack) -> ErrorCode {
53     let errors = errs.errors();
54     if errors.is_empty() {
55         error!("BoringSSL error requested but none available!");
56         return ErrorCode::BoringSslError;
57     }
58     let err = &errors[0]; // safe: length checked above
59     map_openssl_err(err)
60 }
61 
62 /// Stub function for mapping an OpenSSL `ErrorStack` into a KeyMint [`ErrorCode`] value.
63 #[cfg(not(soong))]
map_openssl_err(_err: &openssl::error::Error) -> ErrorCode64 fn map_openssl_err(_err: &openssl::error::Error) -> ErrorCode {
65     ErrorCode::BoringSslError
66 }
67 
68 /// Macro to auto-generate error mapping around invocations of `openssl` methods.
69 /// An invocation like:
70 ///
71 /// ```ignore
72 /// let x = ossl!(y.func(a, b))?;
73 /// ```
74 ///
75 /// will map to:
76 ///
77 /// ```ignore
78 /// let x = y.func(a, b).map_err(openssl_err!("failed to perform: y.func(a, b)"))?;
79 /// ```
80 #[macro_export]
81 macro_rules! ossl {
82     { $e:expr } => {
83         $e.map_err(openssl_err!(concat!("failed to perform: ", stringify!($e))))
84     }
85 }
86 
87 /// Macro to emit a closure that builds an [`Error::Hal`] instance, based on an
88 /// openssl `ErrorStack` together with a format-like message.
89 #[macro_export]
90 macro_rules! openssl_err {
91     { $($arg:tt)+ } => {
92         |e| kmr_common::Error::Hal(
93             $crate::map_openssl_errstack(&e),
94             alloc::format!("{}:{}: {}: {:?}", file!(), line!(), format_args!($($arg)+), e)
95         )
96     };
97 }
98 
99 /// Macro to emit a closure that builds an [`Error::Hal`] instance, based on an openssl `ErrorStack`
100 /// together with a format-like message, plus default `ErrorCode` to be used if no OpenSSL error is
101 /// available.
102 #[macro_export]
103 macro_rules! openssl_err_or {
104     { $default:ident, $($arg:tt)+ } => {
105         |e| {
106             let errors = e.errors();
107             let errcode = if errors.is_empty() {
108                 kmr_wire::keymint::ErrorCode::$default
109             } else {
110                 $crate::map_openssl_err(&errors[0]) // safe: length checked above
111             };
112             kmr_common::Error::Hal(
113                 errcode,
114                 alloc::format!("{}:{}: {}: {:?}", file!(), line!(), format_args!($($arg)+), e)
115             )
116         }
117     };
118 }
119 
120 /// Macro to emit an [`Error`] indicating allocation failure at the current location.
121 #[macro_export]
122 macro_rules! malloc_err {
123     {} => {
124         kmr_common::Error::Alloc(concat!(file!(), ":", line!(), ": BoringSSL allocation failed"))
125     };
126 }
127 
128 /// Translate the most recent OpenSSL error into [`Error`].
openssl_last_err() -> Error129 fn openssl_last_err() -> Error {
130     from_openssl_err(openssl::error::ErrorStack::get())
131 }
132 
133 /// Translate a returned `openssl` error into [`Error`].
from_openssl_err(errs: openssl::error::ErrorStack) -> Error134 fn from_openssl_err(errs: openssl::error::ErrorStack) -> Error {
135     Error::Hal(map_openssl_errstack(&errs), "OpenSSL failure".to_string())
136 }
137 
138 /// Translate a [`keymint::Digest`] into an OpenSSL [`MessageDigest`].
digest_into_openssl(digest: Digest) -> Option<MessageDigest>139 fn digest_into_openssl(digest: Digest) -> Option<MessageDigest> {
140     match digest {
141         Digest::None => None,
142         Digest::Md5 => Some(MessageDigest::md5()),
143         Digest::Sha1 => Some(MessageDigest::sha1()),
144         Digest::Sha224 => Some(MessageDigest::sha224()),
145         Digest::Sha256 => Some(MessageDigest::sha256()),
146         Digest::Sha384 => Some(MessageDigest::sha384()),
147         Digest::Sha512 => Some(MessageDigest::sha512()),
148     }
149 }
150 
151 #[inline]
cvt_p<T>(r: *mut T) -> Result<*mut T, Error>152 fn cvt_p<T>(r: *mut T) -> Result<*mut T, Error> {
153     if r.is_null() {
154         Err(openssl_last_err())
155     } else {
156         Ok(r)
157     }
158 }
159 
160 #[inline]
cvt(r: libc::c_int) -> Result<libc::c_int, Error>161 fn cvt(r: libc::c_int) -> Result<libc::c_int, Error> {
162     if r <= 0 {
163         Err(openssl_last_err())
164     } else {
165         Ok(r)
166     }
167 }
168