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
32 changes: 15 additions & 17 deletions src/rust/cryptography-key-parsing/src/pkcs8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,13 @@ pub enum MlDsaPrivateKey {

/// Extract the ML-KEM seed from a private key.
///
/// For BoringSSL/AWS-LC, round-trips through PKCS#8 encoding to extract the
/// seed. AWS-LC's `raw_private_key()` returns the 2400-byte expanded key, not
/// the seed; since AWS-LC 1.72.0, `private_key_to_pkcs8()` produces RFC 9935
/// seed-format PKCS#8 when the key was created from a seed. BoringSSL's
/// private key serialization also emits RFC 9935 seed-format PKCS#8.
/// For BoringSSL and OpenSSL 3.5+, calls the library's seed extraction API
/// directly (`EVP_PKEY_get_private_seed` / `PKey::seed_into`).
///
/// For vanilla OpenSSL 3.5+, calls `PKey::seed_into` to read the seed
/// directly, avoiding the PKCS#8 round-trip.
/// For AWS-LC, round-trips through PKCS#8 encoding because
/// `raw_private_key()` returns the 2400-byte expanded key. Since AWS-LC
/// 1.72.0, `private_key_to_pkcs8()` produces RFC 9935 seed-format PKCS#8
/// when the key was created from a seed.
#[cfg(any(
CRYPTOGRAPHY_IS_BORINGSSL,
CRYPTOGRAPHY_IS_AWSLC,
Expand All @@ -65,11 +64,11 @@ pub fn mlkem_seed_from_pkey(
pkey: &openssl::pkey::PKeyRef<openssl::pkey::Private>,
) -> Result<MlKemPrivateKey, openssl::error::ErrorStack> {
cfg_if::cfg_if! {
if #[cfg(any(CRYPTOGRAPHY_IS_BORINGSSL, CRYPTOGRAPHY_IS_AWSLC))] {
if #[cfg(CRYPTOGRAPHY_IS_AWSLC)] {
let pkcs8_der = pkey.private_key_to_pkcs8()?;
let pki = asn1::parse_single::<PrivateKeyInfo<'_>>(&pkcs8_der).unwrap();
Ok(asn1::parse_single::<MlKemPrivateKey>(pki.private_key).unwrap())
} else if #[cfg(CRYPTOGRAPHY_OPENSSL_350_OR_GREATER)] {
} else {
let seed = cryptography_openssl::mlkem::mlkem_seed_raw(pkey)?;
Ok(MlKemPrivateKey::Seed(seed))
}
Expand All @@ -78,13 +77,12 @@ pub fn mlkem_seed_from_pkey(

/// Extract the 32-byte ML-DSA seed from a private key.
///
/// For BoringSSL/AWS-LC, round-trips through PKCS#8 encoding to extract the
/// seed (AWS-LC's `raw_private_key()` returns the expanded key, not the seed:
/// https://github.com/aws/aws-lc/issues/3072).
/// For BoringSSL and OpenSSL 3.5+, calls the library's seed extraction API
/// directly (`EVP_PKEY_get_private_seed` / `PKey::seed_into`).
///
/// For vanilla OpenSSL 3.5+, calls `PKey::seed_into` to read the seed
/// directly, since OpenSSL 3.5's PKCS#8 inner encoding differs from
/// BoringSSL/AWS-LC.
/// For AWS-LC, round-trips through PKCS#8 encoding because
/// `raw_private_key()` returns the expanded key, not the seed
/// (https://github.com/aws/aws-lc/issues/3072).
#[cfg(any(
CRYPTOGRAPHY_IS_BORINGSSL,
CRYPTOGRAPHY_IS_AWSLC,
Expand All @@ -94,11 +92,11 @@ pub fn mldsa_seed_from_pkey(
pkey: &openssl::pkey::PKeyRef<openssl::pkey::Private>,
) -> Result<MlDsaPrivateKey, openssl::error::ErrorStack> {
cfg_if::cfg_if! {
if #[cfg(any(CRYPTOGRAPHY_IS_BORINGSSL, CRYPTOGRAPHY_IS_AWSLC))] {
if #[cfg(CRYPTOGRAPHY_IS_AWSLC)] {
let pkcs8_der = pkey.private_key_to_pkcs8()?;
let pki = asn1::parse_single::<PrivateKeyInfo<'_>>(&pkcs8_der).unwrap();
Ok(asn1::parse_single::<MlDsaPrivateKey>(pki.private_key).unwrap())
} else if #[cfg(CRYPTOGRAPHY_OPENSSL_350_OR_GREATER)] {
} else {
let seed = cryptography_openssl::mldsa::mldsa_seed_raw(pkey)?;
Ok(MlDsaPrivateKey::Seed(seed))
}
Expand Down
19 changes: 17 additions & 2 deletions src/rust/cryptography-openssl/src/mldsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,12 +206,27 @@ extern "C" {
///
/// Avoids the PKCS#8 round-trip that vanilla OpenSSL 3.5 encodes
/// differently from BoringSSL/AWS-LC.
#[cfg(CRYPTOGRAPHY_OPENSSL_350_OR_GREATER)]
#[cfg(any(CRYPTOGRAPHY_IS_BORINGSSL, CRYPTOGRAPHY_OPENSSL_350_OR_GREATER))]
pub fn mldsa_seed_raw(
pkey: &openssl::pkey::PKeyRef<openssl::pkey::Private>,
) -> OpenSSLResult<[u8; 32]> {
let mut seed = [0u8; 32];
pkey.seed_into(&mut seed)?;
cfg_if::cfg_if! {
if #[cfg(CRYPTOGRAPHY_IS_BORINGSSL)] {
let mut seed_len = seed.len();
// SAFETY: pkey is a valid EVP_PKEY and seed is a 32-byte buffer.
unsafe {
cvt(ffi::EVP_PKEY_get_private_seed(
pkey.as_ptr(),
seed.as_mut_ptr(),
&mut seed_len,
))?;
}
assert_eq!(seed_len, 32);
} else if #[cfg(CRYPTOGRAPHY_OPENSSL_350_OR_GREATER)] {
pkey.seed_into(&mut seed)?;
}
}
Ok(seed)
}

Expand Down
21 changes: 19 additions & 2 deletions src/rust/cryptography-openssl/src/mlkem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// for complete details.

use foreign_types_shared::ForeignType;
#[cfg(CRYPTOGRAPHY_IS_BORINGSSL)]
use foreign_types_shared::ForeignTypeRef;
use openssl_sys as ffi;
#[cfg(CRYPTOGRAPHY_IS_AWSLC)]
use std::os::raw::c_int;
Expand Down Expand Up @@ -121,12 +123,27 @@ extern "C" {
///
/// Avoids the PKCS#8 round-trip that vanilla OpenSSL 3.5 encodes
/// differently from BoringSSL/AWS-LC.
#[cfg(CRYPTOGRAPHY_OPENSSL_350_OR_GREATER)]
#[cfg(any(CRYPTOGRAPHY_IS_BORINGSSL, CRYPTOGRAPHY_OPENSSL_350_OR_GREATER))]
pub fn mlkem_seed_raw(
pkey: &openssl::pkey::PKeyRef<openssl::pkey::Private>,
) -> OpenSSLResult<[u8; 64]> {
let mut seed = [0u8; 64];
pkey.seed_into(&mut seed)?;
cfg_if::cfg_if! {
if #[cfg(CRYPTOGRAPHY_IS_BORINGSSL)] {
let mut seed_len = seed.len();
// SAFETY: pkey is a valid EVP_PKEY and seed is a 64-byte buffer.
unsafe {
cvt(ffi::EVP_PKEY_get_private_seed(
pkey.as_ptr(),
seed.as_mut_ptr(),
&mut seed_len,
))?;
}
assert_eq!(seed_len, 64);
} else if #[cfg(CRYPTOGRAPHY_OPENSSL_350_OR_GREATER)] {
pkey.seed_into(&mut seed)?;
}
}
Ok(seed)
}

Expand Down
Loading