use auths_core::crypto::ssh::SecureSeed;
use auths_crypto::{CurveType, RingCryptoProvider};
use auths_id::keri::{Event, Prefix};
use auths_id::ports::RegistryBackend;
use auths_id::testing::fakes::FakeRegistryBackend;
use auths_keri::{
CesrKey, DipEvent, DipEventInit, IcpEvent, IcpEventInit, IxnEvent, KeriPublicKey, KeriSequence,
Said, Seal, SourceSeal, Threshold, VersionString, compute_next_commitment, finalize_dip_event,
finalize_icp_event, finalize_ixn_event,
};
use auths_sdk::domains::signing::service as signing;
use auths_sdk::workflows::commit_trust::verify_commit_local;
use auths_verifier::CommitVerdict;
use ssh_key::private::Ed25519Keypair;
const EMPTY_TREE: &str = "4b825dc642cb6eb9a060e54bf899d69f628aca02";
const DEVICE_SEED: [u8; 32] = [7u8; 32];
fn cesr(pk: &KeriPublicKey) -> CesrKey {
CesrKey::new_unchecked(pk.to_qb64().expect("qb64"))
}
fn dummy_key(seed: u8) -> KeriPublicKey {
KeriPublicKey::ed25519(&[seed; 32]).expect("ed25519")
}
fn device_keypair() -> (SecureSeed, KeriPublicKey) {
let seed = SecureSeed::new(DEVICE_SEED);
let kp = Ed25519Keypair::from_seed(seed.as_bytes());
let device_key = KeriPublicKey::ed25519(&kp.public.0).expect("device ed25519 key");
(seed, device_key)
}
struct Fixture {
root_kel: Vec<Event>,
device_kel: Vec<Event>,
root_prefix: Prefix,
device_prefix: Prefix,
root_did: String,
device_did: String,
}
fn build_delegated(device_key: &KeriPublicKey) -> Fixture {
let root_icp = finalize_icp_event(IcpEvent::new(IcpEventInit {
v: VersionString::placeholder(),
d: Said::default(),
i: Prefix::default(),
s: KeriSequence::new(0),
kt: Threshold::Simple(1),
k: vec![cesr(&dummy_key(1))],
nt: Threshold::Simple(1),
n: vec![compute_next_commitment(&dummy_key(2))],
bt: Threshold::Simple(0),
b: vec![],
c: vec![],
a: vec![],
}))
.expect("root icp");
let root_prefix = root_icp.i.clone();
let mut dip = finalize_dip_event(DipEvent::new(DipEventInit {
v: VersionString::placeholder(),
d: Said::default(),
i: Prefix::default(),
s: KeriSequence::new(0),
kt: Threshold::Simple(1),
k: vec![cesr(device_key)],
nt: Threshold::Simple(1),
n: vec![compute_next_commitment(&dummy_key(3))],
bt: Threshold::Simple(0),
b: vec![],
c: vec![],
a: vec![],
di: root_prefix.clone(),
}))
.expect("device dip");
let device_prefix = dip.i.clone();
let dip_said = dip.d.clone();
let ixn = finalize_ixn_event(IxnEvent {
v: VersionString::placeholder(),
d: Said::default(),
i: root_prefix.clone(),
s: KeriSequence::new(1),
p: root_icp.d.clone(),
a: vec![Seal::KeyEvent {
i: device_prefix.clone(),
s: KeriSequence::new(0),
d: dip_said.clone(),
}],
})
.expect("anchor ixn");
dip.source_seal = Some(SourceSeal {
s: KeriSequence::new(1),
d: ixn.d.clone(),
});
Fixture {
root_did: format!("did:keri:{root_prefix}"),
device_did: format!("did:keri:{device_prefix}"),
root_kel: vec![Event::Icp(root_icp), Event::Ixn(ixn)],
device_kel: vec![Event::Dip(dip)],
root_prefix,
device_prefix,
}
}
fn signed_commit(seed: &SecureSeed, root_did: &str, device_did: &str) -> Vec<u8> {
let headers = format!(
"tree {EMPTY_TREE}\n\
author Test User <test@auths.local> 1700000000 +0000\n\
committer Test User <test@auths.local> 1700000000 +0000"
);
let message = format!("test commit\n\nAuths-Id: {root_did}\nAuths-Device: {device_did}\n");
let payload = format!("{headers}\n\n{message}");
let pem = signing::sign_with_seed(seed, payload.as_bytes(), "git", CurveType::Ed25519)
.expect("sign commit payload");
let mut lines = pem.lines();
let first = lines.next().expect("pem first line");
let mut gpgsig = format!("gpgsig {first}\n");
for line in lines {
gpgsig.push(' ');
gpgsig.push_str(line);
gpgsig.push('\n');
}
format!("{headers}\n{gpgsig}\n{message}").into_bytes()
}
fn setup() -> (Fixture, FakeRegistryBackend, Vec<u8>) {
let (seed, device_key) = device_keypair();
let f = build_delegated(&device_key);
let registry = FakeRegistryBackend::new();
for event in &f.root_kel {
registry
.append_event(&f.root_prefix, event)
.expect("append root event");
}
for event in &f.device_kel {
registry
.append_event(&f.device_prefix, event)
.expect("append device event");
}
let commit = signed_commit(&seed, &f.root_did, &f.device_did);
(f, registry, commit)
}
#[tokio::test]
async fn pinned_root_yields_valid() {
let (f, registry, commit) = setup();
let verdict = verify_commit_local(
®istry,
std::slice::from_ref(&f.root_did),
&commit,
&RingCryptoProvider,
)
.await
.expect("trust resolution succeeds");
match verdict {
CommitVerdict::Valid { root_did, .. } => assert_eq!(root_did, f.root_did),
other => panic!("expected Valid for a pinned delegating root, got {other:?}"),
}
}
#[tokio::test]
async fn unpinned_root_yields_root_not_pinned() {
let (_f, registry, commit) = setup();
let verdict = verify_commit_local(®istry, &[], &commit, &RingCryptoProvider)
.await
.expect("trust resolution succeeds");
assert!(
matches!(verdict, CommitVerdict::RootNotPinned(_)),
"an unpinned root must not be trusted, got {verdict:?}"
);
}