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