03 ValidationEN
ValidateAIC Validation Rules
Code:
gateway-core/aic.go:ValidateAIC
Validation is called after ParseAIC and before CheckAdmission.
Core Validation Items
| # | Check | Rule | On Violation |
|---|---|---|---|
| 1 | Capability count limit | len(capabilities) ≤ 256 |
Reject |
| 2 | schemeId length | 1 ≤ len(schemeId) ≤ 128 |
Reject |
| 3 | capabilityId length | 1 ≤ len(capabilityId) ≤ 256 |
Reject |
| 4 | parameters length | len(parameters) ≤ 4096 |
Reject |
| 5 | Extensions unknown critical | Unknown OID with critical=TRUE | Reject |
| 6 | principalUid.realm length | 1 ≤ len(realm) ≤ 128 (ASN.1 SIZE(1..128)) |
Reject |
| 7 | principalUid.identifier length | 1 ≤ len(identifier) ≤ 256 (ASN.1 SIZE(1..256)) |
Reject |
| 8 | keyHash length | Specification 1 ≤ len(keyHash) ≤ 64 (SIZE(1..64), only supports hash algorithm families with output length ≤64 bytes); must equal the output length declared by hashAlgo — current implementation supports full SHA-2/SHA-3 family (SHA-256=32/SHA-384=48/SHA-512=64/SHA3-256=32/SHA3-384=48/SHA3-512=64 bytes); length mismatch or algorithms like SM3/BLAKE2/BLAKE3 requiring external dependencies explicitly report unsupported (P1-A-12) |
Reject |
| 9 | nonce length | len(nonce) == 32 |
Reject |
| 10 | requestedLifetime range | 1 ≤ lifetime ≤ 86400 (SHOULD ≥ 3600) |
Reject |
Note: The
0 → 3600upgrade only exists at API input layer normalization (when caller passes 0, treated as default 3600); the wire value encoded into TBS/DA must already be within 1..86400 range, ASN.1 defines it asINTEGER (1..86400)with no DEFAULT 0. | 11 | Capabilities must not use constraint schemeId | Each MUST NOT haveschemeId = "varwof/constraint-v1"| Reject | | 12 | Non-empty authorization |capabilitiesmust not be empty (at least one entry, CA issuance policy MUST enforce);authorizationConstraintsmay be empty (empty = no restrictions) | Reject issuance |
authorizationConstraints Validation (v1.6)
AIC-Level Constraint Validation
| # | Check | Rule |
|---|---|---|
| C1 | Constraint count limit | len(constraints) ≤ 32 |
| C2 | schemeId whitelist | Each MUST be "varwof/constraint-v1" (recommended by specification), "constraint" or "constraint-v1" (backward compatibility); other values rejected |
| C3 | capabilityId identification | SHOULD be one of network:cidr / session:max-concurrent / time:window / geo-fence; unknown types by default log audit warning and ignore (does not block business); if ops configures StrictConstraints: true, then reject |
| C4 | parameters JSON parseable | MUST be valid JSON (json.Valid), only for constraint type (varwof/constraint-v1 whitelist) parameters — built-in constraint formats are defined by this specification; business capabilities (non-constraint schemeId) parameters are opaque byte strings, encoding defined by schemeId scheme (JSON recommended, CBOR/ASN.1/binary etc. allowed) |
| C5 | Single parameters size | ≤ 512 bytes (after UTF-8 encoding) |
| C6 | capabilityId non-empty | MUST be non-empty string |
PA-Level Constraint Validation (v1.6.1)
PA's authorizationConstraints follows the same format rules as AIC:
| # | Check | Rule |
|---|---|---|
| P1 | Constraint count limit | len(constraints) ≤ 32 |
| P2 | schemeId whitelist | Each MUST be "varwof/constraint-v1" (recommended by specification), "constraint" or "constraint-v1" (backward compatibility); other values rejected |
| P3 | capabilityId non-empty | MUST be non-empty string |
| P4 | parameters JSON parseable | MUST be valid JSON |
| P5 | Single parameters size | ≤ 512 bytes |
| P6 | Runtime check | PA constraints encountering unsupported constraint types degrade to audit warning and ignore (same lenient policy as AIC) |
PA constraints execute independently of AIC constraints: when accessing directly (without AIC), PA constraints are the only constraints; when accessing through delegation, PA and AIC constraints are independently checked at their respective layers, with no subset relationship.
Default lenient (Forward-Compatible): Unknown constraint types are ignored, ensuring new constraints can be gradually rolled out in mixed old/new gateway deployments. Strict mode is controlled by ops configuration switch.
Constraint Parameter Validation Details
network:cidr
Supports two JSON forms (gateway accepts both):
["10.0.0.0/8", "192.168.0.0/16"]
{"cidrs": ["10.0.0.0/8", "192.168.0.0/16"]}
- MUST be JSON array, or
{"cidrs": [...]}object - Each item MUST be a valid CIDR string
- Empty list = no restrictions (equivalent to no such constraint)
- Requires the gateway to provide the connection peer IP (
ClientIP); constraint is skipped when IP is empty (cannot evaluate source address)
session:max-concurrent
{"max": 5}
maxMUST be an integer, 1 ≤ max ≤ 1024- Checked by the gateway connection tracker; skipped during constraint evaluation phase (placeholder type)
time:window
{"start": "22:00", "end": "06:00"}
{"start": "09:00", "end": "18:00", "tz": "Asia/Shanghai"}
start/endMUST be inHH:MMformat (00:00–23:59)tzis an IANA timezone name (optional): window times are interpreted per this timezone and automatically converted at evaluation time; defaults to UTC evaluation (backward compatibility)- Cross-day windows (start > end) indicate spanning days (e.g., 22:00–06:00)
- Window includes the start point but excludes the end point (09:00–18:00 exits the window at exactly 18:00)
geo-fence
Supports two forms: inline table and external resolver:
{"resolver": "inline", "regions": {"CN-SHA": ["10.0.0.0/8", "192.168.0.0/16"]}}
{"resolver": "ip2region", "regions": ["CN-SHA", "CN-BJS"]}
resolveris the region resolver name:inline(default, zero external dependency, regions is a region→CIDR inline table, IP matching any CIDR belongs to that region) or an external resolver- External resolvers must first be registered at the gateway (
RegisterGeoResolver, e.g., ip2region); unregistered resolver evaluation failure = reject connection (fail-closed), not silent pass regionsis the set of allowed region identifiers; client IP resolved region identifier must match- Requires the gateway to provide the connection peer IP; constraint is skipped when IP is empty
Reason Validation (v1.7.1)
DelegationAuthorization.reason and DelegationAuthTBS.reason reuse the same Reason structure (defined in 01-asn1.md §Reason). reason is a required field (authorization must always have a reason), for descriptive purposes (audit/display), does not participate in permission decisions; validation failure only rejects the certificate/signature, does not affect authorization intersection calculation.
| # | Check | Rule |
|---|---|---|
| R1 | reasonCode present |
MUST be present and non-empty (UTF8String) |
| R2 | description present |
MUST be present and non-empty (UTF8String) |
| R3 | reasonCode value style |
SHOULD be SCREAMING_SNAKE (controlled vocabulary, e.g., SCHEDULED_MAINTENANCE) |
| R4 | reasonCode length |
MUST ≤ 64 characters, should be as short as possible |
| R5 | description length |
MUST ≤ 512 characters |
Extensions Known OID List
isKnownExtension recognizes the following OIDs:
| OID | Name |
|---|---|
.1.2 |
PrincipalAuthorization |
.3.1 |
MarketAccessId |
.1.1.1 AgentIdentity and .1.1.2 DelegationAuthorization are embedded fields of the AIC
extension itself (not standalone extensions), so they are intentionally absent from this list.
Other OIDs with critical=true will cause rejection.
AIC and PrincipalAuthorization extensions themselves MUST be non-critical (
critical=TRUEis rejected as unknown extension), ensuring non-AIC-aware systems can safely ignore them.
AdmissionConfig Options
AdmissionConfig provides finer-grained runtime admission control:
| Option | Default | Description |
|---|---|---|
RequireAIC |
false | Reject connections without AIC extension |
RequiredProtocol |
"" | Require Agent to have specified SchemeId |
RequiredCapabilities |
nil | Require Agent to have all specified capabilities; matching is glob wildcard (MatchCapability), AIC declarations (bare capabilityId or schemeId:capabilityId) serve as patterns, declaration-side wildcards can cover detail requirements — e.g., declaring SELECT:* (full name mysql:SELECT:*) covers requirements mysql:SELECT:* / mysql:SELECT:/api/tables, but mysql:INSERT:* / http:GET:/admin is rejected |
DisallowRepresentative |
false | Reject representative mode |
RequireUserAuth |
false | Require DelegationAuthorization signature verification to pass |
EnforceCapSizeConstraints |
false | Validate Capability field lengths |
NonceCache |
nil | Nonce replay protection cache (nil=skip) |
EnforceSize32 |
false | Validate nonce is 32 bytes |
EnforceConstraints |
false | v1.6 whether to enforce authorizationConstraints; both PA-level and AIC-level are controlled by this switch |
EnforceConstraints Behavior
| Constraint Type | Check Logic | On Violation |
|---|---|---|
network:cidr |
Connection peer IP is in any CIDR | Reject |
session:max-concurrent |
Current Agent active connection count has reached the limit | Reject |
time:window |
Current time is within the window (converted per tz, default UTC) | Reject |
geo-fence |
Connection peer IP resolved region identifier is in the allowed set | Reject |
| Unknown type | Log audit warning and ignore (lenient); strict mode can reject | Per configuration |
Verification Sequence (v1.6.1 Clarifies Dual-Level Constraints)
After the gateway completes the TLS handshake, verification is executed in the following order:
1. Certificate chain verification ← Standard X.509 path building
├── Network reachable: MUST validate OCSP Stapling or CRL; reject if not passed
└── Network unreachable/offline mode: skip online revocation check (fail-open),
log high-risk audit; **enforce** remaining certificate validity ≤ 1h
(G2(b) implemented: when ocsp_fallback=allow, gateway injects
OfflineMaxCertLifetime=1h, exceeding = reject)
2. Parse AICExtension ← Extract identity + capabilities + constraints
3. Verify DelegationAuthorization ← Principal signature verification + SPKI hash cross-check
4. Check chainDepth ≤ maxDepth (FUTURE) ← Multi-level delegation chain depth control, single-level deployment can omit
5. **Check PA.authorizationConstraints** ← v1.6.1, PA constraints independent of AIC constraints
6. Check AIC.authorizationConstraints ← Execute first, low-cost fast rejection
└── Runtime constraint checks (IP/time/region/session:max-concurrent)
7. Check capabilities ← Business capability matching (glob wildcard: declarations as patterns covering requirements, see `RequiredCapabilities`)
8. Apply Gateway Policy ← Runtime policies (timeout/retry/rate-limiting/routing)
9. Allow/Reject
Rationale: PA constraints and AIC constraints are two independent check layers, acting on the authorization boundary and execution boundary respectively, with no subset relationship.
Multi-Constraint Combination Logic
When a certificate contains multiple authorizationConstraints:
The gateway MUST require all constraints to be simultaneously satisfied (AND logic). If any single constraint is not satisfied, the request is rejected.
Example:
{
"authorizationConstraints": [
{"schemeId": "constraint", "capabilityId": "time:window",
"parameters": "{\"start\":\"22:00\",\"end\":\"06:00\"}"},
{"schemeId": "constraint", "capabilityId": "network:cidr",
"parameters": "[\"10.0.0.0/8\"]"}
]
}
→ Must satisfy both "night shift time" and "internal network IP" to be allowed.
Decision Model
AIC.capabilities: Agent's capability declarations
AIC.authorizationConstraints: Agent-level authorization boundary constraints (v1.6)
PrincipalAuthorization.grants: Principal's allowed capability grants
PrincipalAuthorization.authorizationConstraints: Principal-level authorization boundary constraints (v1.6.1, independent of AIC constraints)
T_policy: Gateway local policy
EffectiveCapability = P_grants ∩ C_agent ∩ T_policy
EffectiveConstraint = PA_constraints ∩ C_constraint ∩ T_constraint_policy
direct mode (no AIC): audit actor = principal, permission boundary = PA ∎ PA_constraints
authorized mode (has AIC): audit actor = agentId, permission boundary = C_agent ∩ PA_collected ∩ T_policy
representative mode: audit actor = principalUid, permission boundary = P ∩ C ∩ T
Certificate Size Constraints (v1.6)
| Certificate Type | Recommended Limit | Hard Limit | Description |
|---|---|---|---|
| All-protocol safety limit | 12KB | 16KB | Compatible across all four gateways |
| Handshake certificate | 8KB | 16KB | AIC certificate used for mTLS handshake; exceeding 16KB causes QUIC handshake failure |
| Full authorization certificate | 64KB | 128KB | Contains all capabilities + constraints + extensions, application layer transport |
| Single Capability parameters | 512B | 4096B | 05-capability.md §Parameters |
Certificates exceeding the hard limit MUST be rejected by the gateway.
Delegation Depth Control (FUTURE)
When the certificate extension contains DelegationDepthControl:
| # | Check | Rule |
|---|---|---|
| Φ1 | chainDepth ≤ maxDepth | chainDepth MUST ≤ maxDepth; exceeding = reject connection |
| Φ2 | chainDepth continuity | When the Nth-level Agent delegates to a lower level, it sets chainDepth = current value + 1 |
| Φ3 | maxDepth immutability | maxDepth is set by the top-level Principal across the entire delegation chain; lower levels must not tamper with it |
FUTURE: Current gateway only supports single-level delegation (chainDepth = 0); the above rules for multi-level delegation chains are specification reserves.