1*9860b763SAndroid Build Coastguard Worker // Copyright 2022, The Android Open Source Project
2*9860b763SAndroid Build Coastguard Worker //
3*9860b763SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9860b763SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9860b763SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9860b763SAndroid Build Coastguard Worker //
7*9860b763SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*9860b763SAndroid Build Coastguard Worker //
9*9860b763SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9860b763SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9860b763SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9860b763SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9860b763SAndroid Build Coastguard Worker // limitations under the License.
14*9860b763SAndroid Build Coastguard Worker
15*9860b763SAndroid Build Coastguard Worker //! BoringSSL-based implementation of HMAC.
16*9860b763SAndroid Build Coastguard Worker use crate::types::HmacCtx;
17*9860b763SAndroid Build Coastguard Worker use crate::{malloc_err, openssl_last_err};
18*9860b763SAndroid Build Coastguard Worker use alloc::boxed::Box;
19*9860b763SAndroid Build Coastguard Worker use alloc::vec::Vec;
20*9860b763SAndroid Build Coastguard Worker #[cfg(soong)]
21*9860b763SAndroid Build Coastguard Worker use bssl_sys as ffi;
22*9860b763SAndroid Build Coastguard Worker use kmr_common::{crypto, crypto::OpaqueOr, explicit, km_err, vec_try, Error};
23*9860b763SAndroid Build Coastguard Worker use kmr_wire::keymint::Digest;
24*9860b763SAndroid Build Coastguard Worker use log::error;
25*9860b763SAndroid Build Coastguard Worker
26*9860b763SAndroid Build Coastguard Worker /// [`crypto::Hmac`] implementation based on BoringSSL.
27*9860b763SAndroid Build Coastguard Worker pub struct BoringHmac;
28*9860b763SAndroid Build Coastguard Worker
29*9860b763SAndroid Build Coastguard Worker impl crypto::Hmac for BoringHmac {
begin( &self, key: OpaqueOr<crypto::hmac::Key>, digest: Digest, ) -> Result<Box<dyn crypto::AccumulatingOperation>, Error>30*9860b763SAndroid Build Coastguard Worker fn begin(
31*9860b763SAndroid Build Coastguard Worker &self,
32*9860b763SAndroid Build Coastguard Worker key: OpaqueOr<crypto::hmac::Key>,
33*9860b763SAndroid Build Coastguard Worker digest: Digest,
34*9860b763SAndroid Build Coastguard Worker ) -> Result<Box<dyn crypto::AccumulatingOperation>, Error> {
35*9860b763SAndroid Build Coastguard Worker let key = explicit!(key)?;
36*9860b763SAndroid Build Coastguard Worker let op = BoringHmacOperation {
37*9860b763SAndroid Build Coastguard Worker // Safety: BoringSSL emits either null or a valid raw pointer, and the value is
38*9860b763SAndroid Build Coastguard Worker // immediately checked for null below.
39*9860b763SAndroid Build Coastguard Worker ctx: unsafe { HmacCtx(ffi::HMAC_CTX_new()) },
40*9860b763SAndroid Build Coastguard Worker };
41*9860b763SAndroid Build Coastguard Worker if op.ctx.0.is_null() {
42*9860b763SAndroid Build Coastguard Worker return Err(malloc_err!());
43*9860b763SAndroid Build Coastguard Worker }
44*9860b763SAndroid Build Coastguard Worker
45*9860b763SAndroid Build Coastguard Worker let digest = digest_into_openssl_ffi(digest)?;
46*9860b763SAndroid Build Coastguard Worker #[cfg(soong)]
47*9860b763SAndroid Build Coastguard Worker let key_len = key.0.len();
48*9860b763SAndroid Build Coastguard Worker #[cfg(not(soong))]
49*9860b763SAndroid Build Coastguard Worker let key_len = key.0.len() as i32;
50*9860b763SAndroid Build Coastguard Worker
51*9860b763SAndroid Build Coastguard Worker // Safety: `op.ctx` is known non-null and valid, as is the result of
52*9860b763SAndroid Build Coastguard Worker // `digest_into_openssl_ffi()`. `key_len` is length of `key.0`, which is a valid `Vec<u8>`.
53*9860b763SAndroid Build Coastguard Worker let result = unsafe {
54*9860b763SAndroid Build Coastguard Worker ffi::HMAC_Init_ex(
55*9860b763SAndroid Build Coastguard Worker op.ctx.0,
56*9860b763SAndroid Build Coastguard Worker key.0.as_ptr() as *const libc::c_void,
57*9860b763SAndroid Build Coastguard Worker key_len,
58*9860b763SAndroid Build Coastguard Worker digest,
59*9860b763SAndroid Build Coastguard Worker core::ptr::null_mut(),
60*9860b763SAndroid Build Coastguard Worker )
61*9860b763SAndroid Build Coastguard Worker };
62*9860b763SAndroid Build Coastguard Worker if result != 1 {
63*9860b763SAndroid Build Coastguard Worker error!("Failed to HMAC_Init_ex()");
64*9860b763SAndroid Build Coastguard Worker return Err(openssl_last_err());
65*9860b763SAndroid Build Coastguard Worker }
66*9860b763SAndroid Build Coastguard Worker Ok(Box::new(op))
67*9860b763SAndroid Build Coastguard Worker }
68*9860b763SAndroid Build Coastguard Worker }
69*9860b763SAndroid Build Coastguard Worker
70*9860b763SAndroid Build Coastguard Worker /// HMAC operation based on BoringSSL.
71*9860b763SAndroid Build Coastguard Worker ///
72*9860b763SAndroid Build Coastguard Worker /// This implementation uses the `unsafe` wrappers around `HMAC_*` functions directly, because
73*9860b763SAndroid Build Coastguard Worker /// BoringSSL does not support the `EVP_PKEY_HMAC` implementations that are used in the rust-openssl
74*9860b763SAndroid Build Coastguard Worker /// crate.
75*9860b763SAndroid Build Coastguard Worker pub struct BoringHmacOperation {
76*9860b763SAndroid Build Coastguard Worker // Safety: `ctx` is always non-null and valid except for initial error path in `begin()`
77*9860b763SAndroid Build Coastguard Worker ctx: HmacCtx,
78*9860b763SAndroid Build Coastguard Worker }
79*9860b763SAndroid Build Coastguard Worker
80*9860b763SAndroid Build Coastguard Worker impl core::ops::Drop for BoringHmacOperation {
drop(&mut self)81*9860b763SAndroid Build Coastguard Worker fn drop(&mut self) {
82*9860b763SAndroid Build Coastguard Worker // Safety: `self.ctx` might be null (in the error path when `ffi::HMAC_CTX_new` fails)
83*9860b763SAndroid Build Coastguard Worker // but `ffi::HMAC_CTX_free` copes with null.
84*9860b763SAndroid Build Coastguard Worker unsafe {
85*9860b763SAndroid Build Coastguard Worker ffi::HMAC_CTX_free(self.ctx.0);
86*9860b763SAndroid Build Coastguard Worker }
87*9860b763SAndroid Build Coastguard Worker }
88*9860b763SAndroid Build Coastguard Worker }
89*9860b763SAndroid Build Coastguard Worker
90*9860b763SAndroid Build Coastguard Worker impl crypto::AccumulatingOperation for BoringHmacOperation {
update(&mut self, data: &[u8]) -> Result<(), Error>91*9860b763SAndroid Build Coastguard Worker fn update(&mut self, data: &[u8]) -> Result<(), Error> {
92*9860b763SAndroid Build Coastguard Worker // Safety: `self.ctx` is non-null and valid, and `data` is a valid slice.
93*9860b763SAndroid Build Coastguard Worker let result = unsafe { ffi::HMAC_Update(self.ctx.0, data.as_ptr(), data.len()) };
94*9860b763SAndroid Build Coastguard Worker if result != 1 {
95*9860b763SAndroid Build Coastguard Worker return Err(openssl_last_err());
96*9860b763SAndroid Build Coastguard Worker }
97*9860b763SAndroid Build Coastguard Worker Ok(())
98*9860b763SAndroid Build Coastguard Worker }
99*9860b763SAndroid Build Coastguard Worker
finish(self: Box<Self>) -> Result<Vec<u8>, Error>100*9860b763SAndroid Build Coastguard Worker fn finish(self: Box<Self>) -> Result<Vec<u8>, Error> {
101*9860b763SAndroid Build Coastguard Worker let mut output_len = ffi::EVP_MAX_MD_SIZE as u32;
102*9860b763SAndroid Build Coastguard Worker let mut output = vec_try![0; ffi::EVP_MAX_MD_SIZE as usize]?;
103*9860b763SAndroid Build Coastguard Worker
104*9860b763SAndroid Build Coastguard Worker // Safety: `self.ctx` is non-null and valid; `output_len` is correct size of `output`
105*9860b763SAndroid Build Coastguard Worker // buffer.
106*9860b763SAndroid Build Coastguard Worker let result = unsafe {
107*9860b763SAndroid Build Coastguard Worker // (force line break for safety lint limitation)
108*9860b763SAndroid Build Coastguard Worker ffi::HMAC_Final(self.ctx.0, output.as_mut_ptr(), &mut output_len as *mut u32)
109*9860b763SAndroid Build Coastguard Worker };
110*9860b763SAndroid Build Coastguard Worker if result != 1 {
111*9860b763SAndroid Build Coastguard Worker return Err(openssl_last_err());
112*9860b763SAndroid Build Coastguard Worker }
113*9860b763SAndroid Build Coastguard Worker output.truncate(output_len as usize);
114*9860b763SAndroid Build Coastguard Worker Ok(output)
115*9860b763SAndroid Build Coastguard Worker }
116*9860b763SAndroid Build Coastguard Worker }
117*9860b763SAndroid Build Coastguard Worker
118*9860b763SAndroid Build Coastguard Worker /// Translate a [`keymint::Digest`] into a raw [`ffi::EVD_MD`].
digest_into_openssl_ffi(digest: Digest) -> Result<*const ffi::EVP_MD, Error>119*9860b763SAndroid Build Coastguard Worker fn digest_into_openssl_ffi(digest: Digest) -> Result<*const ffi::EVP_MD, Error> {
120*9860b763SAndroid Build Coastguard Worker // Safety: all of the `EVP_<digest>` functions return a non-null valid pointer.
121*9860b763SAndroid Build Coastguard Worker unsafe {
122*9860b763SAndroid Build Coastguard Worker match digest {
123*9860b763SAndroid Build Coastguard Worker Digest::Md5 => Ok(ffi::EVP_md5()),
124*9860b763SAndroid Build Coastguard Worker Digest::Sha1 => Ok(ffi::EVP_sha1()),
125*9860b763SAndroid Build Coastguard Worker Digest::Sha224 => Ok(ffi::EVP_sha224()),
126*9860b763SAndroid Build Coastguard Worker Digest::Sha256 => Ok(ffi::EVP_sha256()),
127*9860b763SAndroid Build Coastguard Worker Digest::Sha384 => Ok(ffi::EVP_sha384()),
128*9860b763SAndroid Build Coastguard Worker Digest::Sha512 => Ok(ffi::EVP_sha512()),
129*9860b763SAndroid Build Coastguard Worker d => Err(km_err!(UnsupportedDigest, "unknown digest {:?}", d)),
130*9860b763SAndroid Build Coastguard Worker }
131*9860b763SAndroid Build Coastguard Worker }
132*9860b763SAndroid Build Coastguard Worker }
133