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