diff --git a/src/der.rs b/src/der.rs index 13f1d77c..487d938b 100644 --- a/src/der.rs +++ b/src/der.rs @@ -14,6 +14,10 @@ use crate::{calendar, time, Error}; pub(crate) use ring::io::der::{CONSTRUCTED, CONTEXT_SPECIFIC}; +#[cfg(feature = "alloc")] +use ring::signature::{ + EcdsaSigningAlgorithm, ECDSA_P256_SHA256_ASN1_SIGNING, ECDSA_P384_SHA384_ASN1_SIGNING, +}; // Copied (and extended) from ring's src/der.rs #[allow(clippy::upper_case_acronyms)] @@ -223,6 +227,93 @@ macro_rules! oid { ) } +/// helper function for converting DER encoded [RFC 5915] format "Sec1" elliptic curve +/// private key material into a more standard DER encoded PKCS8 format. +/// +/// Requires `alloc` feature. +/// +/// This can be removed once https://github.com/briansmith/ring/pull/1456 +/// (or equivalent) is landed. +/// +/// [RFC 5915]: +#[cfg(feature = "alloc")] +pub(crate) fn convert_sec1_to_pkcs8( + sigalg: &EcdsaSigningAlgorithm, + maybe_sec1_der: &[u8], +) -> Result, Error> { + let pkcs8_prefix = if sigalg == &ECDSA_P256_SHA256_ASN1_SIGNING { + PKCS8_PREFIX_ECDSA_NISTP256 + } else if sigalg == &ECDSA_P384_SHA384_ASN1_SIGNING { + PKCS8_PREFIX_ECDSA_NISTP384 + } else { + return Err(Error::UnsupportedSignatureAlgorithm); + }; + + // wrap sec1 encoding in an OCTET STRING + let mut sec1_wrap = Vec::with_capacity(maybe_sec1_der.len() + 8); + sec1_wrap.extend_from_slice(maybe_sec1_der); + wrap_in_asn1_len(&mut sec1_wrap); + #[allow(clippy::as_conversions)] // Infallible conversion. + sec1_wrap.insert(0, Tag::OctetString as u8); + + let mut pkcs8 = Vec::with_capacity(pkcs8_prefix.len() + sec1_wrap.len() + 4); + pkcs8.extend_from_slice(pkcs8_prefix); + pkcs8.extend_from_slice(&sec1_wrap); + wrap_in_sequence(&mut pkcs8); + + Ok(pkcs8) +} + +#[cfg(feature = "alloc")] +pub(crate) fn wrap_in_asn1_len(bytes: &mut Vec) { + let len = bytes.len(); + + if len <= 0x7f { + #[allow(clippy::as_conversions)] // Infallible conversion. + bytes.insert(0, len as u8); + } else { + bytes.insert(0, 0x80u8); + let mut left = len; + while left > 0 { + #[allow(clippy::as_conversions)] // Safe to truncate. + let byte: u8 = (left & 0xff) as u8; + bytes.insert(1, byte); + bytes[0] += 1; + left >>= 8; + } + } +} + +/// Prepend stuff to `bytes` to put it in a DER SEQUENCE. +#[cfg(feature = "alloc")] +pub(crate) fn wrap_in_sequence(bytes: &mut Vec) { + wrap_in_asn1_len(bytes); + #[allow(clippy::as_conversions)] // Infallible conversion. + bytes.insert(0, Tag::Sequence as u8); +} + +// This is (line-by-line): +// - INTEGER Version = 0 +// - SEQUENCE (privateKeyAlgorithm) +// - id-ecPublicKey OID +// - prime256v1 OID +#[cfg(feature = "alloc")] +const PKCS8_PREFIX_ECDSA_NISTP256: &[u8] = b"\x02\x01\x00\ + \x30\x13\ + \x06\x07\x2a\x86\x48\xce\x3d\x02\x01\ + \x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"; + +// This is (line-by-line): +// - INTEGER Version = 0 +// - SEQUENCE (privateKeyAlgorithm) +// - id-ecPublicKey OID +// - secp384r1 OID +#[cfg(feature = "alloc")] +const PKCS8_PREFIX_ECDSA_NISTP384: &[u8] = b"\x02\x01\x00\ + \x30\x10\ + \x06\x07\x2a\x86\x48\xce\x3d\x02\x01\ + \x06\x05\x2b\x81\x04\x00\x22"; + #[cfg(test)] mod tests { #[test] @@ -288,3 +379,76 @@ mod tests { return untrusted::Reader::new(untrusted::Input::from(bytes)); } } + +#[cfg(test)] +#[cfg(feature = "alloc")] +mod der_helper_tests { + use crate::der::wrap_in_sequence; + + #[test] + fn test_empty() { + let mut val = Vec::new(); + wrap_in_sequence(&mut val); + assert_eq!(vec![0x30, 0x00], val); + } + + #[test] + fn test_small() { + let mut val = Vec::new(); + val.insert(0, 0x00); + val.insert(1, 0x11); + val.insert(2, 0x22); + val.insert(3, 0x33); + wrap_in_sequence(&mut val); + assert_eq!(vec![0x30, 0x04, 0x00, 0x11, 0x22, 0x33], val); + } + + #[test] + fn test_medium() { + let mut val = Vec::new(); + val.resize(255, 0x12); + wrap_in_sequence(&mut val); + assert_eq!(vec![0x30, 0x81, 0xff, 0x12, 0x12, 0x12], val[..6].to_vec()); + } + + #[test] + fn test_large() { + let mut val = Vec::new(); + val.resize(4660, 0x12); + wrap_in_sequence(&mut val); + assert_eq!(vec![0x30, 0x82, 0x12, 0x34, 0x12, 0x12], val[..6].to_vec()); + } + + #[test] + fn test_huge() { + let mut val = Vec::new(); + val.resize(0xffff, 0x12); + wrap_in_sequence(&mut val); + assert_eq!(vec![0x30, 0x82, 0xff, 0xff, 0x12, 0x12], val[..6].to_vec()); + assert_eq!(val.len(), 0xffff + 4); + } + + #[test] + fn test_gigantic() { + let mut val = Vec::new(); + val.resize(0x100000, 0x12); + wrap_in_sequence(&mut val); + assert_eq!( + vec![0x30, 0x83, 0x10, 0x00, 0x00, 0x12, 0x12], + val[..7].to_vec() + ); + assert_eq!(val.len(), 0x100000 + 5); + } + + #[test] + fn test_ludicrous() { + let mut val = Vec::new(); + val.resize(0x1000000, 0x12); + wrap_in_sequence(&mut val); + assert_eq!( + vec![0x30, 0x84, 0x01, 0x00, 0x00, 0x00, 0x12, 0x12], + val[..8].to_vec() + ); + assert_eq!(val.len(), 0x1000000 + 6); + } +} diff --git a/src/end_entity.rs b/src/end_entity.rs index 750d4a64..5c8bb73f 100644 --- a/src/end_entity.rs +++ b/src/end_entity.rs @@ -12,12 +12,21 @@ // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -#[cfg(feature = "alloc")] -use crate::subject_name::GeneralDnsNameRef; use crate::{ - cert, signed_data, subject_name, verify_cert, Error, SignatureAlgorithm, SubjectNameRef, Time, + cert, + signed_data::{self, parse_spki_value}, + subject_name, verify_cert, Error, SignatureAlgorithm, SubjectNameRef, Time, TlsClientTrustAnchors, TlsServerTrustAnchors, }; +#[cfg(feature = "alloc")] +use crate::{der, subject_name::GeneralDnsNameRef}; + +use ring::signature::{ + EcdsaKeyPair, Ed25519KeyPair, KeyPair, ECDSA_P256_SHA256_ASN1_SIGNING, + ECDSA_P384_SHA384_ASN1_SIGNING, +}; +#[cfg(feature = "alloc")] +use ring::signature::{EcdsaSigningAlgorithm, RsaKeyPair}; /// An end-entity certificate. /// @@ -185,4 +194,97 @@ impl<'a> EndEntityCert<'a> { pub fn dns_names(&'a self) -> Result>, Error> { subject_name::list_cert_dns_names(self) } + + /// This function tries to verify that the DER encoded `private_key_der` bytes correspond + /// to the public key described in the end-entity certificate's subject public key information. + /// If the provided key isn't usable for this EE certificate [`Error::CertPrivateKeyMismatch`] + /// will be returned. + /// + /// This function supports the following private key algorithms and encodings (matching the + /// supported formats used by Rustls): + /// Key algorithms: + /// * RSA + /// * ECDSA (P-256 or P-384) + /// * Ed25519 + /// Encodings: + /// * PKCS8v1 (RSA, ECDSA, Ed25519) + /// * PKCS8v2 (Ed25519 only) + /// * PKCS1 (RSA only) + /// * Sec1 (ECDSA only) + pub fn verify_private_key(&self, private_key_der: &[u8]) -> Result<(), Error> { + // Parse the SPKI of the EE cert and extract the DER encoded bytes of the public key. + let cert_pub_key = parse_spki_value(self.inner.spki.value())? + .key_value + .as_slice_less_safe(); + + #[cfg(feature = "alloc")] + if let Some(result) = extract_and_compare(private_key_der, rsa_from_der, cert_pub_key) { + return result; + } + + if let Some(result) = extract_and_compare(private_key_der, ecdsa_from_pkcs8, cert_pub_key) { + return result; + } + + #[cfg(feature = "alloc")] + if let Some(result) = extract_and_compare(private_key_der, ecdsa_from_sec1, cert_pub_key) { + return result; + } + + if let Some(result) = extract_and_compare(private_key_der, ed25519_from_pkcs8, cert_pub_key) + { + return result; + } + + Err(Error::CertPrivateKeyMismatch) + } +} + +#[cfg(feature = "alloc")] +fn rsa_from_der(private_key_der: &[u8]) -> Option { + RsaKeyPair::from_pkcs8(private_key_der) + .or_else(|_| RsaKeyPair::from_der(private_key_der)) + .ok() +} + +fn ecdsa_from_pkcs8(pkcs8_der: &[u8]) -> Option { + EcdsaKeyPair::from_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING, pkcs8_der) + .ok() + .or_else(|| EcdsaKeyPair::from_pkcs8(&ECDSA_P384_SHA384_ASN1_SIGNING, pkcs8_der).ok()) +} + +#[cfg(feature = "alloc")] +fn try_sec1_curve(sigalg: &'static EcdsaSigningAlgorithm, sec1_der: &[u8]) -> Option { + der::convert_sec1_to_pkcs8(sigalg, sec1_der) + .and_then(|pkcs8_der| { + EcdsaKeyPair::from_pkcs8(sigalg, &pkcs8_der).map_err(|_| Error::BadDer) + }) + .ok() +} + +#[cfg(feature = "alloc")] +fn ecdsa_from_sec1(sec1_der: &[u8]) -> Option { + try_sec1_curve(&ECDSA_P256_SHA256_ASN1_SIGNING, sec1_der) + .or_else(|| try_sec1_curve(&ECDSA_P384_SHA384_ASN1_SIGNING, sec1_der)) +} + +fn ed25519_from_pkcs8(pkcs8_der: &[u8]) -> Option { + Ed25519KeyPair::from_pkcs8_maybe_unchecked(pkcs8_der).ok() +} + +// use extractor to try and read a `KeyPair` from the `private_key_der`. If the extraction fails, +// return None indicating the caller should try a different extractor. If the extraction succeeds, +// return a result indicating whether the extracted keypair matches the `cert_pub_key`. +fn extract_and_compare( + private_key_der: &[u8], + extractor: impl Fn(&[u8]) -> Option, + cert_pub_key: &[u8], +) -> Option> { + match extractor(private_key_der) { + Some(keypair) => match cert_pub_key == keypair.public_key().as_ref() { + true => Some(Ok(())), + false => Some(Err(Error::CertPrivateKeyMismatch)), + }, + None => None, + } } diff --git a/src/error.rs b/src/error.rs index 9667337a..5f7e2125 100644 --- a/src/error.rs +++ b/src/error.rs @@ -38,6 +38,9 @@ pub enum Error { /// for is earlier than the certificate's notBefore time. CertNotValidYet, + /// The private key provided does not match the subject public key of the certificate. + CertPrivateKeyMismatch, + /// An end-entity certificate is being used as a CA certificate. EndEntityUsedAsCa, diff --git a/src/signed_data.rs b/src/signed_data.rs index eb36c44f..e03551f7 100644 --- a/src/signed_data.rs +++ b/src/signed_data.rs @@ -165,16 +165,16 @@ pub(crate) fn verify_signature( .map_err(|_| Error::InvalidSignatureForPublicKey) } -struct SubjectPublicKeyInfo<'a> { +pub(crate) struct SubjectPublicKeyInfo<'a> { algorithm_id_value: untrusted::Input<'a>, - key_value: untrusted::Input<'a>, + pub(crate) key_value: untrusted::Input<'a>, } // Parse the public key into an algorithm OID, an optional curve OID, and the // key value. The caller needs to check whether these match the // `PublicKeyAlgorithm` for the `SignatureAlgorithm` that is matched when // parsing the signature. -fn parse_spki_value(input: untrusted::Input) -> Result { +pub(crate) fn parse_spki_value(input: untrusted::Input) -> Result { input.read_all(Error::BadDer, |input| { let algorithm_id_value = der::expect_tag_and_get_value(input, der::Tag::Sequence)?; let key_value = der::bit_string_with_no_unused_bits(input)?; diff --git a/tests/ee_keyverify.rs b/tests/ee_keyverify.rs new file mode 100644 index 00000000..938942ed --- /dev/null +++ b/tests/ee_keyverify.rs @@ -0,0 +1,671 @@ +use webpki::{EndEntityCert, Error}; + +// DO NOT EDIT BELOW: generated by tests/generate.py + +#[cfg(feature = "alloc")] +#[test] +fn rsa_2048_pkcs8() { + let ee = include_bytes!("ee_keyverify/rsa_2048_pkcs8.cert.der"); + let ee = EndEntityCert::try_from(ee.as_ref()).unwrap(); + let privkey = include_bytes!("ee_keyverify/rsa_2048_pkcs8.key.der"); + + let rsa_3072_pkcs8 = include_bytes!("ee_keyverify/rsa_3072_pkcs8.key.der"); + let rsa_4096_pkcs8 = include_bytes!("ee_keyverify/rsa_4096_pkcs8.key.der"); + let rsa_2048_pkcs1 = include_bytes!("ee_keyverify/rsa_2048_pkcs1.key.der"); + let rsa_3072_pkcs1 = include_bytes!("ee_keyverify/rsa_3072_pkcs1.key.der"); + let rsa_4096_pkcs1 = include_bytes!("ee_keyverify/rsa_4096_pkcs1.key.der"); + let ec_p256_pkcs8 = include_bytes!("ee_keyverify/ec_p256_pkcs8.key.der"); + let ec_p384_pkcs8 = include_bytes!("ee_keyverify/ec_p384_pkcs8.key.der"); + let ec_p256_sec1 = include_bytes!("ee_keyverify/ec_p256_sec1.key.der"); + let ec_p384_sec1 = include_bytes!("ee_keyverify/ec_p384_sec1.key.der"); + let ed25519_pkcs8 = include_bytes!("ee_keyverify/ed25519_pkcs8.key.der"); + + assert!(ee.verify_private_key(privkey.as_ref()).is_ok()); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ed25519_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); +} + +#[cfg(feature = "alloc")] +#[test] +fn rsa_3072_pkcs8() { + let ee = include_bytes!("ee_keyverify/rsa_3072_pkcs8.cert.der"); + let ee = EndEntityCert::try_from(ee.as_ref()).unwrap(); + let privkey = include_bytes!("ee_keyverify/rsa_3072_pkcs8.key.der"); + + let rsa_2048_pkcs8 = include_bytes!("ee_keyverify/rsa_2048_pkcs8.key.der"); + let rsa_4096_pkcs8 = include_bytes!("ee_keyverify/rsa_4096_pkcs8.key.der"); + let rsa_2048_pkcs1 = include_bytes!("ee_keyverify/rsa_2048_pkcs1.key.der"); + let rsa_3072_pkcs1 = include_bytes!("ee_keyverify/rsa_3072_pkcs1.key.der"); + let rsa_4096_pkcs1 = include_bytes!("ee_keyverify/rsa_4096_pkcs1.key.der"); + let ec_p256_pkcs8 = include_bytes!("ee_keyverify/ec_p256_pkcs8.key.der"); + let ec_p384_pkcs8 = include_bytes!("ee_keyverify/ec_p384_pkcs8.key.der"); + let ec_p256_sec1 = include_bytes!("ee_keyverify/ec_p256_sec1.key.der"); + let ec_p384_sec1 = include_bytes!("ee_keyverify/ec_p384_sec1.key.der"); + let ed25519_pkcs8 = include_bytes!("ee_keyverify/ed25519_pkcs8.key.der"); + + assert!(ee.verify_private_key(privkey.as_ref()).is_ok()); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ed25519_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); +} + +#[cfg(feature = "alloc")] +#[test] +fn rsa_4096_pkcs8() { + let ee = include_bytes!("ee_keyverify/rsa_4096_pkcs8.cert.der"); + let ee = EndEntityCert::try_from(ee.as_ref()).unwrap(); + let privkey = include_bytes!("ee_keyverify/rsa_4096_pkcs8.key.der"); + + let rsa_2048_pkcs8 = include_bytes!("ee_keyverify/rsa_2048_pkcs8.key.der"); + let rsa_3072_pkcs8 = include_bytes!("ee_keyverify/rsa_3072_pkcs8.key.der"); + let rsa_2048_pkcs1 = include_bytes!("ee_keyverify/rsa_2048_pkcs1.key.der"); + let rsa_3072_pkcs1 = include_bytes!("ee_keyverify/rsa_3072_pkcs1.key.der"); + let rsa_4096_pkcs1 = include_bytes!("ee_keyverify/rsa_4096_pkcs1.key.der"); + let ec_p256_pkcs8 = include_bytes!("ee_keyverify/ec_p256_pkcs8.key.der"); + let ec_p384_pkcs8 = include_bytes!("ee_keyverify/ec_p384_pkcs8.key.der"); + let ec_p256_sec1 = include_bytes!("ee_keyverify/ec_p256_sec1.key.der"); + let ec_p384_sec1 = include_bytes!("ee_keyverify/ec_p384_sec1.key.der"); + let ed25519_pkcs8 = include_bytes!("ee_keyverify/ed25519_pkcs8.key.der"); + + assert!(ee.verify_private_key(privkey.as_ref()).is_ok()); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ed25519_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); +} + +#[cfg(feature = "alloc")] +#[test] +fn rsa_2048_pkcs1() { + let ee = include_bytes!("ee_keyverify/rsa_2048_pkcs1.cert.der"); + let ee = EndEntityCert::try_from(ee.as_ref()).unwrap(); + let privkey = include_bytes!("ee_keyverify/rsa_2048_pkcs1.key.der"); + + let rsa_2048_pkcs8 = include_bytes!("ee_keyverify/rsa_2048_pkcs8.key.der"); + let rsa_3072_pkcs8 = include_bytes!("ee_keyverify/rsa_3072_pkcs8.key.der"); + let rsa_4096_pkcs8 = include_bytes!("ee_keyverify/rsa_4096_pkcs8.key.der"); + let rsa_3072_pkcs1 = include_bytes!("ee_keyverify/rsa_3072_pkcs1.key.der"); + let rsa_4096_pkcs1 = include_bytes!("ee_keyverify/rsa_4096_pkcs1.key.der"); + let ec_p256_pkcs8 = include_bytes!("ee_keyverify/ec_p256_pkcs8.key.der"); + let ec_p384_pkcs8 = include_bytes!("ee_keyverify/ec_p384_pkcs8.key.der"); + let ec_p256_sec1 = include_bytes!("ee_keyverify/ec_p256_sec1.key.der"); + let ec_p384_sec1 = include_bytes!("ee_keyverify/ec_p384_sec1.key.der"); + let ed25519_pkcs8 = include_bytes!("ee_keyverify/ed25519_pkcs8.key.der"); + + assert!(ee.verify_private_key(privkey.as_ref()).is_ok()); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ed25519_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); +} + +#[cfg(feature = "alloc")] +#[test] +fn rsa_3072_pkcs1() { + let ee = include_bytes!("ee_keyverify/rsa_3072_pkcs1.cert.der"); + let ee = EndEntityCert::try_from(ee.as_ref()).unwrap(); + let privkey = include_bytes!("ee_keyverify/rsa_3072_pkcs1.key.der"); + + let rsa_2048_pkcs8 = include_bytes!("ee_keyverify/rsa_2048_pkcs8.key.der"); + let rsa_3072_pkcs8 = include_bytes!("ee_keyverify/rsa_3072_pkcs8.key.der"); + let rsa_4096_pkcs8 = include_bytes!("ee_keyverify/rsa_4096_pkcs8.key.der"); + let rsa_2048_pkcs1 = include_bytes!("ee_keyverify/rsa_2048_pkcs1.key.der"); + let rsa_4096_pkcs1 = include_bytes!("ee_keyverify/rsa_4096_pkcs1.key.der"); + let ec_p256_pkcs8 = include_bytes!("ee_keyverify/ec_p256_pkcs8.key.der"); + let ec_p384_pkcs8 = include_bytes!("ee_keyverify/ec_p384_pkcs8.key.der"); + let ec_p256_sec1 = include_bytes!("ee_keyverify/ec_p256_sec1.key.der"); + let ec_p384_sec1 = include_bytes!("ee_keyverify/ec_p384_sec1.key.der"); + let ed25519_pkcs8 = include_bytes!("ee_keyverify/ed25519_pkcs8.key.der"); + + assert!(ee.verify_private_key(privkey.as_ref()).is_ok()); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ed25519_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); +} + +#[cfg(feature = "alloc")] +#[test] +fn rsa_4096_pkcs1() { + let ee = include_bytes!("ee_keyverify/rsa_4096_pkcs1.cert.der"); + let ee = EndEntityCert::try_from(ee.as_ref()).unwrap(); + let privkey = include_bytes!("ee_keyverify/rsa_4096_pkcs1.key.der"); + + let rsa_2048_pkcs8 = include_bytes!("ee_keyverify/rsa_2048_pkcs8.key.der"); + let rsa_3072_pkcs8 = include_bytes!("ee_keyverify/rsa_3072_pkcs8.key.der"); + let rsa_4096_pkcs8 = include_bytes!("ee_keyverify/rsa_4096_pkcs8.key.der"); + let rsa_2048_pkcs1 = include_bytes!("ee_keyverify/rsa_2048_pkcs1.key.der"); + let rsa_3072_pkcs1 = include_bytes!("ee_keyverify/rsa_3072_pkcs1.key.der"); + let ec_p256_pkcs8 = include_bytes!("ee_keyverify/ec_p256_pkcs8.key.der"); + let ec_p384_pkcs8 = include_bytes!("ee_keyverify/ec_p384_pkcs8.key.der"); + let ec_p256_sec1 = include_bytes!("ee_keyverify/ec_p256_sec1.key.der"); + let ec_p384_sec1 = include_bytes!("ee_keyverify/ec_p384_sec1.key.der"); + let ed25519_pkcs8 = include_bytes!("ee_keyverify/ed25519_pkcs8.key.der"); + + assert!(ee.verify_private_key(privkey.as_ref()).is_ok()); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ed25519_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); +} + +#[test] +fn ec_p256_pkcs8() { + let ee = include_bytes!("ee_keyverify/ec_p256_pkcs8.cert.der"); + let ee = EndEntityCert::try_from(ee.as_ref()).unwrap(); + let privkey = include_bytes!("ee_keyverify/ec_p256_pkcs8.key.der"); + + let rsa_2048_pkcs8 = include_bytes!("ee_keyverify/rsa_2048_pkcs8.key.der"); + let rsa_3072_pkcs8 = include_bytes!("ee_keyverify/rsa_3072_pkcs8.key.der"); + let rsa_4096_pkcs8 = include_bytes!("ee_keyverify/rsa_4096_pkcs8.key.der"); + let rsa_2048_pkcs1 = include_bytes!("ee_keyverify/rsa_2048_pkcs1.key.der"); + let rsa_3072_pkcs1 = include_bytes!("ee_keyverify/rsa_3072_pkcs1.key.der"); + let rsa_4096_pkcs1 = include_bytes!("ee_keyverify/rsa_4096_pkcs1.key.der"); + let ec_p384_pkcs8 = include_bytes!("ee_keyverify/ec_p384_pkcs8.key.der"); + let ec_p256_sec1 = include_bytes!("ee_keyverify/ec_p256_sec1.key.der"); + let ec_p384_sec1 = include_bytes!("ee_keyverify/ec_p384_sec1.key.der"); + let ed25519_pkcs8 = include_bytes!("ee_keyverify/ed25519_pkcs8.key.der"); + + assert!(ee.verify_private_key(privkey.as_ref()).is_ok()); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ed25519_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); +} + +#[test] +fn ec_p384_pkcs8() { + let ee = include_bytes!("ee_keyverify/ec_p384_pkcs8.cert.der"); + let ee = EndEntityCert::try_from(ee.as_ref()).unwrap(); + let privkey = include_bytes!("ee_keyverify/ec_p384_pkcs8.key.der"); + + let rsa_2048_pkcs8 = include_bytes!("ee_keyverify/rsa_2048_pkcs8.key.der"); + let rsa_3072_pkcs8 = include_bytes!("ee_keyverify/rsa_3072_pkcs8.key.der"); + let rsa_4096_pkcs8 = include_bytes!("ee_keyverify/rsa_4096_pkcs8.key.der"); + let rsa_2048_pkcs1 = include_bytes!("ee_keyverify/rsa_2048_pkcs1.key.der"); + let rsa_3072_pkcs1 = include_bytes!("ee_keyverify/rsa_3072_pkcs1.key.der"); + let rsa_4096_pkcs1 = include_bytes!("ee_keyverify/rsa_4096_pkcs1.key.der"); + let ec_p256_pkcs8 = include_bytes!("ee_keyverify/ec_p256_pkcs8.key.der"); + let ec_p256_sec1 = include_bytes!("ee_keyverify/ec_p256_sec1.key.der"); + let ec_p384_sec1 = include_bytes!("ee_keyverify/ec_p384_sec1.key.der"); + let ed25519_pkcs8 = include_bytes!("ee_keyverify/ed25519_pkcs8.key.der"); + + assert!(ee.verify_private_key(privkey.as_ref()).is_ok()); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ed25519_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); +} + +#[cfg(feature = "alloc")] +#[test] +fn ec_p256_sec1() { + let ee = include_bytes!("ee_keyverify/ec_p256_sec1.cert.der"); + let ee = EndEntityCert::try_from(ee.as_ref()).unwrap(); + let privkey = include_bytes!("ee_keyverify/ec_p256_sec1.key.der"); + + let rsa_2048_pkcs8 = include_bytes!("ee_keyverify/rsa_2048_pkcs8.key.der"); + let rsa_3072_pkcs8 = include_bytes!("ee_keyverify/rsa_3072_pkcs8.key.der"); + let rsa_4096_pkcs8 = include_bytes!("ee_keyverify/rsa_4096_pkcs8.key.der"); + let rsa_2048_pkcs1 = include_bytes!("ee_keyverify/rsa_2048_pkcs1.key.der"); + let rsa_3072_pkcs1 = include_bytes!("ee_keyverify/rsa_3072_pkcs1.key.der"); + let rsa_4096_pkcs1 = include_bytes!("ee_keyverify/rsa_4096_pkcs1.key.der"); + let ec_p256_pkcs8 = include_bytes!("ee_keyverify/ec_p256_pkcs8.key.der"); + let ec_p384_pkcs8 = include_bytes!("ee_keyverify/ec_p384_pkcs8.key.der"); + let ec_p384_sec1 = include_bytes!("ee_keyverify/ec_p384_sec1.key.der"); + let ed25519_pkcs8 = include_bytes!("ee_keyverify/ed25519_pkcs8.key.der"); + + assert!(ee.verify_private_key(privkey.as_ref()).is_ok()); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ed25519_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); +} + +#[cfg(feature = "alloc")] +#[test] +fn ec_p384_sec1() { + let ee = include_bytes!("ee_keyverify/ec_p384_sec1.cert.der"); + let ee = EndEntityCert::try_from(ee.as_ref()).unwrap(); + let privkey = include_bytes!("ee_keyverify/ec_p384_sec1.key.der"); + + let rsa_2048_pkcs8 = include_bytes!("ee_keyverify/rsa_2048_pkcs8.key.der"); + let rsa_3072_pkcs8 = include_bytes!("ee_keyverify/rsa_3072_pkcs8.key.der"); + let rsa_4096_pkcs8 = include_bytes!("ee_keyverify/rsa_4096_pkcs8.key.der"); + let rsa_2048_pkcs1 = include_bytes!("ee_keyverify/rsa_2048_pkcs1.key.der"); + let rsa_3072_pkcs1 = include_bytes!("ee_keyverify/rsa_3072_pkcs1.key.der"); + let rsa_4096_pkcs1 = include_bytes!("ee_keyverify/rsa_4096_pkcs1.key.der"); + let ec_p256_pkcs8 = include_bytes!("ee_keyverify/ec_p256_pkcs8.key.der"); + let ec_p384_pkcs8 = include_bytes!("ee_keyverify/ec_p384_pkcs8.key.der"); + let ec_p256_sec1 = include_bytes!("ee_keyverify/ec_p256_sec1.key.der"); + let ed25519_pkcs8 = include_bytes!("ee_keyverify/ed25519_pkcs8.key.der"); + + assert!(ee.verify_private_key(privkey.as_ref()).is_ok()); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ed25519_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); +} + +#[test] +fn ed25519_pkcs8() { + let ee = include_bytes!("ee_keyverify/ed25519_pkcs8.cert.der"); + let ee = EndEntityCert::try_from(ee.as_ref()).unwrap(); + let privkey = include_bytes!("ee_keyverify/ed25519_pkcs8.key.der"); + + let rsa_2048_pkcs8 = include_bytes!("ee_keyverify/rsa_2048_pkcs8.key.der"); + let rsa_3072_pkcs8 = include_bytes!("ee_keyverify/rsa_3072_pkcs8.key.der"); + let rsa_4096_pkcs8 = include_bytes!("ee_keyverify/rsa_4096_pkcs8.key.der"); + let rsa_2048_pkcs1 = include_bytes!("ee_keyverify/rsa_2048_pkcs1.key.der"); + let rsa_3072_pkcs1 = include_bytes!("ee_keyverify/rsa_3072_pkcs1.key.der"); + let rsa_4096_pkcs1 = include_bytes!("ee_keyverify/rsa_4096_pkcs1.key.der"); + let ec_p256_pkcs8 = include_bytes!("ee_keyverify/ec_p256_pkcs8.key.der"); + let ec_p384_pkcs8 = include_bytes!("ee_keyverify/ec_p384_pkcs8.key.der"); + let ec_p256_sec1 = include_bytes!("ee_keyverify/ec_p256_sec1.key.der"); + let ec_p384_sec1 = include_bytes!("ee_keyverify/ec_p384_sec1.key.der"); + + assert!(ee.verify_private_key(privkey.as_ref()).is_ok()); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_2048_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_3072_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(rsa_4096_pkcs1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_pkcs8.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p256_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); + assert!(matches!( + ee.verify_private_key(ec_p384_sec1.as_ref()), + Err(Error::CertPrivateKeyMismatch) + )); +} diff --git a/tests/ee_keyverify/ec_p256_pkcs8.cert.der b/tests/ee_keyverify/ec_p256_pkcs8.cert.der new file mode 100644 index 00000000..cbae82fa Binary files /dev/null and b/tests/ee_keyverify/ec_p256_pkcs8.cert.der differ diff --git a/tests/ee_keyverify/ec_p256_pkcs8.key.der b/tests/ee_keyverify/ec_p256_pkcs8.key.der new file mode 100644 index 00000000..5fe21dcf Binary files /dev/null and b/tests/ee_keyverify/ec_p256_pkcs8.key.der differ diff --git a/tests/ee_keyverify/ec_p256_sec1.cert.der b/tests/ee_keyverify/ec_p256_sec1.cert.der new file mode 100644 index 00000000..c1ab09f0 Binary files /dev/null and b/tests/ee_keyverify/ec_p256_sec1.cert.der differ diff --git a/tests/ee_keyverify/ec_p256_sec1.key.der b/tests/ee_keyverify/ec_p256_sec1.key.der new file mode 100644 index 00000000..14e1c487 Binary files /dev/null and b/tests/ee_keyverify/ec_p256_sec1.key.der differ diff --git a/tests/ee_keyverify/ec_p384_pkcs8.cert.der b/tests/ee_keyverify/ec_p384_pkcs8.cert.der new file mode 100644 index 00000000..18203ece Binary files /dev/null and b/tests/ee_keyverify/ec_p384_pkcs8.cert.der differ diff --git a/tests/ee_keyverify/ec_p384_pkcs8.key.der b/tests/ee_keyverify/ec_p384_pkcs8.key.der new file mode 100644 index 00000000..a63fa873 Binary files /dev/null and b/tests/ee_keyverify/ec_p384_pkcs8.key.der differ diff --git a/tests/ee_keyverify/ec_p384_sec1.cert.der b/tests/ee_keyverify/ec_p384_sec1.cert.der new file mode 100644 index 00000000..0ed79782 Binary files /dev/null and b/tests/ee_keyverify/ec_p384_sec1.cert.der differ diff --git a/tests/ee_keyverify/ec_p384_sec1.key.der b/tests/ee_keyverify/ec_p384_sec1.key.der new file mode 100644 index 00000000..b455a0c0 Binary files /dev/null and b/tests/ee_keyverify/ec_p384_sec1.key.der differ diff --git a/tests/ee_keyverify/ed25519_pkcs8.cert.der b/tests/ee_keyverify/ed25519_pkcs8.cert.der new file mode 100644 index 00000000..d114d48f Binary files /dev/null and b/tests/ee_keyverify/ed25519_pkcs8.cert.der differ diff --git a/tests/ee_keyverify/ed25519_pkcs8.key.der b/tests/ee_keyverify/ed25519_pkcs8.key.der new file mode 100644 index 00000000..858dbf7c Binary files /dev/null and b/tests/ee_keyverify/ed25519_pkcs8.key.der differ diff --git a/tests/ee_keyverify/rsa_2048_pkcs1.cert.der b/tests/ee_keyverify/rsa_2048_pkcs1.cert.der new file mode 100644 index 00000000..7911b16f Binary files /dev/null and b/tests/ee_keyverify/rsa_2048_pkcs1.cert.der differ diff --git a/tests/ee_keyverify/rsa_2048_pkcs1.key.der b/tests/ee_keyverify/rsa_2048_pkcs1.key.der new file mode 100644 index 00000000..3472994a Binary files /dev/null and b/tests/ee_keyverify/rsa_2048_pkcs1.key.der differ diff --git a/tests/ee_keyverify/rsa_2048_pkcs8.cert.der b/tests/ee_keyverify/rsa_2048_pkcs8.cert.der new file mode 100644 index 00000000..fad1e71d Binary files /dev/null and b/tests/ee_keyverify/rsa_2048_pkcs8.cert.der differ diff --git a/tests/ee_keyverify/rsa_2048_pkcs8.key.der b/tests/ee_keyverify/rsa_2048_pkcs8.key.der new file mode 100644 index 00000000..2d034bfe Binary files /dev/null and b/tests/ee_keyverify/rsa_2048_pkcs8.key.der differ diff --git a/tests/ee_keyverify/rsa_3072_pkcs1.cert.der b/tests/ee_keyverify/rsa_3072_pkcs1.cert.der new file mode 100644 index 00000000..fa27d8ef Binary files /dev/null and b/tests/ee_keyverify/rsa_3072_pkcs1.cert.der differ diff --git a/tests/ee_keyverify/rsa_3072_pkcs1.key.der b/tests/ee_keyverify/rsa_3072_pkcs1.key.der new file mode 100644 index 00000000..f942d7d9 Binary files /dev/null and b/tests/ee_keyverify/rsa_3072_pkcs1.key.der differ diff --git a/tests/ee_keyverify/rsa_3072_pkcs8.cert.der b/tests/ee_keyverify/rsa_3072_pkcs8.cert.der new file mode 100644 index 00000000..a68853cd Binary files /dev/null and b/tests/ee_keyverify/rsa_3072_pkcs8.cert.der differ diff --git a/tests/ee_keyverify/rsa_3072_pkcs8.key.der b/tests/ee_keyverify/rsa_3072_pkcs8.key.der new file mode 100644 index 00000000..e57e4f9b Binary files /dev/null and b/tests/ee_keyverify/rsa_3072_pkcs8.key.der differ diff --git a/tests/ee_keyverify/rsa_4096_pkcs1.cert.der b/tests/ee_keyverify/rsa_4096_pkcs1.cert.der new file mode 100644 index 00000000..231429d5 Binary files /dev/null and b/tests/ee_keyverify/rsa_4096_pkcs1.cert.der differ diff --git a/tests/ee_keyverify/rsa_4096_pkcs1.key.der b/tests/ee_keyverify/rsa_4096_pkcs1.key.der new file mode 100644 index 00000000..8c4abd1f Binary files /dev/null and b/tests/ee_keyverify/rsa_4096_pkcs1.key.der differ diff --git a/tests/ee_keyverify/rsa_4096_pkcs8.cert.der b/tests/ee_keyverify/rsa_4096_pkcs8.cert.der new file mode 100644 index 00000000..361e2f54 Binary files /dev/null and b/tests/ee_keyverify/rsa_4096_pkcs8.cert.der differ diff --git a/tests/ee_keyverify/rsa_4096_pkcs8.key.der b/tests/ee_keyverify/rsa_4096_pkcs8.key.der new file mode 100644 index 00000000..1f27c6e0 Binary files /dev/null and b/tests/ee_keyverify/rsa_4096_pkcs8.key.der differ diff --git a/tests/generate.py b/tests/generate.py index 4d17f404..b1dd0403 100755 --- a/tests/generate.py +++ b/tests/generate.py @@ -12,9 +12,13 @@ from typing import TextIO, Optional, Union, Any, Callable, Iterable, List from cryptography import x509 -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import rsa, ec, ed25519, padding -from cryptography.hazmat.primitives.serialization import Encoding +from cryptography.hazmat.primitives.serialization import ( + Encoding, + PrivateFormat, + NoEncryption, +) from cryptography.hazmat.backends import default_backend from cryptography.x509.oid import NameOID, ExtendedKeyUsageOID import ipaddress @@ -32,6 +36,9 @@ ANY_PRIV_KEY = Union[ ed25519.Ed25519PrivateKey | ec.EllipticCurvePrivateKey | rsa.RSAPrivateKey ] +ANY_KEY = Union[ + ed25519.Ed25519PrivateKey | ec.EllipticCurvePrivateKey | rsa.RSAPrivateKey +] ANY_PUB_KEY = Union[ ed25519.Ed25519PublicKey | ec.EllipticCurvePublicKey | rsa.RSAPublicKey ] @@ -40,6 +47,15 @@ ] # Note: a bit loosey-goosey here but good enough for tests. +def subject_name_for_test(subject_cn: str, test_name: str) -> x509.Name: + return x509.Name( + [ + x509.NameAttribute(NameOID.COMMON_NAME, subject_cn), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, test_name), + ] + ) + + def trim_top(file_name: str) -> TextIO: """ Reads `file_name`, then writes lines up to a particular comment (the "top" @@ -843,6 +859,121 @@ def client_auth() -> None: ) +def ee_keyverify() -> None: + output_dir = "ee_keyverify" + if not os.path.isdir(output_dir): + os.mkdir(output_dir) + + def _rsa_privkey(key_size: int) -> ANY_PRIV_KEY: + return rsa.generate_private_key( + public_exponent=65537, key_size=key_size, backend=default_backend() + ) + + def _ec_privkey(curve: ec.EllipticCurve) -> ANY_PRIV_KEY: + return ec.generate_private_key(curve=curve, backend=default_backend()) + + def _ed25519_privkey() -> ANY_PRIV_KEY: + return ed25519.Ed25519PrivateKey.generate() + + def _generate_testcert( + name: str, + privkey: ANY_PRIV_KEY, + privkey_format: serialization.PrivateFormat, + ) -> None: + subject: x509.Name = subject_name_for_test("test.example.com", name) + builder: x509.CertificateBuilder = x509.CertificateBuilder() + builder = builder.subject_name(subject) + builder = builder.issuer_name(subject) + builder = builder.not_valid_before(NOT_BEFORE) + builder = builder.not_valid_after(NOT_AFTER) + builder = builder.serial_number(x509.random_serial_number()) + builder = builder.public_key(privkey.public_key()) + builder = builder.add_extension( + x509.BasicConstraints(ca=False, path_length=None), + critical=True, + ) + + algorithm: Union[hashes.SHA256 | None] = hashes.SHA256() + if isinstance(privkey, ed25519.Ed25519PrivateKey): + algorithm = None # Must be none for ED25519 + + cert: x509.Certificate = builder.sign( + private_key=privkey, algorithm=algorithm, backend=default_backend() + ) + + with open(os.path.join(output_dir, f"{name}.key.der"), "wb") as f: + f.write( + privkey.private_bytes( + encoding=Encoding.DER, + format=privkey_format, + encryption_algorithm=NoEncryption(), + ) + ) + with open(os.path.join(output_dir, f"{name}.cert.der"), "wb") as f: + f.write(cert.public_bytes(encoding=Encoding.DER)) + + all_keys: list[tuple[str, ANY_PRIV_KEY, serialization.PrivateFormat]] = [ + ("rsa_2048_pkcs8", _rsa_privkey(2048), PrivateFormat.PKCS8), + ("rsa_3072_pkcs8", _rsa_privkey(3072), PrivateFormat.PKCS8), + ("rsa_4096_pkcs8", _rsa_privkey(4096), PrivateFormat.PKCS8), + ("rsa_2048_pkcs1", _rsa_privkey(2048), PrivateFormat.TraditionalOpenSSL), + ("rsa_3072_pkcs1", _rsa_privkey(3072), PrivateFormat.TraditionalOpenSSL), + ("rsa_4096_pkcs1", _rsa_privkey(4096), PrivateFormat.TraditionalOpenSSL), + ("ec_p256_pkcs8", _ec_privkey(ec.SECP256R1()), PrivateFormat.PKCS8), + ("ec_p384_pkcs8", _ec_privkey(ec.SECP384R1()), PrivateFormat.PKCS8), + ("ec_p256_sec1", _ec_privkey(ec.SECP256R1()), PrivateFormat.TraditionalOpenSSL), + ("ec_p384_sec1", _ec_privkey(ec.SECP384R1()), PrivateFormat.TraditionalOpenSSL), + ("ed25519_pkcs8", _ed25519_privkey(), PrivateFormat.PKCS8), + ] + + def _write_test(test_name: str) -> None: + ee_cert_path = os.path.join(output_dir, f"{test_name}.cert.der") + privkey_path = os.path.join(output_dir, f"{test_name}.key.der") + + other_keys = [key_name for key_name, _, _ in all_keys if key_name != test_name] + other_keys_include_strs = [] + other_keys_assert_strs = [] + for key_name in other_keys: + key_path = os.path.join(output_dir, f"{key_name}.key.der") + other_keys_include_strs.append( + f'let {key_name} = include_bytes!("{key_path}");' + ) + other_keys_assert_strs.append( + f"assert!(matches!(ee.verify_private_key({key_name}.as_ref()), Err(Error::CertPrivateKeyMismatch)));" + ) + + alloc_gate = ( + '#[cfg(feature = "alloc")]' + if test_name.startswith("rsa") or test_name.endswith("sec1") + else "" + ) + other_keys_include_str = "\n".join(other_keys_include_strs) + other_keys_assert_str = "\n".join(other_keys_assert_strs) + print( + """ + %(alloc_gate)s + #[test] + fn %(test_name)s() { + let ee = include_bytes!("%(ee_cert_path)s"); + let ee = EndEntityCert::try_from(ee.as_ref()).unwrap(); + let privkey = include_bytes!("%(privkey_path)s"); + + %(other_keys_include_str)s + + assert!(ee.verify_private_key(privkey.as_ref()).is_ok()); + %(other_keys_assert_str)s + } + """ + % locals(), + file=output, + ) + + with trim_top("ee_keyverify.rs") as output: + for name, privkey, serialization_format in all_keys: + _generate_testcert(name, privkey, serialization_format) + _write_test(name) + + if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument( @@ -863,6 +994,12 @@ def client_auth() -> None: default=True, help="Generate client auth testcases", ) + parser.add_argument( + "--keyverify", + action=argparse.BooleanOptionalAction, + default=True, + help="Generate end entity key verification testcases", + ) parser.add_argument( "--format", action=argparse.BooleanOptionalAction, @@ -875,14 +1012,16 @@ def client_auth() -> None: default=True, help="Run cargo test post-generation", ) - args = parser.parse_args() + args = parser.parse_args() if args.tls_server_certs: tls_server_certs() if args.signatures: signatures() if args.clientauth: client_auth() + if args.keyverify: + ee_keyverify() if args.format: subprocess.run("cargo fmt", shell=True, check=True)