rpki/tests/test_rc_from_der_errors.rs
2026-02-04 17:02:17 +08:00

121 lines
4.7 KiB
Rust

use rpki::data_model::rc::{
ResourceCertificate, ResourceCertificateError, ResourceCertificateParseError,
ResourceCertificateProfileError,
};
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=";
fn decode_b64(b64: &str) -> Vec<u8> {
use base64::Engine as _;
use base64::engine::general_purpose::STANDARD;
STANDARD.decode(b64).unwrap()
}
fn replace_first(haystack: &mut [u8], needle: &[u8], replacement: &[u8]) -> bool {
if needle.len() != replacement.len() {
return false;
}
for i in 0..=haystack.len().saturating_sub(needle.len()) {
if &haystack[i..i + needle.len()] == needle {
haystack[i..i + needle.len()].copy_from_slice(replacement);
return true;
}
}
false
}
fn replace_all(haystack: &mut [u8], needle: &[u8], replacement: &[u8]) -> usize {
if needle.len() != replacement.len() {
return 0;
}
let mut n = 0;
let mut i = 0;
while i + needle.len() <= haystack.len() {
if &haystack[i..i + needle.len()] == needle {
haystack[i..i + needle.len()].copy_from_slice(replacement);
n += 1;
i += needle.len();
} else {
i += 1;
}
}
n
}
#[test]
fn trailing_bytes_after_cert_are_rejected() {
let mut der = decode_b64(TEST_NO_SIA_CERT_DER_B64);
der.push(0);
let err = ResourceCertificate::from_der(&der).unwrap_err();
assert!(matches!(
err,
ResourceCertificateError::Parse(ResourceCertificateParseError::TrailingBytes(1))
));
}
#[test]
fn signature_algorithm_mismatch_is_detected() {
let mut der = decode_b64(TEST_NO_SIA_CERT_DER_B64);
// DER encoding of sha256WithRSAEncryption OID:
// 06 09 2A 86 48 86 F7 0D 01 01 0B
let oid = [
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
];
let mut patched = oid;
patched[10] = 0x01; // rsaEncryption, same length encoding
assert!(replace_first(&mut der, &oid, &patched));
let err = ResourceCertificate::from_der(&der).unwrap_err();
assert!(matches!(
err,
ResourceCertificateError::Validate(
ResourceCertificateProfileError::SignatureAlgorithmMismatch
)
));
}
#[test]
fn unsupported_signature_algorithm_is_detected() {
let mut der = decode_b64(TEST_NO_SIA_CERT_DER_B64);
let oid = [
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
];
let mut patched = oid;
patched[10] = 0x01;
let n = replace_all(&mut der, &oid, &patched);
assert!(
n >= 2,
"expected to patch at least inner+outer AlgorithmIdentifier"
);
let err = ResourceCertificate::from_der(&der).unwrap_err();
assert!(matches!(
err,
ResourceCertificateError::Validate(
ResourceCertificateProfileError::UnsupportedSignatureAlgorithm
)
));
}
#[test]
fn invalid_signature_algorithm_parameters_are_detected() {
let mut der = decode_b64(TEST_NO_SIA_CERT_DER_B64);
// Replace NULL parameters (05 00) right after the sha256WithRSAEncryption OID with
// an empty OCTET STRING (04 00) to keep the encoding length unchanged.
let alg = [
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00,
];
let mut patched = alg;
patched[11] = 0x04;
let n = replace_all(&mut der, &alg, &patched);
assert!(
n >= 2,
"expected to patch at least inner+outer AlgorithmIdentifier parameters"
);
let err = ResourceCertificate::from_der(&der).unwrap_err();
assert!(matches!(
err,
ResourceCertificateError::Validate(
ResourceCertificateProfileError::InvalidSignatureAlgorithmParameters
)
));
}