use rpki::data_model::oid::{ OID_CMS_ATTR_CONTENT_TYPE, OID_CMS_ATTR_MESSAGE_DIGEST, OID_CMS_ATTR_SIGNING_TIME, OID_RSA_ENCRYPTION, OID_SHA256, OID_SHA256_WITH_RSA_ENCRYPTION, OID_SIGNED_DATA, }; use rpki::data_model::signed_object::{RpkiSignedObject, SignedObjectDecodeError}; use sha2::{Digest, Sha256}; use x509_parser::extensions::ParsedExtension; use x509_parser::prelude::FromDer; use x509_parser::prelude::X509Certificate; const TEST_NO_SIA_CERT_DER_B64: &str = "MIIDATCCAemgAwIBAgIUCyQLQJn92+gyAzvIz22q1F/97OMwDQYJKoZIhvcNAQELBQAwGjEYMBYGA1UEAwwPVGVzdCBObyBDUkxTaWduMB4XDTI2MDEyNzAzNTk1OVoXDTM2MDEyNTAzNTk1OVowGjEYMBYGA1UEAwwPVGVzdCBObyBDUkxTaWduMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr/aoMU8J6cddkM2r6F2snd1rCdQPepgo2T2lrqWFcxnQJdcxBL1OYg3wFi95TJmZSeIHIOGauDaJ2abmjgyOUHOC4U68x66JRg4hLkmLxo1cf3uYHWl9Obph6g2qPRvN80ORq70JPuL6mAfUkNiO9hnwK6oQiTzc/rjCQGIFH8kTESBMXLfNCyUpGi+MNztYH6Ha6bKAQuXgd29OFwIkOlGQnYgGC2qBMvnp86eITvV1gTiuI8Ho9m9nZHCmaD7TylvkMDq8Hk5nkIpRcG0uO60SkR2BiMOYe/TNn5dTmHd6bsdbU2GOvgnq1SnqGq3FOWhKIe3ycUJde0uNfZOqRwIDAQABoz8wPTAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUFjyzfJCDNhFfKxVr06kjUkE23dMwDQYJKoZIhvcNAQELBQADggEBAK98n2gVlwKA3Ob1YeAm9f+8hm7pbvrt0tA8GW180CILjf09k7fKgiRlxqGdZ9ySXjU52+zCqu3MpBXVbI87ZC+zA6uK05n4y1F0n85MJ9hGR2UEiPcqou85X73LvioynnSOy/OV1PjKJXReUsqF3GgDtgcMyFssPJ9s/5DWuUCScUJY6pu0kuIGOLQ/oXUw4TvxUeyz73gOTiAJshVTQoLpHUhj0595S7lArjwi7oLI1b8m8guTknvhk0Sc3tJZmUqOcIvYIs0guHpaeC+sMoF4K+6UTrxxOBdX+fUEWNpUyYXWHjdZq25PbJdHwA/VAW2zYVojaVREligf0Qfo6F4="; const TEST_SIA_OTHER_CERT_DER_B64: &str = "MIIDMDCCAhigAwIBAgIUEqpG+JXMZKL3bEarJ9NzqmE0mbMwDQYJKoZIhvcNAQELBQAwGTEXMBUGA1UEAwwOVGVzdCBTSUEgb3RoZXIwHhcNMjYwMTI3MDY1MzA5WhcNMzYwMTI1MDY1MzA5WjAZMRcwFQYDVQQDDA5UZXN0IFNJQSBvdGhlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANheqbavt3/tlRUrGJrZQFHzNqqmjOjnugWqkaxXwKa9WSQUs+sWFpcsKzhLW0dTLyL/6SylCNumXSbNHv92oXj0NQMzD4yXzHb78QceEk+O6Rpwtmcts03vI96kUw/xoW94+A7P4imPYOIwVqMzt0qcSxEkeYxwnN/IA+nLvlDO0Uw+0ctxDwz1/EdhsVFr8WHY5pu0w9n9R7xRPTJoke0fn0Q1ptI07aBpMIVxHMfdEuS7Mabu07LLFc2AC1XxdCbuBpqAgLPgBbFe9w2edTUFCYzCTZ3KiezrpQea0sKElC27JnuJO4ySbrMTbXv/JxlnvRcro1fRjIB0Mv14ptMCAwEAAaNwMG4wCQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwHQYDVR0OBBYEFLXYTYaN8zXjQ5wqrRUbvEKSD3wcMDUGCCsGAQUFBwELBCkwJzAlBggrBgEFBQcwBYYZcnN5bmM6Ly9leGFtcGxlLm5ldC9yZXBvLzANBgkqhkiG9w0BAQsFAAOCAQEAC0/lIV63dWy/jRfx2sYtCBV6ob+wTiOazSJL8s4lpIdZgmABw3YagjTwqHMQim/xVA8ecG9q8QVZ/AXYSnxtK6zTULXhAXDBdYHEUl/slDHOfk1Nvvd8t3qm7yk8wwP74xdqVk17NY5stcIyt5kf3w75adGy0we4jfGPNAKIpcRJpQSvLfhEsecnLzPPq3F4dLFFvyMNLT3rjFrJmxPviqBdt6Dm8l6MqbexxDeNTtqhq7JutBp1arzFzGicOzvG/CEskPKNPK7mIk3jdR9zfG+lygfoZe7cQEmvH3DtoUWVXoAYNALI5b3gE0CutR8x3M8h/jgRg4IutPafWqHXtw=="; const TEST_SIA_HTTPS_CERT_DER_B64: &str = "MIIDODCCAiCgAwIBAgIUBp2fsJYhUBJk711xTOahGbDzwN8wDQYJKoZIhvcNAQELBQAwGTEXMBUGA1UEAwwOVGVzdCBTSUEgaHR0cHMwHhcNMjYwMTI3MDY1MzA5WhcNMzYwMTI1MDY1MzA5WjAZMRcwFQYDVQQDDA5UZXN0IFNJQSBodHRwczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOMHIMaPf4Lr5DVDs1J3wPb6XL+b9EvmuVMo6JRhZHse3+Qx9ubOywowU+3NS50tgFe2H6Xm8XpeXMMhmWyKS/Z81J/6Sa9ZRI/vYLGOZmq1ORV44EDILoxxEazstD3LSgg5w28frAmY1wo0HvCX15Mp54nEwgjmwM9Vssg47iNz859grF/V3bRKlsnTwPhiJ79yt8etpNYZHCEc+h1PUilJh81NYPKnOGOUbJPVUkCF6MnLCM4WdYjKrnaGQzTAlDht15gcEyKmMEczsmU5TJe5ToJf+72bxOeGSvRbqS8iXvi/lZS0EcGVdpOc7oh6yHhC3EcZrHmvDHEeKtav18MCAwEAAaN4MHYwCQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwHQYDVR0OBBYEFHXD07FAu+OLsSH95FGd2ONTX8pGMD0GCCsGAQUFBwELBDEwLzAtBggrBgEFBQcwC4YhaHR0cHM6Ly9leGFtcGxlLm5ldC9yZXBvL3Rlc3QubWZ0MA0GCSqGSIb3DQEBCwUAA4IBAQDG7Haq/PbaDKfnd7kKkvuB9GBkJXhYK8k5qVHoPS1CnWWCWRpVjMfOni6v3Ylxa1TUYmWEdjSeQYso5xzC/vWiWG1nnt8Pn2W34R6vlx/yN9mwBMr6QK+F3IrprTQEbxWY019GFwaFcCSptWff1/YckjeTZFg+eSkuWembXO4788Opqx9d1KPJSviTODK2B0S0U5UQCeRAFD7cuwa1zrZJ/Y5kktI4lChymMAHx3N3CeJC8CvDg6VRncKDNkw0dCzLrcwX/ufQ1BbR4pmiedK9SiBqGKZJRZwUEOSYBLf5uitN/mkmZCTWnQQSySQM+QlNjNRo/+6qiBKWpKpADZlI"; const TEST_SIA_DNS_CERT_DER_B64: &str = "MIIDHjCCAgagAwIBAgIUJlS9d2BCJaamLyjYVTjvMNzWDxMwDQYJKoZIhvcNAQELBQAwFzEVMBMGA1UEAwwMVGVzdCBTSUEgZG5zMB4XDTI2MDEyNzA2NTMwOVoXDTM2MDEyNTA2NTMwOVowFzEVMBMGA1UEAwwMVGVzdCBTSUEgZG5zMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnKIddAQzQpDLbM+ZX3qR707L7CZvZ3MDGYN+tvuPXOfhATcOLtEaxu1dK4ZhV4Ou3ZqdxwYauyC+N4An0qCJW8mVr3zhbxathVGW7w4/S9pEV/+8dGW8ypOiqNixtmV++Ww54PguD6uxMk1S3IUOVTJY+QaetMy+SV9lCbOykZys17J56tMBmHRtuOxGPnaLtzZLddWqGhGFSDthSbKX4yToUIhTUl+wIRRYjBjnbGgzH5jV6eHUgrHRk+n567jNa9fe3cuRCGNBe6ny/8NPQnJEksWpA9lGfJDlEFsDIM9cXY78izr6i4JHeErwfusJiSchTT0ePhHXRAYMQoIqywIDAQABo2IwYDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIHgDAdBgNVHQ4EFgQUaY5MXriJ8s5VVa+s09HoSUloKBUwJwYIKwYBBQUHAQsEGzAZMBcGCCsGAQUFBzALggtleGFtcGxlLm5ldDANBgkqhkiG9w0BAQsFAAOCAQEAZSnkWxPTFWepHaK0XvAV145idY0ztEqY9BWUql2Ythzb4rjBAU1TfDRRklnnlE9o9/I6363ltaZBvj95e3CyTu4YGflxEpHsW+4aTth8ty1ee7YSqsdJ8gN08sroIpMTfr6tvWf65cVLSTkB4yP8cnNEM3zGr37zb32ChPXgUFwS9JFf3SMsXudZ4rHougE/PM4pQZvaOl3tFEzohV5MjA2VD38n3y6bVmx3i0Xqze7UZnl06aDKozzTXmFy/DoDRGG2pd2EjoC8gNAqIOL53uRz5nJlp8WEIBMe5Hmokrzv+zkAywVZZtYo1FvonOdg5etH94oMnZEtgV/OO9joRg=="; fn decode_b64(b64: &str) -> Vec { use base64::{engine::general_purpose, Engine as _}; general_purpose::STANDARD .decode(b64) .expect("decode base64 cert") } fn test_no_sia_cert_der() -> Vec { decode_b64(TEST_NO_SIA_CERT_DER_B64) } fn test_sia_other_cert_der() -> Vec { decode_b64(TEST_SIA_OTHER_CERT_DER_B64) } fn test_sia_https_cert_der() -> Vec { decode_b64(TEST_SIA_HTTPS_CERT_DER_B64) } fn test_sia_dns_cert_der() -> Vec { decode_b64(TEST_SIA_DNS_CERT_DER_B64) } fn extract_ski_from_cert(cert_der: &[u8]) -> Vec { let (_rem, cert) = X509Certificate::from_der(cert_der).expect("parse cert"); cert.extensions() .iter() .find(|ext| ext.oid.to_id_string() == rpki::data_model::oid::OID_SUBJECT_KEY_IDENTIFIER) .and_then(|ext| match ext.parsed_extension() { ParsedExtension::SubjectKeyIdentifier(ki) => Some(ki.0.to_vec()), _ => None, }) .expect("cert has SKI") } fn len_bytes(len: usize) -> Vec { if len < 128 { vec![len as u8] } else { let mut tmp = Vec::new(); let mut n = len; while n > 0 { tmp.push((n & 0xFF) as u8); n >>= 8; } tmp.reverse(); let mut out = vec![0x80 | (tmp.len() as u8)]; out.extend(tmp); out } } fn tlv(tag: u8, content: &[u8]) -> Vec { let mut out = vec![tag]; out.extend(len_bytes(content.len())); out.extend_from_slice(content); out } fn der_integer_u64(v: u64) -> Vec { let mut bytes = Vec::new(); let mut n = v; if n == 0 { bytes.push(0); } else { while n > 0 { bytes.push((n & 0xFF) as u8); n >>= 8; } bytes.reverse(); if bytes[0] & 0x80 != 0 { bytes.insert(0, 0); } } tlv(0x02, &bytes) } fn der_null() -> Vec { vec![0x05, 0x00] } fn der_octet_string(bytes: &[u8]) -> Vec { tlv(0x04, bytes) } fn der_oid(oid: &str) -> Vec { use std::str::FromStr; use der_parser::asn1_rs::ToDer; let oid = der_parser::Oid::from_str(oid).unwrap(); oid.to_der_vec().unwrap() } fn der_sequence(children: Vec>) -> Vec { let mut content = Vec::new(); for c in children { content.extend(c); } tlv(0x30, &content) } fn der_set(mut children: Vec>) -> Vec { // DER requires SET elements to be sorted by their encoded form. children.sort(); let mut content = Vec::new(); for c in children { content.extend(c); } tlv(0x31, &content) } fn cs_prim(tag_no: u8, content: &[u8]) -> Vec { tlv(0x80 | (tag_no & 0x1F), content) } fn cs_cons(tag_no: u8, content: &[u8]) -> Vec { tlv(0xA0 | (tag_no & 0x1F), content) } fn algorithm_id(oid: &str, params: Option>) -> Vec { let mut items = vec![der_oid(oid)]; if let Some(p) = params { items.push(p); } der_sequence(items) } fn cms_attribute(oid: &str, value_der: Vec) -> Vec { der_sequence(vec![der_oid(oid), der_set(vec![value_der])]) } fn cms_attribute_values(oid: &str, values_der: Vec>) -> Vec { der_sequence(vec![der_oid(oid), der_set(values_der)]) } fn signed_attrs_implicit( content_type_oid: &str, message_digest: &[u8], signing_time_der: Vec, extra_attrs: Vec>, ) -> Vec { let mut attrs = vec![ cms_attribute(OID_CMS_ATTR_CONTENT_TYPE, der_oid(content_type_oid)), cms_attribute(OID_CMS_ATTR_MESSAGE_DIGEST, der_octet_string(message_digest)), cms_attribute(OID_CMS_ATTR_SIGNING_TIME, signing_time_der), ]; attrs.extend(extra_attrs); // Content of SET OF Attribute (tag is IMPLICIT in SignerInfo, so we only include the SET content). let mut set_children = attrs; set_children.sort(); let mut content = Vec::new(); for a in set_children { content.extend(a); } cs_cons(0, &content) } fn signed_attrs_raw(mut attrs: Vec>) -> Vec { attrs.sort(); let mut content = Vec::new(); for a in attrs { content.extend(a); } cs_cons(0, &content) } fn signer_info( sid_ski: Vec, digest_oid: &str, signed_attrs: Option>, sig_alg_oid: &str, sig_alg_params: Option>, include_unsigned_attrs: bool, ) -> Vec { let mut fields = Vec::new(); fields.push(der_integer_u64(3)); fields.push(cs_prim(0, &sid_ski)); fields.push(algorithm_id(digest_oid, Some(der_null()))); if let Some(sa) = signed_attrs { fields.push(sa); } fields.push(algorithm_id(sig_alg_oid, sig_alg_params)); fields.push(der_octet_string(b"sig")); if include_unsigned_attrs { fields.push(cs_cons(1, &der_set(vec![der_null()]))); } der_sequence(fields) } fn signer_info_with_version( version: u64, sid_ski: Vec, digest_oid: &str, signed_attrs: Option>, sig_alg_oid: &str, sig_alg_params: Option>, include_unsigned_attrs: bool, ) -> Vec { let mut fields = Vec::new(); fields.push(der_integer_u64(version)); fields.push(cs_prim(0, &sid_ski)); fields.push(algorithm_id(digest_oid, Some(der_null()))); if let Some(sa) = signed_attrs { fields.push(sa); } fields.push(algorithm_id(sig_alg_oid, sig_alg_params)); fields.push(der_octet_string(b"sig")); if include_unsigned_attrs { fields.push(cs_cons(1, &der_set(vec![der_null()]))); } der_sequence(fields) } fn signed_data( version: u64, digest_alg_ids: Vec>, econtent_type_oid: &str, econtent_bytes: Vec, certificates_set_content: Option>, include_crls: bool, signer_infos: Vec>, ) -> Vec { let mut fields = Vec::new(); fields.push(der_integer_u64(version)); fields.push(der_set(digest_alg_ids)); let encap = der_sequence(vec![ der_oid(econtent_type_oid), cs_cons(0, &der_octet_string(&econtent_bytes)), ]); fields.push(encap); if let Some(cert_content) = certificates_set_content { fields.push(cs_cons(0, &cert_content)); } if include_crls { fields.push(cs_cons(1, &der_null())); } fields.push(der_set(signer_infos)); der_sequence(fields) } fn content_info_signed_data(signed_data_der: Vec) -> Vec { der_sequence(vec![der_oid(OID_SIGNED_DATA), cs_cons(0, &signed_data_der)]) } fn load_fixture_mft_ee_cert_and_ski() -> (Vec, Vec) { let mft = std::fs::read( "tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft", ) .expect("read MFT fixture"); let so = rpki::data_model::signed_object::RpkiSignedObject::decode_der(&mft) .expect("decode MFT signed object"); let ee = &so.signed_data.certificates[0]; (ee.raw_der.clone(), ee.subject_key_identifier.clone()) } #[test] fn trailing_bytes_after_object() { let der = std::fs::read( "tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft", ) .expect("read MFT fixture"); let mut bad = der.clone(); bad.push(0); let err = RpkiSignedObject::decode_der(&bad).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::TrailingBytes(1))); } #[test] fn content_info_must_have_two_elements() { let ci = der_sequence(vec![der_oid(OID_SIGNED_DATA)]); let err = RpkiSignedObject::decode_der(&ci).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); } #[test] fn content_info_content_must_be_tag0_explicit() { let sd = signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, b"e".to_vec(), None, false, vec![signer_info(vec![1], OID_SHA256, None, OID_RSA_ENCRYPTION, Some(der_null()), false)], ); let ci = der_sequence(vec![der_oid(OID_SIGNED_DATA), cs_cons(1, &sd)]); let err = RpkiSignedObject::decode_der(&ci).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); } #[test] fn content_info_content_must_contain_only_one_inner_object() { let sd = signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, b"e".to_vec(), None, false, vec![signer_info(vec![1], OID_SHA256, None, OID_RSA_ENCRYPTION, Some(der_null()), false)], ); let mut inner = sd.clone(); inner.extend(der_null()); let ci = der_sequence(vec![der_oid(OID_SIGNED_DATA), cs_cons(0, &inner)]); let err = RpkiSignedObject::decode_der(&ci).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); } #[test] fn signed_data_must_have_expected_element_count() { let sd = der_sequence(vec![ der_integer_u64(3), der_set(vec![algorithm_id(OID_SHA256, Some(der_null()))]), der_sequence(vec![der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST)]), ]); let ci = content_info_signed_data(sd); let err = RpkiSignedObject::decode_der(&ci).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); } #[test] fn signer_infos_missing_is_rejected() { let (cert_der, cert_ski) = load_fixture_mft_ee_cert_and_ski(); let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( cert_ski, OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let sd = der_sequence(vec![ der_integer_u64(3), der_set(vec![algorithm_id(OID_SHA256, Some(der_null()))]), der_sequence(vec![ der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST), cs_cons(0, &der_octet_string(&econtent)), ]), cs_cons(0, &cert_der), // no signerInfos SET ]); let _ = si; // ensure we don't accidentally depend on `si` here let ci = content_info_signed_data(sd); let err = RpkiSignedObject::decode_der(&ci).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); } #[test] fn certificates_field_appears_more_than_once_is_rejected() { let (cert_der, cert_ski) = load_fixture_mft_ee_cert_and_ski(); let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( cert_ski, OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let sd = der_sequence(vec![ der_integer_u64(3), der_set(vec![algorithm_id(OID_SHA256, Some(der_null()))]), der_sequence(vec![ der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST), cs_cons(0, &der_octet_string(&econtent)), ]), cs_cons(0, &cert_der), cs_cons(0, &cert_der), der_set(vec![si]), ]); let ci = content_info_signed_data(sd); let err = RpkiSignedObject::decode_der(&ci).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); } #[test] fn signed_data_unexpected_field_is_rejected() { let sd = der_sequence(vec![ der_integer_u64(3), der_set(vec![algorithm_id(OID_SHA256, Some(der_null()))]), der_sequence(vec![ der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST), cs_cons(0, &der_octet_string(b"e")), ]), der_null(), der_set(vec![signer_info(vec![1], OID_SHA256, None, OID_RSA_ENCRYPTION, Some(der_null()), false)]), ]); let ci = content_info_signed_data(sd); let err = RpkiSignedObject::decode_der(&ci).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); } #[test] fn encap_content_info_length_and_tags_are_validated() { // EncapsulatedContentInfo with 3 elements. let encap = der_sequence(vec![ der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST), cs_cons(0, &der_octet_string(b"e")), der_null(), ]); let sd = der_sequence(vec![ der_integer_u64(3), der_set(vec![algorithm_id(OID_SHA256, Some(der_null()))]), encap, der_set(vec![signer_info(vec![1], OID_SHA256, None, OID_RSA_ENCRYPTION, Some(der_null()), false)]), ]); let ci = content_info_signed_data(sd); let err = RpkiSignedObject::decode_der(&ci).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); // eContent wrong tag number. let encap = der_sequence(vec![ der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST), cs_cons(1, &der_octet_string(b"e")), ]); let sd = der_sequence(vec![ der_integer_u64(3), der_set(vec![algorithm_id(OID_SHA256, Some(der_null()))]), encap, der_set(vec![signer_info(vec![1], OID_SHA256, None, OID_RSA_ENCRYPTION, Some(der_null()), false)]), ]); let ci = content_info_signed_data(sd); let err = RpkiSignedObject::decode_der(&ci).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); // eContent contains trailing bytes inside the explicit wrapper. let mut inner = der_octet_string(b"e"); inner.push(0); let encap = der_sequence(vec![ der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST), cs_cons(0, &inner), ]); let sd = der_sequence(vec![ der_integer_u64(3), der_set(vec![algorithm_id(OID_SHA256, Some(der_null()))]), encap, der_set(vec![signer_info(vec![1], OID_SHA256, None, OID_RSA_ENCRYPTION, Some(der_null()), false)]), ]); let ci = content_info_signed_data(sd); let err = RpkiSignedObject::decode_der(&ci).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); } #[test] fn empty_econtent_is_rejected() { let (cert_der, cert_ski) = load_fixture_mft_ee_cert_and_ski(); let econtent = Vec::new(); let digest = Sha256::digest(&econtent).to_vec(); let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( cert_ski, OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent, Some(cert_der), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::EContentMissing)); } #[test] fn signer_info_sequence_len_and_version_are_validated() { let (cert_der, cert_ski) = load_fixture_mft_ee_cert_and_ski(); let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); // Too-short SignerInfo SEQUENCE. let si_short = der_sequence(vec![ der_integer_u64(3), cs_prim(0, &cert_ski), algorithm_id(OID_SHA256, Some(der_null())), algorithm_id(OID_RSA_ENCRYPTION, Some(der_null())), ]); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si_short], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); // Invalid SignerInfo.version. let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info_with_version( 1, cert_ski, OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent, Some(cert_der), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::InvalidSignerInfoVersion(1))); } #[test] fn signed_attrs_structure_and_presence_are_validated() { let (cert_der, cert_ski) = load_fixture_mft_ee_cert_and_ski(); let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); // Attribute SEQUENCE must have 2 elements. let bad_attr = der_sequence(vec![der_oid(OID_CMS_ATTR_CONTENT_TYPE)]); let signed_attrs = signed_attrs_raw(vec![bad_attr]); let si = signer_info( cert_ski.clone(), OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); // Missing content-type. let signed_attrs = signed_attrs_raw(vec![ cms_attribute(OID_CMS_ATTR_MESSAGE_DIGEST, der_octet_string(&digest)), cms_attribute(OID_CMS_ATTR_SIGNING_TIME, tlv(0x17, b"240101000000Z")), ]); let si = signer_info( cert_ski.clone(), OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); // Missing message-digest. let signed_attrs = signed_attrs_raw(vec![ cms_attribute(OID_CMS_ATTR_CONTENT_TYPE, der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST)), cms_attribute(OID_CMS_ATTR_SIGNING_TIME, tlv(0x17, b"240101000000Z")), ]); let si = signer_info( cert_ski.clone(), OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); // Missing signing-time. let signed_attrs = signed_attrs_raw(vec![ cms_attribute(OID_CMS_ATTR_CONTENT_TYPE, der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST)), cms_attribute(OID_CMS_ATTR_MESSAGE_DIGEST, der_octet_string(&digest)), ]); let si = signer_info( cert_ski, OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent, Some(cert_der), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); } #[test] fn algorithm_identifier_sequence_shape_is_validated() { let sd = signed_data( 3, vec![der_sequence(vec![])], // invalid AlgorithmIdentifier rpki::data_model::oid::OID_CT_RPKI_MANIFEST, b"e".to_vec(), None, false, vec![signer_info(vec![1], OID_SHA256, None, OID_RSA_ENCRYPTION, Some(der_null()), false)], ); let ci = content_info_signed_data(sd); let err = RpkiSignedObject::decode_der(&ci).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::Parse(_))); } #[test] fn ee_certificate_missing_signed_object_sia_is_rejected() { let cert_der = test_no_sia_cert_der(); let cert_ski = extract_ski_from_cert(&cert_der); let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( cert_ski, OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent, Some(cert_der), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::EeCertificateMissingSia | SignedObjectDecodeError::EeCertificateMissingSignedObjectSia )); } #[test] fn ee_certificate_sia_without_signed_object_access_method_is_rejected() { let cert_der = test_sia_other_cert_der(); let cert_ski = extract_ski_from_cert(&cert_der); let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( cert_ski, OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent, Some(cert_der), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::EeCertificateMissingSignedObjectSia )); } #[test] fn ee_certificate_signed_object_sia_must_be_uri() { let cert_der = test_sia_dns_cert_der(); let cert_ski = extract_ski_from_cert(&cert_der); let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( cert_ski, OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent, Some(cert_der), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::EeCertificateSignedObjectSiaNotUri )); } #[test] fn ee_certificate_signed_object_sia_requires_rsync_uri() { let cert_der = test_sia_https_cert_der(); let cert_ski = extract_ski_from_cert(&cert_der); let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( cert_ski, OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent, Some(cert_der), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::EeCertificateSignedObjectSiaNoRsync )); } #[test] fn signed_attrs_duplicate_content_type_is_rejected() { let (cert_der, cert_ski) = load_fixture_mft_ee_cert_and_ski(); let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); let signed_attrs = signed_attrs_raw(vec![ cms_attribute( OID_CMS_ATTR_CONTENT_TYPE, der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST), ), cms_attribute( OID_CMS_ATTR_CONTENT_TYPE, der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST), ), cms_attribute(OID_CMS_ATTR_MESSAGE_DIGEST, der_octet_string(&digest)), cms_attribute(OID_CMS_ATTR_SIGNING_TIME, tlv(0x17, b"240101000000Z")), ]); let si = signer_info( cert_ski, OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent, Some(cert_der), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::DuplicateSignedAttribute(ref oid) if oid == OID_CMS_ATTR_CONTENT_TYPE )); } #[test] fn signed_attrs_duplicate_signing_time_is_rejected() { let (cert_der, cert_ski) = load_fixture_mft_ee_cert_and_ski(); let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); let signed_attrs = signed_attrs_raw(vec![ cms_attribute( OID_CMS_ATTR_CONTENT_TYPE, der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST), ), cms_attribute(OID_CMS_ATTR_MESSAGE_DIGEST, der_octet_string(&digest)), cms_attribute(OID_CMS_ATTR_SIGNING_TIME, tlv(0x17, b"240101000000Z")), cms_attribute(OID_CMS_ATTR_SIGNING_TIME, tlv(0x17, b"240101000000Z")), ]); let si = signer_info( cert_ski, OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent, Some(cert_der), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::DuplicateSignedAttribute(ref oid) if oid == OID_CMS_ATTR_SIGNING_TIME )); } #[test] fn invalid_content_info_content_type() { let sd = der_sequence(vec![der_integer_u64(3), der_set(vec![]), der_sequence(vec![der_oid("1.2.3")]) , der_set(vec![])]); let ci = der_sequence(vec![der_oid("1.2.3.4"), cs_cons(0, &sd)]); let err = RpkiSignedObject::decode_der(&ci).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::InvalidContentInfoContentType(_) )); } #[test] fn invalid_signed_data_version() { let so = content_info_signed_data(signed_data( 4, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, b"e".to_vec(), None, false, vec![signer_info(vec![1], OID_SHA256, None, OID_RSA_ENCRYPTION, Some(der_null()), false)], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::InvalidSignedDataVersion(4) )); } #[test] fn invalid_digest_algorithms_count() { let so = content_info_signed_data(signed_data( 3, vec![ algorithm_id(OID_SHA256, Some(der_null())), algorithm_id(OID_SHA256, Some(der_null())), ], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, b"e".to_vec(), None, false, vec![signer_info(vec![1], OID_SHA256, None, OID_RSA_ENCRYPTION, Some(der_null()), false)], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::InvalidDigestAlgorithmsCount(2) )); } #[test] fn invalid_digest_algorithm_oid() { let so = content_info_signed_data(signed_data( 3, vec![algorithm_id("1.2.3.4", Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, b"e".to_vec(), None, false, vec![signer_info(vec![1], OID_SHA256, None, OID_RSA_ENCRYPTION, Some(der_null()), false)], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::InvalidDigestAlgorithm(_) )); } #[test] fn econtent_missing() { let encap = der_sequence(vec![der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST)]); let sd = der_sequence(vec![ der_integer_u64(3), der_set(vec![algorithm_id(OID_SHA256, Some(der_null()))]), encap, der_set(vec![]), ]); let so = der_sequence(vec![der_oid(OID_SIGNED_DATA), cs_cons(0, &sd)]); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::EContentMissing)); } #[test] fn crls_present_is_rejected() { let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, b"e".to_vec(), None, true, vec![signer_info(vec![1], OID_SHA256, None, OID_RSA_ENCRYPTION, Some(der_null()), false)], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::CrlsPresent)); } #[test] fn certificates_missing_is_rejected() { let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, b"e".to_vec(), None, false, vec![signer_info(vec![1], OID_SHA256, None, OID_RSA_ENCRYPTION, Some(der_null()), false)], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::CertificatesMissing)); } #[test] fn invalid_certificates_count_rejected() { let (cert_der, cert_ski) = load_fixture_mft_ee_cert_and_ski(); let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( cert_ski, OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let mut certs = cert_der.clone(); certs.extend_from_slice(&cert_der); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent, Some(certs), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::InvalidCertificatesCount(2) )); } #[test] fn ee_certificate_parse_error_is_reported() { let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( vec![0x01, 0x02], OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); // CertificateSet contains a DER object, but it's not a certificate. let certs = der_null(); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent, Some(certs), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::EeCertificateParse(_))); } #[test] fn invalid_signer_infos_count_rejected() { let (cert_der, cert_ski) = load_fixture_mft_ee_cert_and_ski(); let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si1 = signer_info( cert_ski.clone(), OID_SHA256, Some(signed_attrs.clone()), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let si2 = signer_info( cert_ski, OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent, Some(cert_der), false, vec![si1, si2], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::InvalidSignerInfosCount(2) )); } #[test] fn signer_info_errors_are_detected() { let (cert_der, cert_ski) = load_fixture_mft_ee_cert_and_ski(); let econtent = b"payload".to_vec(); let digest = Sha256::digest(&econtent).to_vec(); // Missing signedAttrs. let si_no_attrs = signer_info( cert_ski.clone(), OID_SHA256, None, OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si_no_attrs], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::SignedAttrsMissing)); // Invalid signer identifier. let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = der_sequence(vec![ der_integer_u64(3), der_null(), // not [0] SKI algorithm_id(OID_SHA256, Some(der_null())), signed_attrs, algorithm_id(OID_RSA_ENCRYPTION, Some(der_null())), der_octet_string(b"sig"), ]); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::InvalidSignerIdentifier)); // Invalid digest algorithm. let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( cert_ski.clone(), "1.2.3.4", Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::InvalidSignerInfoDigestAlgorithm(_) )); // Invalid signature algorithm OID. let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( cert_ski.clone(), OID_SHA256, Some(signed_attrs), "1.2.3.4", Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::InvalidSignatureAlgorithm(_) )); // Invalid signing-time value. let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, der_null(), vec![], ); let si = signer_info( cert_ski.clone(), OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::InvalidSigningTimeValue )); // signedAttrs has duplicate attribute. let dup = cms_attribute(OID_CMS_ATTR_MESSAGE_DIGEST, der_octet_string(&digest)); let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![dup], ); let si = signer_info( cert_ski.clone(), OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::DuplicateSignedAttribute(_) )); // signedAttrs attrValues count != 1. let bad_values = cms_attribute_values( OID_CMS_ATTR_CONTENT_TYPE, vec![ der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST), der_oid(rpki::data_model::oid::OID_CT_RPKI_MANIFEST), ], ); let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![bad_values], ); let si = signer_info( cert_ski.clone(), OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::InvalidSignedAttributeValuesCount { .. } )); // content-type mismatch. let signed_attrs = signed_attrs_implicit( "1.2.3.4", &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( cert_ski.clone(), OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::ContentTypeAttrMismatch { .. } )); // message-digest mismatch. let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, b"wrong", tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( cert_ski.clone(), OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::MessageDigestMismatch)); // sid_ski mismatch. let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( vec![0u8; 20], OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::SidSkiMismatch)); // Unsupported signedAttrs attribute. let bad_attr = cms_attribute("1.2.3.4", der_null()); let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![bad_attr], ); let si = signer_info( cert_ski.clone(), OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_null()), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::UnsupportedSignedAttribute(_) )); // signatureAlgorithm parameters invalid. let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x18, b"20500101000000Z"), vec![], ); let si = signer_info( cert_ski.clone(), OID_SHA256, Some(signed_attrs), OID_RSA_ENCRYPTION, Some(der_integer_u64(1)), false, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent.clone(), Some(cert_der.clone()), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!( err, SignedObjectDecodeError::InvalidSignatureAlgorithmParameters )); // unsignedAttrs present. let signed_attrs = signed_attrs_implicit( rpki::data_model::oid::OID_CT_RPKI_MANIFEST, &digest, tlv(0x17, b"240101000000Z"), vec![], ); let si = signer_info( cert_ski, OID_SHA256, Some(signed_attrs), OID_SHA256_WITH_RSA_ENCRYPTION, Some(der_null()), true, ); let so = content_info_signed_data(signed_data( 3, vec![algorithm_id(OID_SHA256, Some(der_null()))], rpki::data_model::oid::OID_CT_RPKI_MANIFEST, econtent, Some(cert_der), false, vec![si], )); let err = RpkiSignedObject::decode_der(&so).unwrap_err(); assert!(matches!(err, SignedObjectDecodeError::UnsignedAttrsPresent)); }