use oxideav_pdf::pubsec::der;
use oxideav_pdf::pubsec::signed_data::{
parse_signed_data, SignedData, SignerIdentifier, SignerInfo,
};
fn synth_signed_data_v1_attached(
issuer_der: Vec<u8>,
serial: Vec<u8>,
payload: &[u8],
signature_bytes: &[u8],
) -> Vec<u8> {
let digest_oid = vec![2u64, 16, 840, 1, 101, 3, 4, 2, 1]; let signature_oid = vec![1u64, 2, 840, 113549, 1, 1, 1];
let mut si_body = der::write_integer_u64(1); let ias_body = {
let mut b = issuer_der.clone();
b.extend_from_slice(&der::write_integer_bytes(&serial));
b
};
si_body.extend_from_slice(&der::write_sequence(&ias_body));
let da_alg = {
let mut b = der::write_oid(&digest_oid);
b.extend_from_slice(&der::write_null());
der::write_sequence(&b)
};
si_body.extend_from_slice(&da_alg);
let sig_alg = {
let mut b = der::write_oid(&signature_oid);
b.extend_from_slice(&der::write_null());
der::write_sequence(&b)
};
si_body.extend_from_slice(&sig_alg);
si_body.extend_from_slice(&der::write_octet_string(signature_bytes));
let signer_info = der::write_sequence(&si_body);
let da_set = der::write_set(&da_alg);
let eci_body = {
let mut b = der::write_oid(&[1u64, 2, 840, 113549, 1, 7, 1]); let octet = der::write_octet_string(payload);
b.extend_from_slice(&der::write_context_constructed(0, &octet));
b
};
let eci = der::write_sequence(&eci_body);
let si_set = der::write_set(&signer_info);
let mut sd_body = der::write_integer_u64(1);
sd_body.extend_from_slice(&da_set);
sd_body.extend_from_slice(&eci);
sd_body.extend_from_slice(&si_set);
let sd = der::write_sequence(&sd_body);
let outer_body = {
let mut b = der::write_oid(&[1u64, 2, 840, 113549, 1, 7, 2]); b.extend_from_slice(&der::write_context_constructed(0, &sd));
b
};
der::write_sequence(&outer_body)
}
fn synth_signed_data_with_cert(cert_der: Vec<u8>) -> Vec<u8> {
let issuer_der = der::write_sequence(b"O=Round-19 Test Signer");
let serial = vec![0xAB, 0xCD];
let signature = vec![0xCC; 256];
let digest_oid = vec![2u64, 16, 840, 1, 101, 3, 4, 2, 1];
let signature_oid = vec![1u64, 2, 840, 113549, 1, 1, 1];
let mut si_body = der::write_integer_u64(1);
let ias_body = {
let mut b = issuer_der.clone();
b.extend_from_slice(&der::write_integer_bytes(&serial));
b
};
si_body.extend_from_slice(&der::write_sequence(&ias_body));
let da_alg = {
let mut b = der::write_oid(&digest_oid);
b.extend_from_slice(&der::write_null());
der::write_sequence(&b)
};
si_body.extend_from_slice(&da_alg);
let sig_alg = {
let mut b = der::write_oid(&signature_oid);
b.extend_from_slice(&der::write_null());
der::write_sequence(&b)
};
si_body.extend_from_slice(&sig_alg);
si_body.extend_from_slice(&der::write_octet_string(&signature));
let signer_info = der::write_sequence(&si_body);
let da_set = der::write_set(&da_alg);
let eci = der::write_sequence(&der::write_oid(&[1u64, 2, 840, 113549, 1, 7, 1]));
let certs_tlv = der::write_tlv(der::Class::ContextSpecific, true, 0, &cert_der);
let si_set = der::write_set(&signer_info);
let mut sd_body = der::write_integer_u64(1);
sd_body.extend_from_slice(&da_set);
sd_body.extend_from_slice(&eci);
sd_body.extend_from_slice(&certs_tlv);
sd_body.extend_from_slice(&si_set);
let sd = der::write_sequence(&sd_body);
let outer_body = {
let mut b = der::write_oid(&[1u64, 2, 840, 113549, 1, 7, 2]);
b.extend_from_slice(&der::write_context_constructed(0, &sd));
b
};
der::write_sequence(&outer_body)
}
#[test]
fn parse_attached_signed_data_round_trips_all_fields() {
let issuer_der = der::write_sequence(b"O=Round-19 IAS Signer");
let serial = vec![0x10, 0x20, 0x30];
let payload = b"OXIDEAV-ROUND-19-PAYLOAD".to_vec();
let signature = vec![0xEE; 256];
let blob =
synth_signed_data_v1_attached(issuer_der.clone(), serial.clone(), &payload, &signature);
let parsed: SignedData = parse_signed_data(&blob).expect("parse SignedData");
assert_eq!(parsed.version, 1);
assert_eq!(parsed.digest_algorithms.len(), 1);
assert_eq!(parsed.encap_content_octets.as_deref(), Some(&payload[..]));
assert!(parsed.certs.is_empty());
assert!(parsed.crls.is_empty());
assert_eq!(parsed.signer_infos.len(), 1);
let si: &SignerInfo = &parsed.signer_infos[0];
assert_eq!(si.version, 1);
match &si.sid {
SignerIdentifier::IssuerAndSerial(ias) => {
assert_eq!(ias.issuer_der, issuer_der);
assert_eq!(ias.serial, serial);
}
other => panic!("expected IAS got {other:?}"),
}
assert_eq!(si.signature, signature);
assert!(si.signed_attrs.is_empty(), "no signed attrs in v1 fixture");
assert!(si.signed_attrs_der.is_none());
}
#[test]
fn parse_signed_data_with_certificate_surfaces_certs_array() {
let synthetic_cert = der::write_sequence(b"OXIDEAV-FAKE-CERT-PAYLOAD");
let blob = synth_signed_data_with_cert(synthetic_cert.clone());
let parsed = parse_signed_data(&blob).expect("parse SignedData with certs");
assert_eq!(parsed.certs.len(), 1, "one cert in certs[0]");
assert_eq!(parsed.certs[0], synthetic_cert);
assert!(parsed.encap_content_octets.is_none(), "detached signature");
}
#[test]
fn parse_signed_data_rejects_envelope_with_wrong_oid() {
let inner = der::write_sequence(&der::write_integer_u64(0));
let outer_body = {
let mut b = der::write_oid(&[1u64, 2, 840, 113549, 1, 7, 3]);
b.extend_from_slice(&der::write_context_constructed(0, &inner));
b
};
let envelope = der::write_sequence(&outer_body);
let err = parse_signed_data(&envelope).expect_err("must reject");
assert!(format!("{err}").contains("id-signedData"));
}
#[test]
fn parse_signed_data_rejects_truncated_blob() {
let bad = vec![0x30, 0x02, 0x01, 0x00];
assert!(parse_signed_data(&bad).is_err());
}
#[test]
fn parse_signed_data_with_empty_signer_infos_rejected() {
let digest_oid = vec![2u64, 16, 840, 1, 101, 3, 4, 2, 1];
let da_alg = {
let mut b = der::write_oid(&digest_oid);
b.extend_from_slice(&der::write_null());
der::write_sequence(&b)
};
let da_set = der::write_set(&da_alg);
let eci = der::write_sequence(&der::write_oid(&[1u64, 2, 840, 113549, 1, 7, 1]));
let si_set = der::write_set(b""); let mut sd_body = der::write_integer_u64(1);
sd_body.extend_from_slice(&da_set);
sd_body.extend_from_slice(&eci);
sd_body.extend_from_slice(&si_set);
let sd = der::write_sequence(&sd_body);
let outer_body = {
let mut b = der::write_oid(&[1u64, 2, 840, 113549, 1, 7, 2]);
b.extend_from_slice(&der::write_context_constructed(0, &sd));
b
};
let envelope = der::write_sequence(&outer_body);
assert!(parse_signed_data(&envelope).is_err());
}