From 1db74eeee1a074a3b2701b5c7d4de643ac641716 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Sat, 20 May 2023 13:04:43 -0400 Subject: [PATCH 1/2] end_entity: add verify_private_key fn. This commit introduces a function on the `EndEntityCert` type that can be used to check if a DER encoded private key matches the certificate's subject public key. This is done by un-marshalling the encoded subject public key information of the EE certificate and performing a byte-for-byte comparison of the encoded public key with the encoded public key derived from the encoded private key. If the two match, we consider the private key usable for the certificate. Care is taken to match the algorithms and encoding formats supported by Rustls. --- src/der.rs | 164 ++++++++++++++++++++++++++++++++++++++++++ src/end_entity.rs | 108 +++++++++++++++++++++++++++- src/error.rs | 3 + src/signed_data.rs | 6 +- tests/ee_keyverify.rs | 3 + tests/generate.py | 145 ++++++++++++++++++++++++++++++++++++- 6 files changed, 420 insertions(+), 9 deletions(-) create mode 100644 tests/ee_keyverify.rs 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..0196901a --- /dev/null +++ b/tests/ee_keyverify.rs @@ -0,0 +1,3 @@ +use webpki::{EndEntityCert, Error}; + +// DO NOT EDIT BELOW: generated by tests/generate.py 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) From e39e1615addb20e08c1a3259f085cc4354f27861 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Mon, 5 Jun 2023 12:02:25 -0400 Subject: [PATCH 2/2] tests: generate ee_keyverify testcases. --- tests/ee_keyverify.rs | 668 +++++++++++++++++++++ tests/ee_keyverify/ec_p256_pkcs8.cert.der | Bin 0 -> 379 bytes tests/ee_keyverify/ec_p256_pkcs8.key.der | Bin 0 -> 138 bytes tests/ee_keyverify/ec_p256_sec1.cert.der | Bin 0 -> 378 bytes tests/ee_keyverify/ec_p256_sec1.key.der | Bin 0 -> 121 bytes tests/ee_keyverify/ec_p384_pkcs8.cert.der | Bin 0 -> 442 bytes tests/ee_keyverify/ec_p384_pkcs8.key.der | Bin 0 -> 185 bytes tests/ee_keyverify/ec_p384_sec1.cert.der | Bin 0 -> 439 bytes tests/ee_keyverify/ec_p384_sec1.key.der | Bin 0 -> 167 bytes tests/ee_keyverify/ed25519_pkcs8.cert.der | Bin 0 -> 315 bytes tests/ee_keyverify/ed25519_pkcs8.key.der | Bin 0 -> 48 bytes tests/ee_keyverify/rsa_2048_pkcs1.cert.der | Bin 0 -> 778 bytes tests/ee_keyverify/rsa_2048_pkcs1.key.der | Bin 0 -> 1192 bytes tests/ee_keyverify/rsa_2048_pkcs8.cert.der | Bin 0 -> 778 bytes tests/ee_keyverify/rsa_2048_pkcs8.key.der | Bin 0 -> 1217 bytes tests/ee_keyverify/rsa_3072_pkcs1.cert.der | Bin 0 -> 1034 bytes tests/ee_keyverify/rsa_3072_pkcs1.key.der | Bin 0 -> 1766 bytes tests/ee_keyverify/rsa_3072_pkcs8.cert.der | Bin 0 -> 1034 bytes tests/ee_keyverify/rsa_3072_pkcs8.key.der | Bin 0 -> 1794 bytes tests/ee_keyverify/rsa_4096_pkcs1.cert.der | Bin 0 -> 1290 bytes tests/ee_keyverify/rsa_4096_pkcs1.key.der | Bin 0 -> 2348 bytes tests/ee_keyverify/rsa_4096_pkcs8.cert.der | Bin 0 -> 1290 bytes tests/ee_keyverify/rsa_4096_pkcs8.key.der | Bin 0 -> 2375 bytes 23 files changed, 668 insertions(+) create mode 100644 tests/ee_keyverify/ec_p256_pkcs8.cert.der create mode 100644 tests/ee_keyverify/ec_p256_pkcs8.key.der create mode 100644 tests/ee_keyverify/ec_p256_sec1.cert.der create mode 100644 tests/ee_keyverify/ec_p256_sec1.key.der create mode 100644 tests/ee_keyverify/ec_p384_pkcs8.cert.der create mode 100644 tests/ee_keyverify/ec_p384_pkcs8.key.der create mode 100644 tests/ee_keyverify/ec_p384_sec1.cert.der create mode 100644 tests/ee_keyverify/ec_p384_sec1.key.der create mode 100644 tests/ee_keyverify/ed25519_pkcs8.cert.der create mode 100644 tests/ee_keyverify/ed25519_pkcs8.key.der create mode 100644 tests/ee_keyverify/rsa_2048_pkcs1.cert.der create mode 100644 tests/ee_keyverify/rsa_2048_pkcs1.key.der create mode 100644 tests/ee_keyverify/rsa_2048_pkcs8.cert.der create mode 100644 tests/ee_keyverify/rsa_2048_pkcs8.key.der create mode 100644 tests/ee_keyverify/rsa_3072_pkcs1.cert.der create mode 100644 tests/ee_keyverify/rsa_3072_pkcs1.key.der create mode 100644 tests/ee_keyverify/rsa_3072_pkcs8.cert.der create mode 100644 tests/ee_keyverify/rsa_3072_pkcs8.key.der create mode 100644 tests/ee_keyverify/rsa_4096_pkcs1.cert.der create mode 100644 tests/ee_keyverify/rsa_4096_pkcs1.key.der create mode 100644 tests/ee_keyverify/rsa_4096_pkcs8.cert.der create mode 100644 tests/ee_keyverify/rsa_4096_pkcs8.key.der diff --git a/tests/ee_keyverify.rs b/tests/ee_keyverify.rs index 0196901a..938942ed 100644 --- a/tests/ee_keyverify.rs +++ b/tests/ee_keyverify.rs @@ -1,3 +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 0000000000000000000000000000000000000000..cbae82fa8ca6df8b55dac58986f3ed81948ee8dc GIT binary patch literal 379 zcmXqLVk|dkVw79J%*4pVB$9MQ>H5jKEs_%&mYlNS^3Z!x>AS#yi;Y98&EuRc3p0~} zv7w}aI2&^)3p0;ENosM4UTQ^RZb43}UUGh}p_qXPNQ#SxH#IrFz{u1rz92if*up?g zoY%t4(8$Qxz|hpv&@c+lH8L;&a>+9^(m&SJX$PHaCFt8Y6#*nil_Q}|qvRkZrr^`8S8pZ_`)ew%%zPm;~G&@)$?m^GYb zkC_GEO<62pz-Pb%^ogu6BjbM-CIbfKAYgW9FmPd#x3t^-vYol*tZCUC#w@K_#*S{8 z%3Ds?q}cn0EtQuMW>RE0JVV5*>{RUfz1w-ezxsB`M=794^Rd}4xufeRJihtm%>n?M COn8|9 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..5fe21dcf534567b7260ede5d7fc4a35f3d53e546 GIT binary patch literal 138 zcmXqLY-eI*Fc4;A*J|@PXUoLM#sOw9GqSVf8e}suGO{QH7;*o6TPmpQF=OeSp7h}Q zd8~75)7~)p{V_Qi2CkB=uAyVt#2_1QBA2_4zinExmzZ2U}#p>IR5B486 q@)SN7WEHKxcKzpo#^=9Ih2Lgh>62u0E%eOQCT0z1*<)tGcT)hCCN8?4Zp(3v#;r+?SMC^x#yT5tv2kd%d7QIlVP-Ng zGL$qBXJZa!VdfDiNi8nXORY%EEyzjLOU}poZG`NFLJ>iW;) zI=IpH`sw~G#_i|N?doz4VCU*nEM|JU#zUyQujjt~Cq+g18H>(2+5Gr6SvaarX43qL z-6l>o+BucKrG$f`-rU%@da-~3p8*fho3g@; zjQ?4f3>c8ZhdGnMAdSh8VcWZ}d2N~w{~jAwKh};tnex(DdR5YSt`+k;r^{Yha#xYr zqUETwvb)R9z5gE_<69C2)N;Y^`}HL+xttU_L-xj-XZ;DuQaG|`$^4zlE1qArwPwC? VOC;fGQLC8A`_PZc`(E7A1ptJ$mvaCB literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..a63fa8735f010e424bae9e1fe9e6d66666513d0d GIT binary patch literal 185 zcmV;q07m~Xfwlqx05A{+2P%e0&OHJF1_djD1OOrgfu1mdn*sp=1Ta&5i@icOCz@i5 zbZq!^^=K?S>pg{W?2{c0aYWjpEnQ0l5~Hy;OHK;J? zrcAAm7(RDokX>Cof>Q^x5QpxRfId7DD$K^{5&-Iesu0>>8w0ux^D?ir0b9` zBST38aW>{q7G@rSlGNf7z0``t+=84`z2y8{Ls0`^kQ5gWPik^}fw6^2d~s^Bp@Ez@ zuZ5YRk&&^1p{b>zVHBKeWMBZ~l4WL@fdCsj*i}r7Y^>UiEDTD_NenD<^*#~KpW7d- zz4C$c5l8S`wN1H(JDx7)sSV#h>E!f9M>JIKtkmPXc+xzarSL_KqU62@waiAb=jO;a zTHW<#O89Of`mFXt@S~OTad$5DODz`?}2R>BWa%-gC#_DxA1A>h_I7E5E-9 T?8<(pO~Njo4%eDpa)=247YLVm literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b455a0c04f27daa2da39cee89a73979605723c89 GIT binary patch literal 167 zcmV;Y09gMpfusTf0R%8K`Z-7e(sz(dt!&x2WM1D=E&WRGzwe)Z(ch75;A+fvaGs`( z46A?R9L*Gu-d)9@2L=Tzfdl{|p=1MM00bU?Ojtwnhv2Q$@Co7wQ=KNVZ85mzqYQml zzmmz9qQod9+^H@O(aASg1aatmAsN2leFHLG&YT~CI^9bGVD~f?=6&!};;A2A+|rL4 Vrx#b(cfCDeJ{w_X3kO1j*eD;HOWFVc literal 0 HcmV?d00001 diff --git a/tests/ee_keyverify/ed25519_pkcs8.cert.der b/tests/ee_keyverify/ed25519_pkcs8.cert.der new file mode 100644 index 0000000000000000000000000000000000000000..d114d48fd8adba3b671e7f057a5efc1a5f15e510 GIT binary patch literal 315 zcmXqLVl+2se6@g?iIIs(Bu?N*;pSaF?~YZtS-h=n+jcVGWP|}L8?$z5fq}81q=7ga zb0`Zlk3dOkafx1PMPhD2PO4sVey*XIfe1*7i-$Kg#mLmu&@#RtJGt1xKu(<3!pzXf z$k@Qp)Y8x}3eGh$FaUDNGgJ%eBxXg1*aGHviMqkkUsfx%9^vLH&v1Ld`MK=CTg|7b z6Jqb2a$785z-Pb%begO%BjbM-CIbeTUPp%Wt~~F4atb^u4t#F6t~v4Y?$BHMS8AfV uwGxWhtJYhwc)jOLS)ljps4UAA=PUjfG-pWZHY#0xG3DiF)%+DE)_efYu40`4 literal 0 HcmV?d00001 diff --git a/tests/ee_keyverify/ed25519_pkcs8.key.der b/tests/ee_keyverify/ed25519_pkcs8.key.der new file mode 100644 index 0000000000000000000000000000000000000000..858dbf7c3ef5ed581673ea5641d5d4789ed769a5 GIT binary patch literal 48 zcmXreV`5}5U}a<0PAy{sDt_4ZQ1oW&=*cx^s6?=v#sW#iOp^Jx3d%gD&h z%3xq(C}|+h#vIDR%p*{eT3n)+T9KGrkdvyHoS$nbZXgPh;^N^eDo%_yGBB}-FUU?V zHZ+hE=e001G%_+aFf_F^G>n3CjSLKcTry2k`y+i5P{`w7A!)^1+hR)TynuEJY97TT?R z;!#y>cU-dNe^JmO-;aCExW1m2Nv=Go^0swmc~SPK6t6OFHltMxKfIQ|Vi9Fyx+@Xh z`0v#bp$i9(-I$;2_91uCD!WG;eu*-Fu{-ts>g^@(kINj{6Q34y>;JBUyw&c8Z3>c-rFk@t}5n0O1`|j)VIa!PP z{f}JP@GvCZbK!;KuG^HCdNOH6So>9-WM=d{J1tr1;7py1b3aUC3%s)RtI?kud$^93 zZdiI|(N~YK_6^qEE%Jg%%UL;-r>vcCxY}yzp5lx0$5Oc3mj%qYe{f>@=K{Am&AXPU zsizj!aS7!<({HwlStZxoY_zLx#vk6^eA&HEO71PH(f`6)=5zC5vht%Y&KcKTy$=Te zk`V3H^Ak`=W7^rZAwyq%6$7(=={w(joJ;JisI)iuAw87IAOImjry7jiz3B}vr6zq`oKe{tc8~_O3 BI57YK literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3472994a9073322e3794d998856e61c9138e82b7 GIT binary patch literal 1192 zcmV;Z1Xueof&`=j0RRGm0RaHEq%BFmJGKliN7qYbw*lTS?)+z9Rh$D#W{V`P(?N&- zy(nt`);qR~b=Q>2cjJ@Q@v&Nf;TSx|<|x$VMWJ#484B!;tS9^Ufx+Pp#sckSz!N%C1ZAS2IqN+aPu=*7P^ghb>)!U@+#~j4GUuIm| z|GL2qdoL_*xr_@6wQS3eub;J!afw5fFBWWnt~hSt_fbr0U0vav+?>_r01VmA%>+45 zk^Dy=_;k;{qWzy|4e|j30|5X50)hbmP^`yxW?IEauO7RqNyQ^ImOZ`C8U5zEi(oB5 zC+P!j!`HQ?LD|bGkb|C-(lk%ms_dpW0BfyHms{=_P$$SP_k9>vvLmC*$dcq`d8M8; zjEe)h$NutZ(`FALo|3{&cv*&|3*J)ahs9{4%$yrf6cys!eWfhADUpRE{2)-=-(bN! zy-LU$2Fv*qwi5%IR=UQpeD;+(uv)qCGWHKgCCdAprFovW-cqIC=u%7 zz3wXsQun9}Z_WxL+E*(PV0C@L{$m~Rbam}rIOR46#|m&=O@6O+-}E`Dq`543hpy^w|13&L*>oEWIkeoG;fAeUcis;58MJ5kT_<- z0B1$(-a1m`=;Kfr>3>gA57AEA^&%YX<0c^l+?(f^Bm}1A^nd{W02ZCH!tfnyBxZXmJ=1S^HJy}c=?$VRAy;lQ#zjO88QI_ts z65@J&s_EKi<_uX@IrW*k5gr^FS2J*l5B&*8?-|8)0-SBezek#Eo|h2TiZa7Bj%$?d z9YZ!#b!$2(Y|^o1D9{6&d^Ja7FR%_P0)c>BS@w3MUQ#;bG>;kF$M1VM5VR%c3B4fi zndzN+#H)b~e~e829{h*CX2tyre3gZY#T3xEeMSCfzla}o?w6x_lu(B3!Xp`z0~QyI^>sc*FZL1sgXDr@x4C}jQIx-$Atv%wkio`%Wh8h! z1ix0c)$OGx!;&IaVC3$XPHQq6A#y<+$^Asw>H+x>Yq<+$r`c*#j)tHM`^>Fpm*Kw^ zp=7cfa&V|o6CnKt2Fa?-Wp=1V98_Km+nG}Wfq?*}_o@-w=4Qo}Y>&|L5d$~oU60lq zqlTR0)+nYym-^>B2&z~uZiZTJwrFJwlD_`IQXW&BZV~FGM%mYO00r(+DIIQmcAMWh zoGKu+Xd*DVXZ!FLK>-8dnCUF$IHtj;<91--Sv~LN|0kIMS?eh=oNMuhE4-M%8G#DY G(=7(7Gfs;D literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..fad1e71de98899ee70014df86f24101de0b0dd7b GIT binary patch literal 778 zcmXqLVrDaFVtluNnTe5!Nu(fEj#>Hg!g}VW>yk$Dil1$n`l<|g**LY@JlekVGBR?r zG8mW`N*ai>F^94+^9Yor7MJLyRwU*YaS+{DPw0Q3me4TYtHP`*5r_`kHJpW$`ZHS#?_u}i_#w6Q)2kjQ_ zioAU3LhJ9ygPoV$VxRE3Z}VN5H`m_$$q7G(CF{Pm^4j&>*TXJI?&&iM@r$nTk?VjDYbu>MO-odu`fA1^WB`w-M-2;mA$Jo zx;DS=-m=Mi^dy?{yIR%`x8Iq{q&>KjD=B37#1xCnQrmQd^>XTz^~# E0Dyf*NdN!< literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..2d034bfe41e3d576d4b2170fcce4ce566a638cf4 GIT binary patch literal 1217 zcmV;y1U~yPf&{$+0RS)!1_>&LNQUrr!ay9qXGc{0)hbn0LUUO(*T_F zWz)a#%k+yC0fp~Xt4qxFn#m?iG(1rV1 z!HLpFUE~c%woR#Soj*6^$W8#HuJxWZ;ct_xWWdWkF{kOXcg7mU;kui}BM6jF%Z~o? z!VB2N%jQg`!AMiEnrOav*E_LX^+8=CmL5-=2M&ix3t;zUz0q#mTTUDGs@fKwWL8Qf z{Dt$Hwb4#+Z4w>ofW#tXRz9~`6^JAOEh;;0qpL1wH__OCL8?0RY6xdYG=i1wLQJz; zQBOS#8X)gRW1!$x;CqGXetv009Dm0RUhu zyrj37wFc}NLl|H#E-VW-7LGXK2ksbGnhJATWFXiCF+R#NV(H-dhMlRsk~)VM7!^Bl zrO$hFY>=xkmy9bpj*7PngA$?qv_9qSJvOf97P5UZ6P;OL(aCuYzo!9KfL)iBpUBiG zp{NSc&C4EgPpeA8?; zL35fuq=FhORFc+@=g2?SyXuQI?5c7yg2G6bO#`vjnxsE0BIyFCggg6L_HfLp!$qs)YjnK^aNuvYk*;q`~A( z>UoaVJPrr*{GnC7!}fPe<=#gX@l=bXjF36f37BkArqw#Ttbay&p@wS}Esl&A>&XIv zfE>CaXZE?llu4Lp07ka8nn9W#=Sft@+p6R14nW0%~*k{ytGCS}ln9Rh)Y0N{TzZ%KR>AdajrPkq1|;!syxC5BAX ztKO_9c)?&7mmt(`E4o4aQ0HS0sUA^wo?2*kSZ4o#FRY&S3j`OK@FODlp=Fu@jP8u~ zk=uf)BO@wm;GeWnhE8;%+|U(jy4^$Fs!N>9^`53kig#_eC8YI>v9b^JgrOUbSB);c zaRPyWN!%dKQeiX%r&=d#SXB8Y0Z;DdIfda}@8EqV%W$BK>Qc`?*!@?O|5J(wiM@2x4keZTX!np3 fwTa%P{^-FRdfvpw64PudD<&ZIs%qieLL#D|c-mBM literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..fa27d8efc05813b17535efba39577879e7920657 GIT binary patch literal 1034 zcmXqLVqr6AV#-^<%*4pVBoc7@YU-P~xijN`E4}H-FS>j_EX2=%myJ`a&7uoY%t4(8$Qxz|hpv&@c+lH8L;&a>+EciE$CK^B7qfn41{;84Q{jyO^378ySw= zX>Ho~epBqTgNZ8q6CZyoyn1y7>uSSIFB(NZPe_zE+fccCb=n1sPT_;bTO%3$CQ4;^ z9c0Z2^o_pWoqeIyYVNCf_SN?UY}VhEn)JN;TXw<3zBMXkx9&v$50Do)sTSq@=7d_x zMzN|-!FNOrT=#iw)0yCK)3D`t^T6-F{joqk>8S4gxlG#JJwddax*-FCh5{U!HC;T5~JH}nYA{Vkiz)bX&`YJsWs8Dry} zZ`xaC@tbdc7pzft%WC7EO%EK4bvCaE3}xtP(aV23=dZ!$pnbJk-)oqDT$fC*%DTaJ Oy!`Jx#ar{ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f942d7d95a2d3608e348df6dedc61ad4319f31fe GIT binary patch literal 1766 zcmVmDp)zzp4t1+_Zffe(RVIMZI zdAqA-&^U<`!85g40Zx$`XiC8aXi-gD*Nbb=bvm8uoo>*96#Xq~ zX`lG;%i7f+{n%m{73g_k4mfL5!8U37_(`UOEwd{Td}m;CN!`(Zb^KRR(If_!oHOOq z7i$?37&S~oh4C{HqI8+-cUYjKR zgT&-*V(?C~UF>%+-E--EfzO%mT4T z#L-7lof8N0S^NYdqln(5@1FPE8Fa10areY=$Wv+;{ln5e6e!}mdnG+<#@!~tN!3PZ zH2bdT#nt!Dil#9+n^R!VqQkzrpt7|Z{Pglv5n-#YB`in;SvIS2$LMValfpjjabm5l z(ioMtc*P#Q=JEcUo%h=O`cYl$lJa4$9K|`mnZ6F7ZU@C~uQ^E*Z%xLs z9v&9L^|O23;ZJ9b#!^ z3WId30)fE*;J48l{T@Hx9;yboIWRYuAVnmV6$wlDLZ&=cS$|s^=Il`+!+4aOj&M!% z)2F=IwUEvh4u3_9VV_7a5xGsSMCM1w??<oE5Pfx!L-D>ngpp!*fF~glF^W_3aK&NN{5@+5FN7zy3;5sv0A4s6?1q*-KaSSmE z?*>2eYEe&~MQbzJF4*R}jHmi{(d`(Jn&!~a3g`1wnIm?8I&{VvLlUu50)fCMLx2zP z6tCu%El;lL&gpTQOUN`n`e1&V(Sj~{MHbzmUCsZ}p4@yHdtuH>!7N^bj8dZw|1#j@ zzD11*sAO$}Y0ihhK1Vj82&6UbdcAi(J*R#~pRhJD9SsSxcb;LqR)=uxLU+ias}Za@ zK)bSOx49xkk|JPA0=nqQLMBZf4JrXAOddAHTKZWkx9ph58dMg#P@3Wq-M5FwRWLvj zvOK-`hU)4=%ZR>Rcfxs{%F%Rz=1LW}3%nQ48u=E#Q zxUiRr9#vT}^UEvoG`m)e$lDHs8P z+pZrQQC^@WpQbKzNqu_OJY&It?JCeEBz%h~bDE=EI0{%K*FLx6kIQ#PrAhV|EhG(# zRY3D?Et~ohw%8ig*?OP*=`jLgdge9Jc#8p>>JZ}ZBEf+QI=W|c=gJ1){GaLvj6SP?FfDpxal2*XXtvOoFYv4 z57b!b>74yVs3>-Mb=hrc=FIT*UA=i+`XYk%^fbAzNC?yC`Pmq;-nB>bQqcY626oz= I1N4;cG{SRmxBvhE literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..a68853cda3c39e4413892f52fb2574f4e13f8c7c GIT binary patch literal 1034 zcmXqLVqr6AV#-^<%*4pVB$61JQuOt&Y`B@G{2zM{q=3n+d*UsI>yZYRe$1DC?8%YJcVqtr9F+}3%L6-0n zPff)O3>^bHS2Nj2ylRvdQkyEHec@BuC6D)pjE?jdA}U6 zc=9}gu|Qg6{eerLXPv)iU+%l^{hIDHt@m!WY_Asu++250=}l65sbpN-VmpSF&)q%> zYH&C6{clWoemPu)>$Z*)@5y-KP0yWDGRkAco0rsRu)NaAoo#%^Klfa}@wTc^t-CHe zx28OEuJtgybFk-=LbB|NOQ$}`i~X_HDDd$6RA2KgVLGGjoGhJg!4osGObj0A-MT99 zWOWcHPXfc;v!}JE%`0d;@5jk+D=D6R%WcNp`i?~y8UI^cJ`9n7bh3Lo2@eC)i&{G_cEQXTHFtD@$b!iCiYAF@RKuK zJI{-h*|F3dI5(eprS0Ztmh*wODZ)$n3&ICD5?(;lC+)aX-cS!H|)Pm1q}$M4GL>_7F;to)vHx9Q!DB~v`V Mu6>Yuvd!W<0FTtZ>;M1& literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e57e4f9b2a59bd802349284dd2f24ed20bbc3c04 GIT binary patch literal 1794 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 VVal)0NbmTzRp8O(F5QEz+5kv%HY@-D literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..8c4abd1f2ecbfa0351587f95c4bf5eceaf5f0448 GIT binary patch literal 2348 zcmV+{3Dfp4f(a-B0RRGm0s#QFf7gQ27~ASY;m>CpYvgmW6}RD@ETG*n;p1WT~;zn^ID(2_zrzIB7Np znqjX(9MgVug@T9U*Q#It?0EncMQKlUby~1YKYe4oBGJYr9_v-CxnUu8PXt%pP&@%+ zTm-dV_R@o0#*{s`WTvd9bvpb%8=Id`!?I)GP)3Jj7Cw_#L@5 zv?SFr*qBZHiwW6A){%ceDR;y0B2oiV^bk8FRZIu&uW5r{nF{R;LEr4TXN&@~Q&CW( z^lV*y=DK%gM+IB-+Mgbll+VD^>UBu8Er8mC>X|)GqA!QfkSrA$XQyzcAX?I1Bd@tY z7{eu|X7IM`?7X)E0|5X50)hen2$gZe2J^vSKI$Klw`J_SUQcPWG2Ntq&F6C6oU4XjmAjdhUz3$-EJ#g&8!zHCIyeX{1sVBoi}6iSfXs*d84E zv~^S7>+ING(BE{uKGr32rbp@13PPxGI1~MU?UkD}+bJltq!TOJV`?+vsb!*OvDojI);PuHe5ojO#+?P3Cp&GUyq@7C-}fnA?zr@%Os*2c zsf9+vHI~Szc=?OY zj-SFwSVK_|3gW-{c9a5Tl#e4%j-f&wNvm0xs=BK=AvYG6uViLW<~q^*X!`pDakl>e zYs0CX)y)3?I0pNEq^QnpWH|3DjpBJldtQ6`Ng(-fl5-6X+2ujS z|7NS=3A(YEDYw{#k92zlsmQu-XUgiP5} z-vpgGG?pDhXBY~f#}foUV~?PGIUwBJ`GWDxcoviNddN75<83NvQa#jL=R>ys&qC)M z)4a^YEFIXM6zSQot5?1Ql$jBb&4Ml@`j_H$m|cnBtJLv^_o9@2D%4?)+S3ZB{cRT& zCjcqL3N2;tpFfM>xR_2@Bq(^*&gbT^)2KHsUq zJ+0xWnxKN{jP!oZaM^$2i&c2Z9C^wrak4I{Wm%c^!7G)0xrA1{DoeB)2dmjo^T+@i zXtl;d8%Lxh9i?RR!HjtZT8i{^(?*`5KFRSxZMClhF|C7YR3b@i*$l60nCc-c9JN|M0=-!lzGkZ0o*@$}OVVYk) z3R@{cn2q`md1Q82K9ZbUa#L&{JJoTL32lqJj6FVMMndx^A^(Qy=@?BGa4i;-uNz#1 z1O0!t+qw}^+1YSfsu5c{yIka>xXJgQyl?&Fynfq?(rEH%3ETT43I z8fwXV>>@U3$+fFrtswp&?{p2rCtO6NEzMS-h&v`_mzdrHWa5qLR^j~oVB$=s@;vPW z5WQAF!^wDz;v?ZWhngW|$RTpLwDJ5{Sdie>$_{X(nQ%2Of2@e)gnD}^c^l^GG1K7J zW)=g4XKv?SSaXaRE&&390RaGm<`={fVK;)EqsvmL!t2UN)53KBHbf617f|}5y^;hM z41#C!XX-=3#7KWe)B`?E=YgrN#3er33kZU7k9{ov^>1K1MCwFhRJNfOwH9VaZc9P& ze?rrkQk;JAS#8e0lVo*ds#NvO2L@CvClW?*T9srJomvr3B3}2WwQqkQ*1MQM!z0*MhXL`m#Q63-kUx)9o)lXD3r!B)X^mk}ahy?`B zPD;gWnKp~?$!4;mK~H4@f&lArXwk+QN8C%Cw?0UhCyySNl(^7#(VL$lH{tpKTXudijEVQF0VQ1cJPo zUo8AyhT1HHQu_g4>x;|&XT48 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..361e2f545676da88cab13661bd94b4221c63d159 GIT binary patch literal 1290 zcmXqLVr4UEVtTiLnTe5!NyPV>h2Gl*8()}J*H3=MyT@Zl;kztFk zJ`dCRINv>scTbI8IOhectTe+Vd#;}kXBM2As(MZ9#Jlrr9d%YLtA5hBOmRbC@|=%H zo#*b|*He=~*5|D_j|*kH2q{w>ZVj%E0>I#pH~yd{wI(MC3HmPGy>*x6|b^A ze)T!smLG4E^Yy}l^31=i|Fin|dVWc%sVtH&FQlumoe^Q&a3SX0%EE^;Vug=u{*`X^ zcza6WzW=xL0U|rSzNH6oUJbLkTM+P-cVYKWA)zmcW-}tM%8IacJ*mj_^WpeEyKe9K z4ZkL4|Bm@_xnY6OSVdHuKgQ0@CXPEu}uAN=DYHposz0r$3lWSQfE>rQ{lT)KmH8**g(sQ2TFRAU8 z!t-?VSNRmDPq>iAtTN5{yX=j{Ow5c7jEe;f_zZY}$x>FBk?}tZlK}&AngJ$hV47iM zFt~s6@$%iCF`eB-HS zeOHn<|CqV)(fnSqS2b}{rHvT!Y-BQ8s+TyGHa+`rcdBqh>brcoHAm{&&hGhorR1*u zM+@2Y98r54ANlbh#hqYArPIJoEfaTf?{h?3aHRG(U>ixmsJ1?J<9T{(Q%<5D97D6P$dz zxH|m{wi(|DZn@!DVRmB<-?sJ1=|BAg4l-LrPoK5zZYq21t*U!&XAD^M_TOL2Uh++L zbJme>Q(rvFh}*~3|BkPs+{5Q<#)9v0Z0W}3YL-8q-NhE__yfUcWu^N1Led_3wdS#BwZt+_`b~?Oem35|jG`-|aoX-1&0lwfD~VjQX#w zd3gWLg!Y*!=A3!+S(VKs<;BBTp7%_c&>y67_O-*o6Pok#(u()!n{2R2-SM}e%>Lth Y&GNA2^RmUHYgKe2Im+I?%zI@804LQw`v3p{ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..1f27c6e070f44e976ce8cdd88da381ecfcb4a48f GIT binary patch literal 2375 zcmV-N3Apw!f(b(c0RS)!1_>&LNQUwEii%!DFOii0)heo0JKdn30n>GdWnucu< zbKDfsXS#Dv&|52H?9!TKQ8vy0hJ&)m628>omFA4zuC*CoHJmhX;%Jd7lVTDPO{KfF zx;f)?nd)Rhe^M;ZK3JKF^vg_4$l;>gmJotUSih>t-+Rt2g!t`aZ!T6+Za4I={Hw>W z4;dPj1R3ejXCwy96alc%T+XR+;h0?$$0_|Ag-GqnAm2~+&rlS(O7>?`3Ds6S-EdI# z4WWzq5)$-bHket}9TWzN&~pc2g~+wGzaIa>QK(WtH!Br7$%mYvTt($SGoqi>MGU&XMeFTxF zBu%_*d?0$AW2PeK40H5lhdC3TEpMt!b7zpyW&?MkF5XaY&uW9MeZtgYH{8SMTb!-nj|y%%qwl7kk3&zP zuEUb%8j#{hM)FqG$#Z<=Et-XQZn}rcOMEaw;uJr1rOD8ij+iZ-^YZ&d+7GB=QBvqP z5^sU!BDvGdX℞Fv$QnKUNouJ5U;C3PfNBEb?#h_@9c!W8Z{n#V~NxUF^v(TYTgH z69oZ_A7e=I)GQuF;{d>M`Ujh_*&GNc<=lEaqwN~2R`;)C{j zbo8z=J?`}RSKy4cR?s=JfH6(Oy6y%cU|k?H3`HFfi0Eqmk17d#;GSC98}$3$b?U3s zvGh9G_}c^(Gln=1N5lKwjfWd_l!pYa_0aJZKl7 zvk=?IH}apE(wfejx~h;=<9U=(6;s60h50(E0W8m2shp;q+kn^wkfKdXuYrAKd4#jT z-!Plu44DNz>VGDfPDdkf=%!F=HH27Ko8kF*9*Z5C53Zax01xl<>m4+uatlZ04ak6z zV7?etB_U~i+f&{s%9}t@I$4}E!j+KB|H>8*nS4g#e!I_Xn_%8{dt8`%QMQkWbLQU| z#v>weo72VnVA?DO!k@fWVT;wJLl#`OPKWm6VLd?pU*OO%+3^B`0RaHNwL?I%`|C#F zy)UQnz{Oeg1u}cyiz5<9w)o;jHtXulzn+Cy)M5pNZuV>0M}VJ5KAJz@Rzt>odxpTA z?r{&%oGJXXufek5SwZ@X=~Opq!sRMw5}!VT5{LGPV+S_|RGXYJ1*_k>KjI;;>3i^pu4 z=$X}B_e-OuwHl@Wi3s)KD!l z&%|WAm$#U0t_u`35c*{te;8PqJ@LaUsATwXb#C^JS~XxzaPgb*IL?8kw&`1UrYbi#Qtozh)h8#<`-XSvwk zi*Y60>Dcp)G-gYscQGyrC8TDX$wH$nLrpR4#J7if5qj*uGBce(wLpCK$w=j(q#i&Ioap-cM7-$0)hbmBmYxdh`>n` zj0?Ik9P$U8ws&h?TM}VOgQ4f<1pOr&cgovmN}$HCCbl#affUZ(139IPOA_3f@*SAa ziekDJnE}%Q9iyL=4N*xR*9@dPb5InQTH`>siUxqu^$|!lVa?7J# z)GieSsOZP$r>2N>u*I{I+Ov&yde;YD8mX?YdF?K-ZZtym*~Ba%Vx3o*Sck3KZJ()_ zxaGD@98ujsBZG>+NzRIIhe_h;Km5SGq)x{bW>hNX94D)xk3B@80)hbn0OIK$c}R6@ zvzV4jEp|3U#Sx=LUm@x$!s(GiX5lw!u1cLId#+(_q8DR$sAGzOVx1fsnb<-)aqMgJ z?rH>EG)UYA(SA|4)X5L^O36n{ERGj9$)hIBH**OcuwGRz!2xy zz}8)DmeRSSfcEKhq*IUtB}}4dR>zA12AasH$7CT1Mm-26qZg6)I_tJH@3$YuvdzB# zT|{x3 z=xE2g27Wc_wucFN7v_R0gKlA`b)Kv=(-y^}Z%Xti-?TaJ`LdoIojgi}aWUb4sXwT> tPdaO^75W&n)PP0