use std::sync::Arc;
use tokio::sync::RwLock;
use crate::error::{RegistryError, RegistryResult};
use crate::trust::{KeyMetadata, TrustStore, TrustStoreInner};
use crate::types::TrustedKey;
use crate::verify::compute_key_id;
use super::cache;
use super::decode::{decode_public_key_bytes, decode_verifying_key};
pub(in crate::trust) struct PreparedPinnedKey {
key_id: String,
verifying_key: ed25519_dalek::VerifyingKey,
metadata: KeyMetadata,
}
pub(in crate::trust) fn parse_pinned_roots_json_impl(raw: &str) -> RegistryResult<Vec<TrustedKey>> {
let roots: Vec<TrustedKey> = serde_json::from_str(raw).map_err(|e| RegistryError::Config {
message: format!("invalid production trust roots: {}", e),
})?;
if roots.is_empty() {
return Err(RegistryError::Config {
message: "production trust roots are empty".to_string(),
});
}
let mut seen = std::collections::HashSet::new();
for root in &roots {
if root.algorithm != "Ed25519" {
return Err(RegistryError::Config {
message: format!(
"production trust root {} uses unsupported algorithm {}",
root.key_id, root.algorithm
),
});
}
if root.revoked {
return Err(RegistryError::Config {
message: format!("production trust root {} is revoked", root.key_id),
});
}
if !seen.insert(root.key_id.clone()) {
return Err(RegistryError::Config {
message: format!("duplicate production trust root {}", root.key_id),
});
}
}
Ok(roots)
}
pub(in crate::trust) fn load_production_roots_impl(raw: &str) -> RegistryResult<TrustStore> {
let roots = parse_pinned_roots_json_impl(raw)?;
let mut inner = cache::empty_inner();
for root in &roots {
insert_pinned_key(&mut inner, root).map_err(|err| RegistryError::Config {
message: format!("invalid production trust root {}: {}", root.key_id, err),
})?;
}
Ok(TrustStore {
inner: Arc::new(RwLock::new(inner)),
})
}
pub(in crate::trust) fn prepare_pinned_key(key: &TrustedKey) -> RegistryResult<PreparedPinnedKey> {
let verifying_key = decode_verifying_key(&key.public_key)?;
let computed_id = compute_key_id(&decode_public_key_bytes(&key.public_key)?);
if computed_id != key.key_id {
return Err(RegistryError::SignatureInvalid {
reason: format!(
"key_id mismatch: claimed {}, computed {}",
key.key_id, computed_id
),
});
}
Ok(PreparedPinnedKey {
key_id: key.key_id.clone(),
verifying_key,
metadata: KeyMetadata {
description: key.description.clone(),
added_at: key.added_at,
expires_at: key.expires_at,
revoked: false,
is_pinned: true,
},
})
}
pub(in crate::trust) fn insert_prepared_pinned_key(
inner: &mut TrustStoreInner,
prepared: PreparedPinnedKey,
) {
let PreparedPinnedKey {
key_id,
verifying_key,
metadata,
} = prepared;
inner.keys.insert(key_id.clone(), verifying_key);
inner.metadata.insert(key_id.clone(), metadata);
if !inner.pinned_roots.contains(&key_id) {
inner.pinned_roots.push(key_id);
}
}
pub(in crate::trust) fn insert_pinned_key(
inner: &mut TrustStoreInner,
key: &TrustedKey,
) -> RegistryResult<()> {
let prepared = prepare_pinned_key(key)?;
insert_prepared_pinned_key(inner, prepared);
Ok(())
}