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
7 changes: 4 additions & 3 deletions src/aead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ impl AeadKey {
BCRYPT_FLAGS::default(),
)
.ok()
.map_err(|e| Error::General(format!("AEAD encrypt error: {e}")))?;
.map_err(|_| Error::EncryptError)?;
}
Ok(tag)
}
Expand Down Expand Up @@ -176,7 +176,7 @@ impl AeadKey {
BCRYPT_FLAGS::default(),
)
.ok()
.map_err(|e| Error::General(format!("AEAD decrypt error: {e}")))?;
.map_err(|_| Error::DecryptError)?;
}
size.try_into().map_err(|_| Error::DecryptError)
}
Expand All @@ -186,6 +186,7 @@ impl AeadKey {
mod test {

use crate::aead::{Algorithm, AES_128_GCM, AES_256_GCM, CHACHA20_POLY1305};
use rustls::Error;
use wycheproof::{
aead::{TestFlag, TestName},
TestResult,
Expand Down Expand Up @@ -253,7 +254,7 @@ mod test {

match &test.result {
TestResult::Invalid => {
assert!(res.is_err());
assert_eq!(res, Err(Error::DecryptError));
}
TestResult::Valid | TestResult::Acceptable => {
assert_eq!(res, Ok(test.pt.len()));
Expand Down
42 changes: 12 additions & 30 deletions src/alg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/)
// Copyright 2026 Datadog, Inc.

//! Algorithm provider initialization and cleanup.
//! Algorithm provider initialization.
use once_cell::sync::OnceCell;
use rustls::Error;
use windows::core::Free;
#[cfg(feature = "tls12")]
use windows::Win32::Security::Cryptography::BCRYPT_TLS1_2_KDF_ALGORITHM;
use windows::Win32::Security::Cryptography::{
Expand All @@ -18,42 +17,25 @@ use windows::{
Win32::Security::Cryptography::{BCRYPT_ALG_HANDLE, BCRYPT_OPEN_ALGORITHM_PROVIDER_FLAGS},
};

/// A handle that, when dropped, will free all algorithm providers initialized by this crate.
///
/// Where possible this crate aims to use the shared providers described in
/// <https://learn.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-pseudo-handles>.
///
/// This should be created once at the start of the program and dropped at the end.
pub struct ShutdownHandle {}

impl Drop for ShutdownHandle {
fn drop(&mut self) {
unsafe {
ecdh_x25519().free();
#[cfg(feature = "tls12")]
tls12_kdf().free();
}
}
}

struct Handle(BCRYPT_ALG_HANDLE);
unsafe impl Send for Handle {}
unsafe impl Sync for Handle {}

pub(crate) fn ecdh_x25519() -> BCRYPT_ALG_HANDLE {
static ALG_HANDLE: OnceCell<Handle> = OnceCell::new();
pub(crate) fn ecdh_x25519() -> Result<BCRYPT_ALG_HANDLE, Error> {
static ALG_HANDLE: OnceCell<Option<Handle>> = OnceCell::new();
ALG_HANDLE
.get_or_init(|| {
Handle(
load_algorithm(
BCRYPT_ECDH_ALGORITHM,
BCRYPT_OPEN_ALGORITHM_PROVIDER_FLAGS::default(),
Some((BCRYPT_ECC_CURVE_NAME, BCRYPT_ECC_CURVE_25519)),
)
.unwrap(),
load_algorithm(
BCRYPT_ECDH_ALGORITHM,
BCRYPT_OPEN_ALGORITHM_PROVIDER_FLAGS::default(),
Some((BCRYPT_ECC_CURVE_NAME, BCRYPT_ECC_CURVE_25519)),
)
.ok()
.map(Handle)
})
.0
.as_ref()
.map(|handle| handle.0)
.ok_or_else(|| Error::General("CNG X25519 algorithm provider unavailable".into()))
}

#[cfg(feature = "tls12")]
Expand Down
5 changes: 1 addition & 4 deletions src/hkdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,7 @@ impl<const HASH_SIZE: usize> RustlsHkdfExpander for HkdfExpander<HASH_SIZE> {
unsafe {
BCryptKeyDerivation(*self.key_handle, Some(&params), output, &mut size, 0)
.ok()
.map_err(|e| {
dbg!(e);
OutputLengthError
})?;
.map_err(|_| OutputLengthError)?;
};
if size != output.len() as u32 {
return Err(OutputLengthError);
Expand Down
28 changes: 20 additions & 8 deletions src/kx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ enum KxGroup {
}

impl KxGroup {
fn alg_handle(self) -> BCRYPT_ALG_HANDLE {
fn alg_handle(self) -> Result<BCRYPT_ALG_HANDLE, Error> {
match self {
Self::SECP256R1 => BCRYPT_ECDH_P256_ALG_HANDLE,
Self::SECP384R1 => BCRYPT_ECDH_P384_ALG_HANDLE,
Self::SECP256R1 => Ok(BCRYPT_ECDH_P256_ALG_HANDLE),
Self::SECP384R1 => Ok(BCRYPT_ECDH_P384_ALG_HANDLE),
Self::X25519 => alg::ecdh_x25519(),
}
}
Expand Down Expand Up @@ -92,7 +92,11 @@ fn cng_supports_x25519() -> bool {
];
let y = [0; 32];

import_ecdh_public_key(KxGroup::X25519.alg_handle(), &u, &y).is_ok()
let Ok(handle) = KxGroup::X25519.alg_handle() else {
return false;
};

import_ecdh_public_key(handle, &u, &y).is_ok()
}

struct EcKeyExchange {
Expand Down Expand Up @@ -122,7 +126,7 @@ impl SupportedKxGroup for KxGroup {

unsafe {
BCryptGenerateKeyPair(
self.alg_handle(),
self.alg_handle()?,
&mut *key_handle,
self.key_bits() as u32,
0,
Expand Down Expand Up @@ -223,7 +227,7 @@ impl ActiveKeyExchange for EcKeyExchange {
&[0; 32]
};

let peer_key_handle = import_ecdh_public_key(self.kx_group.alg_handle(), x, y)?;
let peer_key_handle = import_ecdh_public_key(self.kx_group.alg_handle()?, x, y)?;

// Now derive the shared secret
let mut secret = Owned::default();
Expand Down Expand Up @@ -290,6 +294,12 @@ mod test {
assert_eq!(advertises_x25519, super::cng_supports_x25519());
}

#[test]
fn x25519_capability_probe_does_not_panic() {
let _supported = std::panic::catch_unwind(super::cng_supports_x25519)
.expect("X25519 capability probing should return false instead of panicking");
}

#[test]
fn secp256r1() {
let test_set = wycheproof::ecdh::TestSet::load(TestName::EcdhSecp256r1Ecpoint).unwrap();
Expand All @@ -307,7 +317,8 @@ mod test {
public_key: Vec::new(),
};
kx.key_handle =
import_ecdh_private_key(kx.kx_group.alg_handle(), &test.private_key).unwrap();
import_ecdh_private_key(kx.kx_group.alg_handle().unwrap(), &test.private_key)
.unwrap();

let res = Box::new(kx).complete(&test.public_key);
let pub_key_uncompressed = test.public_key.first() == Some(&0x04);
Expand Down Expand Up @@ -353,7 +364,8 @@ mod test {
key[0] &= 0xf8;
key[31] &= 0x7f;
key[31] |= 0x40;
kx.key_handle = import_ecdh_private_key(kx.kx_group.alg_handle(), &key).unwrap();
kx.key_handle =
import_ecdh_private_key(kx.kx_group.alg_handle().unwrap(), &key).unwrap();

let res = Box::new(kx).complete(&test.public_key);

Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ pub mod cipher_suite {
pub use super::tls13::{TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384};
}

pub use alg::ShutdownHandle;
#[cfg(feature = "fips")]
pub use fips::provider as default_provider;
pub use fips::provider as fips_provider;
Expand Down
28 changes: 27 additions & 1 deletion src/tls12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
},
kx: KeyExchangeAlgorithm::ECDHE,
sign: ECDSA_SCHEMES,
aead_alg: &aead::AES_128_GCM,
aead_alg: &aead::AES_256_GCM,
prf_provider: &Prf(SHA384),
});

Expand Down Expand Up @@ -339,3 +339,29 @@ impl MessageDecrypter for ChaCha20Poly1305Crypter {
Ok(msg.into_plain_message())
}
}

#[cfg(test)]
mod test {
use rustls::SupportedCipherSuite;

use super::{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384};

#[test]
fn tls12_aes256_gcm_suites_use_32_byte_keys() {
for suite in [
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
] {
let SupportedCipherSuite::Tls12(suite) = suite else {
panic!("expected a TLS 1.2 cipher suite");
};

assert_eq!(
suite.aead_alg.key_block_shape().enc_key_len,
32,
"{:?} should derive 32-byte AES-256-GCM keys",
suite.common.suite
);
}
}
}
5 changes: 1 addition & 4 deletions src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,10 +269,7 @@ impl<const HASH_SIZE: usize> SignatureVerificationAlgorithm for VerificationAlgo
BCRYPT_PAD_PSS,
)
.ok()
.map_err(|e| {
dbg!(e);
InvalidSignature
})
.map_err(|_| InvalidSignature)
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions tests/it.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,15 @@ fn test_with_provider(
CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
)
)]
#[cfg_attr(
feature = "tls12",
case::tls_ecdhe_ecdsa_with_aes_256_gcm_sha384(
rustls_cng_crypto::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
rustls_cng_crypto::kx_group::SECP256R1,
&rcgen::PKCS_ECDSA_P256_SHA256,
CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
)
)]
// #[cfg_attr(
// feature = "tls12",
// case::ed25519_tls12(
Expand Down
Loading