use std::io::Write;
use base64::Engine;
use super::*;
const SEED: &[u8; 32] = b"lys-cose-conformance-test-seed01";
const MILLIS: u64 = 1_700_000_000_000;
const GOLDEN: &str = "d2845850a301270378276170706c69636174696f6e2f766e642e6c79732e6174746573746174696f6e2e76322b63626f72045820214e41cc8475f5bc9af68dbf33fa56e8adf5144a4a81134268f4ae379e103bfda0582ea20158209404f8b8cec8ad98a88b106d9345d518c273f012c1306b8af5103e865997191e021b0000018bcfe568005840ba6eae66b3a04f25e6116e7278ae8b0e2174a2964bb0917ae53ab2ef326c22a706e90cae6886b20ecd086fee4b515de046d450f90de81f9aa46a9b34bd7f1a09";
fn pem() -> String {
let der = [PKCS8_ED25519_PREFIX.as_slice(), SEED].concat();
let body = base64::engine::general_purpose::STANDARD.encode(der);
format!("-----BEGIN PRIVATE KEY-----\n{body}\n-----END PRIVATE KEY-----\n")
}
#[test]
fn attestation_matches_the_issuer_golden_bytes() {
let key = SigningKey::from_bytes(SEED);
let cose = attest(&key, b"lys attestation conformance payload\n", MILLIS);
assert_eq!(hex(&cose), GOLDEN);
}
#[test]
fn a_pem_file_and_a_seat_file_read_the_same_key() -> Result<(), Box<dyn std::error::Error>> {
let mut plain = tempfile::NamedTempFile::new()?;
plain.write_all(pem().as_bytes())?;
let mut seat = tempfile::NamedTempFile::new()?;
seat.write_all(
serde_json::json!({ "privateKeyPem": pem() })
.to_string()
.as_bytes(),
)?;
let from_pem = read_key(plain.path()).map_err(|refusal| refusal.message)?;
let from_seat = read_key(seat.path()).map_err(|refusal| refusal.message)?;
assert_eq!(from_pem.to_bytes(), *SEED);
assert_eq!(from_seat.to_bytes(), *SEED);
Ok(())
}
#[test]
fn a_key_that_is_not_ed25519_pkcs8_is_refused_without_its_bytes()
-> Result<(), Box<dyn std::error::Error>> {
let mut file = tempfile::NamedTempFile::new()?;
file.write_all(b"-----BEGIN PRIVATE KEY-----\nAAAA\n-----END PRIVATE KEY-----\n")?;
let Err(refusal) = read_key(file.path()) else {
return Err("a malformed key was accepted".into());
};
assert_eq!(refusal.code, "mcp_lys_key_unreadable");
assert!(!refusal.message.contains("AAAA"));
Ok(())
}
#[test]
fn the_header_names_agent_time_nonce_and_a_verifiable_attestation() -> Result<(), String> {
let key = SigningKey::from_bytes(SEED);
let header = signature(
&key,
"agent-under-test",
"/api/agents/agent-under-test/pass",
b"{}",
MILLIS,
)
.map_err(|refusal| refusal.message)?;
let words: Vec<&str> = header.split(' ').collect();
assert_eq!(words.len(), 4);
assert_eq!(words[0], "agent-under-test");
assert_eq!(words[1], MILLIS.to_string());
assert_eq!(words[2].len(), NONCE_BYTES * 2);
let payload = [
REQUEST_DOMAIN,
"POST",
"/api/agents/agent-under-test/pass",
&hex(&Sha256::digest(b"{}")),
&MILLIS.to_string(),
words[2],
]
.join("\n");
assert_eq!(words[3], hex(&attest(&key, payload.as_bytes(), MILLIS)));
Ok(())
}