use crate::hash::Algorithm;
use openssl::pkey::{PKey, Private};
use openssl::sign::Signer;
use rustls::crypto::hash::Hash as _;
use rustls::crypto::hmac::{Key, Tag};
pub(crate) struct Hmac(pub(crate) Algorithm);
struct HmacKey {
key: PKey<Private>,
hash: Algorithm,
}
impl rustls::crypto::hmac::Hmac for Hmac {
fn with_key(&self, key: &[u8]) -> Box<dyn Key> {
Box::new(HmacKey {
key: PKey::hmac(key).expect("Failed to read Hmac Key"),
hash: self.0,
})
}
fn hash_output_len(&self) -> usize {
self.0.output_len()
}
fn fips(&self) -> bool {
crate::fips::enabled()
}
}
impl Key for HmacKey {
fn sign(&self, data: &[&[u8]]) -> Tag {
self.sign_concat(&[], data, &[])
}
fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> Tag {
Signer::new(self.hash.message_digest(), &self.key)
.and_then(|mut signer| {
signer.update(first)?;
for d in middle {
signer.update(d)?;
}
signer.update(last)?;
Ok(Tag::new(&signer.sign_to_vec()?))
})
.expect("HMAC signing failed")
}
fn tag_len(&self) -> usize {
self.hash.output_len()
}
}