rpki/tests/test_signed_object_verify.rs

165 lines
5.2 KiB
Rust

use rpki::data_model::signed_object::{RpkiSignedObject, SignedObjectVerifyError};
use x509_parser::prelude::FromDer;
use x509_parser::prelude::X509Certificate;
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_bytes(bytes: &[u8]) -> Vec<u8> {
tlv(0x02, bytes)
}
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);
}
}
der_integer_bytes(&bytes)
}
fn der_null() -> Vec<u8> {
vec![0x05, 0x00]
}
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_bit_string(unused: u8, bytes: &[u8]) -> Vec<u8> {
let mut content = vec![unused];
content.extend_from_slice(bytes);
tlv(0x03, &content)
}
fn rsa_spki_der_with_modulus_bytes(modulus: &[u8], exponent: u64) -> Vec<u8> {
// SubjectPublicKeyInfo for RSA public key:
// SEQUENCE { algorithm AlgorithmIdentifier, subjectPublicKey BIT STRING }
// subjectPublicKey contains RSAPublicKey DER.
let alg = der_sequence(vec![
der_oid(rpki::data_model::oid::OID_RSA_ENCRYPTION),
der_null(),
]);
let rsa_pk = der_sequence(vec![der_integer_bytes(modulus), der_integer_u64(exponent)]);
let spk = der_bit_string(0, &rsa_pk);
der_sequence(vec![alg, spk])
}
#[test]
fn verify_mft_cms_signature_with_embedded_ee_cert() {
let der = std::fs::read(
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
)
.expect("read MFT fixture");
let so = RpkiSignedObject::decode_der(&der).expect("decode signed object");
so.verify_signature()
.expect("CMS signature should verify with embedded EE cert");
}
#[test]
fn verify_fails_with_wrong_spki() {
let mft_der = std::fs::read(
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
)
.expect("read MFT fixture");
let so = RpkiSignedObject::decode_der(&mft_der).expect("decode signed object");
let issuer_cert_der = std::fs::read(
"tests/fixtures/repository/rpki.apnic.net/repository/B527EF581D6611E2BB468F7C72FD1FF2/BfycW4hQb3wNP4YsiJW-1n6fjro.cer",
)
.expect("read issuer certificate fixture");
let (_rem, issuer_cert) = X509Certificate::from_der(&issuer_cert_der).expect("parse cert");
let wrong_spki_der = issuer_cert.public_key().raw.to_vec();
let err = so
.verify_signature_with_ee_spki_der(&wrong_spki_der)
.unwrap_err();
assert!(matches!(err, SignedObjectVerifyError::InvalidSignature));
}
#[test]
fn verify_fails_with_tampered_signature() {
let der = std::fs::read(
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
)
.expect("read MFT fixture");
let mut so = RpkiSignedObject::decode_der(&der).expect("decode signed object");
so.signed_data.signer_infos[0].signature[0] ^= 0x01;
let err = so.verify_signature().unwrap_err();
assert!(matches!(err, SignedObjectVerifyError::InvalidSignature));
}
#[test]
fn verify_rejects_spki_der_with_trailing_bytes() {
let der = std::fs::read(
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
)
.expect("read MFT fixture");
let so = RpkiSignedObject::decode_der(&der).expect("decode signed object");
let mut spki_der = so.signed_data.certificates[0].spki_der.clone();
spki_der.push(0);
let err = so
.verify_signature_with_ee_spki_der(&spki_der)
.unwrap_err();
assert!(matches!(err, SignedObjectVerifyError::EeSpkiTrailingBytes(1)));
}
#[test]
fn verify_with_all_zero_modulus_exercises_strip_leading_zeros_fallback() {
let der = std::fs::read(
"tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
)
.expect("read MFT fixture");
let so = RpkiSignedObject::decode_der(&der).expect("decode signed object");
// modulus INTEGER 0, exponent 65537 (valid exponent encoding); signature verification must fail
// but the SPKI parsing path should succeed.
let spki_der = rsa_spki_der_with_modulus_bytes(&[0x00], 65537);
let err = so
.verify_signature_with_ee_spki_der(&spki_der)
.unwrap_err();
assert!(matches!(err, SignedObjectVerifyError::InvalidSignature));
}