§18 — Registry Federation Protocol v1.6
RCAN registries federate like email — a robot on registry-1.example can consent-grant access to a robot on registry-2.hospital without either registry having full control over the other's records. v1.6 defines the complete cross-registry trust, consent propagation, and ESTOP propagation protocol.
Registry Tiers
The RCAN protocol defines a three-tier registry hierarchy that controls what trust assertions each registry may make:
| Tier | Value | Trust Level | Example |
|---|---|---|---|
| Root | "root" | Signs authoritative registry keys; manages global trust anchors | RRF (rcan.dev) |
| Authoritative | "authoritative" | Verified by root; can issue LoA 2/3 JWTs; must pass annual audit | hospital-registry.nhs.uk, acme-robots.com |
| Community | "community" | Self-signed; can only issue LoA 1 JWTs; robots MAY reject for control commands | homelab-registry.local, maker-registry.io |
The registry_tier field appears on registry records and in JWT claims issued by that registry:
// Registry record (in Robot Registry Foundation)
{
"registry_id": "hospital-registry.nhs.uk",
"registry_tier": "authoritative",
"public_key_fp": "sha256:4a3f...",
"signed_by": "root.rcan.dev",
"audit_expiry": "2027-01-15",
"dnssec_txt": "_rcan.hospital-registry.nhs.uk"
}
// JWT claim from authoritative registry
{
"iss": "hospital-registry.nhs.uk",
"sub": "user-uuid-alice",
"registry_tier": "authoritative",
"loa": 2,
"aud": "rcan://hospital-registry.nhs.uk/med/delivery/v2/unit-04",
"scope": ["control"],
"exp": 1741003600
} FEDERATION_SYNC Message (Type 12) — Full Payload Spec
The FEDERATION_SYNC message (type 12) is the wire format for cross-registry data synchronization. It was reserved in v1.5; v1.6 defines the complete payload.
// FEDERATION_SYNC (type 12) payload
{
"source_registry": "registry-1.acme.com",
"target_registry": "hospital-registry.nhs.uk",
"sync_type": "consent", // "consent" | "revocation" | "key"
"federation_id": "uuid-v4", // Unique ID for this sync event
"payload": { ... }, // Type-specific payload (see below)
"signature": "ed25519:...", // Source registry signs the full payload
"timestamp": 1741000000,
"expires_at": 1741003600 // Sync event expiry (1h typical)
} sync_type: "consent"
// payload for sync_type: "consent"
{
"consent_record": {
"request_id": "uuid-v4",
"requester_ruri": "rcan://registry-1.acme.com/org/model/v1/robot-A",
"target_ruri": "rcan://hospital.nhs.uk/med/delivery/v2/unit-04",
"granted_scopes": ["status", "control"],
"granted_by": "user-uuid-owner-B",
"granted_at": 1741000000,
"expires_at": 1741086400,
"source_registry": "registry-1.acme.com",
"target_registry": "hospital-registry.nhs.uk",
"owner_signature": "ed25519:...", // Owner of target robot signs the grant
"chain_hash": "sha256:..." // HMAC chain continuity
}
} sync_type: "revocation"
// payload for sync_type: "revocation"
{
"revocation_record": {
"rrn": "rcan://registry-1.acme.com/org/model/v1/robot-A",
"revoked_at": 1741000000,
"reason": "key_compromise",
"authority": "registry-1.acme.com",
"propagate_to": ["hospital-registry.nhs.uk"] // Explicit propagation list
}
} sync_type: "key"
// payload for sync_type: "key"
{
"key_record": {
"registry_id": "registry-1.acme.com",
"kid": "kid-abc123",
"public_key": "ed25519:...",
"algorithm": "Ed25519",
"use": "sig",
"exp": 1772536000,
"issued_at": 1741000000
}
} Cross-Registry JWT Trust Chains
When Robot A (on registry-1) needs to command Robot B (on registry-2), registry-2 must be able to verify that the JWT was issued by a trusted source — without registry-2 having direct knowledge of registry-1's users.
Trust Chain Construction
- Root signs authoritative registry keys. The root registry (rcan.dev) signs the public key of registry-1 and stores the signed record.
- JWT carries the issuing registry tier. JWTs from registry-1 carry
"registry_tier": "authoritative"and the issuer'skid. - Registry-2 verifies via trust chain. Robot B fetches registry-1's public key from its DNSSEC TXT record, verifies the root signature on that key, then verifies the JWT signature.
// Cross-registry JWT (issued by registry-1, trusted by registry-2)
{
"iss": "registry-1.acme.com",
"sub": "user-uuid-alice",
"registry_tier": "authoritative",
"kid": "reg1-key-2026a",
"loa": 2,
"aud": "rcan://hospital.nhs.uk/med/delivery/v2/unit-04",
"scope": ["status"],
"cross_registry": true,
"consent_id": "uuid-of-federated-consent-record",
"exp": 1741003600
} Verification Steps (Robot B's perspective)
1. Parse JWT header → extract kid, iss
2. Lookup iss in local federation cache
→ if miss: fetch _rcan.registry-1.acme.com TXT (DNSSEC)
→ extract public key fingerprint
→ fetch JWKS from registry-1.acme.com/.well-known/rcan-keys.json
→ verify JWKS signature against root public key (rcan.dev)
3. Verify JWT signature against registry-1's public key
4. Validate cross_registry: true + consent_id present
5. Lookup consent_id in local federated consent store
→ verify consent covers requested scope
→ verify consent not expired
6. Check loa >= min_loa_for_control (P66 manifest field)
7. Apply local_safety_wins (Protocol 66 invariant — local always wins) Trust Anchor Discovery (DNSSEC)
The RCAN protocol uses DNSSEC TXT records for trust anchor discovery, eliminating the need for a centralised PKI while leveraging the existing DNS trust hierarchy.
DNS Record Format
// TXT record at: _rcan.<registry-domain>
// Example: _rcan.registry-1.acme.com
_rcan.registry-1.acme.com. 3600 IN TXT "v=rcan1; tier=authoritative; kfp=sha256:4a3f8c...; sig=ed25519:signed-by-root"
// Fields:
// v=rcan1 — record version (required)
// tier= — "root" | "authoritative" | "community"
// kfp= — SHA-256 fingerprint of registry's current Ed25519 public key
// sig= — Root registry's Ed25519 signature over "v=rcan1;tier=...;kfp=..." string Discovery Flow
ROBOT B verifying ROBOT A (from registry-1.acme.com):
1. DNS query: _rcan.registry-1.acme.com TXT (DNSSEC validated)
2. Parse TXT: tier=authoritative, kfp=sha256:4a3f...
3. Verify sig field using root registry public key (pre-loaded / cached)
4. Fetch JWKS: https://registry-1.acme.com/.well-known/rcan-keys.json
5. Match key fingerprint against kfp in TXT record
6. Use matched public key to verify incoming JWT Federated Consent Record Portability
A ConsentRecord issued by registry-1 and sync'd to registry-2 via FEDERATION_SYNC must be accepted by robots on both registries. The format is designed to be self-verifying:
// Portable ConsentRecord (accepted by both registries)
{
"schema_version": "1.6",
"request_id": "uuid-v4",
"requester_ruri": "rcan://registry-1.acme.com/org/model/v1/robot-A",
"requester_owner": "user-uuid-alice@registry-1.acme.com",
"target_ruri": "rcan://hospital.nhs.uk/med/delivery/v2/unit-04",
"target_owner": "user-uuid-bob@hospital.nhs.uk",
"granted_scopes": ["status"],
"consent_type": "cross_registry",
"granted_at": 1741000000,
"expires_at": 1741086400,
"source_registry": "registry-1.acme.com",
"target_registry": "hospital-registry.nhs.uk",
"owner_jwt_sub": "user-uuid-bob@hospital.nhs.uk",
"owner_signature": "ed25519:...", // Target robot owner signs this record
"sync_id": "uuid-of-FEDERATION_SYNC-event",
"chain_hash": "sha256:..." // HMAC continuity for audit
} Portability Rules
- The
owner_signatureis over the entire record (excludingchain_hash). Both registries can verify it using the owner's public key. - Records are stored in both registries' local consent stores after sync.
- Expiry is enforced locally — the record is deleted from both stores at
expires_at. - Revocation is propagated via
FEDERATION_SYNCwithsync_type: "revocation".
Cross-Registry ESTOP Propagation
When Robot A (on registry-1) issues an ESTOP targeting Robot B (on registry-2), the ESTOP bypasses the normal consent-gate and federation trust chain — consistent with the Protocol 66 invariant that ESTOP is always accepted from any identified source.
Propagation Rules
- ESTOP (type 6, SAFETY) from a cross-registry robot is accepted immediately, before trust chain verification.
- The receiving robot MUST log the cross-registry ESTOP with the source RURI and
source_registry. - RESUME after a cross-registry ESTOP requires: (a) verified consent record, (b) trust chain verification, AND (c) local owner acknowledgement.
- An ESTOP from a registry-1 robot does NOT authorize that robot to issue RESUME — RESUME requires consent.
12-Step Federation Flow: Alice → Robot B
Alice is a user on registry-1. Robot B is registered on registry-2. Alice wants to read Robot B's status.
Alice Registry-1 Registry-2 Robot B
│ │ │ │
│ 1. Request federation │ │ │
│ consent for Robot B │ │ │
│──────────────────────▶│ │ │
│ │ 2. Lookup Robot B │ │
│ │ registry (DNS/RRF) │ │
│ │──────────────────────▶│ │
│ │ 3. Registry-2 info │ │
│ │◀──────────────────────│ │
│ │ │ 4. Forward consent │
│ │ CONSENT_REQUEST │ request to │
│ │ (FEDERATION_SYNC) │◀───────────────────▶│
│ │ │ │
│ │ │ 5. Robot B notifies │
│ │ │ owner (Bob) │
│ │ │────────────────────▶│ Bob
│ │ │ │──▶ notify
│ │ │ │
│ │ │ 6. Bob approves │
│ │ │ CONSENT_GRANT │
│ │ │◀────────────────────│
│ │ │ │
│ │ 7. FEDERATION_SYNC │ │
│ │ sync_type=consent │ │
│ │◀──────────────────────│ │
│ │ │ │
│ │ 8. Mint cross-registry│ │
│ │ JWT for Alice │ │
│ │ (scope=status, │ │
│ │ cross_registry=true) │ │
│ 9. Receive scoped JWT │ │ │
│◀──────────────────────│ │ │
│ │ │ │
│ 10. Send STATUS request to Robot B (with JWT) │ │
│───────────────────────────────────────────────────────────────────▶│
│ │ │ │
│ │ │ 11. Robot B verifies│
│ │ │ trust chain: │
│ │ │ DNSSEC → JWKS → │
│ │ │ JWT → consent │
│ │ │ │
│ 12. STATUS response │ │ │
│◀───────────────────────────────────────────────────────────────────│ Protocol 66 and Federation
federation_enabled: false in its Protocol 66 manifest MUST reject all cross-registry commands, including STATUS requests, regardless of JWT validity.
The Protocol 66 manifest gains a new federation_enabled field in v1.6:
GET /api/safety/manifest
{
"protocol": 66,
"rcan_version": "1.6",
...
"federation_enabled": true, // false = reject all cross-registry commands
"trusted_registries": [ // Explicit allowlist (optional; [] = trust all authoritative)
"hospital-registry.nhs.uk",
"acme-robots.com"
],
"min_loa_for_control": 2 // Minimum LoA required for cross-registry control scope
} Implementation Notes
- Robots with
federation_enabled: falseignore allFEDERATION_SYNCmessages. - Community registry JWTs (tier=community) MUST NOT be accepted for cross-registry
controlscope, even whenfederation_enabled: true. - The
trusted_registriesallowlist, when non-empty, acts as an explicit federation allowlist — cross-registry commands from unlisted registries are rejected regardless of tier. - Cross-registry consent records have a maximum expiry of 7 days; long-term access requires periodic re-consent.
rcan-py Federation API
from rcan.federation import FederationSync, FederatedConsentStore, TrustChainVerifier
# Build and send a FEDERATION_SYNC (consent)
sync = FederationSync.build_consent_sync(
source_registry="registry-1.acme.com",
target_registry="hospital-registry.nhs.uk",
consent_record=consent_record,
signing_key=registry_signing_key,
)
await node.send(sync)
# Verify a cross-registry JWT on receipt
verifier = TrustChainVerifier(
root_public_key=RRF_ROOT_PUBLIC_KEY,
dns_resolver=dnssec_resolver,
)
claims = await verifier.verify(jwt_token)
# claims.registry_tier == "authoritative"
# claims.loa == 2
# claims.cross_registry == True
# Store a federated consent record
store = FederatedConsentStore(db_path="~/.rcan/fed-consent.db")
store.put(consent_record)
valid = store.check(requester_ruri, target_ruri, scope="status") Implementation Notes
- DNSSEC dependency: Robots in environments without DNSSEC-capable DNS resolvers MUST fall back to root-signed JWKS fetched over HTTPS (not DNS) and MUST log a WARNING when using the HTTPS fallback.
- Federation cache TTL: Federated registry public keys SHOULD be cached for 1 hour; cross-registry consent records MUST be refreshed at most every 24 hours.
- Circular federation: Registry A trusting Registry B trusting Registry A (circular) is explicitly prohibited. Implementations MUST detect cycles in the trust chain and reject with
FEDERATION_TRUST_CYCLE. - Offline federation: When registry-2 is unreachable, Robot B continues to honour cached cross-registry consent records for up to 1 hour (consistent with §14 offline operation mode).
- ESTOP does not require federation: Cross-registry ESTOP is always accepted. Do not gate ESTOP on federation configuration or DNSSEC lookup availability.
See Also
- §8.7 Identity Verification & LoA — Level of Assurance enforcement for federated JWTs
- §11.2 Consent Wire Protocol — base consent protocol federated consent builds on
- Safety & P66 Conformance —
federation_enabledmanifest field - §12 FEDERATION_SYNC — message type reference
- §8.6 Key Rotation — JWKS format used for cross-registry key exchange