Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mbedtls based hkdf #17

Merged
merged 12 commits into from
Dec 13, 2023
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@ members = [
"rustls-mbedpki-provider",
"rustls-mbedtls-provider-utils",
]
default-members = ["rustls-mbedcrypto-provider", "rustls-mbedpki-provider", "rustls-mbedtls-provider-utils"]
default-members = [
"rustls-mbedcrypto-provider",
"rustls-mbedpki-provider",
"rustls-mbedtls-provider-utils",
]
resolver = "2"
21 changes: 4 additions & 17 deletions rustls-mbedcrypto-provider/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rustls-mbedcrypto-provider"
version = "0.0.1-alpha.1"
version = "0.0.1"
edition = "2021"
license = "MPL-2.0"
description = "Mbedtls based crypto provider for rustls."
Expand All @@ -13,29 +13,19 @@ resolver = "2"

[dependencies]
rustls = { version = "0.22.1", default-features = false }
mbedtls = { version = "0.12.0-alpha.2", default-features = false, features = [
"std",
] }
mbedtls = { version = "0.12.1", default-features = false, features = ["std"] }
log = { version = "0.4.4", optional = true }
webpki = { package = "rustls-webpki", version = "0.102.0", features = [
"alloc",
"std",
], default-features = false }
utils = { package = "rustls-mbedtls-provider-utils", path = "../rustls-mbedtls-provider-utils", version = "0.1.0-alpha.1" }
utils = { package = "rustls-mbedtls-provider-utils", path = "../rustls-mbedtls-provider-utils", version = "0.1.0" }
yasna = { version = "0.3", default-features = false, features = ["bit-vec"] }
bit-vec = "0.6.3"

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

[dev-dependencies]
rustls = { version = "0.22.1", default-features = false, features = [
"ring",
] }
rustls = { version = "0.22.1", default-features = false, features = ["ring"] }
webpki-roots = "0.26.0"
rustls-pemfile = "2"
env_logger = "0.10"
Expand All @@ -59,6 +49,3 @@ path = "examples/internal/bench.rs"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[package.metadata.cargo_check_external_types]
allowed_external_types = ["rustls_pki_types::*"]
122 changes: 110 additions & 12 deletions rustls-mbedcrypto-provider/src/hmac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@

use crate::log::error;
use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;
use rustls::crypto;

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

pub(crate) struct Hmac(&'static super::hash::Algorithm);
pub(crate) struct Hmac(pub(crate) &'static super::hash::Algorithm);

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

impl Hmac {
#[inline]
pub(crate) fn hash_algorithm(&self) -> &'static super::hash::Algorithm {
self.0
}
}

struct HmacKey(MbedHmacKey);

impl crypto::hmac::Key for HmacKey {
fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> crypto::hmac::Tag {
fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> rustls::crypto::hmac::Tag {
let mut ctx = self.0.starts();
ctx.update(first);
for m in middle {
ctx.update(m);
}
ctx.update(last);
crypto::hmac::Tag::new(&ctx.finish())
ctx.finish().into()
}

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

struct MbedHmacKey {
hmac_algo: &'static super::hash::Algorithm,
/// use [`crypto::hmac::Tag`] for saving key material, since they have same max size.
key: crypto::hmac::Tag,
key: Tag,
}

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

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

impl MbedHmacContext {
/// Since the trait does not provider a way to return error, empty vector is returned when getting error from `mbedtls`.
pub(crate) fn finish(self) -> Vec<u8> {
let mut out = vec![0u8; self.hmac_algo.output_len];
match self.ctx.finish(&mut out) {
pub(crate) fn finish(self) -> Tag {
let mut out = Tag::with_len(self.hmac_algo.output_len);
match self.ctx.finish(out.as_mut()) {
Ok(_) => out,
Err(_err) => {
error!("Failed to finish hmac, mbedtls error: {:?}", _err);
vec![]
Tag::with_len(0)
}
}
}
Expand All @@ -93,3 +97,97 @@ impl MbedHmacContext {
}
}
}

/// A HMAC tag, stored as a value.
#[derive(Clone, PartialEq, Eq, Debug)]
pub(crate) struct Tag {
buf: [u8; Self::MAX_LEN],
Taowyoo marked this conversation as resolved.
Show resolved Hide resolved
used: usize,
}

impl Tag {
/// Build a tag by copying a byte slice.
///
/// The slice can be up to [`Tag::MAX_LEN`] bytes in length.
pub(crate) fn new(bytes: &[u8]) -> Self {
let mut tag = Self { buf: [0u8; Self::MAX_LEN], used: bytes.len() };
tag.buf[..tag.used].copy_from_slice(bytes);
tag
}

/// Build a tag with given capacity.
///
/// The slice can be up to [`Tag::MAX_LEN`] bytes in length.
pub(crate) fn with_len(len: usize) -> Self {
Self { buf: [0u8; Self::MAX_LEN], used: len }
}

/// Maximum supported HMAC tag size: supports up to SHA512.
pub(crate) const MAX_LEN: usize = 64;
}

impl Drop for Tag {
fn drop(&mut self) {
mbedtls::zeroize(&mut self.buf)
}
}

impl AsRef<[u8]> for Tag {
fn as_ref(&self) -> &[u8] {
&self.buf[..self.used]
}
}

impl AsMut<[u8]> for Tag {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.buf[..self.used]
}
}

impl From<Tag> for rustls::crypto::hmac::Tag {
fn from(val: Tag) -> Self {
Self::new(&val.buf[..val.used])
}
}

#[cfg(test)]
mod tests {
use rustls::crypto::hmac::Hmac;

use super::*;

#[test]
fn test_hmac_sha256_tag_length() {
let hmac = &HMAC_SHA256;
let key_len = 256 / 8;
let key = vec![0u8; key_len];
test_hmac_tag_length_helper(hmac, &key, key_len);
}

#[test]
fn test_hmac_sha384_tag_length() {
let hmac = &HMAC_SHA384;
let key_len = 384 / 8;
let key = vec![0u8; key_len];
test_hmac_tag_length_helper(hmac, &key, key_len);
}

fn test_hmac_tag_length_helper(hmac: &super::Hmac, key: &[u8], key_len: usize) {
let hmac_key = hmac.with_key(key);
assert_eq!(hmac.hash_output_len(), hmac_key.tag_len());
assert_eq!(hmac.hash_output_len(), key_len);
}

#[test]
fn test_mbed_hmac_context_error() {
let key_len = 256 / 8;
let key = vec![0u8; key_len];
let mut bad_ctx = MbedHmacContext {
hmac_algo: &crate::hash::MBED_SHA_256,
ctx: mbedtls::hash::Hmac::new(crate::hash::MBED_SHA_384.hash_type, &key).unwrap(),
};
bad_ctx.update(&[]);
let tag = bad_ctx.finish();
assert_eq!(tag, Tag::with_len(0));
}
}
Loading