diff --git a/rust/pv/src/crypto.rs b/rust/pv/src/crypto.rs index 5ec90985..65b4f994 100644 --- a/rust/pv/src/crypto.rs +++ b/rust/pv/src/crypto.rs @@ -7,12 +7,14 @@ use std::fmt::Display; use std::ops::Range; use enum_dispatch::enum_dispatch; +use openssl::bn::BigNumContext; use openssl::derive::Deriver; -use openssl::ec::{EcGroup, EcKey}; +use openssl::ec::{EcGroup, EcKey, EcPoint}; +use openssl::error::ErrorStack; use openssl::hash::{DigestBytes, MessageDigest}; use openssl::md::MdRef; use openssl::nid::Nid; -use openssl::pkey::{HasPublic, Id, PKey, PKeyRef, Private, Public}; +use openssl::pkey::{HasPublic, Id, KeyType, PKey, PKeyRef, Private, Public}; use openssl::pkey_ctx::{HkdfMode, PkeyCtx}; use openssl::rand::rand_bytes; use openssl::rsa::Padding; @@ -23,8 +25,51 @@ use openssl::symm::{ use pv_core::request::Confidential; use crate::error::Result; +use crate::openssl_extensions::PkeyEncapsulateContext; +use crate::req::get_pub_ecdh_points; +use crate::request::EcPubKeyCoord; use crate::Error; +/// Compute ECDH shared secret from public and private keys +/// +/// It is expected that the public and private key are with respect to EC-P521. +/// +/// Note that the output is the concatenation of the 80-bytes-left-padded x and +/// 80-bytes-left-padded y coordinate. +fn ecdh_shared_secret( + pub_key: &PKeyRef, + priv_key: &PKeyRef, +) -> Result<[u8; 160], ErrorStack> { + let pub_key = pub_key.ec_key()?; + let priv_key = priv_key.ec_key()?; + + // Verify both keys use the EC-P521 curve (SECP521R1) + assert_eq!( + pub_key.group().curve_name(), + Some(Nid::SECP521R1), + "Public key must use EC-P521 curve" + ); + assert_eq!( + priv_key.group().curve_name(), + Some(Nid::SECP521R1), + "Private key must use EC-P521 curve" + ); + + pub_key.check_key()?; + priv_key.check_key()?; + let group = pub_key.group(); + let mut bn_ctx = BigNumContext::new()?; + let mut point = EcPoint::new(group)?; + point.mul2( + group, + pub_key.public_key(), + priv_key.private_key(), + &mut bn_ctx, + )?; + let coord = get_pub_ecdh_points(&point, group)?; + Ok(coord) +} + /// An AES256-GCM key that will purge itself out of the memory when going out of scope pub type Aes256GcmKey = Confidential<[u8; SymKeyType::AES_256_GCM_KEY_LEN]>; /// An AES256-XTS key that will purge itself out of the memory when going out of scope @@ -214,6 +259,220 @@ pub fn derive_aes256_gcm_key(k1: &PKeyRef, k2: &PKeyRef) -> Res )) } +/// Determines the KeyType of a given PKey by testing against all known key types. +/// +/// This function iterates through all known OpenSSL key types and uses the `is_a()` +/// method to identify which type the provided key matches. This is more reliable than +/// using `Id` to `KeyType` conversion, especially for newer key types like ML-KEM +/// that may not have a direct `Id` mapping. +/// +/// # Parameters +/// +/// * `key` - A reference to the PKey to identify +/// +/// # Returns +/// +/// * `Some(KeyType)` - If the key matches one of the known key types +/// * `None` - If the key type is not recognized or doesn't match any known types +fn pkey_to_keytype(key: &PKeyRef) -> Option { + const KNOWN_KEY_TYPES: &[KeyType] = &[ + KeyType::RSA, + KeyType::RSA_PSS, + KeyType::DSA, + KeyType::DH, + KeyType::EC, + KeyType::HMAC, + KeyType::CMAC, + KeyType::X25519, + KeyType::ED25519, + KeyType::X448, + KeyType::ED448, + KeyType::ML_KEM_512, + KeyType::ML_KEM_768, + KeyType::ML_KEM_1024, + ]; + + KNOWN_KEY_TYPES + .iter() + .find(|&&key_type| key.is_a(key_type)) + .copied() +} + +fn key_type_str(t: KeyType) -> &'static str { + if t == KeyType::RSA { + "RSA" + } else if t == KeyType::RSA_PSS { + "RSA-PSS" + } else if t == KeyType::DSA { + "DSA" + } else if t == KeyType::DH { + "DH" + } else if t == KeyType::EC { + "EC" + } else if t == KeyType::HMAC { + "HMAC" + } else if t == KeyType::CMAC { + "CMAC" + } else if t == KeyType::X25519 { + "X25519" + } else if t == KeyType::ED25519 { + "ED25519" + } else if t == KeyType::X448 { + "X448" + } else if t == KeyType::ED448 { + "ED448" + } else if t == KeyType::ML_KEM_512 { + "ML-KEM-512" + } else if t == KeyType::ML_KEM_768 { + "ML-KEM-768" + } else if t == KeyType::ML_KEM_1024 { + "ML-KEM-1024" + } else { + "unknown" + } +} + +/// Validates that a key matches the expected key type. +/// +/// # Errors +/// +/// Returns an error if the key doesn't match the expected type. +pub(crate) fn validate_key_type( + key: &PKeyRef, + key_name: &str, + expected_type: KeyType, +) -> Result<()> { + if !key.is_a(expected_type) { + return Err(Error::RetrInvKey { + what: "key type", + kind: key_name.to_string(), + value: pkey_to_keytype(key) + .map(key_type_str) + .unwrap_or("unknown") + .to_string(), + exp: key_type_str(expected_type).to_string(), + }); + } + Ok(()) +} + +/// Validates that a key is an EC key with the specified curve. +/// +/// # Errors +/// +/// Returns an error if the key is not an EC key or doesn't use the expected curve. +pub(crate) fn validate_ec_key( + key: &PKeyRef, + key_name: &str, + expected_curve: Nid, +) -> Result<()> { + if key.id() != Id::EC { + return Err(Error::RetrInvKey { + what: "key type", + kind: key_name.to_string(), + value: pkey_to_keytype(key) + .map(key_type_str) + .unwrap_or("unknown") + .to_string(), + exp: format!("EC ({})", expected_curve.long_name().unwrap_or("unknown")), + }); + } + let ec_key = key.ec_key()?; + if ec_key.group().curve_name() != Some(expected_curve) { + return Err(Error::RetrInvKey { + what: "curve", + kind: key_name.to_string(), + value: ec_key + .group() + .curve_name() + .and_then(|nid| nid.long_name().ok()) + .unwrap_or("unknown") + .to_string(), + exp: expected_curve.long_name().unwrap_or("unknown").to_string(), + }); + } + Ok(()) +} + +/// Derive a symmetric AES 256 GCM key from a private target key, a public +/// customer key, and a public ML-KEM target key. +/// +/// # Returns +/// +/// The derived key and the ML-KEM ciphertext (KC). +/// +/// # Errors +/// +/// This function will return an error if something went bad in OpenSSL or the +/// wrong key types were used. +pub fn derive_aes256_gcm_key_hybrid( + priv_ecdh_cust_key: &PKeyRef, + pub_ecdh_target_key: &PKeyRef, + pub_mlkem_target_key: &PKeyRef, +) -> Result<(Aes256GcmKey, Vec)> { + let mut buffer: Vec = vec![0, 0, 0, 1]; + + validate_ec_key(priv_ecdh_cust_key, "ECDH customer key", Nid::SECP521R1)?; + validate_ec_key(pub_ecdh_target_key, "ECDH target key", Nid::SECP521R1)?; + validate_key_type( + pub_mlkem_target_key, + "ML-KEM target key", + KeyType::ML_KEM_1024, + )?; + + // Derive the ECDH shared secret + let ecdh_derived_secret = ecdh_shared_secret(pub_ecdh_target_key, priv_ecdh_cust_key)?; + assert_eq!(ecdh_derived_secret.as_ref().len(), 160); + buffer.extend_from_slice(ecdh_derived_secret.as_ref()); + + // Derive the ML-KEM shared secret + let mut ctx = PkeyCtx::new(pub_mlkem_target_key)?; + ctx.encapsulate_init()?; + let (mut ciphertext, mut shared_secret) = (vec![], vec![]); + ctx.encapsulate_to_vec(&mut ciphertext, &mut shared_secret)?; + assert_eq!(ciphertext.len(), 1568); + assert_eq!(shared_secret.len(), 32); + buffer.extend_from_slice(&shared_secret); + + // Append the private ECDH customer key + let pub_ecdh_cust_key = EcPubKeyCoord::try_from(priv_ecdh_cust_key)?; + assert_eq!(pub_ecdh_cust_key.as_ref().len(), 160); + buffer.extend_from_slice(pub_ecdh_cust_key.as_ref()); + + // Append the ciphertext + buffer.extend_from_slice(&ciphertext); + + // Append the public ECDH target key + let pub_ecdh_target_key: EcPubKeyCoord = pub_ecdh_target_key.try_into()?; + assert_eq!(pub_ecdh_target_key.as_ref().len(), 160); + buffer.extend_from_slice(pub_ecdh_target_key.as_ref()); + + // Append the public ML-KEM target key + assert_eq!(pub_mlkem_target_key.raw_public_key()?.len(), 1568); + buffer.extend_from_slice(&pub_mlkem_target_key.raw_public_key()?); + + // Append the magic string + const STRING: &str = "PQC Secure Execution with Format-2 Key Slots KS2"; + assert_eq!(STRING.len(), 48); + buffer.extend_from_slice(STRING.as_bytes()); + + // Sanity check + assert_eq!(buffer.len(), 4 + 160 + 32 + 160 + 1568 + 160 + 1568 + 48); + + let secr = Confidential::new(buffer); + + // Panic: does not panic as SHA256 digest is 32 bytes long + Ok(( + Aes256GcmKey::new( + hash(MessageDigest::sha256(), secr.value())? + .as_ref() + .try_into() + .unwrap(), + ), + ciphertext, + )) +} + /// Generate a random array. /// /// # Errors @@ -760,6 +1019,112 @@ mod tests { assert_eq!(&calc_key, &exp_key); } + #[test] + fn derive_aes256_gcm_key_hybrid() { + let (cust_key, host_key_1, host_key_2) = get_test_keys_hybrid(); + let entropy = [0x5au8; 4096]; + let nonce = [0xa5u8; 48]; + + let _rng = DeterministicTestRandGuard::install(&entropy, &nonce).unwrap(); + + let exp_key: Aes256GcmKey = [ + 197, 167, 157, 112, 186, 112, 72, 125, 192, 219, 168, 132, 178, 167, 249, 123, 149, 3, + 151, 166, 162, 66, 120, 39, 41, 230, 143, 54, 172, 10, 200, 143, + ] + .into(); + let exp_kc = [ + 54, 117, 96, 77, 148, 147, 170, 100, 34, 177, 95, 7, 35, 243, 145, 115, 7, 87, 178, 9, + 169, 99, 193, 99, 244, 195, 23, 78, 11, 153, 221, 196, 5, 192, 253, 192, 86, 49, 194, + 236, 43, 69, 183, 125, 166, 87, 158, 188, 13, 152, 19, 6, 253, 29, 194, 0, 101, 236, + 28, 171, 3, 236, 53, 186, 191, 109, 7, 83, 220, 93, 126, 29, 19, 203, 201, 39, 59, 7, + 131, 51, 81, 73, 254, 69, 105, 185, 214, 179, 155, 194, 189, 122, 106, 130, 249, 48, 4, + 33, 245, 170, 163, 4, 223, 208, 138, 224, 203, 119, 105, 59, 187, 153, 235, 90, 79, + 127, 29, 136, 230, 142, 78, 83, 27, 131, 58, 126, 76, 53, 129, 20, 85, 108, 86, 64, + 244, 90, 84, 177, 239, 105, 90, 41, 118, 189, 88, 174, 224, 216, 29, 10, 123, 81, 212, + 203, 197, 120, 20, 190, 3, 45, 37, 194, 208, 249, 232, 221, 67, 10, 62, 121, 143, 169, + 227, 165, 17, 30, 85, 223, 44, 141, 114, 142, 105, 119, 187, 41, 46, 8, 6, 17, 29, 165, + 117, 254, 92, 174, 231, 25, 117, 69, 112, 216, 80, 73, 185, 54, 50, 119, 145, 220, 174, + 26, 105, 81, 114, 210, 144, 148, 109, 218, 64, 78, 231, 196, 229, 88, 46, 128, 106, + 125, 204, 58, 184, 127, 193, 207, 86, 163, 98, 164, 57, 242, 29, 59, 251, 227, 185, 60, + 18, 68, 74, 47, 203, 61, 164, 78, 245, 100, 87, 148, 210, 97, 158, 252, 79, 78, 50, + 143, 35, 231, 215, 211, 75, 133, 214, 227, 140, 27, 21, 46, 221, 84, 89, 165, 161, 227, + 46, 117, 193, 254, 190, 237, 130, 28, 57, 52, 14, 235, 154, 115, 172, 185, 67, 116, 34, + 242, 158, 209, 0, 126, 196, 93, 224, 29, 246, 145, 65, 73, 185, 196, 4, 107, 124, 241, + 157, 230, 168, 244, 238, 84, 188, 173, 17, 238, 26, 161, 24, 176, 229, 226, 33, 244, + 167, 41, 107, 156, 29, 226, 248, 64, 146, 191, 210, 234, 76, 144, 219, 92, 136, 173, + 241, 98, 0, 71, 135, 214, 196, 116, 63, 243, 73, 71, 130, 171, 86, 204, 149, 69, 164, + 20, 177, 122, 95, 226, 95, 126, 106, 160, 59, 97, 137, 8, 73, 113, 189, 172, 24, 114, + 60, 62, 249, 193, 3, 99, 34, 153, 42, 238, 77, 181, 80, 185, 223, 39, 8, 44, 215, 119, + 214, 30, 136, 19, 215, 35, 184, 69, 94, 10, 170, 179, 51, 183, 105, 237, 237, 48, 199, + 122, 159, 87, 183, 71, 230, 87, 102, 77, 81, 116, 28, 126, 195, 72, 50, 157, 223, 243, + 83, 36, 16, 168, 111, 209, 132, 12, 96, 56, 140, 57, 144, 75, 253, 119, 123, 168, 2, + 79, 214, 121, 80, 154, 93, 235, 222, 130, 181, 166, 97, 51, 106, 21, 138, 224, 8, 144, + 223, 162, 152, 183, 6, 80, 64, 144, 21, 155, 56, 255, 108, 248, 125, 196, 46, 99, 119, + 94, 104, 63, 46, 15, 165, 30, 98, 75, 212, 193, 116, 151, 189, 65, 42, 83, 253, 183, + 41, 195, 45, 206, 178, 66, 36, 215, 197, 105, 236, 79, 91, 135, 164, 71, 187, 199, 200, + 150, 226, 182, 254, 6, 234, 109, 3, 17, 116, 249, 44, 211, 184, 61, 189, 44, 181, 249, + 8, 58, 230, 236, 8, 188, 14, 178, 100, 120, 250, 29, 1, 204, 158, 46, 161, 39, 66, 76, + 42, 114, 149, 160, 31, 87, 254, 181, 224, 17, 162, 163, 99, 11, 34, 149, 50, 203, 205, + 224, 38, 18, 233, 161, 49, 7, 151, 63, 81, 68, 71, 174, 49, 22, 143, 93, 50, 0, 154, + 152, 178, 134, 147, 152, 118, 196, 241, 233, 67, 102, 149, 179, 213, 176, 118, 64, 172, + 143, 134, 196, 232, 154, 110, 129, 155, 159, 103, 117, 202, 11, 35, 75, 104, 5, 11, + 160, 147, 174, 49, 248, 45, 247, 16, 7, 64, 209, 255, 170, 243, 242, 40, 158, 94, 239, + 194, 225, 113, 24, 90, 243, 73, 137, 217, 175, 130, 50, 133, 139, 250, 145, 190, 76, + 151, 183, 30, 86, 146, 59, 171, 214, 211, 135, 203, 192, 42, 189, 90, 47, 152, 132, + 168, 252, 175, 71, 234, 118, 207, 161, 176, 254, 189, 54, 174, 160, 178, 158, 133, 122, + 63, 75, 95, 201, 55, 139, 2, 208, 232, 110, 74, 201, 196, 135, 244, 156, 87, 208, 101, + 203, 121, 187, 16, 106, 80, 120, 165, 44, 147, 182, 114, 173, 186, 185, 255, 99, 85, + 88, 26, 27, 43, 203, 176, 207, 88, 20, 253, 169, 210, 168, 109, 75, 234, 239, 8, 243, + 244, 65, 164, 193, 255, 240, 215, 54, 158, 188, 93, 93, 54, 46, 77, 152, 78, 174, 154, + 67, 248, 24, 235, 172, 240, 83, 224, 17, 100, 217, 15, 172, 176, 46, 85, 107, 105, 127, + 147, 158, 202, 255, 145, 237, 84, 223, 100, 214, 38, 133, 169, 112, 227, 138, 220, 125, + 72, 197, 5, 227, 94, 245, 42, 70, 33, 209, 243, 70, 229, 37, 118, 214, 147, 43, 87, 39, + 241, 107, 26, 169, 28, 72, 223, 133, 145, 44, 248, 213, 52, 127, 250, 99, 193, 115, + 113, 147, 89, 112, 237, 199, 208, 36, 155, 106, 144, 73, 249, 8, 116, 198, 107, 120, + 233, 145, 11, 155, 178, 7, 66, 157, 255, 206, 128, 155, 233, 111, 148, 194, 214, 238, + 252, 230, 96, 119, 30, 37, 73, 133, 129, 87, 185, 149, 251, 156, 17, 8, 83, 106, 207, + 98, 203, 100, 39, 199, 127, 253, 59, 37, 121, 161, 216, 146, 6, 178, 183, 243, 191, 91, + 106, 243, 132, 111, 216, 163, 87, 210, 197, 173, 146, 65, 131, 194, 96, 70, 6, 7, 192, + 45, 173, 71, 44, 134, 122, 60, 173, 208, 238, 22, 187, 208, 212, 51, 191, 185, 174, 3, + 125, 28, 134, 216, 209, 4, 224, 199, 16, 15, 56, 70, 188, 216, 92, 24, 96, 57, 125, + 138, 151, 73, 254, 245, 106, 53, 4, 150, 74, 43, 42, 4, 157, 238, 125, 168, 41, 224, + 22, 249, 45, 117, 32, 180, 161, 41, 39, 180, 96, 24, 2, 102, 57, 116, 34, 75, 90, 72, + 134, 176, 2, 196, 59, 143, 182, 201, 117, 178, 153, 81, 108, 167, 122, 139, 71, 197, + 55, 114, 60, 161, 130, 14, 29, 79, 152, 55, 136, 62, 190, 228, 202, 53, 126, 4, 173, + 99, 28, 190, 224, 255, 134, 123, 166, 162, 244, 55, 26, 81, 120, 207, 193, 10, 103, + 153, 215, 220, 12, 71, 67, 217, 154, 212, 44, 200, 232, 0, 178, 39, 44, 22, 7, 14, 215, + 183, 192, 104, 51, 46, 93, 102, 195, 65, 9, 191, 241, 237, 151, 5, 64, 103, 228, 162, + 41, 123, 29, 5, 80, 203, 198, 234, 230, 107, 53, 60, 58, 253, 47, 152, 22, 77, 81, 86, + 215, 132, 152, 135, 6, 218, 46, 92, 192, 218, 198, 234, 76, 178, 25, 203, 48, 61, 76, + 215, 96, 6, 49, 195, 37, 225, 10, 175, 222, 186, 133, 63, 50, 236, 215, 247, 17, 199, + 8, 134, 64, 246, 194, 167, 105, 15, 57, 62, 50, 51, 243, 192, 242, 122, 11, 46, 202, + 47, 10, 71, 153, 212, 226, 38, 12, 90, 150, 154, 152, 233, 7, 172, 111, 185, 160, 246, + 0, 166, 113, 90, 37, 203, 166, 43, 53, 255, 211, 127, 139, 73, 7, 10, 164, 1, 168, 223, + 87, 127, 43, 47, 87, 68, 84, 247, 223, 108, 108, 113, 36, 17, 50, 98, 236, 48, 10, 219, + 182, 107, 240, 198, 207, 20, 178, 9, 142, 14, 93, 163, 166, 147, 38, 176, 172, 156, 73, + 174, 238, 175, 231, 130, 159, 51, 128, 76, 34, 37, 138, 19, 3, 59, 71, 78, 144, 238, + 226, 214, 188, 27, 42, 142, 245, 238, 131, 190, 211, 240, 41, 122, 69, 124, 171, 75, + 115, 45, 144, 133, 176, 19, 81, 125, 230, 149, 235, 159, 6, 155, 195, 119, 62, 140, 50, + 52, 209, 124, 3, 93, 232, 20, 130, 138, 110, 60, 183, 177, 161, 52, 114, 91, 19, 211, + 156, 185, 202, 200, 36, 103, 253, 113, 45, 245, 177, 238, 43, 144, 38, 221, 0, 102, 50, + 255, 20, 154, 56, 156, 155, 92, 157, 57, 209, 77, 84, 88, 24, 116, 116, 54, 213, 222, + 76, 212, 193, 168, 216, 247, 125, 135, 114, 226, 128, 140, 250, 103, 82, 215, 238, 32, + 74, 252, 45, 224, 23, 95, 126, 124, 135, 124, 128, 53, 203, 40, 65, 222, 8, 83, 178, + 211, 64, 141, 64, 98, 188, 134, 100, 65, 166, 52, 249, 1, 206, 58, 55, 195, 23, 218, + 239, 41, 73, 88, 113, 148, 132, 209, 93, 37, 205, 58, 92, 14, 1, 133, 168, 162, 192, + 147, 70, 167, 101, 170, 152, 159, 0, 212, 26, 97, 49, 43, 217, 173, 38, 215, 136, 26, + 208, 244, 19, 83, 207, 38, 224, 254, 92, 169, 219, 236, 172, 49, 55, 98, 55, 15, 187, + 173, 114, 99, 130, 211, 78, 168, 221, 209, 250, 88, 189, 17, 186, 172, 129, 56, 90, + 238, 120, 23, 176, 87, 133, 81, 244, 29, 2, 215, 34, 88, 247, 231, 167, 56, + ]; + + let (exc_key, kc) = + super::derive_aes256_gcm_key_hybrid(&cust_key, &host_key_1, &host_key_2).unwrap(); + + assert_eq!(exc_key, exp_key); + assert_eq!(kc, exp_kc); + } + #[test] fn hkdf_rfc_5869() { use openssl::md::Md; @@ -933,4 +1298,94 @@ mod tests { })) )); } + + #[test] + fn validate_ec_key_valid() { + let (cust_key, host_key) = get_test_keys(); + + // Both test keys are SECP521R1 EC keys + assert!(validate_ec_key(&cust_key, "customer key", Nid::SECP521R1).is_ok()); + assert!(validate_ec_key(&host_key, "host key", Nid::SECP521R1).is_ok()); + } + + #[test] + fn validate_ec_key_wrong_curve() { + let (cust_key, _) = get_test_keys(); + + // Test key is SECP521R1, but we expect SECP384R1 + let result = validate_ec_key(&cust_key, "customer key", Nid::SECP384R1); + assert!(result.is_err()); + + if let Err(Error::RetrInvKey { + what, + kind, + value, + exp, + }) = result + { + assert_eq!(what, "curve"); + assert_eq!(kind, "customer key"); + assert_eq!(value, "secp521r1"); + assert_eq!(exp, "secp384r1"); + } else { + panic!("Expected RetrInvKey error"); + } + } + + #[test] + fn validate_ec_key_not_ec() { + let keypair = crate::get_test_asset!("keys/rsa2048key.pem"); + let keypair = PKey::private_key_from_pem(keypair).unwrap(); + + // RSA key is not an EC key + let result = validate_ec_key(&keypair, "EC key", Nid::SECP521R1); + assert!(result.is_err()); + + if let Err(Error::RetrInvKey { + what, + kind, + value, + exp, + }) = result + { + assert_eq!(what, "key type"); + assert_eq!(kind, "EC key"); + assert_eq!(value, "RSA"); + assert_eq!(exp, "EC (secp521r1)"); + } else { + panic!("Expected RetrInvKey error"); + } + } + + #[test] + fn validate_mlkem_key_valid() { + let (_, _, mlkem_key) = get_test_keys_hybrid(); + + // The third key from get_test_keys_hybrid is ML-KEM-1024 + assert!(validate_key_type(&mlkem_key, "ML-KEM key", KeyType::ML_KEM_1024).is_ok()); + } + + #[test] + fn validate_mlkem_key_wrong_type() { + let (ec_key, _) = get_test_keys(); + + // EC key is not ML-KEM + let result = validate_key_type(&ec_key, "EC key", KeyType::ML_KEM_1024); + assert!(result.is_err()); + + if let Err(Error::RetrInvKey { + what, + kind, + value, + exp, + }) = result + { + assert_eq!(what, "key type"); + assert_eq!(kind, "EC key"); + assert_eq!(value, "EC"); + assert_eq!(exp, "ML-KEM-1024"); + } else { + panic!("Expected RetrInvKey error"); + } + } } diff --git a/rust/pv/src/openssl_extensions/mod.rs b/rust/pv/src/openssl_extensions/mod.rs index 81d74a4f..16f6be7f 100644 --- a/rust/pv/src/openssl_extensions/mod.rs +++ b/rust/pv/src/openssl_extensions/mod.rs @@ -14,5 +14,4 @@ mod stackable_crl; pub use akid::*; pub use bio::*; pub use crl::*; -#[expect(unused_imports)] pub use ml_kem::*; diff --git a/rust/pv/src/req/ec_coord.rs b/rust/pv/src/req/ec_coord.rs index b8882e3f..9ec6ca3c 100644 --- a/rust/pv/src/req/ec_coord.rs +++ b/rust/pv/src/req/ec_coord.rs @@ -47,7 +47,10 @@ impl EcPubKeyCoord { /// Get the pub ECDH coordinates in the format the Ultravisor expects it: /// The two coordinates are padded to 80 bytes each. -fn get_pub_ecdh_points(pkey: &EcPointRef, grp: &EcGroupRef) -> Result<[u8; 160], ErrorStack> { +pub(crate) fn get_pub_ecdh_points( + pkey: &EcPointRef, + grp: &EcGroupRef, +) -> Result<[u8; 160], ErrorStack> { let mut x = BigNum::new()?; let mut y = BigNum::new()?; let mut bn_ctx = BigNumContext::new()?; diff --git a/rust/pv/src/req/keyslot.rs b/rust/pv/src/req/keyslot.rs index 768a967e..c4a52ee2 100644 --- a/rust/pv/src/req/keyslot.rs +++ b/rust/pv/src/req/keyslot.rs @@ -9,7 +9,8 @@ use openssl::pkey::{PKey, PKeyRef, Private, Public}; use super::ec_coord::EcPubKeyCoord; use super::encrypt::Encrypt; -use crate::crypto::{derive_aes256_gcm_key, encrypt_aead, hash}; +#[expect(unused)] +use crate::crypto::{derive_aes256_gcm_key, derive_aes256_gcm_key_hybrid, encrypt_aead, hash}; use crate::request::HostKey; use crate::Result; diff --git a/rust/pv/src/req/mod.rs b/rust/pv/src/req/mod.rs index 5bdadacd..acc632e7 100644 --- a/rust/pv/src/req/mod.rs +++ b/rust/pv/src/req/mod.rs @@ -17,6 +17,7 @@ mod request; // Re-export public types pub use context::ReqEncrCtx; +pub(crate) use ec_coord::get_pub_ecdh_points; pub use ec_coord::EcPubKeyCoord; pub use encrypt::{Aad, Encrypt}; pub use header::RequestHdr; diff --git a/rust/pv/src/test_utils.rs b/rust/pv/src/test_utils.rs index fc09e352..b5233238 100644 --- a/rust/pv/src/test_utils.rs +++ b/rust/pv/src/test_utils.rs @@ -89,6 +89,27 @@ pub fn get_test_key_and_cert() -> (PKey, X509) { (cust_key, host_key) } +pub fn get_test_key_and_cert_hybrid() -> (PKey, X509, X509) { + let pub_key = get_test_asset!("keys/public_cust.bin"); + let priv_key = get_test_asset!("keys/private_cust.bin"); + let host_key = get_test_asset!("keys/host.ec.crt"); + let host_keys = get_test_asset!("keys/host.hybrid.crt"); + + assert_eq!(pub_key.len(), 160); + assert_eq!(priv_key.len(), 80); + + let cust_key = get_keypair(pub_key, priv_key).unwrap(); + let host_key1 = X509::from_pem(host_key).unwrap(); + let host_keys = X509::stack_from_pem(host_keys).unwrap(); + assert_eq!(host_keys.len(), 2); + + println!("host_key1 = {host_key1:?}"); + println!("host_keys[0] = {:?}", host_keys[0]); + println!("host_keys[1] = {:?}", host_keys[1]); + + (cust_key, host_key1, host_keys[1].clone()) +} + /// TEST ONLY! Get a fixed private/public pair and a fixed public key /// /// Intended for TESTING only. All parts of the key including the private key are checked in git and @@ -98,6 +119,15 @@ pub fn get_test_keys() -> (PKey, PKey) { (cust_key, host.public_key().unwrap()) } +pub fn get_test_keys_hybrid() -> (PKey, PKey, PKey) { + let (cust_key, host_key_1, host_key_2) = get_test_key_and_cert_hybrid(); + ( + cust_key, + host_key_1.public_key().unwrap(), + host_key_2.public_key().unwrap(), + ) +} + fn read_ecdh_pubkey(coords: &[u8]) -> Result, ErrorStack> { assert!(coords.len() == 160); let x = BigNum::from_slice(&coords[..80])?; diff --git a/rust/pv/tests/assets/keys/create_hybrid_hkd.sh b/rust/pv/tests/assets/keys/create_hybrid_hkd.sh new file mode 100755 index 00000000..0b36590e --- /dev/null +++ b/rust/pv/tests/assets/keys/create_hybrid_hkd.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +set -euo pipefail + +OUT_PREFIX=${1:-host} +SUBJ="/C=US/O=IBM/OU=Testing/CN=Qsafe HK" + +if [ -f "${OUT_PREFIX}.hybrid.crt" ]; then + echo "[*] Nothing to do... ${OUT_PREFIX}.hybrid.crt already exists" + exit 0 +fi + +echo "[*] Generating ML-KEM-1024 keypair..." + +if openssl list -kem-algorithms 2>/dev/null | grep -qi ML-KEM-1024; then + echo " -> OpenSSL OQS provider detected" + + if ! [ -f "${OUT_PREFIX}.mlkem.key" ]; then + echo "[*] Generate ML-KEM key (target public key)" + openssl genpkey -algorithm MLKEM1024 -out "${OUT_PREFIX}.mlkem.key" + openssl pkey -in "${OUT_PREFIX}.mlkem.key" -pubout -out "${OUT_PREFIX}.mlkem.pub.pem" + fi + + if ! [ -f "issuer.key" ] || ! [ -f "issuer.crt" ]; then + echo "[*] Generate RSA issuer (signing key)" + openssl req -x509 -newkey rsa:4096 -nodes \ + -keyout issuer.key \ + -out issuer.crt \ + -days 365 \ + -subj "${SUBJ}" + fi + + if ! [ -f "${OUT_PREFIX}.mlkem.crt" ]; then + echo "[*] Create certificate with injected ML-KEM public key" + + openssl req -new -newkey rsa:2048 -nodes \ + -keyout tmp.key \ + -subj "${SUBJ}" | + openssl x509 -req \ + -CA issuer.crt \ + -CAkey issuer.key \ + -CAcreateserial \ + -days 365 \ + -set_serial 0x66A376DBB5502C74C6 \ + -force_pubkey "${OUT_PREFIX}.mlkem.pub.pem" \ + -extfile <( + cat < No PQ support, using placeholder" + exit 1 +fi + +echo "[*] Building hybrid PEM: ${OUT_PREFIX}.hybrid.pem" + +{ + echo "-----BEGIN CERTIFICATE-----" + + sed '/-----/d' "${OUT_PREFIX}.pem.crt" + + echo "-----END CERTIFICATE-----" + echo "-----BEGIN CERTIFICATE-----" + sed '/-----/d' "${OUT_PREFIX}.mlkem.crt" + + echo "-----END CERTIFICATE-----" +} >"${OUT_PREFIX}.hybrid.crt" + +echo "[✓] Done" +echo " -> ${OUT_PREFIX}.hybrid.crt" diff --git a/rust/pv/tests/assets/keys/host.ec.crt b/rust/pv/tests/assets/keys/host.ec.crt new file mode 100644 index 00000000..4bf9ed4e --- /dev/null +++ b/rust/pv/tests/assets/keys/host.ec.crt @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICXDCCAb6gAwIBAgIUcOg3S9/SHLdnpu6iaI7QI2cszsgwCgYIKoZIzj0EAwIw +QDELMAkGA1UEBhMCVVMxDDAKBgNVBAoMA0lCTTEQMA4GA1UECwwHVGVzdGluZzER +MA8GA1UEAwwIUXNhZmUgSEswHhcNMjYwNjI1MTM1MTE4WhcNMzYwNjIyMTM1MTE4 +WjBAMQswCQYDVQQGEwJVUzEMMAoGA1UECgwDSUJNMRAwDgYDVQQLDAdUZXN0aW5n +MREwDwYDVQQDDAhRc2FmZSBISzCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAfB0 +HaSx/tEDOnA0tv/tSFc2v1t0YarC8L9QcV0bU+o4Gk6OBriQi0GbUna4CndAPWrr +BYvC/ZVd2nKqZhx5WGKNAAq/NObSdvH6uNfjZY27pS56fB2abxa5UzlH/KkYAU+J +m1sFjZhOqD1Bvb/mizhz1WqdHucGSQYO55WDL+KH06Goo1MwUTAdBgNVHQ4EFgQU +/n03CIsLupLkHh5OwcdJFfucD8IwHwYDVR0jBBgwFoAU/n03CIsLupLkHh5OwcdJ +FfucD8IwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgOBiwAwgYcCQTTEnxAy +8/inrBEMtAINb9yA+LAXk5mDQIa7WXOiKRiJKLqHyrjPXqMIAtNgWwSmLggHiIYE +R4MiacrfbVdEOda3AkIBLv0XRN8zEaMLDlis6EdhgF+/AXFtsYxsjafZpoqnfx2X +YfbIgFpLUTcYWwoPi5uopbiAwv3AQy3x5CEFwG3e5PY= +-----END CERTIFICATE----- diff --git a/rust/pv/tests/assets/keys/host.ec.key b/rust/pv/tests/assets/keys/host.ec.key new file mode 100644 index 00000000..8c7c5a57 --- /dev/null +++ b/rust/pv/tests/assets/keys/host.ec.key @@ -0,0 +1,8 @@ +-----BEGIN PRIVATE KEY----- +MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAKog0FWiwlXuAS1jK +dNsahw9KZ+r4zvZrp1LmDSOQNOfkauXHH1EmBEnUkYccsi7PibYkz80sxbtk+NVW +Kk6pGk2hgYkDgYYABAHwdB2ksf7RAzpwNLb/7UhXNr9bdGGqwvC/UHFdG1PqOBpO +jga4kItBm1J2uAp3QD1q6wWLwv2VXdpyqmYceVhijQAKvzTm0nbx+rjX42WNu6Uu +enwdmm8WuVM5R/ypGAFPiZtbBY2YTqg9Qb2/5os4c9VqnR7nBkkGDueVgy/ih9Oh +qA== +-----END PRIVATE KEY----- diff --git a/rust/pv/tests/assets/keys/host.hybrid.crt b/rust/pv/tests/assets/keys/host.hybrid.crt new file mode 100644 index 00000000..8173c4ae --- /dev/null +++ b/rust/pv/tests/assets/keys/host.hybrid.crt @@ -0,0 +1,84 @@ +-----BEGIN CERTIFICATE----- +MIIFFDCCAvygAwIBAgIUO+SNGBgRvkmR/lKiZhiN4l4zS70wDQYJKoZIhvcNAQEN +BQAwgcwxCzAJBgNVBAYTAlVTMTQwMgYDVQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2lu +ZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMTQwMgYDVQQDDCtJbnRlcm5hdGlvbmFs +IEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMREwDwYDVQQIDAhOZXcgWW9y +azEVMBMGA1UEBwwMUG91Z2hrZWVwc2llMScwJQYDVQQLDB5JQk0gWiBIb3N0IEtl +eSBTaWduaW5nIFNlcnZpY2UwIBcNMjMwMzI5MDkwNDQ4WhgPMjM4NzEyMzEwOTA0 +NDhaMIG2MQswCQYDVQQGEwJVUzE0MDIGA1UECgwrSW50ZXJuYXRpb25hbCBCdXNp +bmVzcyBNYWNoaW5lcyBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrSW50ZXJuYXRpb25h +bCBCdXNpbmVzcyBNYWNoaW5lcyBDb3Jwb3JhdGlvbjERMA8GA1UECAwITmV3IFlv +cmsxDzANBgNVBAcMBkFybW9uazEXMBUGA1UECwwOSUJNIFogSG9zdCBLZXkwgZsw +EAYHKoZIzj0CAQYFK4EEACMDgYYABAF2iBzYS4tt5xI8fpAO33jn97aEmZFGsSY7 +qLhshEfwirbUacKxKO2eHDUBWAWs09MCM9ORIvfi+KocKxR7eIO0BgDDRVbCXPkv +Kc5mvUQRTWt7PHjhOj+QvbkAQPaHblJi93imGpN9GzSALrJX404Gct1fKjR63aoo +IDUJKnDDXC55c6OBhzCBhDAyBgNVHR8EKzApMCegJaAjhiFodHRwOi8vMTI3LjAu +MC4xOjEyMzQvY3JsL2libS5jcmwwDgYDVR0PAQH/BAQDAgMIMB8GA1UdIwQYMBaA +FN6M1/Do0NgBB3F9b9loWSA+sGd8MB0GA1UdDgQWBBR6ESQ+J+iXQe0a/KZ2+N+Z +8a9SZjANBgkqhkiG9w0BAQ0FAAOCAgEAVWJHoCxxkqh7b+y93PY4KPy4jJC4gN1S +dAPqttD/yteJ/4mbVel1/KNSoQBk5EpJmRqeBwHCgGJaT/TxYXNw/b8mRPxe/xbb +wieZMqlSmH028UjYDku1eM0IgHISgoCesIR95D5iAOWbMMVUwIHIHTfmhK7DmZVe +SPf7RIkctrpYxZh0Gw8KLZO6Mfy/9tq3dps0A7KS6jjdrF+M9LavPGwFvtfvRMTi +rdteByO2saGAKDvrjtievwlWCNBJlKV1arW9krN7eqJY5YO6eRbX6UjuhbPRgjte +eZ4jL121TBJaKZU7Q/lvYHIWfzstwQdiem2Ua1GyiiEvPZrQlmqQ3gDBtwJQGB4Q +2myP7MY7THiKObjaB8qRsVxKM78ktwAtAYSZv7gZlmSJ/uTMzDV5D2TQxqs7zwCj +sV+psUn4nvh58xP+DW+MYbF/Cpmzvul9FjMKBs270vE1q+gMot27rbQHRRJ4lVN5 +khiG6Oi6blVkPKExIVIiaZ9diXK6NhtWp15PWljNiDxZO+zpkeuw7cKLn/idzmvP +Gcj6m7DqcdsSIHNKbR5iM2VuDhg/j8uBD3uF2Wlymp31TBQgdYWSihJpwZKHNqJD +uq9SmegwI5gYg64KwABZM9hGbl/krXt/0CeCR5HRc+fthanKx/tO2tbCuVT3FR5J +XpKNUy1D78o= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +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 +jq+SvDvKMqeV +-----END CERTIFICATE----- diff --git a/rust/pv/tests/assets/keys/host.mlkem.crt b/rust/pv/tests/assets/keys/host.mlkem.crt new file mode 100644 index 00000000..074f2357 --- /dev/null +++ b/rust/pv/tests/assets/keys/host.mlkem.crt @@ -0,0 +1,54 @@ +-----BEGIN CERTIFICATE----- +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 +jq+SvDvKMqeV +-----END CERTIFICATE----- diff --git a/rust/pv/tests/assets/keys/host.mlkem.key b/rust/pv/tests/assets/keys/host.mlkem.key new file mode 100644 index 00000000..8e19ab7d --- /dev/null +++ b/rust/pv/tests/assets/keys/host.mlkem.key @@ -0,0 +1,71 @@ +-----BEGIN PRIVATE KEY----- +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 ++JA= +-----END PRIVATE KEY----- diff --git a/rust/pv/tests/assets/keys/host.mlkem.pub.pem b/rust/pv/tests/assets/keys/host.mlkem.pub.pem new file mode 100644 index 00000000..fa029e45 --- /dev/null +++ b/rust/pv/tests/assets/keys/host.mlkem.pub.pem @@ -0,0 +1,36 @@ +-----BEGIN PUBLIC KEY----- +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 +pJafxe8R +-----END PUBLIC KEY----- diff --git a/rust/pv/tests/assets/keys/issuer.crt b/rust/pv/tests/assets/keys/issuer.crt new file mode 100644 index 00000000..df7b2086 --- /dev/null +++ b/rust/pv/tests/assets/keys/issuer.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFYTCCA0mgAwIBAgIUIDYNUFtHABjQvM11wfnJrL2T9v8wDQYJKoZIhvcNAQEL +BQAwQDELMAkGA1UEBhMCVVMxDDAKBgNVBAoMA0lCTTEQMA4GA1UECwwHVGVzdGlu +ZzERMA8GA1UEAwwIUXNhZmUgSEswHhcNMjYwNzEzMDg1MTU4WhcNMjcwNzEzMDg1 +MTU4WjBAMQswCQYDVQQGEwJVUzEMMAoGA1UECgwDSUJNMRAwDgYDVQQLDAdUZXN0 +aW5nMREwDwYDVQQDDAhRc2FmZSBISzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC +AgoCggIBAJ9mCfJnjEYsXB6ORAxZtbbvIfAt5+EyG/bhSDhy2O2LH+VSwnrrPDCa +TSp0xlU6tXgJVlIPBH6vKE5cUkJErWGfxtE/nmuhy1j3DnSCN7cGjcAk62iV00bh +DwBpTqDlhqtAxpEFVE04yqLhxblh0ZaWcxhSNFCDFoD5VUnGwuSwxvWcMudd8LzO +XhJDLePUwXDpFa4mhnff0kUMe6VXLHd9QvPIvE7XUEUR5jncjTOD5inu/eyBcYpK +5kqJdBY97DduUt1dtS780p2rPS/HExuSo0qvfeVdt9lo/amugEMqVGFYXsAH6KRz +SpBFRDfd9MGmbX7xOe/cscNx87CjSdwQ8k8frH3xfhaHcqvq0E67WzRP6DGPsytj +26IXIVfpkCVrcfVNUTHPqrTOXjIKje2WbvTwmJv2t+xgwEHuREmrL133BiG1QPwX +GMDYxp1u/RsVvi6k/yX0NMVz8UxRDfhMIMKeU+tiyNL8t4/hikVapYTbvJGUussZ +zIRgbxlEqqPicQH4fdJcWMi+tB1wSyN4wLd93emcb09fVrc95G8LTnJ32UgjXnl2 +V5MHCIgCYIzSaf/+u/uISfQQ5AT5F5eVoVWpN+t2X9cMgFyvL2+fcrkUAYmRbMGN +fm0k7+svquXmDEzPUxIR9BGWTYxwklb3uOdZENiTumqKsUSM7dqhAgMBAAGjUzBR +MB0GA1UdDgQWBBQLbGItsikIfnLb8EIztBn5jfRgQjAfBgNVHSMEGDAWgBQLbGIt +sikIfnLb8EIztBn5jfRgQjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA +A4ICAQCNPAKyNyD+m6tBmfCvXd1kFj1dKZUrgPEuPkpnQk01n6eR12pNXAnUcDDx +HAJM/IFC69zZrekDaFV9lQ5tA5IiZefG09srPHSmEmsISBcDGBJjUx9qZNlKI3R+ +gVchEb812PstD5ErY9qFUByrOKMTWLSUVoUS7k8IMNGHMELbl2mQlvc/sIYD8wt5 +3/W93OQKnemlqEtC1ljCaDPX3T/eCH5qI+VBiC9OXY7lhUujI0Cs0yJAZ/2G7vcM +NIoCIKmZ+C5KKH6r8aG9NE+ciG2yQCvi7J8OWaesJoCLVZxygEYgorIJNxRTcCYH +En1sDGnQR/NKJPcpDT8KNXMriMmzMDXzecSCuE/tE8tL0lbAnncxJ+AlHAWlt09G +x7rSD3v+Axq5oC0S396ctdwgPwETP5FgLvJSuGicXROsUS4VmPW42h0BovMPI/TF +AfjBnKbgQ7aqppeb9nK9JGd7FTLDv1V2iaYsKUP2A2qmAuQVPrSuckNHt+V+xFlC +nkJA0RNUh3XKTFNSNXJtOVpGsr6/kDttnrlKKwDyzk7LAfbMld4RkNV29SSdEY7z +hGmimwe1ogcRYYqVevG1OcVUrugDaj+Ujkvs918VMS7RUW+IOdrjItLgvNKdjjgm +ARZcI7R0xiEH5+CGCTTurP83RIjPfnyuA1A5GRrbVGyE84Wuhg== +-----END CERTIFICATE----- diff --git a/rust/pv/tests/assets/keys/issuer.key b/rust/pv/tests/assets/keys/issuer.key new file mode 100644 index 00000000..27779666 --- /dev/null +++ b/rust/pv/tests/assets/keys/issuer.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +YFF7USKdWC1isfkk3OmsHvIwXzfRUA== +-----END PRIVATE KEY-----