Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions rustls-wolfcrypt-provider/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Turns on the `fips` cfg when wolfssl-wolfcrypt is built against a FIPS
// wolfSSL. The crate publishes that as FIPS=1 in its build metadata, which
// Cargo hands to crates depending on it directly as DEP_WOLFSSL_FIPS.
fn main() {
println!("cargo::rustc-check-cfg=cfg(fips)");
println!("cargo::rerun-if-env-changed=DEP_WOLFSSL_FIPS");
if std::env::var("DEP_WOLFSSL_FIPS").as_deref() == Ok("1") {
println!("cargo::rustc-cfg=fips");
}
}
8 changes: 8 additions & 0 deletions rustls-wolfcrypt-provider/src/aead/aes128gcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ const GCM_TAG_LENGTH: usize = 16;
pub struct Aes128Gcm;

impl Tls12AeadAlgorithm for Aes128Gcm {
fn fips(&self) -> bool {
crate::fips()
}

fn encrypter(&self, key: AeadKey, iv: &[u8], extra: &[u8]) -> Box<dyn MessageEncrypter> {
let mut iv_as_array = [0u8; GCM_NONCE_LENGTH];
iv_as_array[..(GCM_NONCE_LENGTH - 8)].copy_from_slice(iv); // implicit
Expand Down Expand Up @@ -177,6 +181,10 @@ impl MessageDecrypter for WCTls12Decrypter {
}

impl Tls13AeadAlgorithm for Aes128Gcm {
fn fips(&self) -> bool {
crate::fips()
}

fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> {
Box::new(WCTls13Cipher {
cipher: new_cipher(&key),
Expand Down
8 changes: 8 additions & 0 deletions rustls-wolfcrypt-provider/src/aead/aes256gcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ const GCM_TAG_LENGTH: usize = 16;
pub struct Aes256Gcm;

impl Tls12AeadAlgorithm for Aes256Gcm {
fn fips(&self) -> bool {
crate::fips()
}

fn encrypter(&self, key: AeadKey, iv: &[u8], extra: &[u8]) -> Box<dyn MessageEncrypter> {
let mut iv_as_array = [0u8; GCM_NONCE_LENGTH];
iv_as_array[..(GCM_NONCE_LENGTH - 8)].copy_from_slice(iv); // implicit
Expand Down Expand Up @@ -177,6 +181,10 @@ impl MessageDecrypter for WCTls12Decrypter {
}

impl Tls13AeadAlgorithm for Aes256Gcm {
fn fips(&self) -> bool {
crate::fips()
}

fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> {
Box::new(WCTls13Cipher {
cipher: new_cipher(&key),
Expand Down
43 changes: 39 additions & 4 deletions rustls-wolfcrypt-provider/src/aead/quic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@

use aead::{AeadInPlace, KeyInit};
use alloc::vec;
#[cfg(not(fips))]
use core::mem;
#[cfg(not(fips))]
use foreign_types::ForeignType;
use zeroize::Zeroizing;

use crate::alloc::string::ToString;
#[cfg(not(fips))]
use crate::error::check_if_zero;
#[cfg(not(fips))]
use crate::types::ChaChaObject;
use alloc::boxed::Box;
use alloc::vec::Vec;
Expand All @@ -18,8 +22,10 @@ use rustls::crypto::cipher::{Iv, Nonce};
use rustls::quic::Tag;
use rustls::{crypto::cipher::AeadKey, quic, Error};
use wolfssl_wolfcrypt::aes::{Aes128Gcm, Aes256Gcm, ECB};
#[cfg(not(fips))]
use wolfssl_wolfcrypt::chacha20_poly1305::ChaCha20Poly1305Aead;
// The crate has no safe wrapper for plain ChaCha20, used for header protection.
#[cfg(not(fips))]
use wolfssl_wolfcrypt::sys::{
wc_Chacha_Process, wc_Chacha_SetIV, wc_Chacha_SetKey, word32, ChaCha,
};
Expand All @@ -37,6 +43,7 @@ macro_rules! mask_array {
}
pub enum Cipher {
Aes(AesCipher),
#[cfg(not(fips))]
ChaCha20(ChaChaCipher),
}

Expand All @@ -48,6 +55,7 @@ pub(crate) const TAG_LEN: usize = 16;
pub const AES_128_KEY_LEN: usize = 128 / 8;
pub const AES_256_KEY_LEN: usize = 256 / 8;

#[cfg(not(fips))]
pub const CHACHA_KEY_LEN: usize = 32;
pub const SAMPLE_LEN: usize = TAG_LEN;
pub const MASK_LEN: usize = 5;
Expand Down Expand Up @@ -82,6 +90,7 @@ impl HPAlgorithm {
pub enum HPAlgorithmID {
Aes128,
Aes256,
#[cfg(not(fips))]
ChaCha20,
}

Expand Down Expand Up @@ -118,6 +127,7 @@ fn init_hp_aes_cipher(key: &[u8]) -> Result<Cipher, Error> {
fn generate_mask_aes(hp_cipher: &Cipher, sample: &[u8]) -> Result<[u8; MASK_LEN], Error> {
let aes_cipher = match hp_cipher {
Cipher::Aes(c) => c,
#[cfg(not(fips))]
_ => return Err(Error::General("Invalid cipher type".into())),
};

Expand All @@ -128,19 +138,22 @@ fn generate_mask_aes(hp_cipher: &Cipher, sample: &[u8]) -> Result<[u8; MASK_LEN]
}

/// ChaCha20.
#[cfg(not(fips))]
pub static CHACHA20: HPAlgorithm = HPAlgorithm {
key_len: CHACHA_KEY_LEN,
init: init_hp_chacha20_cipher,
hp_mask: generate_mask_chacha20,
id: HPAlgorithmID::ChaCha20,
};

#[cfg(not(fips))]
fn init_hp_chacha20_cipher(key: &[u8]) -> Result<Cipher, Error> {
let mut chacha_cipher = ChaChaCipher::new(None)?;
chacha_cipher.set_key(key)?;
Ok(Cipher::ChaCha20(chacha_cipher))
}

#[cfg(not(fips))]
fn generate_mask_chacha20(hp_cipher: &Cipher, sample: &[u8]) -> Result<[u8; MASK_LEN], Error> {
let chacha20_cipher = match hp_cipher {
Cipher::ChaCha20(c) => c,
Expand Down Expand Up @@ -260,6 +273,7 @@ impl quic::HeaderProtectionKey for HeaderProtectionKey {
pub(crate) enum PacketKeyAlgorithmID {
Aes128Gcm,
Aes256Gcm,
#[cfg(not(fips))]
ChaCha20Poly1305,
}

Expand Down Expand Up @@ -334,6 +348,7 @@ fn encrypt_aes_gcm(
) -> Result<Tag, Error> {
let aes_cipher = match packet_cipher {
Cipher::Aes(c) => c,
#[cfg(not(fips))]
_ => return Err(Error::General("Invalid cipher type".into())),
};
aes_cipher.encrypt_separate_tag(nonce, aad, in_out)
Expand All @@ -347,6 +362,7 @@ pub(super) fn decrypt_aes_gcm(
) -> Result<(), Error> {
let aes_cipher = match packet_cipher {
Cipher::Aes(aes_key) => aes_key,
#[cfg(not(fips))]
_ => return Err(Error::General("Invalid cipher type".into())),
};
aes_cipher.decrypt(nonce, aad, in_out)
Expand All @@ -357,6 +373,7 @@ pub(super) fn decrypt_aes_gcm(
/// The keys are 256 bits long and the nonces are 96 bits long.
///
/// [RFC 8439]: https://tools.ietf.org/html/rfc8439
#[cfg(not(fips))]
pub static CHACHA20_POLY1305: AeadAlgorithm = AeadAlgorithm {
init: init_chacha20_poly1305_cipher,
encrypt: encrypt_chacha20_poly1305,
Expand All @@ -365,13 +382,15 @@ pub static CHACHA20_POLY1305: AeadAlgorithm = AeadAlgorithm {
id: PacketKeyAlgorithmID::ChaCha20Poly1305,
};

#[cfg(not(fips))]
fn init_chacha20_poly1305_cipher(key: &[u8]) -> Result<Cipher, Error> {
let key_array = <[u8; 32]>::try_from(key)
.map_err(|_| Error::General("Invalid key length for ChaCha20-Poly1305".into()))?;
let chacha_cipher = ChaChaCipher::new(Some(key_array))?;
Ok(Cipher::ChaCha20(chacha_cipher))
}

#[cfg(not(fips))]
fn encrypt_chacha20_poly1305(
packet_cipher: &Cipher,
nonce: &[u8],
Expand All @@ -385,6 +404,7 @@ fn encrypt_chacha20_poly1305(
chacha_cipher.encrypt_separate_tag(nonce, aad, in_out)
}

#[cfg(not(fips))]
fn decrypt_chacha20_poly1305(
packet_cipher: &Cipher,
nonce: &[u8],
Expand Down Expand Up @@ -523,7 +543,7 @@ impl quic::Algorithm for KeyFactory {
}

fn fips(&self) -> bool {
false
crate::fips()
}
}

Expand Down Expand Up @@ -628,10 +648,12 @@ impl AesCipher {
}
}

#[cfg(not(fips))]
pub struct ChaChaCipher {
key: Option<Zeroizing<[u8; CHACHA_KEY_LEN]>>,
}

#[cfg(not(fips))]
impl ChaChaCipher {
pub fn new(key: Option<[u8; CHACHA_KEY_LEN]>) -> Result<Self, Error> {
Ok(Self {
Expand Down Expand Up @@ -764,16 +786,21 @@ impl ChaChaCipher {
#[cfg(test)]
mod tests {
use hex_literal::hex;
#[cfg(not(fips))]
use rustls::crypto::tls13::HkdfExpander;
use std::prelude::v1::Vec;
use std::vec;

use crate::aead;
#[cfg(not(fips))]
use rustls::crypto::cipher::{AeadKey, Iv, NONCE_LEN};
use rustls::quic::*;

use crate::default_provider;
use crate::{TLS13_AES_128_GCM_SHA256, TLS13_CHACHA20_POLY1305_SHA256};
use crate::TLS13_AES_128_GCM_SHA256;
#[cfg(not(fips))]
use crate::TLS13_CHACHA20_POLY1305_SHA256;
#[cfg(not(fips))]
use rustls::crypto::tls13::OkmBlock;
use rustls::internal::msgs::codec::Codec;
use rustls::{ClientConfig, Error, ServerConfig, Side, SideData};
Expand Down Expand Up @@ -973,6 +1000,7 @@ mod tests {
pub body: Vec<u8>,
}

#[cfg(not(fips))]
#[derive(Debug, Clone)]
struct ChaCha20TestVector {
key: [u8; 32],
Expand All @@ -993,6 +1021,7 @@ mod tests {
},
}

#[cfg(not(fips))]
fn hkdf_expand_label(
expander: &Box<dyn HkdfExpander>,
label: &[u8],
Expand All @@ -1018,6 +1047,7 @@ mod tests {
let _ = expander.expand_slice(info, output);
}

#[cfg(not(fips))]
fn test_short_packet(version: rustls::quic::Version, expected: &[u8]) {
// Code taken from rustls with modification
let chacha_key_len = TLS13_CHACHA20_POLY1305_SHA256
Expand Down Expand Up @@ -1132,6 +1162,7 @@ mod tests {
assert_eq!(plain, &PLAIN[4..]);
}

#[cfg(not(fips))]
#[test]
fn short_packet_header_protection() {
// https://www.rfc-editor.org/rfc/rfc9001.html#name-chacha20-poly1305-short-hea
Expand All @@ -1144,6 +1175,7 @@ mod tests {
);
}

#[cfg(not(fips))]
#[test]
fn short_packet_header_protection_v2() {
// https://www.ietf.org/archive/id/draft-ietf-quic-v2-10.html#name-chacha20-poly1305-short-head
Expand Down Expand Up @@ -1550,6 +1582,7 @@ mod tests {
}
}

#[cfg(not(fips))]
#[test]
fn test_chacha_mask_generation() {
//Test idea taken from ring
Expand All @@ -1571,9 +1604,10 @@ mod tests {

#[test]
fn test_sample_len() {
let hp_algs: Vec<&aead::quic::HPAlgorithm> = vec![
let hp_algs: &[&aead::quic::HPAlgorithm] = &[
&aead::quic::AES_128,
&aead::quic::AES_256,
#[cfg(not(fips))]
&aead::quic::CHACHA20,
];
let mut first = vec![0u8; 1];
Expand Down Expand Up @@ -1623,9 +1657,10 @@ mod tests {

#[test]
fn test_key_len() {
let hp_algs: Vec<&aead::quic::HPAlgorithm> = vec![
let hp_algs: &[&aead::quic::HPAlgorithm] = &[
&aead::quic::AES_128,
&aead::quic::AES_256,
#[cfg(not(fips))]
&aead::quic::CHACHA20,
];
for alg in hp_algs {
Expand Down
4 changes: 4 additions & 0 deletions rustls-wolfcrypt-provider/src/hash/sha256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ use wolfssl_wolfcrypt::sha::SHA256;
pub struct WCSha256;

impl hash::Hash for WCSha256 {
fn fips(&self) -> bool {
crate::fips()
}

fn start(&self) -> Box<dyn hash::Context> {
let sha256 = SHA256::new().expect("SHA256::new failed");
Box::new(WCSha256Context::new(sha256))
Expand Down
4 changes: 4 additions & 0 deletions rustls-wolfcrypt-provider/src/hash/sha384.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ use wolfssl_wolfcrypt::sha::SHA384;
pub struct WCSha384;

impl hash::Hash for WCSha384 {
fn fips(&self) -> bool {
crate::fips()
}

fn start(&self) -> Box<dyn hash::Context> {
let sha384 = SHA384::new().expect("SHA384::new failed");
Box::new(WCSha384Context::new(sha384))
Expand Down
24 changes: 19 additions & 5 deletions rustls-wolfcrypt-provider/src/hkdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@ use rustls::crypto::hmac::Hmac as RustlsHmac;
use rustls::crypto::tls13::{self, Hkdf as RustlsHkdf};
use wolfssl_wolfcrypt::hkdf::{hkdf_expand, hkdf_extract};

#[cfg(fips)]
use wolfssl_wolfcrypt::fips::PrivateKeyRead;

use crate::hmac::WCShaHmac;
use zeroize::Zeroizing;

pub struct WCHkdfUsingHmac(pub WCShaHmac);

impl RustlsHkdf for WCHkdfUsingHmac {
fn fips(&self) -> bool {
crate::fips()
}

fn extract_from_zero_ikm(
&self,
salt: Option<&[u8]>,
Expand All @@ -30,6 +37,8 @@ impl RustlsHkdf for WCHkdfUsingHmac {
let zero_salt = vec![0u8; hash_len];
let salt_bytes = salt.unwrap_or(&zero_salt);

#[cfg(fips)]
let _read = PrivateKeyRead::enable().ok();
hkdf_extract(
self.0.hash_type(),
Some(salt_bytes),
Expand Down Expand Up @@ -94,6 +103,8 @@ impl tls13::HkdfExpander for WolfHkdfExpander {
return Err(tls13::OutputLengthError);
}

#[cfg(fips)]
let _read = PrivateKeyRead::enable().ok();
hkdf_expand(
self.hash_type,
&self.extracted_key,
Expand All @@ -118,9 +129,9 @@ impl tls13::HkdfExpander for WolfHkdfExpander {
#[cfg(test)]
mod tests {
use super::*;
use crate::{
TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256,
};
#[cfg(not(fips))]
use crate::TLS13_CHACHA20_POLY1305_SHA256;
use crate::{TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384};
use hex_literal::hex;
use wycheproof::{hkdf::TestName, TestResult};

Expand Down Expand Up @@ -237,8 +248,11 @@ mod tests {

#[test]
fn test_hkdf_wycheproof_sha256() {
let suites: &[rustls::SupportedCipherSuite] =
&[TLS13_AES_128_GCM_SHA256, TLS13_CHACHA20_POLY1305_SHA256];
let suites: &[rustls::SupportedCipherSuite] = &[
TLS13_AES_128_GCM_SHA256,
#[cfg(not(fips))]
TLS13_CHACHA20_POLY1305_SHA256,
];

let test_name: TestName = TestName::HkdfSha256;

Expand Down
Loading
Loading