Skip to content

Commit f9aed56

Browse files
authored
Add mbedtls based hkdf (#17)
* add mbedtls based hkdf * fix patch * cargo fmt * chore: resolve review comments * chore(deps): upgrade to use mbedtls 0.12.0 * build: bump version to 0.1.0 * style: better naming for Tag::with_capacity * test patch fix * test patch fix 2 * remove patch * cleaning + add unit tests
1 parent 1efc8f6 commit f9aed56

File tree

7 files changed

+329
-63
lines changed

7 files changed

+329
-63
lines changed

Cargo.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,9 @@ members = [
55
"rustls-mbedpki-provider",
66
"rustls-mbedtls-provider-utils",
77
]
8-
default-members = ["rustls-mbedcrypto-provider", "rustls-mbedpki-provider", "rustls-mbedtls-provider-utils"]
8+
default-members = [
9+
"rustls-mbedcrypto-provider",
10+
"rustls-mbedpki-provider",
11+
"rustls-mbedtls-provider-utils",
12+
]
913
resolver = "2"

rustls-mbedcrypto-provider/Cargo.toml

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "rustls-mbedcrypto-provider"
3-
version = "0.0.1-alpha.1"
3+
version = "0.0.1"
44
edition = "2021"
55
license = "MPL-2.0"
66
description = "Mbedtls based crypto provider for rustls."
@@ -13,29 +13,19 @@ resolver = "2"
1313

1414
[dependencies]
1515
rustls = { version = "0.22.1", default-features = false }
16-
mbedtls = { version = "0.12.0-alpha.2", default-features = false, features = [
17-
"std",
18-
] }
16+
mbedtls = { version = "0.12.1", default-features = false, features = ["std"] }
1917
log = { version = "0.4.4", optional = true }
2018
webpki = { package = "rustls-webpki", version = "0.102.0", features = [
2119
"alloc",
2220
"std",
2321
], default-features = false }
24-
utils = { package = "rustls-mbedtls-provider-utils", path = "../rustls-mbedtls-provider-utils", version = "0.1.0-alpha.1" }
22+
utils = { package = "rustls-mbedtls-provider-utils", path = "../rustls-mbedtls-provider-utils", version = "0.1.0" }
2523
yasna = { version = "0.3", default-features = false, features = ["bit-vec"] }
2624
bit-vec = "0.6.3"
2725

28-
[target.'cfg(target_env = "msvc")'.dependencies]
29-
# mbedtls need feature `time` to build when targeting msvc
30-
mbedtls = { version = "0.12.0-alpha.2", default-features = false, features = [
31-
"std",
32-
"time",
33-
] }
3426

3527
[dev-dependencies]
36-
rustls = { version = "0.22.1", default-features = false, features = [
37-
"ring",
38-
] }
28+
rustls = { version = "0.22.1", default-features = false, features = ["ring"] }
3929
webpki-roots = "0.26.0"
4030
rustls-pemfile = "2"
4131
env_logger = "0.10"
@@ -59,6 +49,3 @@ path = "examples/internal/bench.rs"
5949
[package.metadata.docs.rs]
6050
all-features = true
6151
rustdoc-args = ["--cfg", "docsrs"]
62-
63-
[package.metadata.cargo_check_external_types]
64-
allowed_external_types = ["rustls_pki_types::*"]

rustls-mbedcrypto-provider/src/hmac.rs

Lines changed: 110 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77

88
use crate::log::error;
99
use alloc::boxed::Box;
10-
use alloc::vec;
11-
use alloc::vec::Vec;
1210
use rustls::crypto;
1311

1412
/// HMAC using SHA-256.
@@ -17,7 +15,7 @@ pub(crate) static HMAC_SHA256: Hmac = Hmac(&super::hash::MBED_SHA_256);
1715
/// HMAC using SHA-384.
1816
pub(crate) static HMAC_SHA384: Hmac = Hmac(&super::hash::MBED_SHA_384);
1917

20-
pub(crate) struct Hmac(&'static super::hash::Algorithm);
18+
pub(crate) struct Hmac(pub(crate) &'static super::hash::Algorithm);
2119

2220
impl crypto::hmac::Hmac for Hmac {
2321
fn with_key(&self, key: &[u8]) -> Box<dyn crypto::hmac::Key> {
@@ -29,17 +27,24 @@ impl crypto::hmac::Hmac for Hmac {
2927
}
3028
}
3129

30+
impl Hmac {
31+
#[inline]
32+
pub(crate) fn hash_algorithm(&self) -> &'static super::hash::Algorithm {
33+
self.0
34+
}
35+
}
36+
3237
struct HmacKey(MbedHmacKey);
3338

3439
impl crypto::hmac::Key for HmacKey {
35-
fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> crypto::hmac::Tag {
40+
fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> rustls::crypto::hmac::Tag {
3641
let mut ctx = self.0.starts();
3742
ctx.update(first);
3843
for m in middle {
3944
ctx.update(m);
4045
}
4146
ctx.update(last);
42-
crypto::hmac::Tag::new(&ctx.finish())
47+
ctx.finish().into()
4348
}
4449

4550
fn tag_len(&self) -> usize {
@@ -49,13 +54,12 @@ impl crypto::hmac::Key for HmacKey {
4954

5055
struct MbedHmacKey {
5156
hmac_algo: &'static super::hash::Algorithm,
52-
/// use [`crypto::hmac::Tag`] for saving key material, since they have same max size.
53-
key: crypto::hmac::Tag,
57+
key: Tag,
5458
}
5559

5660
impl MbedHmacKey {
5761
pub(crate) fn new(hmac_algo: &'static super::hash::Algorithm, key: &[u8]) -> Self {
58-
Self { hmac_algo, key: crypto::hmac::Tag::new(key) }
62+
Self { hmac_algo, key: Tag::new(key) }
5963
}
6064

6165
pub(crate) fn starts(&self) -> MbedHmacContext {
@@ -73,13 +77,13 @@ struct MbedHmacContext {
7377

7478
impl MbedHmacContext {
7579
/// Since the trait does not provider a way to return error, empty vector is returned when getting error from `mbedtls`.
76-
pub(crate) fn finish(self) -> Vec<u8> {
77-
let mut out = vec![0u8; self.hmac_algo.output_len];
78-
match self.ctx.finish(&mut out) {
80+
pub(crate) fn finish(self) -> Tag {
81+
let mut out = Tag::with_len(self.hmac_algo.output_len);
82+
match self.ctx.finish(out.as_mut()) {
7983
Ok(_) => out,
8084
Err(_err) => {
8185
error!("Failed to finish hmac, mbedtls error: {:?}", _err);
82-
vec![]
86+
Tag::with_len(0)
8387
}
8488
}
8589
}
@@ -93,3 +97,97 @@ impl MbedHmacContext {
9397
}
9498
}
9599
}
100+
101+
/// A HMAC tag, stored as a value.
102+
#[derive(Clone, PartialEq, Eq, Debug)]
103+
pub(crate) struct Tag {
104+
buf: [u8; Self::MAX_LEN],
105+
used: usize,
106+
}
107+
108+
impl Tag {
109+
/// Build a tag by copying a byte slice.
110+
///
111+
/// The slice can be up to [`Tag::MAX_LEN`] bytes in length.
112+
pub(crate) fn new(bytes: &[u8]) -> Self {
113+
let mut tag = Self { buf: [0u8; Self::MAX_LEN], used: bytes.len() };
114+
tag.buf[..tag.used].copy_from_slice(bytes);
115+
tag
116+
}
117+
118+
/// Build a tag with given capacity.
119+
///
120+
/// The slice can be up to [`Tag::MAX_LEN`] bytes in length.
121+
pub(crate) fn with_len(len: usize) -> Self {
122+
Self { buf: [0u8; Self::MAX_LEN], used: len }
123+
}
124+
125+
/// Maximum supported HMAC tag size: supports up to SHA512.
126+
pub(crate) const MAX_LEN: usize = 64;
127+
}
128+
129+
impl Drop for Tag {
130+
fn drop(&mut self) {
131+
mbedtls::zeroize(&mut self.buf)
132+
}
133+
}
134+
135+
impl AsRef<[u8]> for Tag {
136+
fn as_ref(&self) -> &[u8] {
137+
&self.buf[..self.used]
138+
}
139+
}
140+
141+
impl AsMut<[u8]> for Tag {
142+
fn as_mut(&mut self) -> &mut [u8] {
143+
&mut self.buf[..self.used]
144+
}
145+
}
146+
147+
impl From<Tag> for rustls::crypto::hmac::Tag {
148+
fn from(val: Tag) -> Self {
149+
Self::new(&val.buf[..val.used])
150+
}
151+
}
152+
153+
#[cfg(test)]
154+
mod tests {
155+
use rustls::crypto::hmac::Hmac;
156+
157+
use super::*;
158+
159+
#[test]
160+
fn test_hmac_sha256_tag_length() {
161+
let hmac = &HMAC_SHA256;
162+
let key_len = 256 / 8;
163+
let key = vec![0u8; key_len];
164+
test_hmac_tag_length_helper(hmac, &key, key_len);
165+
}
166+
167+
#[test]
168+
fn test_hmac_sha384_tag_length() {
169+
let hmac = &HMAC_SHA384;
170+
let key_len = 384 / 8;
171+
let key = vec![0u8; key_len];
172+
test_hmac_tag_length_helper(hmac, &key, key_len);
173+
}
174+
175+
fn test_hmac_tag_length_helper(hmac: &super::Hmac, key: &[u8], key_len: usize) {
176+
let hmac_key = hmac.with_key(key);
177+
assert_eq!(hmac.hash_output_len(), hmac_key.tag_len());
178+
assert_eq!(hmac.hash_output_len(), key_len);
179+
}
180+
181+
#[test]
182+
fn test_mbed_hmac_context_error() {
183+
let key_len = 256 / 8;
184+
let key = vec![0u8; key_len];
185+
let mut bad_ctx = MbedHmacContext {
186+
hmac_algo: &crate::hash::MBED_SHA_256,
187+
ctx: mbedtls::hash::Hmac::new(crate::hash::MBED_SHA_384.hash_type, &key).unwrap(),
188+
};
189+
bad_ctx.update(&[]);
190+
let tag = bad_ctx.finish();
191+
assert_eq!(tag, Tag::with_len(0));
192+
}
193+
}

0 commit comments

Comments
 (0)