use base64::engine::general_purpose::STANDARD as B64;
use base64::Engine;
use ed25519_dalek::{Signature, Verifier, VerifyingKey};
use serde::{Deserialize, Serialize};
pub const POLICY_FORMAT_VERSION: u32 = 1;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyBundle {
pub policy_format_version: u32,
pub alg: String,
pub key_id: String,
pub issuer: String,
pub payload: PolicyPayload,
pub signature: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyPayload {
pub org_id: String,
pub bundle_id: String,
pub issued_at: String,
pub rules: Vec<PolicyRule>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyRule {
pub id: String,
pub target: String,
pub level: String,
pub reason: String,
}
#[derive(Debug, Clone)]
pub struct TrustedKey {
pub key_id: String,
pub public_key: [u8; 32],
}
pub fn default_trusted_keys() -> Vec<TrustedKey> {
Vec::new()
}
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
pub enum PolicyError {
#[error("unsupported policy_format_version {0} (expected {POLICY_FORMAT_VERSION})")]
UnsupportedVersion(u32),
#[error("unsupported signature algorithm {0:?} (expected \"ed25519\")")]
UnsupportedAlg(String),
#[error("no trusted key matches key_id {0:?}")]
UnknownKey(String),
#[error("policy bundle signature verification failed (corrupt, tampered, or wrong key)")]
SignatureInvalid,
}
#[derive(Debug, Clone)]
pub struct VerifiedBundle {
pub org_id: String,
pub bundle_id: String,
pub rules: Vec<PolicyRule>,
}
fn canonical_payload_bytes(payload: &PolicyPayload) -> Vec<u8> {
#[derive(Serialize)]
struct CanonicalRule<'a> {
id: &'a str,
target: &'a str,
level: &'a str,
reason: &'a str,
}
#[derive(Serialize)]
struct Canonical<'a> {
org_id: &'a str,
bundle_id: &'a str,
issued_at: &'a str,
rules: Vec<CanonicalRule<'a>>,
}
let canonical = Canonical {
org_id: &payload.org_id,
bundle_id: &payload.bundle_id,
issued_at: &payload.issued_at,
rules: payload
.rules
.iter()
.map(|r| CanonicalRule {
id: &r.id,
target: &r.target,
level: &r.level,
reason: &r.reason,
})
.collect(),
};
serde_json::to_vec(&canonical).expect("canonical serialization cannot fail")
}
pub fn verify_bundle(
bundle: &PolicyBundle,
trusted_keys: &[TrustedKey],
) -> Result<VerifiedBundle, PolicyError> {
if bundle.policy_format_version != POLICY_FORMAT_VERSION {
return Err(PolicyError::UnsupportedVersion(
bundle.policy_format_version,
));
}
if bundle.alg != "ed25519" {
return Err(PolicyError::UnsupportedAlg(bundle.alg.clone()));
}
let trusted = trusted_keys
.iter()
.find(|k| k.key_id == bundle.key_id)
.ok_or_else(|| PolicyError::UnknownKey(bundle.key_id.clone()))?;
let verifying =
VerifyingKey::from_bytes(&trusted.public_key).map_err(|_| PolicyError::SignatureInvalid)?;
let sig_bytes = B64
.decode(bundle.signature.as_bytes())
.map_err(|_| PolicyError::SignatureInvalid)?;
let sig_arr: [u8; 64] = sig_bytes
.as_slice()
.try_into()
.map_err(|_| PolicyError::SignatureInvalid)?;
let signature = Signature::from_bytes(&sig_arr);
let canonical = canonical_payload_bytes(&bundle.payload);
verifying
.verify(&canonical, &signature)
.map_err(|_| PolicyError::SignatureInvalid)?;
Ok(VerifiedBundle {
org_id: bundle.payload.org_id.clone(),
bundle_id: bundle.payload.bundle_id.clone(),
rules: bundle.payload.rules.clone(),
})
}
#[cfg(test)]
mod tests {
use super::*;
use ed25519_dalek::{Signer, SigningKey};
const TEST_SEED: [u8; 32] = [7u8; 32];
fn test_key() -> (SigningKey, TrustedKey) {
let sk = SigningKey::from_bytes(&TEST_SEED);
let public_key = sk.verifying_key().to_bytes();
(
sk,
TrustedKey {
key_id: "test-key-1".into(),
public_key,
},
)
}
fn sample_payload() -> PolicyPayload {
PolicyPayload {
org_id: "acme".into(),
bundle_id: "b-001".into(),
issued_at: "2026-06-28T00:00:00Z".into(),
rules: vec![PolicyRule {
id: "PHI-1".into(),
target: "src/payments/**".into(),
level: "deny".into(),
reason: "PHI files require consultation".into(),
}],
}
}
fn sign_with(sk: &SigningKey, key_id: &str, payload: PolicyPayload) -> PolicyBundle {
let sig = sk.sign(&canonical_payload_bytes(&payload));
PolicyBundle {
policy_format_version: POLICY_FORMAT_VERSION,
alg: "ed25519".into(),
key_id: key_id.to_string(),
issuer: "acme".into(),
payload,
signature: B64.encode(sig.to_bytes()),
}
}
#[test]
fn accepts_a_correctly_signed_bundle() {
let (sk, trusted) = test_key();
let bundle = sign_with(&sk, &trusted.key_id, sample_payload());
let verified = verify_bundle(&bundle, &[trusted]).expect("should verify");
assert_eq!(verified.org_id, "acme");
assert_eq!(verified.rules.len(), 1);
assert_eq!(verified.rules[0].id, "PHI-1");
assert_eq!(verified.rules[0].level, "deny");
}
#[test]
fn rejects_a_tampered_payload() {
let (sk, trusted) = test_key();
let mut bundle = sign_with(&sk, &trusted.key_id, sample_payload());
bundle.payload.rules[0].level = "advisory".into(); assert!(matches!(
verify_bundle(&bundle, &[trusted]),
Err(PolicyError::SignatureInvalid)
));
}
#[test]
fn rejects_an_unknown_key_id() {
let (sk, trusted) = test_key();
let bundle = sign_with(&sk, "some-other-key", sample_payload());
assert!(matches!(
verify_bundle(&bundle, &[trusted]),
Err(PolicyError::UnknownKey(_))
));
}
#[test]
fn rejects_a_signature_from_an_untrusted_key() {
let (_sk, trusted) = test_key();
let attacker = SigningKey::from_bytes(&[9u8; 32]);
let payload = sample_payload();
let sig = attacker.sign(&canonical_payload_bytes(&payload));
let bundle = PolicyBundle {
policy_format_version: POLICY_FORMAT_VERSION,
alg: "ed25519".into(),
key_id: trusted.key_id.clone(),
issuer: "acme".into(),
payload,
signature: B64.encode(sig.to_bytes()),
};
assert!(matches!(
verify_bundle(&bundle, &[trusted]),
Err(PolicyError::SignatureInvalid)
));
}
#[test]
fn rejects_bad_version_and_alg() {
let (sk, trusted) = test_key();
let mut v = sign_with(&sk, &trusted.key_id, sample_payload());
v.policy_format_version = 999;
assert!(matches!(
verify_bundle(&v, std::slice::from_ref(&trusted)),
Err(PolicyError::UnsupportedVersion(999))
));
let mut a = sign_with(&sk, &trusted.key_id, sample_payload());
a.alg = "rsa".into();
assert!(matches!(
verify_bundle(&a, &[trusted]),
Err(PolicyError::UnsupportedAlg(_))
));
}
#[test]
fn oss_core_trusts_no_keys_so_floor_is_dormant() {
let (sk, trusted) = test_key();
let bundle = sign_with(&sk, &trusted.key_id, sample_payload());
assert!(matches!(
verify_bundle(&bundle, &default_trusted_keys()),
Err(PolicyError::UnknownKey(_))
));
}
}