Skip to main content

agentmux_srv/server/reactive/
channel_v2.rs

1//! Identity M4d-6 (`SPEC_AGENT_IDENTITY_CARRIED_NOT_DERIVED_2026_09_23.md`
2//! ยง6.5.10): cross-channel jekts verified by the sender's UID, not its name.
3
4use super::{agent_registry, AppState, InjectionRequest, CHANNEL_SIG_MAX_AGE_SECS};
5
6/// Settle a cross-channel jekt's checks by its v2 signature, when it proves
7/// the sender is the agent this instance knows by the claimed name (or one it
8/// knows no agent by). `true` when settled, either way; `false` leaves the
9/// name's checks to the caller.
10pub(super) fn settle_by_uid(
11    state: &AppState,
12    req: &mut InjectionRequest,
13    claimed: &str,
14    shared_dir: &std::path::Path,
15    now_secs: i64,
16) -> bool {
17    if verify_channel_v2(req, shared_dir, now_secs) != Some(true) {
18        return false;
19    }
20    let uid = req.source_uid.clone().unwrap_or_default();
21    match state.mstore.agent_ids_for_slug_folded(claimed).as_deref() {
22        Ok([local]) if *local == uid => {
23            req.channel_verified = Some(true);
24            req.sig_verified = None;
25            if req.audit_source_uid.is_empty() {
26                req.audit_source_uid = uid;
27            }
28            true
29        }
30        Ok([]) if !matches!(state.mstore.agent_jekt_key_load(claimed), Ok(Some(_))) => {
31            req.channel_verified = Some(true);
32            if req.audit_source_uid.is_empty() {
33                req.audit_source_uid = uid;
34            }
35            true
36        }
37        // Proven to be another agent than the one this instance knows by the
38        // name (or the name is ambiguous here): v1, which accepts any key
39        // published under the name, must not pass it as that name.
40        Ok(_) => {
41            crate::backend::agent_resolve::record_uid_fallback("m4d.channel_v2_other_agent");
42            req.channel_verified = Some(false);
43            true
44        }
45        // The store couldn't say: the name's own checks decide.
46        Err(_) => false,
47    }
48}
49
50/// Identity M4d-6: the v2 cross-channel signature against the keys published
51/// for its `source_uid` (M4d-5). `None` when there is nothing to check (no
52/// v2 sent, no key published for the UID); `Some(false)` when one was
53/// published and the signature, or its freshness, fails.
54fn verify_channel_v2(
55    req: &InjectionRequest,
56    shared_dir: &std::path::Path,
57    now_secs: i64,
58) -> Option<bool> {
59    let sig = req.channel_sig_v2.as_deref()?;
60    let uid = req.source_uid.as_deref().filter(|u| !u.is_empty())?;
61    let source = req.source_agent.as_deref()?;
62    let keys: Vec<Vec<u8>> = agent_registry::lookup_shared_by_uid(shared_dir, uid)
63        .into_iter()
64        .filter_map(|e| agentmux_common::jekt_sign::decode_key(&e.uid_public_key))
65        .collect();
66    if keys.is_empty() {
67        return None;
68    }
69    let ts = req.ts_secs.unwrap_or(0);
70    let fresh = ts > 0 && (now_secs - ts).abs() <= CHANNEL_SIG_MAX_AGE_SECS;
71    let msgid = req.request_id.as_deref().unwrap_or("");
72    let channel = req.source_channel.as_deref().unwrap_or("");
73    Some(
74        fresh
75            && keys.iter().any(|key| {
76                agentmux_common::jekt_sign::verify_channel_jekt_v2(
77                    key,
78                    msgid,
79                    source,
80                    uid,
81                    channel,
82                    &req.target_agent,
83                    ts,
84                    &req.message,
85                    sig,
86                )
87            }),
88    )
89}