121 lines
4.7 KiB
Rust
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
|
|
)
|
|
));
|
|
}
|