Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions docs/spec/instrument/specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ The full envelope schemas are [`request-envelope.json`](https://genai-security-p

Required at session start, before any hook traffic. Wire method: `handshake/hello`. Schema: [`handshake.json`](https://genai-security-project.github.io/agent-control-standard/schema/v0.1.0/handshake.json) (`$defs/ClientHello` and `$defs/ServerHello`).

**Observed Agent → Guardian Agent (ClientHello):** `acs_versions_supported`, `methods_implemented`, `transports_supported`, `max_payload_size_bytes`, `provenance_producer`, `wrapped_protocols`, `profiles_supported` (conformance profiles the client implements; see [Conformance](../conformance.md)).
**Observed Agent → Guardian Agent (ClientHello):** `acs_versions_supported`, `methods_implemented`, `transports_supported`, `max_payload_size_bytes`, `provenance_producer`, `wrapped_protocols`, `profiles_supported` (conformance profiles the client implements; see [Conformance](../conformance.md)), `signature_algorithms_supported` (optional; algorithms the client can sign and verify; omitting it negotiates only the baseline `HMAC-SHA256`).

**Guardian Agent → Observed Agent (ServerHello):** `negotiated_version`, `methods_evaluated`, `selected_transport`, `signature_algorithms_supported`, `timeout_config` (default and per-method), `on_decision_failure` (failure posture, §6.4), `skew_window_ms` (request-timestamp skew tolerance for replay protection, §10.3), `approver_types_supported`, `policy_requires_provenance`, `agbom_serializations_supported` (Inspect-pillar serialization formats the Guardian renders on request), `trace_emission` (whether the Guardian emits OTel and/or OCSF for the Trace pillar, plus optional OTLP collector endpoint), `profiles_accepted`.
**Guardian Agent → Observed Agent (ServerHello):** `negotiated_version`, `methods_evaluated`, `selected_transport`, `signature_algorithms_supported` (algorithms the Guardian can sign and verify; the negotiated set for both directions is the intersection of this field and the client's `signature_algorithms_supported`), `timeout_config` (default and per-method), `on_decision_failure` (failure posture, §6.4), `skew_window_ms` (request-timestamp skew tolerance for replay protection, §10.3), `approver_types_supported`, `policy_requires_provenance`, `agbom_serializations_supported` (Inspect-pillar serialization formats the Guardian renders on request), `trace_emission` (whether the Guardian emits OTel and/or OCSF for the Trace pillar, plus optional OTLP collector endpoint), `profiles_accepted`.

Version mismatch terminates with `UNSUPPORTED_VERSION` (`-32001`, §17.1). Unknown fields MUST be ignored. If the client declares `provenance_producer: "none"` and the Guardian's `policy_requires_provenance` is true, the Guardian MUST refuse the session at handshake time with `PROVENANCE_REQUIRED` (`-32002`, §17.1) rather than silently degrading enforcement.

Expand Down Expand Up @@ -347,17 +347,27 @@ This rule preserves the security guarantee (actions that would have been `ASK`'d

## 10. Cryptographic Signatures

A signature over the §10 canonical input is REQUIRED in ACS-Core. The signature envelope is `{ algorithm, value, key_id }`, the algorithm drawn from the registry below and the per-direction supported set declared in the handshake. `HMAC-SHA256` is the baseline that satisfies the requirement; ACS-Core does not require asymmetric or post-quantum signatures, which are the ACS-Crypto profile (§10.1). The per-session HMAC key is `HKDF`-derived from deployment-provided input keying material (a pre-shared secret, or a transport channel binding such as a TLS exporter) together with the `session_id`. ACS v0.1 defines no in-band key-exchange: a deployment with neither a shared secret nor a secure transport cannot use the HMAC baseline and satisfies the requirement with an ACS-Crypto algorithm whose key distribution it manages out of band.
A signature over the §10 canonical input is REQUIRED in ACS-Core for every request and response except `system/ping` (§13) and error responses where no signing key can be resolved (such as `SIGNATURE_INVALID` for an unknown `key_id`). `signature` is optional in the base JSON Schemas, so schema validation alone does not establish ACS-Core baseline integrity. The signature envelope is `{ algorithm, value, key_id }`, the algorithm drawn from the registry below and the per-direction supported set declared in the handshake. `HMAC-SHA256` is the baseline that satisfies the requirement; ACS-Core does not require asymmetric or post-quantum signatures, which are the ACS-Crypto profile (§10.1). The per-session HMAC key is `HKDF`-derived from deployment-provided input keying material (a pre-shared secret, or a transport channel binding such as a TLS exporter) together with the `session_id`. ACS v0.1 defines no in-band key-exchange: a deployment with neither a shared secret nor a secure transport cannot use the HMAC baseline and satisfies the requirement with an ACS-Crypto algorithm whose key distribution it manages out of band.

**HMAC key derivation.** For `HMAC-SHA256`, the per-session key is HKDF ([RFC 5869](https://www.rfc-editor.org/rfc/rfc5869)) with SHA-256, no salt (RFC 5869's default, a string of 32 zero bytes, which gives the same key as an empty salt), `info` set to the UTF-8 bytes of `metadata.session_id`, and a 32-byte output, applied to the secret that `key_id` names. Both parties MUST derive the key with exactly these parameters, so independent implementations holding the same secret derive the same key. `info` is the `session_id` string exactly as the request carries it, not parsed or normalized first: an uppercase or `urn:uuid:` spelling of the same UUID derives a different key. A response carries no `session_id`, so it is signed and verified with the key of the request it answers. The secret MUST be at least 32 bytes from a cryptographically secure random source. HKDF does no key stretching, so a passphrase used as the secret can be recovered offline from one captured signature. This derivation is defined for a pre-shared secret. v0.1 defines no exporter label or context for a channel-binding input, so that input is not yet interoperable between implementations. For example, the 32-byte secret `000102…1e1f` (the bytes 0 through 31) and the `session_id` `6b1f2c9e-4d7a-4e3b-8a51-9c0d2e7f1a36` give the key `80f0dc8c611279bfc2af2d5f374c5cb685888192ce1af5c3e0673d8fa748e8a4`.

**`key_id` for HMAC.** For `HMAC-SHA256`, `key_id` is an opaque label, chosen by the deployment, that names one configured secret. This specification reserves no values, and an implementation takes the label from its configuration. It does not hardcode one. A verifier MUST reject an unknown `key_id` (`SIGNATURE_INVALID`, §17.1) and MUST NOT fall back to another secret. `key_id` MUST NOT be derived from the secret. A Guardian that signs its response with `HMAC-SHA256` uses the secret, and the `key_id`, that the request named. The `SIGNATURE_INVALID` error for an unknown `key_id` is unsigned, because no configured secret matches it. A deployment rotating its secret configures the new secret under a new label, such as `"2026-10"`, so a verifier can hold both secrets while the rotation is in progress. That is what the §17.1 recovery for `SIGNATURE_INVALID`, re-resolving `key_id`, relies on. For the asymmetric algorithms of ACS-Crypto, `key_id` identifies the public key or hybrid key descriptor (§10.2).

**Signed input.** The signed input for every algorithm is the RFC 8785 (JCS) canonicalization of the request or response envelope with the `signature` field removed, encoded as UTF-8. This binds the signature to the whole envelope, including `method`, `metadata.session_id`, `request_id`, and `timestamp`, so a captured signature cannot be lifted into a different envelope (for example, re-wrapping a signed `toolCallResult` under a different `session_id`). A verifier MUST recompute this canonical form and MUST reject a signature that does not cover it (`SIGNATURE_INVALID`, §17.1). The input is fixed by this rule, not declared per message: a discoverable `signed_fields` would let a producer advertise partial coverage that omits `session_id`, reopening the gap this closes. Alternative canonicalization is not permitted in v0.1, matching the chain-hash rule in §8.

**Verifier rules (normative).** These rules apply to every conformant verifier, regardless of algorithm:

1. **Verification order and state isolation.** A Guardian MUST perform parsing, size-limit checks, and `key_id` resolution before signature verification. Until both the signature check and the timestamp check (§10.3) pass, the request MUST NOT alter session state, replay state, audit-chain state, or authorization state, and policy MUST NOT evaluate it. Security logs and rate-limit counters that are maintained outside the session audit chain MAY be updated on rejected requests. Checking the `request_id` for replay and reserving it MUST be one atomic operation performed after both checks pass, so that two copies of the same request arriving concurrently cannot both pass the replay check, and so that a skewed but validly signed request cannot burn an ID.

2. **Constant-time comparison.** For MAC tags (HMAC-SHA256), verifiers MUST compare the decoded signature bytes in constant time to prevent timing-based recovery of the key. For asymmetric signatures (ECDSA, RSA-PSS, ML-DSA), verifiers MUST NOT compare base64-encoded wire text, and MUST NOT leak the key or secret material through an early exit or data-dependent timing.

3. **Missing signature.** An envelope that lacks a `signature` field MUST be rejected with `SIGNATURE_INVALID` (`-32004`, §17.1), except the envelopes §10 exempts.

4. **Non-negotiated algorithm.** The negotiated set for both directions (requests and responses) is the intersection of `ClientHello.signature_algorithms_supported` and `ServerHello.signature_algorithms_supported` (§4). If the ClientHello omits `signature_algorithms_supported`, the negotiated set contains only the ACS-Core baseline `HMAC-SHA256`. A Guardian MUST reject a request whose `signature.algorithm` is outside the negotiated set, returning `SIGNATURE_INVALID`, with no fallback to another algorithm or key. An Observed Agent MUST refuse a response whose `signature.algorithm` is outside the negotiated set locally, with no fallback. During the `handshake/hello` exchange itself, the Guardian verifies the ClientHello request against the algorithms it supports, and the Observed Agent verifies the ServerHello response against `ClientHello.signature_algorithms_supported` (or the baseline if omitted), because the intersection is not known until the ServerHello is processed.

### 10.1 Algorithm registry

The registry is crypto-agile: the `{ algorithm, value, key_id }` envelope supports any registered algorithm, and the handshake declares which algorithms each side supports. v0.1 prioritizes adoption breadth over cryptographic maximalism: signatures are already field-optional, and a spec that ships without PQC mandates protects more deployments than a spec that mandates PQC and doesn't ship. PQC algorithms from NIST FIPS 203–205 (2024) are registered and available; a future version is expected to promote PQC to RECOMMENDED once ecosystem support matures.
The registry is crypto-agile: the `{ algorithm, value, key_id }` envelope supports any registered algorithm, and the handshake declares which algorithms each side supports. v0.1 prioritizes adoption breadth over cryptographic maximalism: `HMAC-SHA256` satisfies the ACS-Core requirement without asymmetric PKI (while `signature` remains optional in the base JSON Schema only for exempted control traffic such as `system/ping`, §13), and a spec that ships without PQC mandates protects more deployments than a spec that mandates PQC and doesn't ship. PQC algorithms from NIST FIPS 203–205 (2024) are registered and available; a future version is expected to promote PQC to RECOMMENDED once ecosystem support matures.

| Algorithm | Class | v0.1.0 status |
|---|---|---|
Expand Down
21 changes: 20 additions & 1 deletion specification/v0.1.0/handshake.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,25 @@
"enum": ["acs-core", "acs-trace", "acs-inspect", "acs-inspect-dynamic", "acs-provenance", "acs-crypto", "acs-audit"]
},
"description": "Conformance profiles this Observed Agent implements. 'acs-core' is the mandatory baseline and SHOULD always be included. Other profiles are optional and independently claimable. See Section 4 (Conformance Profiles) for definitions."
},
"signature_algorithms_supported": {
"type": "array",
"items": {
"type": "string",
"enum": [
"HMAC-SHA256",
"ECDSA-P256",
"RSA-PSS-SHA256",
"ML-DSA-65",
"ML-DSA-44",
"ML-DSA-87",
"SLH-DSA-128s",
"SLH-DSA-128f",
"ML-DSA-65+ECDSA-P256",
"ML-DSA-65+RSA-PSS-SHA256"
]
},
"description": "Signature algorithms the Observed Agent can sign and verify. The negotiated set for both directions (requests and responses) is the intersection of this field and ServerHello.signature_algorithms_supported. If this field is omitted, the negotiated set contains only the ACS-Core baseline HMAC-SHA256. During the handshake itself, the Guardian verifies the ClientHello against the algorithms it supports, and the Observed Agent verifies the ServerHello against this field (or the baseline if omitted)."
}
}
},
Expand Down Expand Up @@ -100,7 +119,7 @@
"ML-DSA-65+RSA-PSS-SHA256"
]
},
"description": "Signature algorithms the Guardian can verify on incoming requests. Empty array = signatures not supported / not required. 'HMAC-SHA256' is the v0.1 RECOMMENDED default (simplest deployment path). Classical asymmetric ('ECDSA-P256', 'RSA-PSS-SHA256') and PQC ('ML-DSA-*', 'SLH-DSA-*') are OPTIONAL. A future ACS version is expected to promote PQC to RECOMMENDED once ecosystem support matures."
"description": "Signature algorithms the Guardian can sign and verify. The negotiated set for both directions (requests and responses) is the intersection of this field and ClientHello.signature_algorithms_supported. 'HMAC-SHA256' is the v0.1 RECOMMENDED default (simplest deployment path). Classical asymmetric ('ECDSA-P256', 'RSA-PSS-SHA256') and PQC ('ML-DSA-*', 'SLH-DSA-*') are OPTIONAL. A future ACS version is expected to promote PQC to RECOMMENDED once ecosystem support matures. ACS-Core conformance requires signatures on every envelope except system/ping and key-resolution errors (Specification section 10, verifier rules)."
},
"timeout_config": {
"type": "object",
Expand Down
Loading
Loading