rpki/tests/test_signed_object_decode_errors.rs

1524 lines
50 KiB
Rust

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<u8> {
use base64::{engine::general_purpose, Engine as _};
general_purpose::STANDARD
.decode(b64)
.expect("decode base64 cert")
}
fn test_no_sia_cert_der() -> Vec<u8> {
decode_b64(TEST_NO_SIA_CERT_DER_B64)
}
fn test_sia_other_cert_der() -> Vec<u8> {
decode_b64(TEST_SIA_OTHER_CERT_DER_B64)
}
fn test_sia_https_cert_der() -> Vec<u8> {
decode_b64(TEST_SIA_HTTPS_CERT_DER_B64)
}
fn test_sia_dns_cert_der() -> Vec<u8> {
decode_b64(TEST_SIA_DNS_CERT_DER_B64)
}
fn extract_ski_from_cert(cert_der: &[u8]) -> Vec<u8> {
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<u8> {
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<u8> {
let mut out = vec![tag];
out.extend(len_bytes(content.len()));
out.extend_from_slice(content);
out
}
fn der_integer_u64(v: u64) -> Vec<u8> {
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<u8> {
vec![0x05, 0x00]
}
fn der_octet_string(bytes: &[u8]) -> Vec<u8> {
tlv(0x04, bytes)
}
fn der_oid(oid: &str) -> Vec<u8> {
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<u8>>) -> Vec<u8> {
let mut content = Vec::new();
for c in children {
content.extend(c);
}
tlv(0x30, &content)
}
fn der_set(mut children: Vec<Vec<u8>>) -> Vec<u8> {
// 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<u8> {
tlv(0x80 | (tag_no & 0x1F), content)
}
fn cs_cons(tag_no: u8, content: &[u8]) -> Vec<u8> {
tlv(0xA0 | (tag_no & 0x1F), content)
}
fn algorithm_id(oid: &str, params: Option<Vec<u8>>) -> Vec<u8> {
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<u8>) -> Vec<u8> {
der_sequence(vec![der_oid(oid), der_set(vec![value_der])])
}
fn cms_attribute_values(oid: &str, values_der: Vec<Vec<u8>>) -> Vec<u8> {
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<u8>,
extra_attrs: Vec<Vec<u8>>,
) -> Vec<u8> {
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<u8>>) -> Vec<u8> {
attrs.sort();
let mut content = Vec::new();
for a in attrs {
content.extend(a);
}
cs_cons(0, &content)
}
fn signer_info(
sid_ski: Vec<u8>,
digest_oid: &str,
signed_attrs: Option<Vec<u8>>,
sig_alg_oid: &str,
sig_alg_params: Option<Vec<u8>>,
include_unsigned_attrs: bool,
) -> Vec<u8> {
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<u8>,
digest_oid: &str,
signed_attrs: Option<Vec<u8>>,
sig_alg_oid: &str,
sig_alg_params: Option<Vec<u8>>,
include_unsigned_attrs: bool,
) -> Vec<u8> {
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<Vec<u8>>,
econtent_type_oid: &str,
econtent_bytes: Vec<u8>,
certificates_set_content: Option<Vec<u8>>,
include_crls: bool,
signer_infos: Vec<Vec<u8>>,
) -> Vec<u8> {
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<u8>) -> Vec<u8> {
der_sequence(vec![der_oid(OID_SIGNED_DATA), cs_cons(0, &signed_data_der)])
}
fn load_fixture_mft_ee_cert_and_ski() -> (Vec<u8>, Vec<u8>) {
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));
}