rustls_mbedcrypto_provider/
hmac.rs1use crate::log::error;
9use alloc::boxed::Box;
10use rustls::crypto;
11
12pub static HMAC_SHA256: Hmac = Hmac(&super::hash::MBED_SHA_256);
14
15pub static HMAC_SHA384: Hmac = Hmac(&super::hash::MBED_SHA_384);
17
18pub struct Hmac(pub(crate) &'static super::hash::Algorithm);
20
21impl crypto::hmac::Hmac for Hmac {
22 fn with_key(&self, key: &[u8]) -> Box<dyn crypto::hmac::Key> {
23 Box::new(HmacKey(MbedHmacKey::new(self.0, key)))
24 }
25
26 fn hash_output_len(&self) -> usize {
27 self.0.output_len
28 }
29}
30
31impl Hmac {
32 #[inline]
33 pub(crate) fn hash_algorithm(&self) -> &'static super::hash::Algorithm {
34 self.0
35 }
36}
37
38struct HmacKey(MbedHmacKey);
39
40impl crypto::hmac::Key for HmacKey {
41 fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> crypto::hmac::Tag {
42 let mut ctx = self.0.starts();
43 ctx.update(first);
44 for m in middle {
45 ctx.update(m);
46 }
47 ctx.update(last);
48 ctx.finish().into()
49 }
50
51 fn tag_len(&self) -> usize {
52 self.0.hmac_algo.output_len
53 }
54}
55
56struct MbedHmacKey {
57 hmac_algo: &'static super::hash::Algorithm,
58 key: Vec<u8>,
59}
60
61impl MbedHmacKey {
62 pub(crate) fn new(hmac_algo: &'static super::hash::Algorithm, key: &[u8]) -> Self {
63 Self { hmac_algo, key: key.to_vec() }
64 }
65
66 pub(crate) fn starts(&self) -> MbedHmacContext {
67 MbedHmacContext {
68 hmac_algo: self.hmac_algo,
69 ctx: mbedtls::hash::Hmac::new(self.hmac_algo.hash_type, &self.key).expect("input validated"),
70 }
71 }
72}
73
74impl Drop for MbedHmacKey {
75 fn drop(&mut self) {
76 mbedtls::zeroize(&mut self.key)
77 }
78}
79
80struct MbedHmacContext {
81 hmac_algo: &'static super::hash::Algorithm,
82 ctx: mbedtls::hash::Hmac,
83}
84
85impl MbedHmacContext {
86 pub(crate) fn finish(self) -> Tag {
88 let mut out = Tag::with_len(self.hmac_algo.output_len);
89 match self.ctx.finish(out.as_mut()) {
90 Ok(_) => out,
91 Err(_err) => {
92 error!("Failed to finish hmac, mbedtls error: {_err:?}");
93 Tag::with_len(0)
94 }
95 }
96 }
97
98 pub(crate) fn update(&mut self, data: &[u8]) {
99 match self.ctx.update(data) {
100 Ok(_) => {}
101 Err(_err) => {
102 error!("Failed to update hmac, mbedtls error: {_err:?}");
103 }
104 }
105 }
106}
107
108#[derive(Clone, PartialEq, Eq, Debug)]
110pub(crate) struct Tag {
111 buf: [u8; Self::MAX_LEN],
112 used: usize,
113}
114
115impl Tag {
116 pub(crate) fn with_len(len: usize) -> Self {
120 Self { buf: [0u8; Self::MAX_LEN], used: len }
121 }
122
123 pub(crate) const MAX_LEN: usize = 64;
125}
126
127impl Drop for Tag {
128 fn drop(&mut self) {
129 mbedtls::zeroize(&mut self.buf)
130 }
131}
132
133impl AsRef<[u8]> for Tag {
134 fn as_ref(&self) -> &[u8] {
135 &self.buf[..self.used]
136 }
137}
138
139impl AsMut<[u8]> for Tag {
140 fn as_mut(&mut self) -> &mut [u8] {
141 &mut self.buf[..self.used]
142 }
143}
144
145impl From<Tag> for crypto::hmac::Tag {
146 fn from(val: Tag) -> Self {
147 Self::new(&val.buf[..val.used])
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use rustls::crypto::hmac::Hmac;
154
155 use super::*;
156
157 #[test]
158 fn test_hmac_sha256_tag_length() {
159 let hmac = &HMAC_SHA256;
160 let key_len = 256 / 8;
161 let key = vec![0u8; key_len];
162 test_hmac_tag_length_helper(hmac, &key, key_len);
163 }
164
165 #[test]
166 fn test_hmac_sha384_tag_length() {
167 let hmac = &HMAC_SHA384;
168 let key_len = 384 / 8;
169 let key = vec![0u8; key_len];
170 test_hmac_tag_length_helper(hmac, &key, key_len);
171 }
172
173 fn test_hmac_tag_length_helper(hmac: &super::Hmac, key: &[u8], key_len: usize) {
174 let hmac_key = hmac.with_key(key);
175 assert_eq!(hmac.hash_output_len(), hmac_key.tag_len());
176 assert_eq!(hmac.hash_output_len(), key_len);
177 }
178
179 #[test]
180 fn test_mbed_hmac_context_error() {
181 let key_len = 256 / 8;
182 let key = vec![0u8; key_len];
183 let mut bad_ctx = MbedHmacContext {
184 hmac_algo: &crate::hash::MBED_SHA_256,
185 ctx: mbedtls::hash::Hmac::new(crate::hash::MBED_SHA_384.hash_type, &key).unwrap(),
186 };
187 bad_ctx.update(&[]);
188 let tag = bad_ctx.finish();
189 assert_eq!(tag, Tag::with_len(0));
190 }
191}