@peac/protocol 0.11.2 → 0.12.0-preview.1

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/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export * from './verify-local';
8
8
  export * from './headers';
9
9
  export * from './discovery';
10
10
  export * from './jwks-resolver';
11
+ export { computePolicyDigestJcs, checkPolicyBinding } from './policy-binding';
11
12
  export * from './verifier-types';
12
13
  export * from './verifier-core';
13
14
  export * from './verification-report';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAGhC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAGhC,OAAO,EACL,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,SAAS,EACT,MAAM,GACP,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAGhC,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAG9E,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAGhC,OAAO,EACL,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,SAAS,EACT,MAAM,GACP,MAAM,cAAc,CAAC"}
package/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import { uuidv7 } from 'uuidv7';
2
- import { sign, decode, verify, sha256Hex, computeJwkThumbprint, jwkToPublicKeyBytes, base64urlDecode } from '@peac/crypto';
2
+ import { sign, signWire02, decode, verify, jcsHash, sha256Hex, computeJwkThumbprint, jwkToPublicKeyBytes, base64urlDecode } from '@peac/crypto';
3
3
  export { base64urlDecode, base64urlEncode, computeJwkThumbprint, generateKeypair, jwkToPublicKeyBytes, sha256Bytes, sha256Hex, verify } from '@peac/crypto';
4
4
  import { ZodError } from 'zod';
5
- import { isValidPurposeToken, isCanonicalPurpose, isValidPurposeReason, isValidWorkflowContext, createWorkflowContextInvalidError, hasValidDagSemantics, createWorkflowDagInvalidError, WORKFLOW_EXTENSION_KEY, validateKernelConstraints, createConstraintViolationError, ReceiptClaims, createEvidenceNotJsonError, validateSubjectSnapshot, PEAC_ISSUER_CONFIG_MAX_BYTES, PEAC_ISSUER_CONFIG_PATH, PEAC_POLICY_MAX_BYTES, PEAC_POLICY_PATH, PEAC_POLICY_FALLBACK_PATH, parseReceiptClaims, PEAC_RECEIPT_HEADER, PEAC_PURPOSE_HEADER, parsePurposeHeader, PEAC_PURPOSE_APPLIED_HEADER, PEAC_PURPOSE_REASON_HEADER } from '@peac/schema';
5
+ import { isValidPurposeToken, isCanonicalPurpose, isValidPurposeReason, isValidWorkflowContext, createWorkflowContextInvalidError, hasValidDagSemantics, createWorkflowDagInvalidError, WORKFLOW_EXTENSION_KEY, validateKernelConstraints, createConstraintViolationError, ReceiptClaims, createEvidenceNotJsonError, validateSubjectSnapshot, isCanonicalIss, Wire02ClaimsSchema, PEAC_ISSUER_CONFIG_MAX_BYTES, validateRevokedKeys, PEAC_ISSUER_CONFIG_PATH, PEAC_POLICY_MAX_BYTES, PEAC_POLICY_PATH, PEAC_POLICY_FALLBACK_PATH, WARNING_TYP_MISSING, parseReceiptClaims, checkOccurredAtSkew, REGISTERED_RECEIPT_TYPES, WARNING_TYPE_UNREGISTERED, REGISTERED_EXTENSION_GROUP_KEYS, isValidExtensionKey, WARNING_UNKNOWN_EXTENSION, verifyPolicyBinding, sortWarnings, PEAC_RECEIPT_HEADER, PEAC_PURPOSE_HEADER, parsePurposeHeader, PEAC_PURPOSE_APPLIED_HEADER, PEAC_PURPOSE_REASON_HEADER } from '@peac/schema';
6
6
  import { createHash } from 'crypto';
7
- import { VERIFIER_LIMITS, VERIFIER_NETWORK, VERIFIER_POLICY_VERSION, VERIFICATION_REPORT_VERSION, WIRE_TYPE } from '@peac/kernel';
7
+ import { VERIFIER_LIMITS, VERIFIER_NETWORK, HASH, VERIFIER_POLICY_VERSION, VERIFICATION_REPORT_VERSION, WIRE_TYPE } from '@peac/kernel';
8
8
 
9
9
  // src/issue.ts
10
10
  function fireTelemetryHook(fn, input) {
@@ -178,6 +178,52 @@ async function issueJws(options) {
178
178
  const result = await issue(options);
179
179
  return result.jws;
180
180
  }
181
+ async function issueWire02(options) {
182
+ if (!isCanonicalIss(options.iss)) {
183
+ throw new IssueError({
184
+ code: "E_ISS_NOT_CANONICAL",
185
+ category: "validation",
186
+ severity: "error",
187
+ retryable: false,
188
+ http_status: 400,
189
+ details: {
190
+ message: `iss is not in canonical form: "${options.iss}". Use https:// origin or did: identifier.`
191
+ }
192
+ });
193
+ }
194
+ const jti = options.jti ?? uuidv7();
195
+ const iat = Math.floor(Date.now() / 1e3);
196
+ const claims = {
197
+ peac_version: "0.2",
198
+ kind: options.kind,
199
+ type: options.type,
200
+ iss: options.iss,
201
+ iat,
202
+ jti,
203
+ ...options.sub !== void 0 && { sub: options.sub },
204
+ ...options.pillars !== void 0 && { pillars: options.pillars },
205
+ ...options.occurred_at !== void 0 && { occurred_at: options.occurred_at },
206
+ ...options.purpose_declared !== void 0 && { purpose_declared: options.purpose_declared },
207
+ ...options.policy !== void 0 && { policy: options.policy },
208
+ ...options.extensions !== void 0 && { extensions: options.extensions }
209
+ };
210
+ const parseResult = Wire02ClaimsSchema.safeParse(claims);
211
+ if (!parseResult.success) {
212
+ const firstIssue = parseResult.error.issues[0];
213
+ throw new IssueError({
214
+ code: "E_INVALID_FORMAT",
215
+ category: "validation",
216
+ severity: "error",
217
+ retryable: false,
218
+ http_status: 400,
219
+ details: {
220
+ message: `Wire 0.2 claims schema validation failed: ${firstIssue?.message ?? "unknown"}`
221
+ }
222
+ });
223
+ }
224
+ const jws = await signWire02(claims, options.privateKey, options.kid);
225
+ return { jws };
226
+ }
181
227
  function parseIssuerConfig(json) {
182
228
  let config;
183
229
  if (typeof json === "string") {
@@ -237,6 +283,17 @@ function parseIssuerConfig(json) {
237
283
  throw new Error("payment_rails must be an array");
238
284
  }
239
285
  }
286
+ let revokedKeys;
287
+ if (obj.revoked_keys !== void 0) {
288
+ if (!Array.isArray(obj.revoked_keys)) {
289
+ throw new Error("revoked_keys must be an array");
290
+ }
291
+ const result = validateRevokedKeys(obj.revoked_keys);
292
+ if (!result.ok) {
293
+ throw new Error(`Invalid revoked_keys: ${result.error}`);
294
+ }
295
+ revokedKeys = result.value;
296
+ }
240
297
  return {
241
298
  version: obj.version,
242
299
  issuer: obj.issuer,
@@ -245,7 +302,8 @@ function parseIssuerConfig(json) {
245
302
  receipt_versions: obj.receipt_versions,
246
303
  algorithms: obj.algorithms,
247
304
  payment_rails: obj.payment_rails,
248
- security_contact: obj.security_contact
305
+ security_contact: obj.security_contact,
306
+ revoked_keys: revokedKeys
249
307
  };
250
308
  }
251
309
  async function fetchIssuerConfig(issuerUrl) {
@@ -932,6 +990,53 @@ async function fetchPointerSafe(pointerUrl, options) {
932
990
  var DEFAULT_CACHE_TTL_MS = 5 * 60 * 1e3;
933
991
  var DEFAULT_MAX_CACHE_ENTRIES = 1e3;
934
992
  var jwksCache = /* @__PURE__ */ new Map();
993
+ var KID_RETENTION_MS = 30 * 24 * 60 * 60 * 1e3;
994
+ var MAX_KID_THUMBPRINT_ENTRIES = 1e4;
995
+ var kidThumbprints = /* @__PURE__ */ new Map();
996
+ function pruneExpiredKidEntries(now) {
997
+ for (const [key, entry] of kidThumbprints) {
998
+ if (now - entry.firstSeen >= KID_RETENTION_MS) {
999
+ kidThumbprints.delete(key);
1000
+ }
1001
+ }
1002
+ }
1003
+ function evictOldestKidEntries() {
1004
+ if (kidThumbprints.size <= MAX_KID_THUMBPRINT_ENTRIES) return;
1005
+ const entries = Array.from(kidThumbprints.entries()).sort(
1006
+ (a, b) => a[1].firstSeen - b[1].firstSeen
1007
+ );
1008
+ const toRemove = kidThumbprints.size - MAX_KID_THUMBPRINT_ENTRIES;
1009
+ for (let i = 0; i < toRemove; i++) {
1010
+ kidThumbprints.delete(entries[i][0]);
1011
+ }
1012
+ }
1013
+ function checkKidReuse(issuer, jwks, now) {
1014
+ pruneExpiredKidEntries(now);
1015
+ for (const key of jwks.keys) {
1016
+ if (!key.kid || !key.x) continue;
1017
+ const mapKey = `${issuer}|${key.kid}`;
1018
+ const existing = kidThumbprints.get(mapKey);
1019
+ if (existing) {
1020
+ if (now - existing.firstSeen < KID_RETENTION_MS) {
1021
+ if (existing.thumbprint !== key.x) {
1022
+ return `Kid reuse detected: kid=${key.kid} for issuer ${issuer} maps to different key material`;
1023
+ }
1024
+ } else {
1025
+ kidThumbprints.set(mapKey, { thumbprint: key.x, firstSeen: now });
1026
+ }
1027
+ } else {
1028
+ kidThumbprints.set(mapKey, { thumbprint: key.x, firstSeen: now });
1029
+ }
1030
+ }
1031
+ evictOldestKidEntries();
1032
+ return null;
1033
+ }
1034
+ function clearKidThumbprints() {
1035
+ kidThumbprints.clear();
1036
+ }
1037
+ function getKidThumbprintSize() {
1038
+ return kidThumbprints.size;
1039
+ }
935
1040
  function cacheGet(key, now) {
936
1041
  const entry = jwksCache.get(key);
937
1042
  if (!entry) return void 0;
@@ -1020,7 +1125,7 @@ async function resolveJWKS(issuerUrl, options) {
1020
1125
  if (!noCache) {
1021
1126
  const cached = cacheGet(normalizedIssuer, now);
1022
1127
  if (cached) {
1023
- return { ok: true, jwks: cached.jwks, fromCache: true };
1128
+ return { ok: true, jwks: cached.jwks, fromCache: true, revokedKeys: cached.revokedKeys };
1024
1129
  }
1025
1130
  }
1026
1131
  if (!normalizedIssuer.startsWith("https://")) {
@@ -1115,14 +1220,28 @@ async function resolveJWKS(issuerUrl, options) {
1115
1220
  message: `JWKS has too many keys: ${jwks.keys.length} > ${VERIFIER_LIMITS.maxJwksKeys}`
1116
1221
  };
1117
1222
  }
1223
+ const kidReuseError = checkKidReuse(normalizedIssuer, jwks, now);
1224
+ if (kidReuseError) {
1225
+ return {
1226
+ ok: false,
1227
+ code: "E_KID_REUSE_DETECTED",
1228
+ message: kidReuseError
1229
+ };
1230
+ }
1231
+ const revokedKeys = issuerConfig.revoked_keys?.map((entry) => ({
1232
+ kid: entry.kid,
1233
+ revoked_at: entry.revoked_at,
1234
+ reason: entry.reason
1235
+ }));
1118
1236
  if (!noCache) {
1119
- cacheSet(normalizedIssuer, { jwks, expiresAt: now + cacheTtlMs }, maxCacheEntries);
1237
+ cacheSet(normalizedIssuer, { jwks, expiresAt: now + cacheTtlMs, revokedKeys }, maxCacheEntries);
1120
1238
  }
1121
1239
  return {
1122
1240
  ok: true,
1123
1241
  jwks,
1124
1242
  fromCache: false,
1125
- rawBytes: jwksResult.rawBytes
1243
+ rawBytes: jwksResult.rawBytes,
1244
+ revokedKeys
1126
1245
  };
1127
1246
  }
1128
1247
 
@@ -1183,6 +1302,25 @@ async function verifyReceipt(optionsOrJws) {
1183
1302
  if (!jwksResult.fromCache) {
1184
1303
  jwksFetchTime = performance.now() - jwksFetchStart;
1185
1304
  }
1305
+ if (jwksResult.revokedKeys) {
1306
+ const revokedEntry = jwksResult.revokedKeys.find((rk) => rk.kid === header.kid);
1307
+ if (revokedEntry) {
1308
+ const durationMs = performance.now() - startTime;
1309
+ fireTelemetryHook(telemetry?.onReceiptVerified, {
1310
+ receiptHash: hashReceipt(receiptJws),
1311
+ valid: false,
1312
+ reasonCode: "key_revoked",
1313
+ issuer: payload.iss,
1314
+ kid: header.kid,
1315
+ durationMs
1316
+ });
1317
+ return {
1318
+ ok: false,
1319
+ reason: "key_revoked",
1320
+ details: `Key kid=${header.kid} was revoked at ${revokedEntry.revoked_at}${revokedEntry.reason ? ` (reason: ${revokedEntry.reason})` : ""}`
1321
+ };
1322
+ }
1323
+ }
1186
1324
  const jwk = jwksResult.jwks.keys.find((k) => k.kid === header.kid);
1187
1325
  if (!jwk) {
1188
1326
  const durationMs = performance.now() - startTime;
@@ -1260,6 +1398,13 @@ var FORMAT_ERROR_CODES = /* @__PURE__ */ new Set([
1260
1398
  "CRYPTO_INVALID_ALG",
1261
1399
  "CRYPTO_INVALID_KEY_LENGTH"
1262
1400
  ]);
1401
+ var JOSE_CODE_MAP = {
1402
+ CRYPTO_JWS_EMBEDDED_KEY: "E_JWS_EMBEDDED_KEY",
1403
+ CRYPTO_JWS_CRIT_REJECTED: "E_JWS_CRIT_REJECTED",
1404
+ CRYPTO_JWS_MISSING_KID: "E_JWS_MISSING_KID",
1405
+ CRYPTO_JWS_B64_REJECTED: "E_JWS_B64_REJECTED",
1406
+ CRYPTO_JWS_ZIP_REJECTED: "E_JWS_ZIP_REJECTED"
1407
+ };
1263
1408
  var MAX_PARSE_ISSUES = 25;
1264
1409
  function sanitizeParseIssues(issues) {
1265
1410
  if (!Array.isArray(issues)) return void 0;
@@ -1269,7 +1414,16 @@ function sanitizeParseIssues(issues) {
1269
1414
  }));
1270
1415
  }
1271
1416
  async function verifyLocal(jws, publicKey, options = {}) {
1272
- const { issuer, audience, subjectUri, rid, requireExp = false, maxClockSkew = 300 } = options;
1417
+ const {
1418
+ issuer,
1419
+ audience,
1420
+ subjectUri,
1421
+ rid,
1422
+ requireExp = false,
1423
+ maxClockSkew = 300,
1424
+ strictness = "strict",
1425
+ policyDigest
1426
+ } = options;
1273
1427
  const now = options.now ?? Math.floor(Date.now() / 1e3);
1274
1428
  try {
1275
1429
  const result = await verify(jws, publicKey);
@@ -1280,6 +1434,20 @@ async function verifyLocal(jws, publicKey, options = {}) {
1280
1434
  message: "Ed25519 signature verification failed"
1281
1435
  };
1282
1436
  }
1437
+ const accumulatedWarnings = [];
1438
+ if (result.header.typ === void 0) {
1439
+ if (strictness === "strict") {
1440
+ return {
1441
+ valid: false,
1442
+ code: "E_INVALID_FORMAT",
1443
+ message: "Missing JWS typ header: strict mode requires typ to be present"
1444
+ };
1445
+ }
1446
+ accumulatedWarnings.push({
1447
+ code: WARNING_TYP_MISSING,
1448
+ message: "JWS typ header is absent; accepted in interop mode"
1449
+ });
1450
+ }
1283
1451
  const constraintResult = validateKernelConstraints(result.payload);
1284
1452
  if (!constraintResult.valid) {
1285
1453
  const v = constraintResult.violations[0];
@@ -1298,46 +1466,136 @@ async function verifyLocal(jws, publicKey, options = {}) {
1298
1466
  details: { parse_code: pr.error.code, issues: sanitizeParseIssues(pr.error.issues) }
1299
1467
  };
1300
1468
  }
1301
- if (issuer !== void 0 && pr.claims.iss !== issuer) {
1469
+ if (pr.wireVersion === "0.2") {
1470
+ accumulatedWarnings.push(...pr.warnings);
1471
+ }
1472
+ if (pr.wireVersion === "0.2") {
1473
+ const claims = pr.claims;
1474
+ if (issuer !== void 0 && claims.iss !== issuer) {
1475
+ return {
1476
+ valid: false,
1477
+ code: "E_INVALID_ISSUER",
1478
+ message: `Issuer mismatch: expected "${issuer}", got "${claims.iss}"`
1479
+ };
1480
+ }
1481
+ if (subjectUri !== void 0 && claims.sub !== subjectUri) {
1482
+ return {
1483
+ valid: false,
1484
+ code: "E_INVALID_SUBJECT",
1485
+ message: `Subject mismatch: expected "${subjectUri}", got "${claims.sub ?? "undefined"}"`
1486
+ };
1487
+ }
1488
+ if (claims.iat > now + maxClockSkew) {
1489
+ return {
1490
+ valid: false,
1491
+ code: "E_NOT_YET_VALID",
1492
+ message: `Receipt not yet valid: issued at ${new Date(claims.iat * 1e3).toISOString()}, now is ${new Date(now * 1e3).toISOString()}`
1493
+ };
1494
+ }
1495
+ if (claims.kind === "evidence") {
1496
+ const skewResult = checkOccurredAtSkew(claims.occurred_at, claims.iat, now, maxClockSkew);
1497
+ if (skewResult === "future_error") {
1498
+ return {
1499
+ valid: false,
1500
+ code: "E_OCCURRED_AT_FUTURE",
1501
+ message: `occurred_at is in the future beyond tolerance (${maxClockSkew}s)`
1502
+ };
1503
+ }
1504
+ if (skewResult !== null) {
1505
+ accumulatedWarnings.push(skewResult);
1506
+ }
1507
+ }
1508
+ if (!REGISTERED_RECEIPT_TYPES.has(claims.type)) {
1509
+ accumulatedWarnings.push({
1510
+ code: WARNING_TYPE_UNREGISTERED,
1511
+ message: "Receipt type is not in the recommended type registry",
1512
+ pointer: "/type"
1513
+ });
1514
+ }
1515
+ if (claims.extensions !== void 0) {
1516
+ for (const key of Object.keys(claims.extensions)) {
1517
+ if (!REGISTERED_EXTENSION_GROUP_KEYS.has(key) && isValidExtensionKey(key)) {
1518
+ const escapedKey = key.replace(/~/g, "~0").replace(/\//g, "~1");
1519
+ accumulatedWarnings.push({
1520
+ code: WARNING_UNKNOWN_EXTENSION,
1521
+ message: "Unknown extension key preserved without schema validation",
1522
+ pointer: `/extensions/${escapedKey}`
1523
+ });
1524
+ }
1525
+ }
1526
+ }
1527
+ if (policyDigest !== void 0 && !HASH.pattern.test(policyDigest)) {
1528
+ return {
1529
+ valid: false,
1530
+ code: "E_INVALID_FORMAT",
1531
+ message: "policyDigest option must be in sha256:<64 lowercase hex> format"
1532
+ };
1533
+ }
1534
+ const receiptPolicyDigest = claims.policy?.digest;
1535
+ const bindingStatus = receiptPolicyDigest === void 0 || policyDigest === void 0 ? "unavailable" : verifyPolicyBinding(receiptPolicyDigest, policyDigest);
1536
+ if (bindingStatus === "failed") {
1537
+ return {
1538
+ valid: false,
1539
+ code: "E_POLICY_BINDING_FAILED",
1540
+ message: "Policy binding check failed: receipt policy digest does not match local policy",
1541
+ details: {
1542
+ receipt_policy_digest: receiptPolicyDigest,
1543
+ local_policy_digest: policyDigest,
1544
+ ...claims.policy?.uri !== void 0 && { policy_uri: claims.policy.uri }
1545
+ }
1546
+ };
1547
+ }
1548
+ return {
1549
+ valid: true,
1550
+ variant: "wire-02",
1551
+ claims,
1552
+ kid: result.header.kid,
1553
+ wireVersion: "0.2",
1554
+ warnings: sortWarnings(accumulatedWarnings),
1555
+ policy_binding: bindingStatus
1556
+ };
1557
+ }
1558
+ const w01 = pr.claims;
1559
+ if (issuer !== void 0 && w01.iss !== issuer) {
1302
1560
  return {
1303
1561
  valid: false,
1304
1562
  code: "E_INVALID_ISSUER",
1305
- message: `Issuer mismatch: expected "${issuer}", got "${pr.claims.iss}"`
1563
+ message: `Issuer mismatch: expected "${issuer}", got "${w01.iss}"`
1306
1564
  };
1307
1565
  }
1308
- if (audience !== void 0 && pr.claims.aud !== audience) {
1566
+ if (audience !== void 0 && w01.aud !== audience) {
1309
1567
  return {
1310
1568
  valid: false,
1311
1569
  code: "E_INVALID_AUDIENCE",
1312
- message: `Audience mismatch: expected "${audience}", got "${pr.claims.aud}"`
1570
+ message: `Audience mismatch: expected "${audience}", got "${w01.aud}"`
1313
1571
  };
1314
1572
  }
1315
- if (rid !== void 0 && pr.claims.rid !== rid) {
1573
+ if (rid !== void 0 && w01.rid !== rid) {
1316
1574
  return {
1317
1575
  valid: false,
1318
1576
  code: "E_INVALID_RECEIPT_ID",
1319
- message: `Receipt ID mismatch: expected "${rid}", got "${pr.claims.rid}"`
1577
+ message: `Receipt ID mismatch: expected "${rid}", got "${w01.rid}"`
1320
1578
  };
1321
1579
  }
1322
- if (requireExp && pr.claims.exp === void 0) {
1580
+ if (requireExp && w01.exp === void 0) {
1323
1581
  return {
1324
1582
  valid: false,
1325
1583
  code: "E_MISSING_EXP",
1326
1584
  message: "Receipt missing required exp claim"
1327
1585
  };
1328
1586
  }
1329
- if (pr.claims.iat > now + maxClockSkew) {
1587
+ if (w01.iat > now + maxClockSkew) {
1330
1588
  return {
1331
1589
  valid: false,
1332
1590
  code: "E_NOT_YET_VALID",
1333
- message: `Receipt not yet valid: issued at ${new Date(pr.claims.iat * 1e3).toISOString()}, now is ${new Date(now * 1e3).toISOString()}`
1591
+ message: `Receipt not yet valid: issued at ${new Date(w01.iat * 1e3).toISOString()}, now is ${new Date(now * 1e3).toISOString()}`
1334
1592
  };
1335
1593
  }
1336
- if (pr.claims.exp !== void 0 && pr.claims.exp < now - maxClockSkew) {
1594
+ if (w01.exp !== void 0 && w01.exp < now - maxClockSkew) {
1337
1595
  return {
1338
1596
  valid: false,
1339
1597
  code: "E_EXPIRED",
1340
- message: `Receipt expired at ${new Date(pr.claims.exp * 1e3).toISOString()}`
1598
+ message: `Receipt expired at ${new Date(w01.exp * 1e3).toISOString()}`
1341
1599
  };
1342
1600
  }
1343
1601
  if (pr.variant === "commerce") {
@@ -1354,6 +1612,8 @@ async function verifyLocal(jws, publicKey, options = {}) {
1354
1612
  variant: "commerce",
1355
1613
  claims,
1356
1614
  kid: result.header.kid,
1615
+ wireVersion: "0.1",
1616
+ warnings: [],
1357
1617
  policy_binding: "unavailable"
1358
1618
  };
1359
1619
  } else {
@@ -1370,11 +1630,20 @@ async function verifyLocal(jws, publicKey, options = {}) {
1370
1630
  variant: "attestation",
1371
1631
  claims,
1372
1632
  kid: result.header.kid,
1633
+ wireVersion: "0.1",
1634
+ warnings: [],
1373
1635
  policy_binding: "unavailable"
1374
1636
  };
1375
1637
  }
1376
1638
  } catch (err) {
1377
1639
  if (isCryptoError(err)) {
1640
+ if (Object.prototype.hasOwnProperty.call(JOSE_CODE_MAP, err.code)) {
1641
+ return {
1642
+ valid: false,
1643
+ code: JOSE_CODE_MAP[err.code],
1644
+ message: err.message
1645
+ };
1646
+ }
1378
1647
  if (FORMAT_ERROR_CODES.has(err.code)) {
1379
1648
  return {
1380
1649
  valid: false,
@@ -1389,6 +1658,13 @@ async function verifyLocal(jws, publicKey, options = {}) {
1389
1658
  message: err.message
1390
1659
  };
1391
1660
  }
1661
+ if (err.code === "CRYPTO_WIRE_VERSION_MISMATCH") {
1662
+ return {
1663
+ valid: false,
1664
+ code: "E_WIRE_VERSION_MISMATCH",
1665
+ message: err.message
1666
+ };
1667
+ }
1392
1668
  }
1393
1669
  if (err !== null && typeof err === "object" && "name" in err && err.name === "SyntaxError") {
1394
1670
  const syntaxMessage = "message" in err && typeof err.message === "string" ? err.message : "Invalid JSON";
@@ -1412,6 +1688,9 @@ function isCommerceResult(r) {
1412
1688
  function isAttestationResult(r) {
1413
1689
  return r.valid === true && r.variant === "attestation";
1414
1690
  }
1691
+ function isWire02Result(r) {
1692
+ return r.valid === true && r.variant === "wire-02";
1693
+ }
1415
1694
  function setReceiptHeader(headers, receiptJws) {
1416
1695
  headers.set(PEAC_RECEIPT_HEADER, receiptJws);
1417
1696
  }
@@ -1453,6 +1732,16 @@ function setVaryPurposeHeader(headers) {
1453
1732
  headers.set("Vary", PEAC_PURPOSE_HEADER);
1454
1733
  }
1455
1734
  }
1735
+ async function computePolicyDigestJcs(policy) {
1736
+ const hex = await jcsHash(policy);
1737
+ return `${HASH.prefix}${hex}`;
1738
+ }
1739
+ function checkPolicyBinding(receiptDigest, localDigest) {
1740
+ if (receiptDigest === void 0 || localDigest === void 0) {
1741
+ return "unavailable";
1742
+ }
1743
+ return verifyPolicyBinding(receiptDigest, localDigest);
1744
+ }
1456
1745
  var DEFAULT_VERIFIER_LIMITS = {
1457
1746
  max_receipt_bytes: VERIFIER_LIMITS.maxReceiptBytes,
1458
1747
  max_jwks_bytes: VERIFIER_LIMITS.maxJwksBytes,
@@ -2728,6 +3017,6 @@ async function verifyAndFetchPointer(pointerHeader, fetchOptions) {
2728
3017
  });
2729
3018
  }
2730
3019
 
2731
- export { CHECK_IDS, DEFAULT_NETWORK_SECURITY, DEFAULT_VERIFIER_LIMITS, IssueError, NON_DETERMINISTIC_ARTIFACT_KEYS, VerificationReportBuilder, buildFailureReport, buildSuccessReport, clearJWKSCache, computeReceiptDigest, createDefaultPolicy, createDigest, createEmptyReport, createReportBuilder, fetchDiscovery, fetchIssuerConfig, fetchJWKSSafe, fetchPointerSafe, fetchPointerWithDigest, fetchPolicyManifest, getJWKSCacheSize, getPurposeHeader, getReceiptHeader, getSSRFCapabilities, isAttestationResult, isBlockedIP, isCommerceResult, issue, issueJws, parseBodyProfile, parseDiscovery, parseHeaderProfile, parseIssuerConfig, parsePointerProfile, parsePolicyManifest, parseTransportProfile, reasonCodeToErrorCode, reasonCodeToSeverity, resetSSRFCapabilitiesCache, resolveJWKS, setPurposeAppliedHeader, setPurposeReasonHeader, setReceiptHeader, setVaryHeader, setVaryPurposeHeader, ssrfErrorToReasonCode, ssrfSafeFetch, verifyAndFetchPointer, verifyLocal, verifyReceipt, verifyReceiptCore };
3020
+ export { CHECK_IDS, DEFAULT_NETWORK_SECURITY, DEFAULT_VERIFIER_LIMITS, IssueError, NON_DETERMINISTIC_ARTIFACT_KEYS, VerificationReportBuilder, buildFailureReport, buildSuccessReport, checkPolicyBinding, clearJWKSCache, clearKidThumbprints, computePolicyDigestJcs, computeReceiptDigest, createDefaultPolicy, createDigest, createEmptyReport, createReportBuilder, fetchDiscovery, fetchIssuerConfig, fetchJWKSSafe, fetchPointerSafe, fetchPointerWithDigest, fetchPolicyManifest, getJWKSCacheSize, getKidThumbprintSize, getPurposeHeader, getReceiptHeader, getSSRFCapabilities, isAttestationResult, isBlockedIP, isCommerceResult, isWire02Result, issue, issueJws, issueWire02, parseBodyProfile, parseDiscovery, parseHeaderProfile, parseIssuerConfig, parsePointerProfile, parsePolicyManifest, parseTransportProfile, reasonCodeToErrorCode, reasonCodeToSeverity, resetSSRFCapabilitiesCache, resolveJWKS, setPurposeAppliedHeader, setPurposeReasonHeader, setReceiptHeader, setVaryHeader, setVaryPurposeHeader, ssrfErrorToReasonCode, ssrfSafeFetch, verifyAndFetchPointer, verifyLocal, verifyReceipt, verifyReceiptCore };
2732
3021
  //# sourceMappingURL=index.mjs.map
2733
3022
  //# sourceMappingURL=index.mjs.map