// Copyright 2022, The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Implementations of [`kmr_common::crypto`] traits based on BoringSSL. #![no_std] extern crate alloc; use alloc::string::ToString; use kmr_common::Error; use kmr_wire::keymint::{Digest, ErrorCode}; use log::error; use openssl::hash::MessageDigest; #[cfg(soong)] // There is no OpenSSL CMAC API that is available in both BoringSSL for Android (which has `cmac.h` // functions but not `EVP_PKEY_CMAC` functionality) and in tip OpenSSL (which has `EVP_PKEY_CMAC` // functionality but which has removed `cmac.h`). So only build AES-CMAC for Android. pub mod aes_cmac; pub mod aes; pub mod des; pub mod ec; pub mod eq; pub mod hmac; pub mod rng; pub mod rsa; pub mod sha256; #[cfg(soong)] mod err; #[cfg(soong)] use err::*; #[cfg(test)] mod tests; mod types; /// Map an OpenSSL `ErrorStack` into a KeyMint [`ErrorCode`] value. pub(crate) fn map_openssl_errstack(errs: &openssl::error::ErrorStack) -> ErrorCode { let errors = errs.errors(); if errors.is_empty() { error!("BoringSSL error requested but none available!"); return ErrorCode::BoringSslError; } let err = &errors[0]; // safe: length checked above map_openssl_err(err) } /// Stub function for mapping an OpenSSL `ErrorStack` into a KeyMint [`ErrorCode`] value. #[cfg(not(soong))] fn map_openssl_err(_err: &openssl::error::Error) -> ErrorCode { ErrorCode::BoringSslError } /// Macro to auto-generate error mapping around invocations of `openssl` methods. /// An invocation like: /// /// ```ignore /// let x = ossl!(y.func(a, b))?; /// ``` /// /// will map to: /// /// ```ignore /// let x = y.func(a, b).map_err(openssl_err!("failed to perform: y.func(a, b)"))?; /// ``` #[macro_export] macro_rules! ossl { { $e:expr } => { $e.map_err(openssl_err!(concat!("failed to perform: ", stringify!($e)))) } } /// Macro to emit a closure that builds an [`Error::Hal`] instance, based on an /// openssl `ErrorStack` together with a format-like message. #[macro_export] macro_rules! openssl_err { { $($arg:tt)+ } => { |e| kmr_common::Error::Hal( $crate::map_openssl_errstack(&e), alloc::format!("{}:{}: {}: {:?}", file!(), line!(), format_args!($($arg)+), e) ) }; } /// Macro to emit a closure that builds an [`Error::Hal`] instance, based on an openssl `ErrorStack` /// together with a format-like message, plus default `ErrorCode` to be used if no OpenSSL error is /// available. #[macro_export] macro_rules! openssl_err_or { { $default:ident, $($arg:tt)+ } => { |e| { let errors = e.errors(); let errcode = if errors.is_empty() { kmr_wire::keymint::ErrorCode::$default } else { $crate::map_openssl_err(&errors[0]) // safe: length checked above }; kmr_common::Error::Hal( errcode, alloc::format!("{}:{}: {}: {:?}", file!(), line!(), format_args!($($arg)+), e) ) } }; } /// Macro to emit an [`Error`] indicating allocation failure at the current location. #[macro_export] macro_rules! malloc_err { {} => { kmr_common::Error::Alloc(concat!(file!(), ":", line!(), ": BoringSSL allocation failed")) }; } /// Translate the most recent OpenSSL error into [`Error`]. fn openssl_last_err() -> Error { from_openssl_err(openssl::error::ErrorStack::get()) } /// Translate a returned `openssl` error into [`Error`]. fn from_openssl_err(errs: openssl::error::ErrorStack) -> Error { Error::Hal(map_openssl_errstack(&errs), "OpenSSL failure".to_string()) } /// Translate a [`keymint::Digest`] into an OpenSSL [`MessageDigest`]. fn digest_into_openssl(digest: Digest) -> Option { match digest { Digest::None => None, Digest::Md5 => Some(MessageDigest::md5()), Digest::Sha1 => Some(MessageDigest::sha1()), Digest::Sha224 => Some(MessageDigest::sha224()), Digest::Sha256 => Some(MessageDigest::sha256()), Digest::Sha384 => Some(MessageDigest::sha384()), Digest::Sha512 => Some(MessageDigest::sha512()), } } #[inline] fn cvt_p(r: *mut T) -> Result<*mut T, Error> { if r.is_null() { Err(openssl_last_err()) } else { Ok(r) } } #[inline] fn cvt(r: libc::c_int) -> Result { if r <= 0 { Err(openssl_last_err()) } else { Ok(r) } }