01 Asn1EN

AIC ASN.1 Type Definitions

Corresponds to specification version v1.7.1. Known limitations (parameter-level subset validation) are listed in 02-code-map.md. Key files: gateway-core/aic.go, gateway-core/decision.go, gateway-core/constraints.go

AIC Overall Structure

AIC ::= SEQUENCE {
    version                     INTEGER DEFAULT 1,
    agentId                     UTF8String (SIZE(1..256)),
    principalUid                PrincipalUid,
    capabilities                SEQUENCE SIZE(0..256) OF Capability,
    delegationMode              DelegationMode DEFAULT authorized,
    authorizationConstraints    [0] EXPLICIT SEQUENCE SIZE(0..32) OF Capability OPTIONAL,
    delegationAuthorization     DelegationAuthorization,
    extensions                  [1] EXPLICIT Extensions OPTIONAL
}

DelegationMode ::= INTEGER {
    authorized (0),
    representative (1)
} (0..1)
Field Type Constraint Description
version INTEGER DEFAULT 1 Only defines v1 AIC version number
agentId UTF8String SIZE(1..256) Agent unique identifier, unchanged across renewals
principalUid SEQUENCE See below Principal identity identifier
capabilities SEQUENCE OF Capability 0–256 entries CA-certified Capability declarations
delegationMode INTEGER (0..1) authorized / representative Delegation mode
authorizationConstraints SEQUENCE OF Capability OPTIONAL 0–32 entries Authorization boundary constraints (added in v1.6)
delegationAuthorization SEQUENCE See below Principal signature evidence
extensions Extensions OPTIONAL ≤32 entries General extension slot

delegationAuthorization is a required field. In dual-certificate deployment, both the handshake certificate and authorization certificate are complete AICs and MUST carry DA (see 08-dual-cert.md).

authorizationConstraints

Reuses the Capability container; schemeId MUST be "varwof/constraint-v1" (recommended by specification); for backward compatibility, the code also accepts "constraint" and "constraint-v1"; other schemeIds are skipped, and capabilityId identifies the specific constraint type:

capabilityId parameters format Description
network:cidr ["10.0.0.0/8", "192.168.0.0/16"] Allowed IP ranges
session:max-concurrent {"max": 5} Maximum concurrent Agent instances
time:window {"start": "22:00", "end": "06:00"} Allowed execution time window

Maximum constraint count ≤ 32 entries (unified at wire format + CA issuance phase), single parameters ≤ 512 bytes.

Design principle ("constrained but not overstepping"):

  • Only authorization boundary constraints, not runtime policies (timeout/retry/rate-limiting/routing)
  • Determined by the authorizer, varies per individual, infrequent changes
  • Verified offline by the gateway during the TLS handshake phase, no external system dependency

Encoding Tag Conventions (Context Tags)

For cross-platform, cross-language stable implementation, encoding tags follow these rules (v1.7.1):

  1. Required fields use universal tags (INTEGER / UTF8String / OCTET STRING / SEQUENCE, etc.) without context tags; required fields with the same tag are decoded in structural order without ambiguity.
  2. All OPTIONAL fields uniformly use context-specific explicit tags [n] EXPLICIT, numbered starting from 0 in field appearance order within the structure; numbers are unique within the same structure but can repeat across structures.
  3. Standard external types (AlgorithmIdentifier, Extensions, etc.) follow RFC 5280 encoding conventions and are not subject to this rule (e.g., AlgorithmIdentifier.parameters remains tagless OPTIONAL).
  4. DEFAULT field encoding: DER allows omitting fields equal to their default value; implementations MUST tolerate both forms; Go encoding/asn1 currently always encodes DEFAULT fields (not minimal DER, but parseable).
Structure Field tag Description
AIC authorizationConstraints [0] Same SEQUENCE tag as capabilities / delegationAuthorization, must be distinguished
AIC extensions [1] At end of structure, explicit tag prevents future ambiguity
DelegationAuthTBS authorizationConstraints [0] Same SEQUENCE tag as capabilities, must be distinguished
PrincipalAuthorization authorizationConstraints [0] Same SEQUENCE tag as grants, must be distinguished
PrincipalAuthorization delegationPolicy [1] Same SEQUENCE tag as grants / constraints, must be distinguished
PrincipalAuthorization extensions [2] All SEQUENCE field tags within structure are unique
DelegationPolicy maxSessionHours [0] Distinguished from three required INTEGER fields
PrincipalUid hashAlgo [0] Optional at end
Capability parameters [0] Existing convention, unchanged

Note: DelegationMode / DelegationModeEnum is defined as INTEGER + named constants + range constraint ((0..1)), natively supported by Go encoding/asn1, ensuring cross-language implementation consistency.

PrincipalUid

PrincipalUid ::= SEQUENCE {
    version     INTEGER (0..255) DEFAULT 1,
    realm       UTF8String (SIZE(1..128)),
    identifier  UTF8String (SIZE(1..256)),
    keyHash     OCTET STRING (SIZE(1..64)),
    hashAlgo    [0] EXPLICIT AlgorithmIdentifier OPTIONAL
}
-- When hashAlgo is omitted, defaults to SHA-256 (OID 2.16.840.1.101.3.4.2.1); keyHash = hashAlgo(SPKI);
-- The specification only supports hash algorithms with output length ≤64 bytes
-- (SHA-2/SHA-3 family, BLAKE2/BLAKE3, Chinese SM3, etc. all satisfy this)
Field Description
realm Global namespace (e.g., organization domain corp.com), SIZE(1..128)
identifier Unique identifier within the namespace (e.g., zhangsan), SIZE(1..256)
keyHash Hash of SPKI computed per hashAlgo (SHA-256/SM3 = 32 bytes), length determined by algorithm
hashAlgo Hash algorithm identifier for keyHash computation; defaults to SHA-256 when omitted

keyHash binds to SPKI rather than certificate fingerprints or pure identity strings. Rationale: certificate fingerprints change on certificate renewal, breaking identity continuity; pure identity strings have no cryptographic binding and cannot verify ownership offline; SPKI hashes enable offline ownership verification, maintain identity continuity across certificate renewals with the same key, and invalidate all associated authorization on key replacement. When a new certificate is issued with the same key pair, SPKI remains unchanged and the Agent certificate automatically continues.

keyHash computation MUST use the hash algorithm declared in hashAlgo on the subject SPKI (keyHash = hashAlgo(SPKI)); when omitted, defaults to SHA-256 (OID 2.16.840.1.101.3.4.2.1). The specification only supports hash algorithms with output length ≤ 64 bytes (constrained by keyHash OCTET STRING (SIZE(1..64))): current implementation (pki-types P1-A-12) already supports full SHA-2/SHA-3 family computation — SHA-256 (32 bytes) / SHA-384 (48) / SHA-512 (64) / SHA3-256 (32) / SHA3-384 (48) / SHA3-512 (64), keyHash length varies with algorithm output length without structure modification; BLAKE2/BLAKE3, Chinese SM3, etc. with output length ≤64 bytes register OID+length mapping only under pki-types zero-external-dependency policy (explicit "unsupported" without silent degradation), implementers can provide their own computation on the dependency side; if future support for algorithms with output length exceeding 64 bytes (e.g., SHAKE long output) is needed, AIC version must be upgraded and SIZE constraint relaxed.

Security policy: Principal key rotation will cause PrincipalUid.String() to change (due to KeyHash change). In this case, already-issued existing Agent certificates MUST be invalidated through the revocation process (CRL/OCSP). This design enforces strong binding between the principal key and Agent authorization, preventing identity spoofing and conforming to the short-lived certificate security model.

The communication format realm:identifier:keyFingerprint is for human reading and log output only; machine comparison MUST be based on ASN.1 structure deserialization. For subject lookup/association (cascading revocation, audit, certificate queries), this can be done via database index or PrincipalUid.realm / identifier fields; this lookup is for management association only, authorization binding and revocation still use keyHash as the authoritative source.

Capability

Capability is the only generic container in the protocol, with semantics defined by schemeId.

Capability ::= SEQUENCE {
    schemeId        UTF8String (SIZE(1..128)),
    capabilityId    UTF8String (SIZE(1..256)),
    parameters      [0] EXPLICIT OCTET STRING (SIZE(0..4096)) OPTIONAL
}

Glob matching rules:

Pattern Meaning Example
http:GET:/api/v1/users Exact match Only this path
http:GET:/api/v1/* Single-segment wildcard (* does not include /) /api/v1/users
http:*:/api/v1/* Wildcard HTTP method Any method on /api/v1/
varwof-gateway-v1:* All capabilities under scheme Any capabilityId under this schemeId
/api/v1/** Cross-path arbitrary depth /api/v1/users, /api/v1/users/roles

Reason

Delegation authorization reason description, for audit and display purposes, does not participate in permission decisions. Semantics are determined by the authorizer. reason is only used in DelegationAuthorization / DelegationAuthTBS (describing the reason for this delegation), not included in PrincipalAuthorization.

Reason ::= SEQUENCE {
    reasonCode  UTF8String (SIZE(1..64)),     -- Machine-identifiable standard reason code (controlled vocabulary, e.g., "SCHEDULED_MAINTENANCE"), should be as short as possible
    description UTF8String (SIZE(1..512))     -- Human-readable detailed description (e.g., "Due to v2.3.1 launch, old cache needs temporary shutdown")
}
Field Type Constraint Description
reasonCode UTF8String SIZE(1..64), MUST be non-empty Machine-identifiable standard reason code (controlled vocabulary, e.g., SCHEDULED_MAINTENANCE), should be as short as possible
description UTF8String SIZE(1..512), MUST be non-empty Human-readable detailed description (e.g., Due to v2.3.1 launch, old cache needs temporary shutdown)

Added in v1.7.1. Both reasonCode and description MUST be present; Reason is a required field in DelegationAuthorization / DelegationAuthTBS (authorization must always have a reason). reasonCode uses a controlled vocabulary: values use SCREAMING_SNAKE style (e.g., SCHEDULED_MAINTENANCE, AUTO_RENEWAL), should be as short as possible (numbers or brief text, ≤64); new values require registration (currently a maintained whitelist by implementers, registration mechanism TBD).

DelegationAuthorization

DelegationAuthorization ::= SEQUENCE {
    reason             Reason,                          -- v1.7.1 addition: delegation authorization reason (required)
    requestedLifetime  INTEGER (1..86400),              -- SHOULD 3600–86400; API input layer 0 → 3600 normalization, wire value is always 1..86400
    timestamp          GeneralizedTime,
    nonce              OCTET STRING (SIZE(32)),
    signatureAlgorithm AlgorithmIdentifier,
    signatureValue     OCTET STRING
}

Design decision: signatureAlgorithm / signatureValue are flat, not merged into a nested Signature type (v1.7.1 finalized, reviewed and confirmed 2026-08-06)

In DelegationAuthorization, the signature algorithm and signature value are flat as two parallel fields: signatureAlgorithm AlgorithmIdentifier + signatureValue OCTET STRING, consistent with the RFC 5280 §4.1 Certificate ::= SEQUENCE { tbsCertificate, signatureAlgorithm, signatureValue } top-level three-segment convention (CMS/PKCS#7 is the same). Rationale:

  1. Unified parsing path: Verifiers use the same parsing order (first get algorithm OID, then get signature value) for both CA signatures and principal signatures; no need for two sets of parsing logic for dual-layer signatures;
  2. Convention consistency: X.509/CMS both use flat structure; merging into nested Signature ::= SEQUENCE { algorithm, value } is non-conventional with no security or functional benefit;
  3. No reuse need: The signature structure currently only appears in DA; if reuse is needed in the future, a separate type can be defined in a new version without affecting the existing wire format.

signatureAlgorithm / signatureValue MUST NOT be merged into a nested SEQUENCE.

  • nonce: Required 32 bytes, for anti-replay
  • requestedLifetime: 1–86400 seconds (SHOULD 3600–86400), default 3600 (1 hour). Wire value is always 1..86400; "0 → 3600" only exists at API input layer normalization (when caller passes 0, treated as default 3600); the value encoded into TBS/DA must already be within the 1..86400 range.
  • timestamp: MUST be UTC (GeneralizedTime Z form)
  • reason: Added in v1.7.1, required, positioned at the start of the structure; same delegation reason as DelegationAuthTBS.reason (covered by signature within TBS)

DelegationAuthTBS (Signature-Covered Structure)

The principal's private key signs the DER encoding of the following structure:

DelegationAuthTBS ::= SEQUENCE {
    version                  INTEGER DEFAULT 1,
    agentId                  UTF8String (SIZE(1..256)),
    principalUid             PrincipalUid,
    reason                   Reason,                          -- v1.7.1 addition: delegation authorization reason (required, covered by signature)
    capabilities             SEQUENCE SIZE(0..256) OF Capability,
    delegationMode           DelegationMode,
    authorizationConstraints [0] EXPLICIT SEQUENCE SIZE(0..32) OF Capability OPTIONAL,
    requestedLifetime        INTEGER (1..86400),              -- SHOULD 3600–86400
    timestamp                GeneralizedTime,                 -- MUST use UTC (Z form)
    nonce                    OCTET STRING (SIZE(32))
}

v1.6 added the authorizationConstraints field. For backward compatibility, this field is OPTIONAL. Old certificates without this field are not affected during verification.

Design decision: DelegationAuthTBS does not contain Agent public key hash (agentKeyHash) (v1.7.1 finalized, reviewed and confirmed 2026-08-06)

1. Responsibility model: Current AI/Agents belong to the machine domain and do not possess legal entity status; the authorization responsibility principal is the natural person (anchored by principalUid.keyHash). The user/responsible principal only needs to sign over the "authorization scope" (agentId + capabilities + authorization boundary + authorization reason + lifetime + nonce); the Agent's "identity ↔ public key" binding is completed by the CA at certificate issuance time (CSR key proof + certificate-level SPKI binding), no need to redundantly enter the authorization evidence chain.

2. Simplicity: The AIC certificate's TBSCertificate already contains the Agent SPKI; adding agentKeyHash to TBS is redundant information that increases wire format complexity and user review burden (requiring a natural person to verify key fingerprints is impractical).

3. Trust boundary: The remaining risk (key-swap in the issuance channel: replacing the CSR public key between user confirmation and CA issuance) belongs to the "uncontrolled issuance channel" scenario, on the same trust root/channel breach boundary as CA private key leakage; this specification assumes the issuance channel is controlled.

4. Evolution reserve: When AI/Agents obtain legal entity status (becoming independent rights/obligation subjects), or when deployment requires a completely untrusted issuance channel, agentKeyHash (hashAlgo(Agent SPKI)) can be added through TBS version upgrade in a backward-compatible manner, making the principal's signature cover "this public key authorized to this agentId," thereby including the Agent itself in the authorization evidence chain. Old certificates and old verification logic are unaffected (distinguished by the version field, following the v1.6 → v1.7 evolution pattern).

v1.7.1: reason is located in DelegationAuthTBS (after principalUid) and DelegationAuthorization (at the start of the structure), both are required — authorization must always have a reason; the reason within TBS is covered by the principal signature, meaning the principal is aware of the delegation reason when signing.

PrincipalAuthorization

PrincipalAuthorization ::= SEQUENCE {
    version                     INTEGER DEFAULT 1,
    grants                      SEQUENCE SIZE(0..256) OF Capability,
    authorizationConstraints    [0] EXPLICIT SEQUENCE SIZE(0..32) OF Capability OPTIONAL,
    delegationPolicy            [1] EXPLICIT DelegationPolicy OPTIONAL,
    extensions                  [2] EXPLICIT Extensions OPTIONAL
}

DelegationPolicy ::= SEQUENCE {
    version             INTEGER DEFAULT 1,
    maxAgents           INTEGER DEFAULT 1,
    allowedMode         DelegationModeEnum DEFAULT authorizedOnly,
    maxSessionHours     [0] EXPLICIT INTEGER OPTIONAL
}

DelegationModeEnum ::= INTEGER {
    authorizedOnly (0),
    representativeAllowed (1)
} (0..1)
Field Type Constraint Description
version INTEGER DEFAULT 1 Only defines v1 Version number
grants SEQUENCE OF Capability ≤ 256 entries Principal's allowed capability grant set. When used directly = permission ceiling; when delegating = upper bound for Agent capabilities
authorizationConstraints SEQUENCE OF Capability OPTIONAL SIZE(0..32) v1.6.1. Principal-level authorization boundary constraints, defining under what conditions the Principal exercises authorization. Reuses Capability container, schemeId MUST be "varwof/constraint-v1" (recommended by specification, backward compatible with "constraint" / "constraint-v1"). CA issuance phase and wire format unified limit of 32 entries
delegationPolicy SEQUENCE OPTIONAL Delegation policy
extensions Extensions OPTIONAL ≤ 32 entries General extension slot

Delegation constraints (v1.6):

  • Currently only supports Principal → Agent single-level delegation (chainDepth = 0)
  • Multi-level delegation chain (FUTURE): Authorized Agents can use their own private keys to sign new DelegationAuthorization for lower-level Agents, forming a recursively verifiable cryptographic evidence chain
  • Agent certificates MUST be end-entity certificates (cA = FALSE)
  • Current Agents MUST NOT derive lower-level Agents

DelegationDepthControl (FUTURE — specification reserve, not yet implemented)

Placed in AIC extensions slot, OID 1.3.6.1.4.1.66257.1.1.4:

DelegationDepthControl ::= SEQUENCE {
    chainDepth  INTEGER (0..255),  -- OID .1.1.4.1
    maxDepth    INTEGER (0..255)   -- OID .1.1.4.2
}
Field Type Description
chainDepth INTEGER (0..255) Current delegation level. Direct authorization = 0, first-level delegation = 1, and so on
maxDepth INTEGER (0..255) Maximum allowed delegation depth. Gateway verifies chainDepth ≤ maxDepth, exceeding = rejection

Design principles:

  • This extension is only used when multi-level delegation chains are enabled; single-level deployment can omit it
  • Each delegation level's DelegationAuthorization is independently signed; tampering with any hop causes the entire chain to fail
  • Verifiers complete offline: parse certificate extension → verify signature level by level → check chainDepth ≤ maxDepth, no external service dependency
  • In multi-level delegation mode, when an Agent with chainDepth = N delegates to a lower level, the DelegationDepthControl it constructs has chainDepth = N+1 with maxDepth unchanged
  • Not yet implemented: Current gateway only supports single-level delegation (direct authorization = 0); multi-level delegation chain CA issuance logic, gateway verification pipeline, and audit tracing are all FUTURE

Permission Intersection Formula

CapabilityId-level intersection:

EffectiveCapability = P_grants ∩ C_agent ∩ T_policy
Set Source Description
P_grants PrincipalAuthorization.grants Capabilities the principal allows to grant
C_agent AIC.capabilities CA-certified Agent capability declarations
T_policy Gateway local policy Deployment-side configured policy constraints

Capability Parameters Intersection Semantics (clarified in v1.6):

For each matching Capability:
  if C_agent.parameters exceeds the boundary range of P_grants.parameters:
    this Capability is considered invalid (filtered or rejected)
  else:
    C_agent.parameters are adopted entirely (taking the Agent's values, but not exceeding boundaries)

Example:

Principal Authorization Agent Declaration Result
mysql:SELECT:* (max_rows=1000) mysql:SELECT:* (max_rows=100) ✅ Pass, take max_rows=100
mysql:SELECT:* (max_rows=1000) mysql:SELECT:* (max_rows=5000) ❌ Reject (exceeds principal boundary)
http:GET:/api/v1/* http:GET:/api/v1/users ✅ Pass, take Agent's specific path

The principal defines the maximum permission boundary; the Agent declares specific operation parameters. Agent parameters MUST be within the principal authorization range; exceeding = rejection.

Execution layer (clarified in v1.7.1): This parameter-level subset validation is mechanically executed by the CA at the issuance phase (at the same level as capability-level subset: capabilities ⊆ grants with each parameter not exceeding bounds); at gateway runtime, capability-level P∩C∩T intersection is executed without per-parameter comparison (parameter boundaries are already consolidated at issuance). This rule only applies to the capability layer (capabilities/grants); the authorization constraint layer (authorizationConstraints) does not apply subset relationships — PA and AIC constraints are independently checked at their respective layers (v1.6.1 preserved).

Certificate Size Constraints

Certificate Type Recommended Limit Hard Limit Description
All-protocol safety limit 12KB 16KB DER encoding ensures TCP/HTTP/DTLS/QUIC all four gateways compatible. 16KB corresponds to QUIC CRYPTO_BUFFER_EXCEEDED (quic-go hard limit); exceeding = handshake failure
Handshake certificate (AIC lightweight) 8KB 16KB Used for mTLS/DTLS/QUIC handshake. In dual-certificate deployment, contains agentId + principalUid + delegationMode + DelegationAuthorization; capabilities at least one entry (specific placeholder capabilities defined by deployment per registry)
Full authorization certificate (all constraints + extensions) 64KB 128KB Transmitted via application layer after handshake completion. Exceeding 128KB MUST be rejected by the gateway
Capabilities entries ≤ 256 entries Approximately 250 capability declarations ≈ 12KB DER. 256 is the ASN.1 SEQUENCE SIZE upper limit

v1.6: See 08-dual-cert.md for dual-certificate deployment details. The handshake certificate only contains agentId + principalUid + delegationMode + DelegationAuthorization (capabilities at least one entry, specific placeholder capabilities defined by deployment per registry), always under 8KB, ensuring stable pass-through across all transport layer protocols.