use base64::Engine;
use serde_json::{Value, json};
use super::build_issuer_metadata;
use super::issuer_metadata::metadata_for_keys;
use super::test_fixtures::*;
use crate::test_support::temp_store;
#[test]
fn issuer_metadata_carries_the_issuer_and_exactly_one_key_source() {
let store = temp_store("sdjwtvc-meta", KEY_ID);
let metadata = build_issuer_metadata(&store, ISSUER, KEY_ID).expect("metadata");
assert_eq!(metadata["issuer"], json!(ISSUER));
assert!(metadata.get("jwks").is_some());
assert!(metadata.get("jwks_uri").is_none());
let keys = metadata["jwks"]["keys"].as_array().unwrap();
assert_eq!(keys.len(), 1);
assert_eq!(keys[0]["kty"], json!("OKP"));
assert_eq!(keys[0]["crv"], json!("Ed25519"));
assert_eq!(keys[0]["alg"], json!("EdDSA"));
assert_eq!(keys[0]["use"], json!("sig"));
}
#[test]
fn the_metadata_kid_matches_the_kid_in_the_signed_token() {
let store = temp_store("sdjwtvc-kid", KEY_ID);
let jwt = issued(&store).jwt().to_owned();
let header: Value = serde_json::from_slice(
&base64::engine::general_purpose::URL_SAFE_NO_PAD
.decode(jwt.split('.').next().unwrap())
.unwrap(),
)
.unwrap();
let metadata = build_issuer_metadata(&store, ISSUER, KEY_ID).unwrap();
assert_eq!(metadata["jwks"]["keys"][0]["kid"], header["kid"]);
}
#[test]
fn issuer_metadata_is_none_for_a_key_the_store_does_not_have() {
let store = temp_store("sdjwtvc-nokey", KEY_ID);
assert!(build_issuer_metadata(&store, ISSUER, "absent").is_none());
}
fn kids(metadata: &Value) -> Vec<String> {
metadata["jwks"]["keys"]
.as_array()
.expect("a key set")
.iter()
.map(|k| {
k["kid"]
.as_str()
.expect("every key names its kid")
.to_owned()
})
.collect()
}
#[test]
fn a_revoked_key_is_not_published_after_a_compromise_rotation() {
let store = temp_store("sdjwtvc-revoke", KEY_ID);
let revoked = store
.load_key(KEY_ID)
.expect("current key")
.fingerprint
.clone();
let replacement = store
.revoke_and_rotate(KEY_ID)
.expect("revoke and rotate")
.fingerprint
.clone();
let metadata = build_issuer_metadata(&store, ISSUER, KEY_ID).expect("metadata");
assert_eq!(kids(&metadata), [replacement]);
assert!(!kids(&metadata).contains(&revoked));
}
#[test]
fn a_rotated_key_stays_published() {
let store = temp_store("sdjwtvc-rotate", KEY_ID);
let old = store
.load_key(KEY_ID)
.expect("current key")
.fingerprint
.clone();
let new = store
.rotate_key(KEY_ID)
.expect("rotate")
.fingerprint
.clone();
let metadata = build_issuer_metadata(&store, ISSUER, KEY_ID).expect("metadata");
let published = kids(&metadata);
assert_eq!(published.len(), 2, "{published:?}");
assert!(published.contains(&old) && published.contains(&new));
}
#[test]
fn a_revoked_current_key_is_not_published() {
let store = temp_store("sdjwtvc-revoked-current", KEY_ID);
let mut current = store.public_key(KEY_ID).expect("current key");
current.revoked = true;
assert!(metadata_for_keys(ISSUER, ¤t, &[]).is_none());
let archived = store.public_key(KEY_ID).expect("current key");
let metadata = metadata_for_keys(ISSUER, ¤t, &[archived]).expect("metadata");
assert_eq!(kids(&metadata).len(), 1);
}
#[test]
fn issuer_metadata_carries_no_private_key_material() {
let store = temp_store("sdjwtvc-private", KEY_ID);
let metadata = build_issuer_metadata(&store, ISSUER, KEY_ID).unwrap();
let serialised = metadata.to_string();
for private_member in ["\"d\"", "\"p\"", "\"q\"", "privateKey"] {
assert!(
!serialised.contains(private_member),
"{private_member} in published metadata"
);
}
}