open-standards/joule-code/joule-code-rs/crates/joule-moq-room/tests/common/rfc_test_keys.rs

84 lines
5.6 KiB
Rust

//! Published RSA test keys, as the age-assurance corpus carries them (WAI
//! `wai/live-conformance/age/`): RFC 7517 Appendix A.2's RSA key (the threshold 13 here), RFC
//! 9500 §2.1's `testRSA2048` (16) and RFC 9578 Appendix A.2's issuer key (18). Their private
//! exponents are published with them; they sign the tests' tokens directly, the signature the
//! blind protocol of RFC 9578 §6 would also yield. They are test keys and nothing else.
//!
//! Shared by the unit tests of `src/age.rs` and `tests/age_admission.rs`; under `tests/common/`,
//! so that cargo makes no test target of it.
#![allow(dead_code)]
pub const N_7517: &str = "d2fc7b6a0a1e6c67104aeb8f88b257669b4df679ddad099b5c4a6cd9a88015b5a133bf0b856c7871b6df000b554fceb3c2ed512bb68f145c6e8434752fab52a1cfc124408f79b58a4578c16428855789f7a249e384cb2d9fae2d67fd96fb926c198e077399fdc815c0af097dde5aadeff44de70e827f4878432439bfeeb96068d0474fc50d6d90bf3a98dfaf1040c89c02d692ab3b3c2896609d86fd73b774ce0740647ceeeaa310bd12f985a8eb9f59fdd426cea5b2120f4f2a34bcab764b7e6c54d6840238bcc40587a59e66ed1f33894577635c470af75cf92c20d1da43e1bfc419e222a6f0d0bb358c5e38f9cb050aeafe904814f1ac1aa49cca9ea0ca83";
pub const D_7517: &str = "5f8713b5e258fe09f81583ec5c1f2b7578b1e6fc2c83514b37913711a1ba449a151fe1cb2ca0fd33b771e68a3b1944649dc867ad1c1e5240bb853e5f24b33459b14028d2d6636befec1e8da974b352fc53d3f6127ea8a3c29dd14f3941682c56a78768164e4dda8f06cbf9c734aae8003224278ea9454a21b17cb06d178075868cc05b3db6ff1dfdc3d56378b4edadedf0c37a4cdc26d1d49ac26f6fe3b5220a5dd29396621bbc688cf2eee2c6e0d54da3c782014cd0739db252cc51caeba8d3f1b824baab24d068ec903264d7d678ab08f06ec9e7e23d960628b744bf94b3694656463c7e417399ed73d076c891fcf463a9aa9ce62da9cd17e237dc2a8002f1";
pub const N_9500: &str = "b0f9e81943a7ae9892aade17ca7c40f8744fed2f8148e6c8eaa27b7d001548fb5192ab28b56c5060b118ccd131e594874c6ca989b56c27296f09fb93a034df32e97c6ff0998cfd8e6f42dda58acd1fa97986f144f3d154d67650175e6854b3a952003bc06887b8455ac2b19f7b2f76504ebc98ec945571b07892150ddc6a74ca0fbcd35497ce81534daf9418844b13aea31f9d5a6b9557bbdf619efd4e887f2d42b8dd8bc987eae1bf89cab85ee21e356305df6c07a8838e3ef41c595dcce43dafc49123ef4d8abba93d3905e4028d7ba91484a27596e07b4b6ed992f077b524d3dcfe7ddd5549be7cce8da035cfa0b3fb8f9e46f732b2a86b460165c08f5313";
pub const D_9500: &str = "41188b20cfdbdbc2cf1ffe752dcbaa723906352e2615d49dce80597fcf0a05403bef00fa065182f72decfb596f4b0ce8ff5970baf07a89a519ecc816b2f4ffac5069af1b06bfef7bf6bcd79e4e81c8c5a3a7d9130dc3cfbadae5f6d288f9aee3f6ff92fae0f81af597bec96ae9fab9402cd5fe41f705bebdb47bb736d3fe6c5a51e0e20732a97b5e46c1cbdb26d74854c6b6604aed463735ff9076046557caf949bf448895c20432c1e09c014ea75660434f1a0f3be294babc5d530e6a10213f53b60375fc84a7573f2af1215584f5b4bda6d4e8f9e17a78d97e77b86da4a1846475318a7a10a561014effa23a81ec56e9e4109def8cb3f797223f7d8d0d4351";
pub const D_9578: &str = "2f309b7738b58cf779f0c915f822dfc9f490dbeadf1e7adfac578ffd5703c6bba2da9d5a49725889b7ba112f8c6ff30551d9473e000bc35c50e167ab7fa73a0c2b21965c4b59257c1ac06cbdcf28e863f6718ea8c29043c1c6da84629490fd0491bf52d172c959c1921b96949c725747b8a7c7871995fa0b9eb1107ba854c6c32a6f4747c5d1c304c7467d55b080aa233a3a52ffdf26114cbb541ffa6b696b7a096f8dcff69ca08ab58efb0fb753aa5185c73001696bbce8c099e3f435dcbbfe05e7dbaad23db2a659c23add521407f150b1af2d9054c4164229d6840b7a32a4f8481493ae8959cf0aea8def0c3c9f75b9a34c75718b7072c8dbab17cefeca49";
/// One key: its modulus, its private exponent and its SubjectPublicKeyInfo (RFC 9578 §6.5).
pub struct TestKey {
pub n: Vec<u8>,
pub d: Vec<u8>,
pub spki: Vec<u8>,
}
fn der(tag: u8, content: &[u8]) -> Vec<u8> {
let mut o = vec![tag];
match content.len() {
n if n < 0x80 => o.push(n as u8),
n if n < 0x100 => o.extend_from_slice(&[0x81, n as u8]),
n => o.extend_from_slice(&[0x82, (n >> 8) as u8, n as u8]),
}
o.extend_from_slice(content);
o
}
fn der_uint(x: &[u8]) -> Vec<u8> {
let x = &x[x.iter().position(|&b| b != 0).unwrap_or(x.len() - 1)..];
let mut c = if x[0] & 0x80 != 0 { vec![0] } else { vec![] };
c.extend_from_slice(x);
der(0x02, &c)
}
fn spki_of(n: &[u8]) -> Vec<u8> {
let rsa_key = der(0x30, &[der_uint(n), der_uint(&[1, 0, 1])].concat());
der(0x30, &[wai::age_assurance::PSS_ALGORITHM.to_vec(), der(0x03, &[&[0u8][..], &rsa_key].concat())].concat())
}
fn key(n: &str, d: &str) -> TestKey {
let n = hex::decode(n).unwrap();
TestKey { spki: spki_of(&n), n, d: hex::decode(d).unwrap() }
}
pub fn k13() -> TestKey {
key(N_7517, D_7517)
}
pub fn k16() -> TestKey {
key(N_9500, D_9500)
}
pub fn k18() -> TestKey {
let spki = hex::decode(wai::live_ads::presentation_corpus::RFC9578_PKI).unwrap();
let (n, _) = wai::live_ads::presentation::rsa_public_key(&spki).unwrap();
let mut n = n.to_bytes_be();
while n.len() < 256 {
n.insert(0, 0);
}
assert_eq!(spki_of(&n), spki, "RFC 9578 A.2's key, written as §6.5 has it");
TestKey { n, d: hex::decode(D_9578).unwrap(), spki }
}
/// A token of type 0x0002 for `challenge` under `k` (RFC 9577 §2.2.1, RFC 9578 §6), its nonce
/// and its PSS salt drawn from `seed`.
pub fn mint(k: &TestKey, challenge: &[u8], seed: u8) -> Vec<u8> {
use sha2::{Digest, Sha256};
let mut t = vec![0, 2];
t.extend_from_slice(&Sha256::digest([b"nonce".as_slice(), &[seed]].concat()));
t.extend_from_slice(&Sha256::digest(challenge));
t.extend_from_slice(&Sha256::digest(&k.spki));
let salt: [u8; 48] = [Sha256::digest([b"salt-a".as_slice(), &[seed]].concat()).to_vec(), Sha256::digest([b"salt-b".as_slice(), &[seed]].concat())[..16].to_vec()].concat().try_into().unwrap();
let sig = wai::live_ads::presentation::pss_sign(&k.n, &k.d, &t, &salt);
t.extend_from_slice(&sig);
t
}