@intyga/verify 0.0.0-bootstrap.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +162 -0
- package/LICENSE +201 -0
- package/README.md +296 -2
- package/dist/approval-policy.d.ts +37 -0
- package/dist/approval-policy.js +149 -0
- package/dist/index.d.ts +803 -0
- package/dist/index.js +2236 -0
- package/dist/ledger-anchor.d.ts +195 -0
- package/dist/ledger-anchor.js +314 -0
- package/dist/ledger-bundle.d.ts +235 -0
- package/dist/ledger-bundle.js +419 -0
- package/dist/ledger-chain.d.ts +58 -0
- package/dist/ledger-chain.js +121 -0
- package/dist/ledger-evidence.d.ts +193 -0
- package/dist/ledger-evidence.js +613 -0
- package/dist/ledger-leaf.d.ts +25 -0
- package/dist/ledger-leaf.js +44 -0
- package/dist/ledger-merkle.d.ts +46 -0
- package/dist/ledger-merkle.js +183 -0
- package/dist/ledger-proof.d.ts +40 -0
- package/dist/ledger-proof.js +29 -0
- package/dist/ledger-rekor.d.ts +49 -0
- package/dist/ledger-rekor.js +187 -0
- package/dist/ledger-rfc3161.d.ts +25 -0
- package/dist/ledger-rfc3161.js +345 -0
- package/dist/ledger-signature.d.ts +16 -0
- package/dist/ledger-signature.js +61 -0
- package/package.json +57 -4
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,803 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A DIV Proof Envelope — a verifiable proof of what the human approved, returned once a challenge is
|
|
3
|
+
* APPROVED. `canonicalPayload` is the exact signed bytes (the DIV Intent Payload); the remaining
|
|
4
|
+
* fields are the signature metadata needed to verify it, extended beyond DIV §4.4's raw-ES256 shape
|
|
5
|
+
* with the WebAuthn assertion components so a passkey approval — the primary approver path — is
|
|
6
|
+
* representable.
|
|
7
|
+
*/
|
|
8
|
+
export interface ApprovalReceipt {
|
|
9
|
+
canonicalPayload: string;
|
|
10
|
+
target?: string | null;
|
|
11
|
+
actionType?: string | null;
|
|
12
|
+
actionDescription: string;
|
|
13
|
+
params: Record<string, unknown>;
|
|
14
|
+
/**
|
|
15
|
+
* EVERY witness signature over `canonicalPayload`. A quorum receipt carries one entry per approver;
|
|
16
|
+
* a single-signer receipt carries one. Emitting only the first approval made an M-of-N approval
|
|
17
|
+
* indistinguishable from a 1-of-1 one, so the quorum could not be verified offline at all.
|
|
18
|
+
*/
|
|
19
|
+
signatures?: ApprovalWitness[] | null;
|
|
20
|
+
signerDid?: string | null;
|
|
21
|
+
signerPublicKey?: string | null;
|
|
22
|
+
signature?: string | null;
|
|
23
|
+
sigAlg?: string | null;
|
|
24
|
+
authenticatorData?: string | null;
|
|
25
|
+
clientDataJSON?: string | null;
|
|
26
|
+
requester?: RequesterIdentity | null;
|
|
27
|
+
verificationCode: string;
|
|
28
|
+
}
|
|
29
|
+
/** One approver's signature over the canonical payload. */
|
|
30
|
+
export interface ApprovalWitness {
|
|
31
|
+
signerDid: string;
|
|
32
|
+
signerPublicKey: string;
|
|
33
|
+
signature: string;
|
|
34
|
+
sigAlg?: string | null;
|
|
35
|
+
authenticatorData?: string | null;
|
|
36
|
+
clientDataJSON?: string | null;
|
|
37
|
+
}
|
|
38
|
+
/** Thrown when a value outside the JSON data model is handed to the canonicalizer. */
|
|
39
|
+
export declare class NonCanonicalValue extends Error {
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Deterministic JSON with recursively sorted keys — identical to mcp-schemas.stableStringify.
|
|
43
|
+
*
|
|
44
|
+
* STRICT: RFC 8785 defines a mapping over JSON data, so anything outside that domain is REJECTED
|
|
45
|
+
* rather than coerced. The permissive version silently collapsed distinct runtime values onto one
|
|
46
|
+
* canonical string — `new Date(0)`, `{}`, `new Map()` and any class instance all serialized to `{}`,
|
|
47
|
+
* and a `toJSON` method was emitted as a `null`-valued key instead of being honoured. For a function
|
|
48
|
+
* whose entire job is "these bytes are exactly what was signed", quietly mapping several inputs onto
|
|
49
|
+
* one output is the wrong failure mode: the relying party's `expected.params` come from its own live
|
|
50
|
+
* runtime objects, so it is the caller most likely to hand us a Date.
|
|
51
|
+
*
|
|
52
|
+
* Exported so the shared golden vectors can pin THIS copy directly (vectors.test.ts) — every other
|
|
53
|
+
* port pins its canonicalizer against the committed file; the shipped relying-party verifier must
|
|
54
|
+
* not be the one implementation pinned only transitively.
|
|
55
|
+
*/
|
|
56
|
+
export declare function stableStringify(value: unknown): string;
|
|
57
|
+
/** The requesting workload's identity, as bound into a DIV Intent Payload. Mirrors mcp-schemas. */
|
|
58
|
+
export interface RequesterIdentity {
|
|
59
|
+
did: string;
|
|
60
|
+
attestation: {
|
|
61
|
+
method: string;
|
|
62
|
+
issuer: string;
|
|
63
|
+
subject: string;
|
|
64
|
+
} | null;
|
|
65
|
+
}
|
|
66
|
+
/** Agent-only DIV v1 claims. Configuration and execution truth are checked by the RP's PEP. */
|
|
67
|
+
export interface AgentIntentContext {
|
|
68
|
+
action: {
|
|
69
|
+
reversibility: "reversible" | "irreversible";
|
|
70
|
+
amount: {
|
|
71
|
+
amount: string;
|
|
72
|
+
currency: string;
|
|
73
|
+
} | null;
|
|
74
|
+
};
|
|
75
|
+
agent: {
|
|
76
|
+
label: string;
|
|
77
|
+
configDigest: string;
|
|
78
|
+
delegatedBy: string | null;
|
|
79
|
+
};
|
|
80
|
+
session: {
|
|
81
|
+
id: string;
|
|
82
|
+
seq: string;
|
|
83
|
+
prev: string | null;
|
|
84
|
+
aggregate: {
|
|
85
|
+
amount: string;
|
|
86
|
+
currency: string;
|
|
87
|
+
} | null;
|
|
88
|
+
};
|
|
89
|
+
nbf: string;
|
|
90
|
+
}
|
|
91
|
+
export declare function validateAgentIntentContext(context: AgentIntentContext, expiresAt: string): void;
|
|
92
|
+
/** DIV protocol version and type discriminator — identical to mcp-schemas. */
|
|
93
|
+
export declare const DIV_VERSION = 1;
|
|
94
|
+
export declare const DIV_INTENT_TYPE = "div-intent-verification";
|
|
95
|
+
/**
|
|
96
|
+
* OFFLINE APPROVAL (docs/DIV.md §5a.2): a normal approval, signed by real humans through the normal
|
|
97
|
+
* quorum, but collected OUT OF BAND at incident time because the gateway is unreachable. The relying
|
|
98
|
+
* party builds the challenge itself, the humans review and sign it on a disconnected device, and the
|
|
99
|
+
* result is verified by the ordinary §5 procedure.
|
|
100
|
+
*
|
|
101
|
+
* This deliberately replaces the older pre-signed "sealed break-glass" token. Pre-signing puts a
|
|
102
|
+
* bearer capability on disk and captures a human judgment about a HYPOTHETICAL; moving the ceremony
|
|
103
|
+
* off the network instead keeps the human in the loop for the ACTUAL incident and leaves nothing at
|
|
104
|
+
* rest to steal. See DIV §5a.1.
|
|
105
|
+
*
|
|
106
|
+
* The distinct `type` is the single most important guardrail in the whole mechanism. It sits inside
|
|
107
|
+
* the signed bytes, so:
|
|
108
|
+
* - an offline proof can NEVER verify as a normal approval, and
|
|
109
|
+
* - a normal approval can NEVER be replayed as an offline one.
|
|
110
|
+
* Neither direction is possible even with a byte-identical action, because the reconstructed payload
|
|
111
|
+
* differs and the signature comparison fails. Do not "simplify" this into a flag outside the payload.
|
|
112
|
+
*/
|
|
113
|
+
export declare const DIV_OFFLINE_INTENT_TYPE = "div-offline-intent";
|
|
114
|
+
/**
|
|
115
|
+
* DELEGATION (docs/DIV.md §5a.5): signed in advance by the ordinary quorum, it transfers the
|
|
116
|
+
* AUTHORITY TO APPROVE one pre-declared action to a named set of local operators.
|
|
117
|
+
*
|
|
118
|
+
* A delegation authorizes NOTHING by itself. `verifyApprovalReceipt` refuses this type outright and
|
|
119
|
+
* there is deliberately no opt-in flag that would let it through — see `verifyDelegation`, which is a
|
|
120
|
+
* separate operation for exactly that reason. A delegation that could authorize its own action would
|
|
121
|
+
* be the pre-signed bearer capability DIV §5a.1 rejects.
|
|
122
|
+
*/
|
|
123
|
+
export declare const DIV_DELEGATION_TYPE = "div-delegation";
|
|
124
|
+
/**
|
|
125
|
+
* Agent authority (DIV §5b): a quorum-signed statement of STANDING SCOPE for one agent. Authorizes
|
|
126
|
+
* no action on its own; `verifyApprovalReceipt` refuses it outright, and `verifyAgentAuthority` is
|
|
127
|
+
* the only door. Mirrors mcp-schemas.
|
|
128
|
+
*/
|
|
129
|
+
export declare const DIV_AGENT_AUTHORITY_TYPE = "div-agent-authority";
|
|
130
|
+
/**
|
|
131
|
+
* Platform hash-only intent (DIV §5c): an integrating platform's subject signs the DIGEST of the
|
|
132
|
+
* platform's own canonical payload. `verifyApprovalReceipt` refuses it outright;
|
|
133
|
+
* `verifyPlatformReceipt` is the only door. Mirrors mcp-schemas.
|
|
134
|
+
*/
|
|
135
|
+
export declare const DIV_PLATFORM_INTENT_TYPE = "div-platform-intent";
|
|
136
|
+
/**
|
|
137
|
+
* Hard ceiling on an offline proof's validity window, enforced at verification and not only at mint.
|
|
138
|
+
* An offline proof is created and redeemed within one incident, so the window is minutes — it exists
|
|
139
|
+
* to bound a proof whose `expiresAt` was minted over-long, which is otherwise indistinguishable at
|
|
140
|
+
* verification time from a correct one (DIV §5a.3).
|
|
141
|
+
*/
|
|
142
|
+
export declare const MAX_OFFLINE_WINDOW_MINUTES = 60;
|
|
143
|
+
/**
|
|
144
|
+
* Ceiling on the witness list this verifier will process. A DIV quorum is single digits — this is a
|
|
145
|
+
* denial-of-service bound, not a policy limit, because verification runs in the relying party's own
|
|
146
|
+
* process on an attacker-supplied receipt immediately before an irreversible action.
|
|
147
|
+
*/
|
|
148
|
+
export declare const MAX_WITNESSES = 64;
|
|
149
|
+
/**
|
|
150
|
+
* Hard ceiling on a delegation's validity window. Hours, not the 30 days the old sealed token
|
|
151
|
+
* allowed: a delegation cannot be revoked at an offline relying party, so the short window IS the
|
|
152
|
+
* revocation story (DIV §5a.6).
|
|
153
|
+
*/
|
|
154
|
+
export declare const MAX_DELEGATION_WINDOW_HOURS = 72;
|
|
155
|
+
/**
|
|
156
|
+
* The approval policy in force for a challenge, frozen at creation and SIGNED as part of the payload.
|
|
157
|
+
*
|
|
158
|
+
* This exists because the gateway enforces a rich requirement (quorum, four-eyes, hardware class) that
|
|
159
|
+
* used to appear nowhere in the signed bytes. A receipt from a 3-of-3, hardware-key-pinned challenge
|
|
160
|
+
* was byte-for-byte indistinguishable from a 1-of-1, no-hardware one — so a relying party doing
|
|
161
|
+
* "offline verification" still had to take the gateway's word for the entire policy, which is the
|
|
162
|
+
* exact class of trust the offline verifier exists to remove. Binding it into the payload also means
|
|
163
|
+
* the APPROVER sees and attests to the policy their signature is being counted toward.
|
|
164
|
+
*
|
|
165
|
+
* What a verifier can check offline, and what it cannot:
|
|
166
|
+
* - `requiredApprovals` — fully checkable. Counts distinct trusted approver signatures.
|
|
167
|
+
* - `requesterCannotApprove` — fully checkable. The requester DID is in the same signed payload.
|
|
168
|
+
* - `requireHardwareKey` — PARTIALLY checkable. A verifier can confirm the witness is a WebAuthn
|
|
169
|
+
* assertion rather than a bare P-256 key, and it refuses one whose signed authenticatorData says
|
|
170
|
+
* Backup Eligible or Backup State (a synced passkey announcing itself). An assertion carries no
|
|
171
|
+
* attestation, though, so BE=0 is the authenticator's claim, not proof of a discrete security key.
|
|
172
|
+
* - `allowedAaguids` — NOT checkable offline. The AAGUID lives in attestedCredentialData, which is
|
|
173
|
+
* present at REGISTRATION, not in an assertion. Only the gateway (which stored it at enrollment)
|
|
174
|
+
* can enforce the model. What a verifier CAN do is refuse what obviously cannot satisfy it: a
|
|
175
|
+
* non-empty allowlist is treated exactly like `requireHardwareKey` — a bare-key witness is refused
|
|
176
|
+
* and an offline proof is refused outright (`requiresHardwareCredential`).
|
|
177
|
+
* - `signerClass` — PARTIALLY checkable, and differently per witness kind. For a WEBAUTHN witness
|
|
178
|
+
* the UV flag (already required by `verifyWebAuthnSignature`) is cryptographic evidence a
|
|
179
|
+
* user-verification ceremony — a human gesture — happened at signing. An ES256 witness carries no
|
|
180
|
+
* signer-class evidence at all: there the class rests on the issuing deployment's signing-time
|
|
181
|
+
* enforcement, or, for an offline proof, on the delegation ceremony that named the operators.
|
|
182
|
+
* The verifier's own obligation is narrower and absolute: REFUSE any value it does not
|
|
183
|
+
* recognize (only "human" is defined today), so a future signer class can never verify as
|
|
184
|
+
* human-approved by default. It deliberately does NOT reject ES256 witnesses under
|
|
185
|
+
* `signerClass: "human"` — humans legitimately sign with raw P-256 keys (offline break-glass);
|
|
186
|
+
* a deployment wanting cryptographic proof of the ceremony pins `requireHardwareKey`.
|
|
187
|
+
*/
|
|
188
|
+
/**
|
|
189
|
+
* Whether a signed requirement can only be met by a hardware-backed WebAuthn credential: an explicit
|
|
190
|
+
* `requireHardwareKey`, OR a non-empty `allowedAaguids` model allowlist. The two are the same class of
|
|
191
|
+
* policy for every check a verifier can make — a bare key satisfies neither, and neither can be met
|
|
192
|
+
* offline — so they are refused together. Treating the allowlist as "not checkable, so not checked"
|
|
193
|
+
* let a bare software key satisfy a YubiKey-only rule on every offline path.
|
|
194
|
+
*/
|
|
195
|
+
export declare function requiresHardwareCredential(requirement: {
|
|
196
|
+
requireHardwareKey?: unknown;
|
|
197
|
+
allowedAaguids?: unknown;
|
|
198
|
+
}): boolean;
|
|
199
|
+
export interface ApprovalRequirementAttestation {
|
|
200
|
+
requiredApprovals: number;
|
|
201
|
+
requireHardwareKey: boolean;
|
|
202
|
+
allowedAaguids: string[];
|
|
203
|
+
requesterCannotApprove: boolean;
|
|
204
|
+
/** Required signer class — `"human"` is the only value defined today. Unrecognized values are refused. */
|
|
205
|
+
signerClass: string;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* The one signer class defined by DIV today (docs/DIV.md §4.3.2). Mirrors mcp-schemas, like
|
|
209
|
+
* DIV_VERSION — this package deliberately imports nothing from it.
|
|
210
|
+
*/
|
|
211
|
+
export declare const SIGNER_CLASS_HUMAN = "human";
|
|
212
|
+
/**
|
|
213
|
+
* Canonical DIV Intent Payload (docs/DIV.md v1) — byte-identical to
|
|
214
|
+
* mcp-schemas.canonicalIntentPayload. Strict RFC 8785 JCS: the whole object is serialized with every
|
|
215
|
+
* key sorted recursively by UTF-16 code unit via `stableStringify`. Do NOT hand-order keys.
|
|
216
|
+
*/
|
|
217
|
+
export declare function canonicalIntentPayload(input: {
|
|
218
|
+
target: string;
|
|
219
|
+
actionType: string;
|
|
220
|
+
display: string;
|
|
221
|
+
params: Record<string, unknown>;
|
|
222
|
+
requester: RequesterIdentity;
|
|
223
|
+
requirement: ApprovalRequirementAttestation;
|
|
224
|
+
nonce: string;
|
|
225
|
+
expiresAt: string;
|
|
226
|
+
agentContext?: AgentIntentContext;
|
|
227
|
+
}): string;
|
|
228
|
+
/**
|
|
229
|
+
* Canonical OFFLINE INTENT payload (DIV §5a.2). Deliberately a separate function rather than a `type`
|
|
230
|
+
* parameter on `canonicalIntentPayload`.
|
|
231
|
+
*
|
|
232
|
+
* A parameter would mean every existing call site could silently produce the wrong kind by passing
|
|
233
|
+
* the wrong argument, and the normal approval path — which is the overwhelmingly common one — would
|
|
234
|
+
* carry a footgun for the sake of a rare one. Two functions cannot be confused: you either called the
|
|
235
|
+
* offline builder or you did not.
|
|
236
|
+
*
|
|
237
|
+
* `challengedAt` is the only extra field, and it exists so the verifier can bound the validity
|
|
238
|
+
* WINDOW. Without it, a payload minted with a 10-year `expiresAt` would be indistinguishable from a
|
|
239
|
+
* correctly minted one at verification time.
|
|
240
|
+
*/
|
|
241
|
+
export declare function canonicalOfflineIntentPayload(input: {
|
|
242
|
+
target: string;
|
|
243
|
+
actionType: string;
|
|
244
|
+
display: string;
|
|
245
|
+
params: Record<string, unknown>;
|
|
246
|
+
requester: RequesterIdentity;
|
|
247
|
+
requirement: ApprovalRequirementAttestation;
|
|
248
|
+
nonce: string;
|
|
249
|
+
challengedAt: string;
|
|
250
|
+
expiresAt: string;
|
|
251
|
+
}): string;
|
|
252
|
+
/**
|
|
253
|
+
* Canonical DELEGATION payload (DIV §5a.5) — a signed statement about WHO MAY APPROVE, not about
|
|
254
|
+
* what may run.
|
|
255
|
+
*
|
|
256
|
+
* `delegatedTo` is sorted because it is a SET: the same three operators in a different order must
|
|
257
|
+
* produce the same bytes, exactly as for `allowedAaguids`. `requirement` here describes the quorum
|
|
258
|
+
* that signed this delegation, while `delegatedQuorum` is how many of `delegatedTo` must sign at
|
|
259
|
+
* incident time — two different quorums, which is why both are in the signed bytes.
|
|
260
|
+
*/
|
|
261
|
+
export declare function canonicalDelegationPayload(input: {
|
|
262
|
+
target: string;
|
|
263
|
+
actionType: string;
|
|
264
|
+
display: string;
|
|
265
|
+
params: Record<string, unknown>;
|
|
266
|
+
requester: RequesterIdentity;
|
|
267
|
+
requirement: ApprovalRequirementAttestation;
|
|
268
|
+
delegatedTo: string[];
|
|
269
|
+
delegatedQuorum: number;
|
|
270
|
+
nonce: string;
|
|
271
|
+
sealedAt: string;
|
|
272
|
+
expiresAt: string;
|
|
273
|
+
}): string;
|
|
274
|
+
/**
|
|
275
|
+
* Canonical AGENT AUTHORITY payload (DIV §5b) — byte-identical to
|
|
276
|
+
* mcp-schemas.canonicalAgentAuthorityPayload; parity is enforced by `canonical-parity.test.ts`.
|
|
277
|
+
*
|
|
278
|
+
* Not a delegation: `div-delegation` deliberately covers exactly one action, forbids wildcards and
|
|
279
|
+
* caps its window at 72 hours, because it pre-authorizes WHO MAY APPROVE at incident time. An
|
|
280
|
+
* authority is governance enforced online — it may carry a scope (patterns) and a long validity
|
|
281
|
+
* precisely because it authorizes nothing offline. `actionPatterns` is sorted because it is a SET,
|
|
282
|
+
* exactly as `allowedAaguids` is.
|
|
283
|
+
*/
|
|
284
|
+
export declare function canonicalAgentAuthorityPayload(input: {
|
|
285
|
+
target: string;
|
|
286
|
+
actionPatterns: string[];
|
|
287
|
+
display: string;
|
|
288
|
+
agent: {
|
|
289
|
+
did: string;
|
|
290
|
+
};
|
|
291
|
+
parentReceiptHash?: string | null;
|
|
292
|
+
requester: RequesterIdentity;
|
|
293
|
+
requirement: ApprovalRequirementAttestation;
|
|
294
|
+
nonce: string;
|
|
295
|
+
sealedAt: string;
|
|
296
|
+
expiresAt: string;
|
|
297
|
+
}): string;
|
|
298
|
+
/**
|
|
299
|
+
* Canonical PLATFORM HASH-ONLY INTENT payload (DIV §5c.2) — byte-parity with mcp-schemas' copy is
|
|
300
|
+
* enforced by canonical-parity.test.ts. This mirror REPRODUCES bytes and does not validate the
|
|
301
|
+
* digest grammar (producers normalize, verifiers reproduce); `verifyPlatformReceipt` enforces the
|
|
302
|
+
* lowercase-hex rule on the RELYING PARTY's expected value instead.
|
|
303
|
+
*/
|
|
304
|
+
export declare function canonicalPlatformIntentPayload(input: {
|
|
305
|
+
payloadHash: string;
|
|
306
|
+
rpId: string;
|
|
307
|
+
subjectExternalId: string;
|
|
308
|
+
signedAt: string;
|
|
309
|
+
expiresAt: string;
|
|
310
|
+
nonce: string;
|
|
311
|
+
}): string;
|
|
312
|
+
/** Short verification code (first 8 hex of SHA-256 of the canonical payload), grouped XXXX-XXXX. */
|
|
313
|
+
export declare function verificationCode(canonical: string): string;
|
|
314
|
+
/** Verify a raw ECDSA P-256 signature (base64, DER or IEEE-P1363) over `payload` against an SPKI key. */
|
|
315
|
+
export declare function verifyEcdsaP256(publicKeyB64: string, payload: string, signatureB64: string): boolean;
|
|
316
|
+
/** Default clock-skew tolerance for expiry validation (DIV §6.2 RECOMMENDED ±30s). */
|
|
317
|
+
export declare const DEFAULT_CLOCK_SKEW_SECONDS = 30;
|
|
318
|
+
/**
|
|
319
|
+
* The MINIMUM approval requirement YOUR policy demands for this action (DIV §5 step 3d).
|
|
320
|
+
*
|
|
321
|
+
* The signed `requirement` is authored by whoever composed the bytes the approvers signed — the
|
|
322
|
+
* issuing gateway, or any one approver composing their own payload. Its signature protects it
|
|
323
|
+
* against third parties, NOT against the signers the quorum constrains: an approver who is also
|
|
324
|
+
* the requester can sign `{ requiredApprovals: 1, requesterCannotApprove: false }` alone and, without
|
|
325
|
+
* a floor, that receipt verifies. Supplying the floor makes the verifier refuse any signed
|
|
326
|
+
* requirement weaker than it, before a single signature is counted.
|
|
327
|
+
*
|
|
328
|
+
* Without a floor the verifier proves only the signers' OWN stated quorum. Supply one whenever you
|
|
329
|
+
* hold the approval rule (a trust bundle, a pinned policy, your own configuration).
|
|
330
|
+
*
|
|
331
|
+
* Only strictly weaker values are refused: a signed requirement at least as strict passes, and the
|
|
332
|
+
* signed value is what is then enforced. `allowedAaguids` is not floored — express a model
|
|
333
|
+
* restriction as `requireHardwareKey`, which a verifier can at least partially check.
|
|
334
|
+
*/
|
|
335
|
+
export interface RequirementFloor {
|
|
336
|
+
/** Integer ≥ 1. The signed `requiredApprovals` must be at least this. */
|
|
337
|
+
requiredApprovals: number;
|
|
338
|
+
/** When true, the signed requirement must also forbid the requester approving. Defaults to false. */
|
|
339
|
+
requesterCannotApprove?: boolean;
|
|
340
|
+
/** When true, the signed requirement must also demand a hardware key. Defaults to false. */
|
|
341
|
+
requireHardwareKey?: boolean;
|
|
342
|
+
}
|
|
343
|
+
/** The reason stem every port uses when a signed requirement is below the caller's floor. */
|
|
344
|
+
export declare const WEAKER_REQUIREMENT_REASON = "signed requirement is weaker than the relying party's policy";
|
|
345
|
+
/**
|
|
346
|
+
* The approver identities/keys YOU trust, resolved from your own key-management policy.
|
|
347
|
+
*
|
|
348
|
+
* This is the single most important input to verification. Without it, `verifyApprovalReceipt` would
|
|
349
|
+
* verify a signature using the public key carried INSIDE the receipt — which proves only that the
|
|
350
|
+
* receipt is internally consistent, i.e. nothing. Anyone able to hand you a receipt (per the DIV
|
|
351
|
+
* threat model, that includes the untrusted agent itself) could mint a keypair, sign a payload over
|
|
352
|
+
* the nonce you issued and the params you are about to run, put any string in `signerDid`, and be
|
|
353
|
+
* told the action was approved by a human. DIV §3 Invariant 3 and §5 step 3 require the Approver key
|
|
354
|
+
* to be resolved from deployment key-management policy; this type is that step.
|
|
355
|
+
*
|
|
356
|
+
* - `{ publicKeys }` — a direct allowlist of base64 SPKI / COSE keys.
|
|
357
|
+
* - `{ dids, resolveKey }` — a DID allowlist plus your own resolver (directory lookup, pinned
|
|
358
|
+
* enrollment record, etc). Return `null` for an unknown DID to reject it.
|
|
359
|
+
*
|
|
360
|
+
* PREFER DID MODE where you can. In `publicKeys` mode the receipt's `signerDid` is an unverified
|
|
361
|
+
* string, so quorum has to count distinct KEYS instead of distinct approvers — and a delegation
|
|
362
|
+
* (DIV §5a.6), which names identities, cannot be enforced at all.
|
|
363
|
+
*
|
|
364
|
+
* `resolveKey` may return SEVERAL keys for one DID. An approver commonly holds a software key plus
|
|
365
|
+
* one or more registered authenticators, and any of them is legitimately theirs; returning them all
|
|
366
|
+
* keeps the identity intact instead of forcing callers to flatten everything into `publicKeys` mode
|
|
367
|
+
* and lose the DID binding. Every key returned for a DID counts as that ONE approver.
|
|
368
|
+
*
|
|
369
|
+
* SELF-CERTIFYING DIDs need no resolver. A pinned DID of the form `did:intyga:key:<fingerprint>`
|
|
370
|
+
* (see {@link SELF_CERTIFYING_DID_PREFIX}) is itself a commitment to the enrolled public key, so the
|
|
371
|
+
* witness-carried key can be validated against the DID by hashing — no key distribution at all.
|
|
372
|
+
* `resolveKey` is therefore optional: it is required only for pinned DIDs that are NOT
|
|
373
|
+
* self-certifying, and verification fails closed with an explicit reason when such a DID is
|
|
374
|
+
* encountered without one.
|
|
375
|
+
*
|
|
376
|
+
* PRECEDENCE: when `resolveKey` DOES return keys for a self-certifying DID, those keys are the
|
|
377
|
+
* anchor and the hash commitment is not consulted. That is what lets a deployment widen the DID to
|
|
378
|
+
* the person's later-enrolled credentials, and — the security-relevant direction — NARROW it: a
|
|
379
|
+
* compromised credential is dropped by mapping the DID to the remaining keys, which a
|
|
380
|
+
* commitment-always-wins rule would silently keep trusting.
|
|
381
|
+
*/
|
|
382
|
+
export type ApproverTrustAnchor = {
|
|
383
|
+
publicKeys: string[];
|
|
384
|
+
dids?: undefined;
|
|
385
|
+
resolveKey?: undefined;
|
|
386
|
+
} | {
|
|
387
|
+
dids: string[];
|
|
388
|
+
resolveKey?: (did: string) => string | string[] | null;
|
|
389
|
+
publicKeys?: undefined;
|
|
390
|
+
};
|
|
391
|
+
/**
|
|
392
|
+
* Prefix of a self-certifying Intyga DID: `did:intyga:key:<base64url(sha256(publicKey bytes))>`.
|
|
393
|
+
* The identifier IS a commitment to the enrolled public key (the issuing gateway's derivation), so a
|
|
394
|
+
* DID of this form can serve as a complete trust anchor entry on its own. The commitment is to the
|
|
395
|
+
* EXACT enrolled key bytes — an approver signing with a different credential (say, a browser passkey
|
|
396
|
+
* registered later) does not match it, and needs a `resolveKey` mapping under a stable DID instead.
|
|
397
|
+
*/
|
|
398
|
+
export declare const SELF_CERTIFYING_DID_PREFIX = "did:intyga:key:";
|
|
399
|
+
/**
|
|
400
|
+
* Derive the self-certifying DID for a public key (base64; the DECODED bytes are hashed, so padded
|
|
401
|
+
* and unpadded encodings of the same key derive the same DID). Mirrors the gateway's derivation.
|
|
402
|
+
*/
|
|
403
|
+
export declare function selfCertifyingDid(publicKeyB64: string): string;
|
|
404
|
+
/** What you assert the receipt must say. `target`, `nonce` and `approvers` are required. */
|
|
405
|
+
export interface ReceiptExpectation {
|
|
406
|
+
/**
|
|
407
|
+
* REQUIRED. The approvers you trust — see ApproverTrustAnchor. There is deliberately no default:
|
|
408
|
+
* a receipt cannot be permitted to vouch for its own signer.
|
|
409
|
+
*/
|
|
410
|
+
approvers: ApproverTrustAnchor;
|
|
411
|
+
/**
|
|
412
|
+
* YOUR target identifier — the Relying Party / execution environment this approval must be bound to
|
|
413
|
+
* (DIV Target Isolation). Required and asserted from your own identity, never read from the
|
|
414
|
+
* receipt: this is what rejects an approval minted for a different service (cross-service replay).
|
|
415
|
+
*/
|
|
416
|
+
target: string;
|
|
417
|
+
actionType: string;
|
|
418
|
+
params: Record<string, unknown>;
|
|
419
|
+
/**
|
|
420
|
+
* The challenge nonce YOU issued and are redeeming. Required: it is what ties this receipt to one
|
|
421
|
+
* specific request you are tracking. See the replay note on verifyApprovalReceipt.
|
|
422
|
+
*/
|
|
423
|
+
nonce: string;
|
|
424
|
+
/** Optionally assert WHICH workload the approval was granted to. */
|
|
425
|
+
requesterDid?: string;
|
|
426
|
+
/** Independent PEP state for an AI_AGENT receipt. Never copy this from the receipt. */
|
|
427
|
+
agentContext?: AgentIntentContext;
|
|
428
|
+
/**
|
|
429
|
+
* STRONGLY RECOMMENDED. The minimum requirement YOUR approval rule demands for this action — see
|
|
430
|
+
* RequirementFloor. Without it this verifier enforces only the quorum the signers themselves
|
|
431
|
+
* stated, which one approver (possibly the requester) can set to 1-of-1. Under a delegation, pass
|
|
432
|
+
* the ORDINARY rule: the delegated quorum must already be at least as strict (DIV §5a.5).
|
|
433
|
+
*/
|
|
434
|
+
requirement?: RequirementFloor;
|
|
435
|
+
}
|
|
436
|
+
/** Verification options. The WebAuthn expectations are mandatory for a WEBAUTHN receipt. */
|
|
437
|
+
export interface VerifyReceiptOptions {
|
|
438
|
+
allowAutoApproved?: boolean;
|
|
439
|
+
/** A complete root-to-leaf, independently trusted chain is mandatory for delegated agent receipts. */
|
|
440
|
+
agentAuthorityChain?: Array<{
|
|
441
|
+
receipt: ApprovalReceipt;
|
|
442
|
+
expected: {
|
|
443
|
+
approvers: ApproverTrustAnchor;
|
|
444
|
+
target: string;
|
|
445
|
+
agentDid: string;
|
|
446
|
+
requirement?: RequirementFloor;
|
|
447
|
+
};
|
|
448
|
+
}>;
|
|
449
|
+
/**
|
|
450
|
+
* Accept an OFFLINE APPROVAL (`type: "div-offline-intent"`). Defaults to FALSE — an offline proof is
|
|
451
|
+
* refused on every ordinary call site, exactly like `allowAutoApproved`.
|
|
452
|
+
*
|
|
453
|
+
* Pass this at the SPECIFIC call that is allowed to run under an offline approval, never globally. A
|
|
454
|
+
* process-wide default would mean every gated action in the service silently accepts an
|
|
455
|
+
* out-of-band approval, which is the difference between an emergency mechanism and a hole.
|
|
456
|
+
*
|
|
457
|
+
* Setting it does not weaken any other check: the quorum, four-eyes and target binding signed into
|
|
458
|
+
* the payload are still enforced, the window is capped at MAX_OFFLINE_WINDOW_MINUTES, and a proof
|
|
459
|
+
* whose signed policy demands a hardware key is REFUSED (DIV §5a.3 step 4) because that requirement
|
|
460
|
+
* cannot be satisfied offline.
|
|
461
|
+
*/
|
|
462
|
+
allowOffline?: boolean;
|
|
463
|
+
/**
|
|
464
|
+
* A delegation that has ALREADY been verified by `verifyDelegation`, substituting the eligible
|
|
465
|
+
* approver set and the quorum for this one verification (DIV §5a.6).
|
|
466
|
+
*
|
|
467
|
+
* Only meaningful together with `allowOffline`. This narrows rather than widens: the delegation's
|
|
468
|
+
* target/actionType/params must equal what you are executing, and the offline payload's signed
|
|
469
|
+
* `requiredApprovals` must equal the delegation's `delegatedQuorum`, so the operators still sign the
|
|
470
|
+
* policy their signatures are counted toward. Its expiry is rechecked at this verification's
|
|
471
|
+
* evaluation time even if the successful seal verification was cached.
|
|
472
|
+
*/
|
|
473
|
+
delegation?: VerifiedDelegation;
|
|
474
|
+
/** Exact `origin` the assertion must carry, e.g. "https://app.example.com". Required for WEBAUTHN. */
|
|
475
|
+
expectedOrigin?: string;
|
|
476
|
+
/** RP ID the authenticatorData must hash to, e.g. "app.example.com". Required for WEBAUTHN. */
|
|
477
|
+
expectedRpId?: string;
|
|
478
|
+
/** Demand the User-Verified flag (biometric/PIN, not mere possession). Defaults to true. */
|
|
479
|
+
requireUserVerification?: boolean;
|
|
480
|
+
/**
|
|
481
|
+
* Accept an assertion produced inside a cross-origin frame. Defaults to FALSE (refuse).
|
|
482
|
+
*
|
|
483
|
+
* `origin` alone cannot detect this: inside a cross-origin iframe the browser reports the FRAME's
|
|
484
|
+
* origin — which for an embedded RP page is the RP's own origin — and rpIdHash matches too. So with
|
|
485
|
+
* `publickey-credentials-get` delegated, a third-party embedder can drive a high-risk approval
|
|
486
|
+
* ceremony while every other check here passes. `crossOrigin` is the only signal that distinguishes
|
|
487
|
+
* the two (W3C WebAuthn L3 §7.2 step 9).
|
|
488
|
+
*/
|
|
489
|
+
allowCrossOrigin?: boolean;
|
|
490
|
+
/**
|
|
491
|
+
* Expiry handling (DIV §5 step 8 / §6.2). By DEFAULT this verifier is fail-closed on `expiresAt`: a proof
|
|
492
|
+
* whose expiry is in the past (beyond the skew tolerance) is rejected — the correct behaviour for a
|
|
493
|
+
* pre-execution check. Set `allowExpired: true` ONLY for post-hoc audit/forensic re-verification,
|
|
494
|
+
* where you deliberately want to confirm a signature that was valid at the time even though it has
|
|
495
|
+
* since expired. `asOf` overrides "now" for deterministic/replayed checks.
|
|
496
|
+
*/
|
|
497
|
+
allowExpired?: boolean;
|
|
498
|
+
/**
|
|
499
|
+
* Wall-clock instant to evaluate time against. Defaults to `new Date()`.
|
|
500
|
+
*
|
|
501
|
+
* Also the reference point for the forward-dating rule (DIV §5a.3 rule 3), which — unlike expiry —
|
|
502
|
+
* `allowExpired` does NOT waive: that option re-examines a proof that was valid and has lapsed,
|
|
503
|
+
* which says nothing about accepting one dated in the future.
|
|
504
|
+
*/
|
|
505
|
+
asOf?: Date;
|
|
506
|
+
/** Clock-skew tolerance in seconds for expiry and forward-dating. Defaults to DEFAULT_CLOCK_SKEW_SECONDS. */
|
|
507
|
+
clockSkewSeconds?: number;
|
|
508
|
+
}
|
|
509
|
+
/** One WebAuthn assertion and the exact payload it claims to sign — a single stored witness row. */
|
|
510
|
+
export interface WebAuthnWitness {
|
|
511
|
+
/** The string whose UTF-8 bytes were the assertion challenge (the canonical payload), as signed. */
|
|
512
|
+
signedPayload: string;
|
|
513
|
+
/**
|
|
514
|
+
* The credential's P-256 public key, base64 or base64url: a COSE_Key (as recorded at registration)
|
|
515
|
+
* or DER SubjectPublicKeyInfo. Supply it from YOUR record of the credential — never from the thing
|
|
516
|
+
* being verified — or any key the presenter chose will do.
|
|
517
|
+
*/
|
|
518
|
+
publicKey: string;
|
|
519
|
+
/** base64 or base64url, as the browser returned them. */
|
|
520
|
+
authenticatorData: string;
|
|
521
|
+
clientDataJSON: string;
|
|
522
|
+
/** The DER ECDSA assertion signature. */
|
|
523
|
+
signature: string;
|
|
524
|
+
}
|
|
525
|
+
export interface WebAuthnWitnessExpectation {
|
|
526
|
+
/** The origin(s) the assertion may carry, e.g. "https://app.example.com". Required. */
|
|
527
|
+
expectedOrigin: string | readonly string[];
|
|
528
|
+
/** The RP ID the authenticatorData must hash to, e.g. "app.example.com". Required. */
|
|
529
|
+
expectedRpId: string;
|
|
530
|
+
/** Demand the User-Verified flag. Defaults to TRUE; User-Present is always required. */
|
|
531
|
+
requireUserVerification?: boolean;
|
|
532
|
+
/** Accept `clientDataJSON.crossOrigin: true`. Defaults to FALSE (DIV §4.4.5 rule 5). */
|
|
533
|
+
allowCrossOrigin?: boolean;
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Verify ONE WebAuthn assertion on its own — the §4.4.5 checks every receipt verifier here applies
|
|
537
|
+
* to each WEBAUTHN witness, without a receipt around it: one approver of a quorum, a console step-up,
|
|
538
|
+
* a login approval, a row read back out of an audit ledger. Same implementation, not a copy.
|
|
539
|
+
*
|
|
540
|
+
* It answers only "did the holder of THIS key sign THIS payload, at THIS relying party, with the
|
|
541
|
+
* user present". It knows nothing of quorum, validity windows, payload type, the signed requirement
|
|
542
|
+
* or who the key belongs to: a caller verifying an approval must use verifyApprovalReceipt (or the
|
|
543
|
+
* delegation/agent-authority/platform verifiers), which also enforce those. Never throws.
|
|
544
|
+
*/
|
|
545
|
+
export declare function verifyWebAuthnWitness(witness: WebAuthnWitness, expectation: WebAuthnWitnessExpectation): {
|
|
546
|
+
ok: true;
|
|
547
|
+
} | {
|
|
548
|
+
ok: false;
|
|
549
|
+
reason: string;
|
|
550
|
+
};
|
|
551
|
+
/**
|
|
552
|
+
* Independently verify an approval receipt against the instruction you are ABOUT to execute. Recomputes
|
|
553
|
+
* the canonical payload from your params, confirms it byte-matches what was signed, and verifies the
|
|
554
|
+
* human's P-256 or WebAuthn signature — with no Intyga secret.
|
|
555
|
+
*
|
|
556
|
+
* WHAT THIS PROVES: that enough APPROVERS YOU ALREADY TRUST (`expected.approvers`) signed exactly this
|
|
557
|
+
* action, with exactly these params, for exactly the target and nonce you pass in `expected`; that the
|
|
558
|
+
* number of distinct valid signatures meets the quorum recorded in the signed payload; that the
|
|
559
|
+
* requester did not self-approve when the signed policy forbids it; and that the proof has not expired.
|
|
560
|
+
*
|
|
561
|
+
* THE SIGNED QUORUM IS THE SIGNERS' OWN STATEMENT. The signed `requirement` is authored by whoever
|
|
562
|
+
* composed the bytes — so one approver (possibly the requester) can sign a 1-of-1 payload alone. Pass
|
|
563
|
+
* `expected.requirement` (your own rule, see RequirementFloor) and a weaker signed requirement is
|
|
564
|
+
* refused (DIV §5 step 3d). Without it, "quorum met" means only "the quorum the signers stated".
|
|
565
|
+
*
|
|
566
|
+
* THE TRUST ANCHOR IS NOT OPTIONAL. Verification uses the key you resolve for an approver, never the
|
|
567
|
+
* `signerPublicKey` carried in the receipt. A receipt verified against its own embedded key proves
|
|
568
|
+
* only internal consistency — anyone who can hand you a receipt could have minted the keypair.
|
|
569
|
+
*
|
|
570
|
+
* EXPIRY: the signed `expiresAt` is enforced fail-closed by default (±30s skew) — a lapsed proof is
|
|
571
|
+
* rejected. Pass `{ allowExpired: true }` ONLY for post-hoc audit/forensic re-verification, where
|
|
572
|
+
* confirming a signature that was valid AT THE TIME is the point.
|
|
573
|
+
*
|
|
574
|
+
* WHAT THIS DOES NOT PROVE: that the approval has not ALREADY BEEN USED within its validity window.
|
|
575
|
+
* Expiry bounds how long a proof is valid, but single-use enforcement is separate and lives in the
|
|
576
|
+
* gateway's /authorize/verify (which atomically marks the challenge CONSUMED) — this function is a
|
|
577
|
+
* defense-in-depth companion to that call, not a replacement for it. If you verify offline and skip
|
|
578
|
+
* the consume step, YOU must record redeemed nonces yourself; requiring `expected.nonce` here is what
|
|
579
|
+
* makes that possible, since you cannot call this without having tracked the nonce you issued.
|
|
580
|
+
*
|
|
581
|
+
* Returns `{ ok: false, reason }` on any mismatch.
|
|
582
|
+
*/
|
|
583
|
+
export declare function verifyApprovalReceipt(receipt: ApprovalReceipt, expected: ReceiptExpectation, opts?: VerifyReceiptOptions): {
|
|
584
|
+
ok: boolean;
|
|
585
|
+
reason?: string;
|
|
586
|
+
autoApproved?: boolean;
|
|
587
|
+
signers?: string[];
|
|
588
|
+
};
|
|
589
|
+
/** A platform hash-only receipt (DIV §5c) as issued by the gateway's platform plane. */
|
|
590
|
+
export interface PlatformReceipt {
|
|
591
|
+
/** The exact bytes the subject's passkey signed (the §5c.2 payload). */
|
|
592
|
+
canonicalPayload: string;
|
|
593
|
+
/** Display copies only — verification reconstructs from the RELYING PARTY's own values. */
|
|
594
|
+
payloadHash?: string | null;
|
|
595
|
+
rpId?: string | null;
|
|
596
|
+
subject?: {
|
|
597
|
+
externalId?: string | null;
|
|
598
|
+
} | null;
|
|
599
|
+
signedAt?: string | null;
|
|
600
|
+
expiresAt?: string | null;
|
|
601
|
+
nonce?: string | null;
|
|
602
|
+
signatures?: ApprovalWitness[] | null;
|
|
603
|
+
signerDid?: string | null;
|
|
604
|
+
signerPublicKey?: string | null;
|
|
605
|
+
signature?: string | null;
|
|
606
|
+
sigAlg?: string | null;
|
|
607
|
+
authenticatorData?: string | null;
|
|
608
|
+
clientDataJSON?: string | null;
|
|
609
|
+
verificationCode?: string;
|
|
610
|
+
}
|
|
611
|
+
export interface PlatformReceiptExpectation {
|
|
612
|
+
/** REQUIRED. The subject keys you trust — same modes as ReceiptExpectation.approvers. */
|
|
613
|
+
approvers: ApproverTrustAnchor;
|
|
614
|
+
/**
|
|
615
|
+
* REQUIRED. The SHA-256 (lowercase hex) YOU recompute from your own copy of the canonical
|
|
616
|
+
* payload — never read from the receipt. This is the §5c data-minimization anchor: the payload
|
|
617
|
+
* itself never traveled, so this digest is the entire content binding.
|
|
618
|
+
*/
|
|
619
|
+
payloadHash: string;
|
|
620
|
+
/** REQUIRED. YOUR registered WebAuthn RP ID — used for the signed-bytes binding AND as the
|
|
621
|
+
* assertion's expected rpIdHash. Asserted from your own configuration, never the receipt. */
|
|
622
|
+
rpId: string;
|
|
623
|
+
/** REQUIRED. The signing challenge nonce you are redeeming. */
|
|
624
|
+
nonce: string;
|
|
625
|
+
/** Optionally assert WHICH of your subjects signed. */
|
|
626
|
+
subjectExternalId?: string;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Verify a PLATFORM HASH-ONLY receipt (DIV §5c.3). Deliberately a separate function:
|
|
630
|
+
* `verifyApprovalReceipt` refuses the `div-platform-intent` type outright, and this function
|
|
631
|
+
* refuses every other type, so neither proof kind can ever pass through the other's door.
|
|
632
|
+
*
|
|
633
|
+
* Every witness must be a WebAuthn assertion (this plane's subjects only ever sign with enrolled
|
|
634
|
+
* passkeys on the platform's registered origin), so `opts.expectedOrigin` is REQUIRED and the RP ID
|
|
635
|
+
* expectation comes from `expected.rpId`. `AUTO_APPROVED` is refused with no override — policy
|
|
636
|
+
* pre-approval does not exist on this plane.
|
|
637
|
+
*/
|
|
638
|
+
export declare function verifyPlatformReceipt(receipt: PlatformReceipt, expected: PlatformReceiptExpectation, opts?: VerifyReceiptOptions): {
|
|
639
|
+
ok: boolean;
|
|
640
|
+
reason?: string;
|
|
641
|
+
signers?: string[];
|
|
642
|
+
};
|
|
643
|
+
/** A delegation whose own signature, quorum and window have been verified by `verifyDelegation`. */
|
|
644
|
+
export interface VerifiedDelegation {
|
|
645
|
+
/** Identities permitted to approve at incident time. Enforced against the witness DIDs. */
|
|
646
|
+
delegatedTo: string[];
|
|
647
|
+
/** How many distinct members of `delegatedTo` must sign. */
|
|
648
|
+
delegatedQuorum: number;
|
|
649
|
+
/** The single action this delegation covers. All three must equal what is being executed. */
|
|
650
|
+
target: string;
|
|
651
|
+
actionType: string;
|
|
652
|
+
params: Record<string, unknown>;
|
|
653
|
+
/** The delegation's OWN nonce — for the audit trail, never for authorization. */
|
|
654
|
+
nonce: string;
|
|
655
|
+
/** Who signed the delegation itself. */
|
|
656
|
+
signers: string[];
|
|
657
|
+
expiresAt: string;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Verify a DELEGATION (DIV §5a.6 step 1) — a statement, signed in advance by the ordinary quorum, that
|
|
661
|
+
* names local operators who may approve one pre-declared action while the gateway is unreachable.
|
|
662
|
+
*
|
|
663
|
+
* Deliberately a SEPARATE function from `verifyApprovalReceipt`, which refuses this payload type
|
|
664
|
+
* outright. A delegation authorizes nothing, and the only way to keep that true structurally is to
|
|
665
|
+
* make it impossible to hand one to the approval verifier and get an `ok: true` back. What you get here
|
|
666
|
+
* is a `VerifiedDelegation` — an input to a later approval check, never a substitute for one.
|
|
667
|
+
*
|
|
668
|
+
* `approvers` MUST be the ORDINARY approver set (from your trust bundle), not the delegated operators:
|
|
669
|
+
* the point of the check is that the people entitled to approve this action are the ones who signed
|
|
670
|
+
* away that entitlement.
|
|
671
|
+
*/
|
|
672
|
+
export declare function verifyDelegation(receipt: ApprovalReceipt, expected: {
|
|
673
|
+
/** The ORDINARY approvers entitled to delegate. Resolved from your own trust policy. */
|
|
674
|
+
approvers: ApproverTrustAnchor;
|
|
675
|
+
/** YOUR target identifier, asserted independently of the delegation (DIV Target Isolation). */
|
|
676
|
+
target: string;
|
|
677
|
+
actionType: string;
|
|
678
|
+
params: Record<string, unknown>;
|
|
679
|
+
/**
|
|
680
|
+
* STRONGLY RECOMMENDED. The ORDINARY approval rule for the delegated action: the delegation's
|
|
681
|
+
* sealing requirement must be at least this strict (DIV §5a.5, §5 step 3d). Without it only the
|
|
682
|
+
* sealers' own stated quorum is enforced.
|
|
683
|
+
*/
|
|
684
|
+
requirement?: RequirementFloor;
|
|
685
|
+
}, opts?: VerifyReceiptOptions): {
|
|
686
|
+
ok: boolean;
|
|
687
|
+
reason?: string;
|
|
688
|
+
delegation?: VerifiedDelegation;
|
|
689
|
+
};
|
|
690
|
+
/** An agent authority whose sealing signatures, quorum and window verified (`verifyAgentAuthority`). */
|
|
691
|
+
export interface VerifiedAgentAuthority {
|
|
692
|
+
/** The agent the authority is ABOUT — from the signed bytes, asserted by the caller. */
|
|
693
|
+
agentDid: string;
|
|
694
|
+
target: string;
|
|
695
|
+
/**
|
|
696
|
+
* The signed scope, deduplicated. Case-insensitive substring patterns over the machine
|
|
697
|
+
* `actionType` ONLY — deliberately NOT the human-readable description, which is authored by the
|
|
698
|
+
* agent being bounded and would let an out-of-scope request cover itself by quoting a pattern
|
|
699
|
+
* (DIV §5b.2). "*" = all.
|
|
700
|
+
*/
|
|
701
|
+
actionPatterns: string[];
|
|
702
|
+
parentReceiptHash: string | null;
|
|
703
|
+
/** The authority's OWN nonce — for the audit trail, never for authorization. */
|
|
704
|
+
nonce: string;
|
|
705
|
+
/** Who sealed it. */
|
|
706
|
+
signers: string[];
|
|
707
|
+
sealedAt: string;
|
|
708
|
+
expiresAt: string;
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Verify an AGENT AUTHORITY (DIV §5b) — a statement, sealed by a human quorum, of the standing scope
|
|
712
|
+
* one agent may operate under.
|
|
713
|
+
*
|
|
714
|
+
* Deliberately a SEPARATE function from `verifyApprovalReceipt`, which refuses this payload type
|
|
715
|
+
* outright — the same structural rule as delegations. What you get back is governance EVIDENCE:
|
|
716
|
+
* "these named humans granted this agent this scope, and the grant was live at `asOf`". It is never
|
|
717
|
+
* an approval; executing an action still requires an ordinary receipt.
|
|
718
|
+
*
|
|
719
|
+
* Two things the caller asserts and never reads from the artifact (DIV Invariant 3):
|
|
720
|
+
* `expected.approvers` (the sealing quorum's keys, from your own trust policy) and
|
|
721
|
+
* `expected.target` / `expected.agentDid` (what YOU are checking authority over). Revocation is
|
|
722
|
+
* authoritative online only — an offline verifier sees validity, not revocation; treat a seal like
|
|
723
|
+
* a certificate, not a bearer token.
|
|
724
|
+
*/
|
|
725
|
+
export declare function verifyAgentAuthority(receipt: ApprovalReceipt, expected: {
|
|
726
|
+
/** The sealing approvers entitled to grant. Resolved from your own trust policy. */
|
|
727
|
+
approvers: ApproverTrustAnchor;
|
|
728
|
+
/** YOUR target identifier, asserted independently of the artifact (DIV Target Isolation). */
|
|
729
|
+
target: string;
|
|
730
|
+
/** The agent whose authority you are checking, asserted independently of the artifact. */
|
|
731
|
+
agentDid: string;
|
|
732
|
+
/**
|
|
733
|
+
* STRONGLY RECOMMENDED. YOUR sealing policy for agent authority: the signed sealing requirement
|
|
734
|
+
* must be at least this strict (DIV §5b.3, §5 step 3d). Without it only the sealers' own stated
|
|
735
|
+
* quorum is enforced.
|
|
736
|
+
*/
|
|
737
|
+
requirement?: RequirementFloor;
|
|
738
|
+
}, opts?: VerifyReceiptOptions): {
|
|
739
|
+
ok: boolean;
|
|
740
|
+
reason?: string;
|
|
741
|
+
authority?: VerifiedAgentAuthority;
|
|
742
|
+
};
|
|
743
|
+
/** Hash the COMPLETE proof, including every witness. Hashing only the intent would permit a
|
|
744
|
+
* never-approved pending intent to be used as a parent receipt. */
|
|
745
|
+
export declare function agentReceiptDigest(receipt: ApprovalReceipt): string;
|
|
746
|
+
/** Verify a root-to-leaf chain of human-sealed agent scopes. Each child commits the COMPLETE
|
|
747
|
+
* parent receipt. A child's substring pattern denotes a subset only when it contains one of the
|
|
748
|
+
* parent's patterns; this deliberately rejects scopes whose inclusion cannot be proved. */
|
|
749
|
+
export declare function verifyAgentDelegationChain(chain: Array<{
|
|
750
|
+
receipt: ApprovalReceipt;
|
|
751
|
+
expected: {
|
|
752
|
+
approvers: ApproverTrustAnchor;
|
|
753
|
+
target: string;
|
|
754
|
+
agentDid: string;
|
|
755
|
+
requirement?: RequirementFloor;
|
|
756
|
+
};
|
|
757
|
+
}>, action: {
|
|
758
|
+
target: string;
|
|
759
|
+
actionType: string;
|
|
760
|
+
agentDid: string;
|
|
761
|
+
delegatedBy: string;
|
|
762
|
+
}, opts?: VerifyReceiptOptions): {
|
|
763
|
+
ok: boolean;
|
|
764
|
+
reason?: string;
|
|
765
|
+
};
|
|
766
|
+
/** RP-side commitment to the exact model/tool/prompt configuration handed to the agent runtime.
|
|
767
|
+
* This is an RP assertion, not an integrity attestation. The PEP must recalculate it immediately
|
|
768
|
+
* before execution and refuse any mismatch with the signed intent. Raw prompt text is never logged. */
|
|
769
|
+
export declare function agentConfigDigest(config: {
|
|
770
|
+
model: {
|
|
771
|
+
provider: string;
|
|
772
|
+
version: string;
|
|
773
|
+
};
|
|
774
|
+
tools: Array<{
|
|
775
|
+
id: string;
|
|
776
|
+
version: string;
|
|
777
|
+
schemaDigest: string;
|
|
778
|
+
}>;
|
|
779
|
+
systemPrompt: string;
|
|
780
|
+
}): string;
|
|
781
|
+
/** Verify a complete ordered session bundle against a head pinned OUTSIDE the bundle. An
|
|
782
|
+
* unanchored single branch cannot prove another branch was not withheld. */
|
|
783
|
+
export declare function verifyAgentSessionChain(entries: Array<{
|
|
784
|
+
receipt: ApprovalReceipt;
|
|
785
|
+
expected: ReceiptExpectation;
|
|
786
|
+
}>, trustedHead: string, opts?: VerifyReceiptOptions): {
|
|
787
|
+
ok: boolean;
|
|
788
|
+
reason?: string;
|
|
789
|
+
aggregate?: {
|
|
790
|
+
amount: string;
|
|
791
|
+
currency: string;
|
|
792
|
+
} | null;
|
|
793
|
+
};
|
|
794
|
+
export { ALGORITHM_REGISTRY, type AlgorithmRegistry, AUDIT_PROFILE, BUNDLE_KIND, type BundleVerification, type CheckResult, DEWP_PROTOCOL, DEWP_VERSION, deriveVerificationLevel, leafCountMismatch, type ProofBundle, type TrustedCheckpoint, type VerificationLevel, type VerificationProperties, verifyBundle, verifyEmbeddedSignature, type VerifyOptions, } from "./ledger-bundle.js";
|
|
795
|
+
export { EVIDENCE_BUNDLE_KIND, type EvidenceAnchorSet, type EvidenceBundle, type EvidenceEntry, type EvidenceVerification, type EvidenceVerifyOptions, type RedactionRecord, verifyEvidenceBundle, } from "./ledger-evidence.js";
|
|
796
|
+
export { ANCHOR_ALGORITHMS, ANCHOR_CLOCK_SKEW_SECONDS, type AnchorInput, type AnchorKeyResolver, type AnchorPolicy, type AnchorQuorumResult, DEFAULT_MAX_ANCHOR_LAG_SECONDS, type ExpectedCheckpoint, type ExternalAnchorKeys, anchorDigest, anchorDigestHex, anchorPreimage, isWellFormedAnchor, parseAnchorTimestampMs, signAnchor, type SignedAnchor, verifyAnchorQuorum, verifyAnchorSignature, } from "./ledger-anchor.js";
|
|
797
|
+
export { type ChainInput, type ChainVerification, chainHash, chainPreimage, GENESIS_PREV_CHAIN_HASH, type RootsChainEntry, verifyRootsChain, } from "./ledger-chain.js";
|
|
798
|
+
export { parseRekorEvidence, type RekorEvidence, type RekorVerification, rekorPayloadHashFor, verifyRekorAnchor, } from "./ledger-rekor.js";
|
|
799
|
+
export { type AuditLeaf, canonicalPreimage, leafHash } from "./ledger-leaf.js";
|
|
800
|
+
export { hashLeaf, hashPair, merkleProof, merkleRoot, type ProofStep, sha256Hex, verifyMerkleProof, } from "./ledger-merkle.js";
|
|
801
|
+
export { type InclusionProof, verifyInclusionProof } from "./ledger-proof.js";
|
|
802
|
+
export { verifyRfc3161Anchor, verifyRfc3161Timestamp, verifyRfc3161TimestampAsync, type Rfc3161Trust, type Rfc3161Verification, } from "./ledger-rfc3161.js";
|
|
803
|
+
export { verifyAuditSignature, type AuditSignaturePolicy, type AuditSignatureCheck, } from "./ledger-signature.js";
|