@credo-ts/core 0.7.3 → 0.7.4

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.
Files changed (92) hide show
  1. package/build/agent/TrustedIssuerContext.d.mts +11 -1
  2. package/build/agent/TrustedIssuerContext.d.mts.map +1 -1
  3. package/build/agent/TrustedIssuerContext.mjs +7 -0
  4. package/build/agent/TrustedIssuerContext.mjs.map +1 -1
  5. package/build/agent/TrustedIssuersForVerification.d.mts +11 -1
  6. package/build/agent/TrustedIssuersForVerification.d.mts.map +1 -1
  7. package/build/index.d.mts +3 -3
  8. package/build/index.mjs +2 -2
  9. package/build/modules/dcql/DcqlService.d.mts.map +1 -1
  10. package/build/modules/dcql/DcqlService.mjs +24 -12
  11. package/build/modules/dcql/DcqlService.mjs.map +1 -1
  12. package/build/modules/dids/domain/verificationMethod/JsonWebKey2020.d.mts +24 -24
  13. package/build/modules/dids/methods/jwk/DidJwk.d.mts +24 -24
  14. package/build/modules/dids/services/DidResolverService.d.mts +4 -0
  15. package/build/modules/dids/services/DidResolverService.d.mts.map +1 -1
  16. package/build/modules/dids/services/DidResolverService.mjs +21 -5
  17. package/build/modules/dids/services/DidResolverService.mjs.map +1 -1
  18. package/build/modules/kms/KeyManagementApi.d.mts +14 -14
  19. package/build/modules/kms/jwk/jwa.d.mts +1 -1
  20. package/build/modules/kms/jwk/knownJwk.d.mts +4 -4
  21. package/build/modules/kms/jwk/kty/ec/P256PublicJwk.d.mts +1 -1
  22. package/build/modules/kms/jwk/kty/ec/P384PublicJwk.d.mts +1 -1
  23. package/build/modules/kms/jwk/kty/ec/P521PublicJwk.d.mts +1 -1
  24. package/build/modules/kms/jwk/kty/ec/Secp256k1PublicJwk.d.mts +1 -1
  25. package/build/modules/kms/jwk/kty/okp/Ed25519PublicJwk.d.mts +2 -2
  26. package/build/modules/kms/jwk/kty/okp/X25519PublicJwk.d.mts +1 -1
  27. package/build/modules/kms/jwk/kty/okp/okpJwk.d.mts +2 -2
  28. package/build/modules/kms/options/KmsCreateKeyOptions.d.mts +3 -3
  29. package/build/modules/kms/options/KmsSignOptions.d.mts +1 -1
  30. package/build/modules/kms/options/KmsVerifyOptions.d.mts +2 -2
  31. package/build/modules/mdoc/repository/MdocRecord.d.mts +1 -1
  32. package/build/modules/sd-jwt-vc/repository/SdJwtVcRecord.d.mts +1 -1
  33. package/build/modules/sd-jwt-vc/utils.mjs +4 -4
  34. package/build/modules/sd-jwt-vc/utils.mjs.map +1 -1
  35. package/build/modules/vc/W3cCredentialServiceOptions.d.mts +5 -5
  36. package/build/modules/vc/W3cCredentialServiceOptions.d.mts.map +1 -1
  37. package/build/modules/vc/W3cV2CredentialService.d.mts +5 -1
  38. package/build/modules/vc/W3cV2CredentialService.d.mts.map +1 -1
  39. package/build/modules/vc/W3cV2CredentialService.mjs +72 -26
  40. package/build/modules/vc/W3cV2CredentialService.mjs.map +1 -1
  41. package/build/modules/vc/W3cV2CredentialServiceOptions.d.mts +14 -6
  42. package/build/modules/vc/W3cV2CredentialServiceOptions.d.mts.map +1 -1
  43. package/build/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.d.mts +0 -18
  44. package/build/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.d.mts.map +1 -1
  45. package/build/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.mjs +38 -36
  46. package/build/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.mjs.map +1 -1
  47. package/build/modules/vc/data-integrity/v2-di-utils.mjs +17 -35
  48. package/build/modules/vc/data-integrity/v2-di-utils.mjs.map +1 -1
  49. package/build/modules/vc/jwt-vc/W3cJwtCredentialService.d.mts +0 -23
  50. package/build/modules/vc/jwt-vc/W3cJwtCredentialService.d.mts.map +1 -1
  51. package/build/modules/vc/jwt-vc/W3cJwtCredentialService.mjs +17 -68
  52. package/build/modules/vc/jwt-vc/W3cJwtCredentialService.mjs.map +1 -1
  53. package/build/modules/vc/jwt-vc/W3cV2JwtCredentialService.d.mts.map +1 -1
  54. package/build/modules/vc/jwt-vc/W3cV2JwtCredentialService.mjs +11 -17
  55. package/build/modules/vc/jwt-vc/W3cV2JwtCredentialService.mjs.map +1 -1
  56. package/build/modules/vc/linked-data-proofs/W3cJsonLdCredentialService.d.mts +5 -0
  57. package/build/modules/vc/linked-data-proofs/W3cJsonLdCredentialService.d.mts.map +1 -1
  58. package/build/modules/vc/linked-data-proofs/W3cJsonLdCredentialService.mjs +18 -4
  59. package/build/modules/vc/linked-data-proofs/W3cJsonLdCredentialService.mjs.map +1 -1
  60. package/build/modules/vc/models/W3cV2VerifyResult.d.mts +6 -0
  61. package/build/modules/vc/models/W3cV2VerifyResult.d.mts.map +1 -1
  62. package/build/modules/vc/resolveSigner.mjs +74 -0
  63. package/build/modules/vc/resolveSigner.mjs.map +1 -0
  64. package/build/modules/vc/sd-jwt-vc/W3cV2SdJwtCredentialService.d.mts.map +1 -1
  65. package/build/modules/vc/sd-jwt-vc/W3cV2SdJwtCredentialService.mjs +16 -18
  66. package/build/modules/vc/sd-jwt-vc/W3cV2SdJwtCredentialService.mjs.map +1 -1
  67. package/build/modules/vc/sd-jwt-vc/disclosureFrame.d.mts +1 -1
  68. package/build/modules/vc/sd-jwt-vc/disclosureFrame.d.mts.map +1 -1
  69. package/build/modules/vc/sd-jwt-vc/disclosureFrame.mjs +2 -1
  70. package/build/modules/vc/sd-jwt-vc/disclosureFrame.mjs.map +1 -1
  71. package/build/modules/vc/v2-jwt-utils.mjs +54 -55
  72. package/build/modules/vc/v2-jwt-utils.mjs.map +1 -1
  73. package/build/modules/x509/X509ModuleConfig.d.mts +5 -13
  74. package/build/modules/x509/X509ModuleConfig.d.mts.map +1 -1
  75. package/build/modules/x509/X509ModuleConfig.mjs +2 -1
  76. package/build/modules/x509/X509ModuleConfig.mjs.map +1 -1
  77. package/build/modules/x509/X509RevocationService.d.mts.map +1 -1
  78. package/build/modules/x509/X509RevocationService.mjs +17 -20
  79. package/build/modules/x509/X509RevocationService.mjs.map +1 -1
  80. package/build/modules/x509/X509Service.mjs +1 -1
  81. package/build/modules/x509/X509Service.mjs.map +1 -1
  82. package/build/modules/x509/X509ServiceOptions.d.mts +4 -6
  83. package/build/modules/x509/X509ServiceOptions.d.mts.map +1 -1
  84. package/build/modules/x509/X509ValidationOptions.d.mts +19 -2
  85. package/build/modules/x509/X509ValidationOptions.d.mts.map +1 -1
  86. package/build/modules/x509/X509ValidationOptions.mjs +21 -1
  87. package/build/modules/x509/X509ValidationOptions.mjs.map +1 -1
  88. package/build/modules/x509/index.d.mts +2 -2
  89. package/build/modules/x509/index.mjs +2 -2
  90. package/build/modules/x509/utils/crlFetcher.mjs +1 -11
  91. package/build/modules/x509/utils/crlFetcher.mjs.map +1 -1
  92. package/package.json +1 -1
@@ -4,13 +4,12 @@ import { asArray } from "../../utils/array.mjs";
4
4
  import { isDid } from "../../utils/did.mjs";
5
5
  import "../../utils/index.mjs";
6
6
  import "../../agent/index.mjs";
7
- import { PublicJwk } from "../kms/jwk/PublicJwk.mjs";
8
7
  import "../kms/index.mjs";
9
8
  import { parseDid } from "../dids/domain/parse.mjs";
10
- import { getPublicJwkFromVerificationMethod, getSupportedVerificationMethodTypesForPublicJwk } from "../dids/domain/key-type/keyDidMapping.mjs";
11
- import { DidResolverService } from "../dids/services/DidResolverService.mjs";
9
+ import { getPublicJwkFromVerificationMethod } from "../dids/domain/key-type/keyDidMapping.mjs";
12
10
  import { DidsApi } from "../dids/DidsApi.mjs";
13
11
  import "../dids/index.mjs";
12
+ import { resolveJwtSigner } from "./resolveSigner.mjs";
14
13
  import { extractKeyFromHolderBinding, parseHolderBindingFromCredential } from "../sd-jwt-vc/utils.mjs";
15
14
  import { W3cV2JwtVerifiableCredential } from "./jwt-vc/W3cV2JwtVerifiableCredential.mjs";
16
15
  import { W3cV2SdJwtVerifiableCredential } from "./sd-jwt-vc/W3cV2SdJwtVerifiableCredential.mjs";
@@ -34,9 +33,18 @@ async function extractHolderFromPresentationCredentials(agentContext, presentati
34
33
  if (holderDid) {
35
34
  if (!isDid(holderDid)) throw new CredoError(`Presentation holder '${holderDid}' is not a valid did`);
36
35
  const { didDocument, keys } = await agentContext.resolve(DidsApi).resolveCreatedDidDocumentWithKeys(holderDid);
37
- const candidateMethods = didDocument.findVerificationMethodsByPurpose(["authentication"]).filter((method) => keys?.some(({ didDocumentRelativeKeyId }) => method.id.endsWith(didDocumentRelativeKeyId)));
36
+ let candidateMethods = didDocument.findVerificationMethodsByPurpose(["authentication"]).filter((method) => keys?.some(({ didDocumentRelativeKeyId }) => method.id.endsWith(didDocumentRelativeKeyId)));
38
37
  if (candidateMethods.length === 0) throw new CredoError(`Unable to determine signer key for presentation holder '${holderDid}'. No locally controlled authentication verification method found.`);
39
- if (candidateMethods.length > 1) throw new CredoError(`Unable to deterministically resolve signer key for presentation holder '${holderDid}'. Multiple locally controlled authentication verification methods found.`);
38
+ if (candidateMethods.length > 1) {
39
+ const credentialHolders = await getCredentialHolders(agentContext, credentials, { didPurposes: ["authentication"] });
40
+ const boundMethods = candidateMethods.filter((method) => {
41
+ const publicJwk = getPublicJwkFromVerificationMethod(method);
42
+ return credentialHolders.some((holder) => holder.publicJwk.equals(publicJwk));
43
+ });
44
+ if (boundMethods.length === 0) throw new CredoError(`Unable to deterministically resolve signer key for presentation holder '${holderDid}'. Multiple locally controlled authentication verification methods found, and the presentation credentials are not bound to any of them.`);
45
+ if (boundMethods.length > 1) throw new CredoError(`Unable to deterministically resolve signer key for presentation holder '${holderDid}'. Multiple locally controlled authentication verification methods found, and the presentation credentials are bound to more than one of them.`);
46
+ candidateMethods = boundMethods;
47
+ }
40
48
  const selectedMethod = candidateMethods[0];
41
49
  const publicJwk = getPublicJwkFromVerificationMethod(selectedMethod);
42
50
  publicJwk.keyId = keys?.find(({ didDocumentRelativeKeyId }) => selectedMethod.id.endsWith(didDocumentRelativeKeyId))?.kmsKeyId ?? publicJwk.legacyKeyId;
@@ -48,7 +56,16 @@ async function extractHolderFromPresentationCredentials(agentContext, presentati
48
56
  cnf: { kid: selectedMethod.id }
49
57
  };
50
58
  }
51
- const fallbackHolders = [];
59
+ const credentialHolders = await getCredentialHolders(agentContext, credentials, { forSigning: true });
60
+ if (credentialHolders.length === 0) throw new CredoError("Unable to determine signer from presentation credentials, and presentation.holder is missing");
61
+ if (credentialHolders.length > 1) throw new CredoError("Unable to determine signer from presentation credentials. Multiple distinct holder bindings found and presentation.holder is missing.");
62
+ return credentialHolders[0];
63
+ }
64
+ /**
65
+ * Returns the distinct keys that the credentials are bound to with `cnf`.
66
+ */
67
+ async function getCredentialHolders(agentContext, credentials, options) {
68
+ const holders = /* @__PURE__ */ new Map();
52
69
  for (const credential of credentials) {
53
70
  if (!(credential instanceof W3cV2EnvelopedVerifiableCredential)) continue;
54
71
  let claims;
@@ -57,60 +74,42 @@ async function extractHolderFromPresentationCredentials(agentContext, presentati
57
74
  else continue;
58
75
  const holderBinding = parseHolderBindingFromCredential(claims);
59
76
  if (!holderBinding) continue;
60
- fallbackHolders.push(await extractKeyFromHolderBinding(agentContext, holderBinding, { forSigning: true }));
77
+ const holder = await extractKeyFromHolderBinding(agentContext, holderBinding, options);
78
+ holders.set(holder.publicJwk.fingerprint, holder);
61
79
  }
62
- if (fallbackHolders.length === 0) throw new CredoError("Unable to determine signer from presentation credentials, and presentation.holder is missing");
63
- const uniqueFallbackHolders = new Map(fallbackHolders.map((holder) => [holder.publicJwk.fingerprint, holder]));
64
- if (uniqueFallbackHolders.size > 1) throw new CredoError("Unable to determine signer from presentation credentials. Multiple distinct holder bindings found and presentation.holder is missing.");
65
- return uniqueFallbackHolders.values().next().value;
80
+ return Array.from(holders.values());
66
81
  }
67
82
  /**
68
- * This method tries to find the verification method associated with the JWT credential or presentation.
69
- * This verification method can then be used to verify the credential or presentation signature.
83
+ * Resolves the signer of a JWT credential or presentation. When no `iss` is present, the `issuer`
84
+ * of a credential or the `holder` of a presentation must be the signer.
70
85
  */
71
- async function getVerificationMethodForJwt(agentContext, credential, purpose) {
72
- let alg;
73
- let kid;
74
- let iss;
75
- if (credential instanceof W3cV2JwtVerifiableCredential) {
76
- alg = credential.jwt.header.alg;
77
- kid = credential.jwt.header.kid;
78
- iss = credential.jwt.payload.iss ?? credential.resolvedCredential.issuerId;
79
- } else if (credential instanceof W3cV2JwtVerifiablePresentation) {
80
- alg = credential.jwt.header.alg;
81
- kid = credential.jwt.header.kid;
82
- iss = credential.jwt.payload.iss ?? credential.resolvedPresentation.holderId;
83
- } else if (credential instanceof W3cV2SdJwtVerifiableCredential) {
84
- alg = credential.sdJwt.header.alg;
85
- kid = credential.sdJwt.header.kid;
86
- iss = credential.sdJwt.payload.iss ?? credential.resolvedCredential.issuerId;
87
- } else {
88
- alg = credential.sdJwt.header.alg;
89
- kid = credential.sdJwt.header.kid;
90
- iss = credential.sdJwt.payload.iss ?? credential.resolvedPresentation.holderId;
91
- }
92
- const didResolver = agentContext.dependencyManager.resolve(DidResolverService);
93
- let verificationMethod;
94
- if (kid?.startsWith("#")) {
95
- if (!iss || !isDid(iss)) throw new CredoError(`JWT 'iss' MUST be a did when 'kid' is a relative did url`);
96
- verificationMethod = (await didResolver.resolveDidDocument(agentContext, iss)).dereferenceKey(`${iss}${kid}`, purpose);
97
- } else if (kid && isDid(kid)) {
98
- const didDocument = await didResolver.resolveDidDocument(agentContext, kid);
99
- verificationMethod = didDocument.dereferenceKey(kid, purpose);
100
- if (iss && didDocument.id !== iss) throw new CredoError(`kid '${kid}' does not match id of signer (holder/issuer) '${iss}'`);
101
- } else {
102
- if (!iss) throw new CredoError(`JWT 'iss' MUST be present in payload when no 'kid' is specified`);
103
- const jwkClass = PublicJwk.supportedPublicJwkClassForSignatureAlgorithm(alg);
104
- const supportedVerificationMethodTypes = getSupportedVerificationMethodTypesForPublicJwk(jwkClass);
105
- const verificationMethods = (await didResolver.resolveDidDocument(agentContext, iss)).findVerificationMethodsByTypeAndPurpose(supportedVerificationMethodTypes, ["assertionMethod"]);
106
- if (verificationMethods.length === 0) throw new CredoError(`No verification methods found for signer '${iss}' and key type '${jwkClass.name}' for alg '${alg}'. Unable to determine which public key is associated with the credential.`);
107
- if (verificationMethods.length > 1) throw new CredoError(`Multiple verification methods found for signer '${iss}' and key type '${jwkClass.name}' for alg '${alg}'. Unable to determine which public key is associated with the credential.`);
108
- verificationMethod = verificationMethods[0];
109
- }
110
- if (iss && verificationMethod.controller !== iss) throw new CredoError(`Verification method controller '${verificationMethod.controller}' does not match the signer '${iss}'`);
111
- return verificationMethod;
86
+ async function getSignerForJwt(agentContext, credential, purpose) {
87
+ if (credential instanceof W3cV2JwtVerifiableCredential) return resolveJwtSigner(agentContext, {
88
+ alg: credential.jwt.header.alg,
89
+ kid: credential.jwt.header.kid,
90
+ iss: credential.jwt.payload.iss ?? credential.resolvedCredential.issuerId,
91
+ purpose
92
+ });
93
+ if (credential instanceof W3cV2JwtVerifiablePresentation) return resolveJwtSigner(agentContext, {
94
+ alg: credential.jwt.header.alg,
95
+ kid: credential.jwt.header.kid,
96
+ iss: credential.jwt.payload.iss ?? credential.resolvedPresentation.holderId,
97
+ purpose
98
+ });
99
+ if (credential instanceof W3cV2SdJwtVerifiableCredential) return resolveJwtSigner(agentContext, {
100
+ alg: credential.sdJwt.header.alg,
101
+ kid: credential.sdJwt.header.kid,
102
+ iss: credential.sdJwt.payload.iss ?? credential.resolvedCredential.issuerId,
103
+ purpose
104
+ });
105
+ return resolveJwtSigner(agentContext, {
106
+ alg: credential.sdJwt.header.alg,
107
+ kid: credential.sdJwt.header.kid,
108
+ iss: credential.sdJwt.payload.iss ?? credential.resolvedPresentation.holderId,
109
+ purpose
110
+ });
112
111
  }
113
112
  //#endregion
114
- export { extractHolderFromPresentationCredentials, getVerificationMethodForJwt, validateAndResolveVerificationMethod };
113
+ export { extractHolderFromPresentationCredentials, getSignerForJwt, validateAndResolveVerificationMethod };
115
114
 
116
115
  //# sourceMappingURL=v2-jwt-utils.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"v2-jwt-utils.mjs","names":[],"sources":["../../../src/modules/vc/v2-jwt-utils.ts"],"sourcesContent":["import { AgentContext } from '../../agent'\nimport { CredoError } from '../../error'\nimport { asArray, isDid } from '../../utils'\nimport {\n type DidPurpose,\n DidResolverService,\n DidsApi,\n getPublicJwkFromVerificationMethod,\n parseDid,\n VerificationMethod,\n} from '../dids'\nimport { getSupportedVerificationMethodTypesForPublicJwk } from '../dids/domain/key-type/keyDidMapping'\nimport { type KnownJwaSignatureAlgorithm, PublicJwk } from '../kms'\nimport { extractKeyFromHolderBinding, parseHolderBindingFromCredential } from '../sd-jwt-vc/utils'\nimport { W3cV2JwtVerifiableCredential } from './jwt-vc/W3cV2JwtVerifiableCredential'\nimport { W3cV2JwtVerifiablePresentation } from './jwt-vc/W3cV2JwtVerifiablePresentation'\nimport { W3cV2EnvelopedVerifiableCredential } from './models/credential/W3cV2EnvelopedVerifiableCredential'\nimport type { W3cV2Presentation } from './models/presentation/W3cV2Presentation'\nimport { W3cV2SdJwtVerifiableCredential } from './sd-jwt-vc/W3cV2SdJwtVerifiableCredential'\nimport { W3cV2SdJwtVerifiablePresentation } from './sd-jwt-vc/W3cV2SdJwtVerifiablePresentation'\n\nexport async function validateAndResolveVerificationMethod(\n agentContext: AgentContext,\n verificationMethod: string,\n allowsPurposes?: DidPurpose[]\n) {\n if (!isDid(verificationMethod)) {\n throw new CredoError('Only did identifiers are supported as verification method')\n }\n\n const parsedDid = parseDid(verificationMethod)\n if (!parsedDid.fragment) {\n throw new CredoError(`didUrl '${parsedDid.didUrl}' does not contain a '#'. Unable to derive key from did document`)\n }\n\n const dids = agentContext.resolve(DidsApi)\n const { didDocument, keys } = await dids.resolveCreatedDidDocumentWithKeys(parsedDid.did)\n const verificationMethodObject = didDocument.dereferenceKey(verificationMethod, allowsPurposes)\n const publicJwk = getPublicJwkFromVerificationMethod(verificationMethodObject)\n\n publicJwk.keyId =\n keys?.find(({ didDocumentRelativeKeyId }) => verificationMethodObject.id.endsWith(didDocumentRelativeKeyId))\n ?.kmsKeyId ?? publicJwk.legacyKeyId\n\n return publicJwk\n}\n\nexport async function extractHolderFromPresentationCredentials(\n agentContext: AgentContext,\n presentation: W3cV2Presentation\n) {\n const credentials = asArray(presentation.verifiableCredential)\n\n const holderDid = presentation.holderId\n if (holderDid) {\n if (!isDid(holderDid)) {\n throw new CredoError(`Presentation holder '${holderDid}' is not a valid did`)\n }\n\n const dids = agentContext.resolve(DidsApi)\n const { didDocument, keys } = await dids.resolveCreatedDidDocumentWithKeys(holderDid)\n\n const authenticationMethods = didDocument.findVerificationMethodsByPurpose(['authentication'])\n\n const candidateMethods = authenticationMethods.filter((method) =>\n keys?.some(({ didDocumentRelativeKeyId }) => method.id.endsWith(didDocumentRelativeKeyId))\n )\n\n if (candidateMethods.length === 0) {\n throw new CredoError(\n `Unable to determine signer key for presentation holder '${holderDid}'. No locally controlled authentication verification method found.`\n )\n }\n\n if (candidateMethods.length > 1) {\n throw new CredoError(\n `Unable to deterministically resolve signer key for presentation holder '${holderDid}'. Multiple locally controlled authentication verification methods found.`\n )\n }\n\n const selectedMethod = candidateMethods[0]\n const publicJwk = getPublicJwkFromVerificationMethod(selectedMethod)\n publicJwk.keyId =\n keys?.find(({ didDocumentRelativeKeyId }) => selectedMethod.id.endsWith(didDocumentRelativeKeyId))?.kmsKeyId ??\n publicJwk.legacyKeyId\n\n const [alg] = publicJwk.supportedSignatureAlgorithms\n if (!alg) {\n throw new CredoError(\n `No supported JWA signature algorithms found for holder verification method '${selectedMethod.id}'`\n )\n }\n\n return {\n alg,\n publicJwk,\n cnf: {\n kid: selectedMethod.id,\n },\n }\n }\n\n const fallbackHolders: Array<Awaited<ReturnType<typeof extractKeyFromHolderBinding>>> = []\n\n for (const credential of credentials) {\n if (!(credential instanceof W3cV2EnvelopedVerifiableCredential)) continue\n\n let claims: Record<string, unknown>\n if (credential.envelopedCredential instanceof W3cV2SdJwtVerifiableCredential) {\n claims = credential.envelopedCredential.sdJwt.prettyClaims\n } else if (credential.envelopedCredential instanceof W3cV2JwtVerifiableCredential) {\n claims = credential.envelopedCredential.jwt.payload.toJson()\n } else {\n continue\n }\n\n const holderBinding = parseHolderBindingFromCredential(claims)\n if (!holderBinding) continue\n\n fallbackHolders.push(await extractKeyFromHolderBinding(agentContext, holderBinding, { forSigning: true }))\n }\n\n if (fallbackHolders.length === 0) {\n throw new CredoError('Unable to determine signer from presentation credentials, and presentation.holder is missing')\n }\n\n const uniqueFallbackHolders = new Map(fallbackHolders.map((holder) => [holder.publicJwk.fingerprint, holder]))\n if (uniqueFallbackHolders.size > 1) {\n throw new CredoError(\n 'Unable to determine signer from presentation credentials. Multiple distinct holder bindings found and presentation.holder is missing.'\n )\n }\n\n return uniqueFallbackHolders.values().next().value as Awaited<ReturnType<typeof extractKeyFromHolderBinding>>\n}\n\n/**\n * This method tries to find the verification method associated with the JWT credential or presentation.\n * This verification method can then be used to verify the credential or presentation signature.\n */\nexport async function getVerificationMethodForJwt(\n agentContext: AgentContext,\n credential:\n | W3cV2JwtVerifiableCredential\n | W3cV2JwtVerifiablePresentation\n | W3cV2SdJwtVerifiableCredential\n | W3cV2SdJwtVerifiablePresentation,\n purpose?: DidPurpose[]\n) {\n let alg: KnownJwaSignatureAlgorithm\n let kid: string | undefined\n let iss: string | undefined\n\n // Determine the algorithm, kid and iss based on the type of credential / presentation\n if (credential instanceof W3cV2JwtVerifiableCredential) {\n alg = credential.jwt.header.alg as KnownJwaSignatureAlgorithm\n kid = credential.jwt.header.kid\n iss = credential.jwt.payload.iss ?? credential.resolvedCredential.issuerId\n } else if (credential instanceof W3cV2JwtVerifiablePresentation) {\n alg = credential.jwt.header.alg as KnownJwaSignatureAlgorithm\n kid = credential.jwt.header.kid\n iss = credential.jwt.payload.iss ?? credential.resolvedPresentation.holderId\n } else if (credential instanceof W3cV2SdJwtVerifiableCredential) {\n alg = credential.sdJwt.header.alg as KnownJwaSignatureAlgorithm\n kid = credential.sdJwt.header.kid\n iss = credential.sdJwt.payload.iss ?? credential.resolvedCredential.issuerId\n } else {\n alg = credential.sdJwt.header.alg as KnownJwaSignatureAlgorithm\n kid = credential.sdJwt.header.kid\n iss = credential.sdJwt.payload.iss ?? credential.resolvedPresentation.holderId\n }\n\n const didResolver = agentContext.dependencyManager.resolve(DidResolverService)\n let verificationMethod: VerificationMethod\n\n // If the kid starts with # we assume it is a relative did url, and we resolve\n //it based on the `iss` and the `kid`\n if (kid?.startsWith('#')) {\n if (!iss || !isDid(iss)) {\n throw new CredoError(`JWT 'iss' MUST be a did when 'kid' is a relative did url`)\n }\n\n const didDocument = await didResolver.resolveDidDocument(agentContext, iss)\n verificationMethod = didDocument.dereferenceKey(`${iss}${kid}`, purpose)\n } else if (kid && isDid(kid)) {\n const didDocument = await didResolver.resolveDidDocument(agentContext, kid)\n verificationMethod = didDocument.dereferenceKey(kid, purpose)\n\n if (iss && didDocument.id !== iss) {\n throw new CredoError(`kid '${kid}' does not match id of signer (holder/issuer) '${iss}'`)\n }\n } else {\n if (!iss) {\n throw new CredoError(`JWT 'iss' MUST be present in payload when no 'kid' is specified`)\n }\n\n // Find the verificationMethod in the did document based on the alg and proofPurpose\n const jwkClass = PublicJwk.supportedPublicJwkClassForSignatureAlgorithm(alg)\n const supportedVerificationMethodTypes = getSupportedVerificationMethodTypesForPublicJwk(jwkClass)\n\n const didDocument = await didResolver.resolveDidDocument(agentContext, iss)\n const verificationMethods = didDocument.findVerificationMethodsByTypeAndPurpose(supportedVerificationMethodTypes, [\n 'assertionMethod',\n ])\n\n if (verificationMethods.length === 0) {\n throw new CredoError(\n `No verification methods found for signer '${iss}' and key type '${jwkClass.name}' for alg '${alg}'. Unable to determine which public key is associated with the credential.`\n )\n }\n if (verificationMethods.length > 1) {\n throw new CredoError(\n `Multiple verification methods found for signer '${iss}' and key type '${jwkClass.name}' for alg '${alg}'. Unable to determine which public key is associated with the credential.`\n )\n }\n\n verificationMethod = verificationMethods[0]\n }\n\n // Verify the controller of the verificationMethod matches the signer of the credential\n if (iss && verificationMethod.controller !== iss) {\n throw new CredoError(\n `Verification method controller '${verificationMethod.controller}' does not match the signer '${iss}'`\n )\n }\n\n return verificationMethod\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"v2-jwt-utils.mjs","names":[],"sources":["../../../src/modules/vc/v2-jwt-utils.ts"],"sourcesContent":["import { AgentContext } from '../../agent'\nimport { CredoError } from '../../error'\nimport { asArray, isDid } from '../../utils'\nimport { type DidPurpose, DidsApi, getPublicJwkFromVerificationMethod, parseDid } from '../dids'\nimport { type KnownJwaSignatureAlgorithm } from '../kms'\nimport { extractKeyFromHolderBinding, parseHolderBindingFromCredential } from '../sd-jwt-vc/utils'\nimport { W3cV2JwtVerifiableCredential } from './jwt-vc/W3cV2JwtVerifiableCredential'\nimport { W3cV2JwtVerifiablePresentation } from './jwt-vc/W3cV2JwtVerifiablePresentation'\nimport { W3cV2EnvelopedVerifiableCredential } from './models/credential/W3cV2EnvelopedVerifiableCredential'\nimport type { W3cV2Presentation, W3cV2PresentationCredentialEntry } from './models/presentation/W3cV2Presentation'\nimport { resolveJwtSigner } from './resolveSigner'\nimport { W3cV2SdJwtVerifiableCredential } from './sd-jwt-vc/W3cV2SdJwtVerifiableCredential'\nimport { W3cV2SdJwtVerifiablePresentation } from './sd-jwt-vc/W3cV2SdJwtVerifiablePresentation'\n\nexport async function validateAndResolveVerificationMethod(\n agentContext: AgentContext,\n verificationMethod: string,\n allowsPurposes?: DidPurpose[]\n) {\n if (!isDid(verificationMethod)) {\n throw new CredoError('Only did identifiers are supported as verification method')\n }\n\n const parsedDid = parseDid(verificationMethod)\n if (!parsedDid.fragment) {\n throw new CredoError(`didUrl '${parsedDid.didUrl}' does not contain a '#'. Unable to derive key from did document`)\n }\n\n const dids = agentContext.resolve(DidsApi)\n const { didDocument, keys } = await dids.resolveCreatedDidDocumentWithKeys(parsedDid.did)\n const verificationMethodObject = didDocument.dereferenceKey(verificationMethod, allowsPurposes)\n const publicJwk = getPublicJwkFromVerificationMethod(verificationMethodObject)\n\n publicJwk.keyId =\n keys?.find(({ didDocumentRelativeKeyId }) => verificationMethodObject.id.endsWith(didDocumentRelativeKeyId))\n ?.kmsKeyId ?? publicJwk.legacyKeyId\n\n return publicJwk\n}\n\nexport async function extractHolderFromPresentationCredentials(\n agentContext: AgentContext,\n presentation: W3cV2Presentation\n) {\n const credentials = asArray(presentation.verifiableCredential)\n\n const holderDid = presentation.holderId\n if (holderDid) {\n if (!isDid(holderDid)) {\n throw new CredoError(`Presentation holder '${holderDid}' is not a valid did`)\n }\n\n const dids = agentContext.resolve(DidsApi)\n const { didDocument, keys } = await dids.resolveCreatedDidDocumentWithKeys(holderDid)\n\n const authenticationMethods = didDocument.findVerificationMethodsByPurpose(['authentication'])\n\n let candidateMethods = authenticationMethods.filter((method) =>\n keys?.some(({ didDocumentRelativeKeyId }) => method.id.endsWith(didDocumentRelativeKeyId))\n )\n\n if (candidateMethods.length === 0) {\n throw new CredoError(\n `Unable to determine signer key for presentation holder '${holderDid}'. No locally controlled authentication verification method found.`\n )\n }\n\n if (candidateMethods.length > 1) {\n // Pick the key the credentials are bound to\n const credentialHolders = await getCredentialHolders(agentContext, credentials, {\n didPurposes: ['authentication'],\n })\n const boundMethods = candidateMethods.filter((method) => {\n const publicJwk = getPublicJwkFromVerificationMethod(method)\n return credentialHolders.some((holder) => holder.publicJwk.equals(publicJwk))\n })\n\n if (boundMethods.length === 0) {\n throw new CredoError(\n `Unable to deterministically resolve signer key for presentation holder '${holderDid}'. Multiple locally controlled authentication verification methods found, and the presentation credentials are not bound to any of them.`\n )\n }\n\n if (boundMethods.length > 1) {\n throw new CredoError(\n `Unable to deterministically resolve signer key for presentation holder '${holderDid}'. Multiple locally controlled authentication verification methods found, and the presentation credentials are bound to more than one of them.`\n )\n }\n\n candidateMethods = boundMethods\n }\n\n const selectedMethod = candidateMethods[0]\n const publicJwk = getPublicJwkFromVerificationMethod(selectedMethod)\n publicJwk.keyId =\n keys?.find(({ didDocumentRelativeKeyId }) => selectedMethod.id.endsWith(didDocumentRelativeKeyId))?.kmsKeyId ??\n publicJwk.legacyKeyId\n\n const [alg] = publicJwk.supportedSignatureAlgorithms\n if (!alg) {\n throw new CredoError(\n `No supported JWA signature algorithms found for holder verification method '${selectedMethod.id}'`\n )\n }\n\n return {\n alg,\n publicJwk,\n cnf: {\n kid: selectedMethod.id,\n },\n }\n }\n\n const credentialHolders = await getCredentialHolders(agentContext, credentials, { forSigning: true })\n if (credentialHolders.length === 0) {\n throw new CredoError('Unable to determine signer from presentation credentials, and presentation.holder is missing')\n }\n\n if (credentialHolders.length > 1) {\n throw new CredoError(\n 'Unable to determine signer from presentation credentials. Multiple distinct holder bindings found and presentation.holder is missing.'\n )\n }\n\n return credentialHolders[0]\n}\n\n/**\n * Returns the distinct keys that the credentials are bound to with `cnf`.\n */\nasync function getCredentialHolders(\n agentContext: AgentContext,\n credentials: W3cV2PresentationCredentialEntry[],\n options: Parameters<typeof extractKeyFromHolderBinding>[2]\n) {\n const holders = new Map<string, Awaited<ReturnType<typeof extractKeyFromHolderBinding>>>()\n\n for (const credential of credentials) {\n if (!(credential instanceof W3cV2EnvelopedVerifiableCredential)) continue\n\n let claims: Record<string, unknown>\n if (credential.envelopedCredential instanceof W3cV2SdJwtVerifiableCredential) {\n claims = credential.envelopedCredential.sdJwt.prettyClaims\n } else if (credential.envelopedCredential instanceof W3cV2JwtVerifiableCredential) {\n claims = credential.envelopedCredential.jwt.payload.toJson()\n } else {\n continue\n }\n\n const holderBinding = parseHolderBindingFromCredential(claims)\n if (!holderBinding) continue\n\n const holder = await extractKeyFromHolderBinding(agentContext, holderBinding, options)\n holders.set(holder.publicJwk.fingerprint, holder)\n }\n\n return Array.from(holders.values())\n}\n\n/**\n * Resolves the signer of a JWT credential or presentation. When no `iss` is present, the `issuer`\n * of a credential or the `holder` of a presentation must be the signer.\n */\nexport async function getSignerForJwt(\n agentContext: AgentContext,\n credential:\n | W3cV2JwtVerifiableCredential\n | W3cV2JwtVerifiablePresentation\n | W3cV2SdJwtVerifiableCredential\n | W3cV2SdJwtVerifiablePresentation,\n purpose: DidPurpose[]\n) {\n if (credential instanceof W3cV2JwtVerifiableCredential) {\n return resolveJwtSigner(agentContext, {\n alg: credential.jwt.header.alg as KnownJwaSignatureAlgorithm,\n kid: credential.jwt.header.kid,\n iss: credential.jwt.payload.iss ?? credential.resolvedCredential.issuerId,\n purpose,\n })\n }\n if (credential instanceof W3cV2JwtVerifiablePresentation) {\n return resolveJwtSigner(agentContext, {\n alg: credential.jwt.header.alg as KnownJwaSignatureAlgorithm,\n kid: credential.jwt.header.kid,\n iss: credential.jwt.payload.iss ?? credential.resolvedPresentation.holderId,\n purpose,\n })\n }\n if (credential instanceof W3cV2SdJwtVerifiableCredential) {\n return resolveJwtSigner(agentContext, {\n alg: credential.sdJwt.header.alg as KnownJwaSignatureAlgorithm,\n kid: credential.sdJwt.header.kid,\n iss: credential.sdJwt.payload.iss ?? credential.resolvedCredential.issuerId,\n purpose,\n })\n }\n return resolveJwtSigner(agentContext, {\n alg: credential.sdJwt.header.alg as KnownJwaSignatureAlgorithm,\n kid: credential.sdJwt.header.kid,\n iss: credential.sdJwt.payload.iss ?? credential.resolvedPresentation.holderId,\n purpose,\n })\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { X509Certificate } from "./X509Certificate.mjs";
2
- import { X509RevocationCheckOptions } from "./X509ValidationOptions.mjs";
2
+ import { X509RevocationCheckOptions, X509RevocationCheckOptionsWithDefaults } from "./X509ValidationOptions.mjs";
3
3
  import { SdJwtVc } from "../sd-jwt-vc/SdJwtVcService.mjs";
4
4
  import { JwtPayload } from "../../crypto/jose/jwt/JwtPayload.mjs";
5
5
  import { W3cJwtVerifiableCredential } from "../vc/jwt-vc/W3cJwtVerifiableCredential.mjs";
@@ -100,17 +100,9 @@ export interface X509ModuleConfigOptions {
100
100
  */
101
101
  getTrustedCertificatesForVerification?(agentContext: AgentContext, verificationContext: X509VerificationContext): Promise<string[] | undefined | X509VerificationTrustedCertificates[]> | string[] | X509VerificationTrustedCertificates[] | undefined;
102
102
  /**
103
- * Configuration for certificate revocation checking
104
- * @default
105
- * ```
106
- * {
107
- * mode: X509RevocationCheckMode.SoftFail, // do not fail on network error
108
- * checkFullChain: true, // check the leaf and all intermediate CAs
109
- * timeoutMs: 5000, // 5 seconds
110
- * maxCrlSizeBytes: 10485760, // 10MB
111
- * crlCacheExpirySeconds: 3600 // 1 hour
112
- * }
113
- * ```
103
+ * Configuration for certificate revocation checking. Options that are not set use
104
+ * {@link defaultX509RevocationCheckOptions}: `SoftFail` (do not fail on network error) for the
105
+ * leaf and all intermediate CAs, a 5 second timeout, a 10 MB CRL size limit and a 1 hour cache.
114
106
  */
115
107
  revocationCheck?: X509RevocationCheckOptions;
116
108
  }
@@ -126,7 +118,7 @@ export declare class X509ModuleConfig {
126
118
  * @deprecated use the global `getTrustedIssuersForVerification` instead
127
119
  */
128
120
  setTrustedCertificatesForVerification(fn: X509ModuleConfigOptions['getTrustedCertificatesForVerification']): void;
129
- get revocationCheck(): X509RevocationCheckOptions | undefined;
121
+ get revocationCheck(): X509RevocationCheckOptionsWithDefaults;
130
122
  setRevocationCheck(options?: X509RevocationCheckOptions): void;
131
123
  setTrustedCertificates(trustedCertificates?: Array<string | X509Certificate>): void;
132
124
  addTrustedCertificate(trustedCertificate: string | X509Certificate): void;
@@ -1 +1 @@
1
- {"version":3,"file":"X509ModuleConfig.d.mts","names":[],"sources":["../../../src/modules/x509/X509ModuleConfig.ts"],"mappings":";;;;;;;;;;YAUY;EACV;EACA;;YAGU;EACV;EACA,YAAY,UAAU,OAAO,6BAA6B;;;;EAK1D;;;;EAKA;;;;;;;;;YAUU,qCAAqC;YAKrC;EACV;EACA;IACE;IACA,SAAS;;;YAID;EACV;;;;;EAOA;EAGA;IACE;IACA,SAAS;;;YAID;EACV;EAGA;IACE;IACA,SAAS;;;YAID;EACV;;;;;EAOA;EAGA;IACE;IACA,SAAS;;;iBAII;;;;;;;;EAQf,kBAAkB;EAElB,cACI,iCACA,qCACA,wDACA,8CACA,+CACA;;iBAGW;;;;;EAKf,sBAAsB,eAAe;;;;;;;;;;;;EAarC,uCACE,cAAc,cACd,qBAAqB,0BAEnB,+BAA+B,oDAE/B;;;;;;;;;;;;;;EAgBJ,kBAAkB;;qBAGP;;EAKQ,YAAA,UAAU;MAUlB;;;;MASA,2CAAqC,cAhDhC,cAAY,qBACL,4BAEnB,+BAA+B,oDAE/B;;;;EAkDG,sCAAsC,IAAI;MAItC,mBAAmB;EAIvB,mBAAmB,UAAU;EAI7B,uBAAuB,sBAAsB,eAAe;EAS5D,sBAAsB,6BAA6B"}
1
+ {"version":3,"file":"X509ModuleConfig.d.mts","names":[],"sources":["../../../src/modules/x509/X509ModuleConfig.ts"],"mappings":";;;;;;;;;;YAcY;EACV;EACA;;YAGU;EACV;EACA,YAAY,UAAU,OAAO,6BAA6B;;;;EAK1D;;;;EAKA;;;;;;;;;YAUU,qCAAqC;YAKrC;EACV;EACA;IACE;IACA,SAAS;;;YAID;EACV;;;;;EAOA;EAGA;IACE;IACA,SAAS;;;YAID;EACV;EAGA;IACE;IACA,SAAS;;;YAID;EACV;;;;;EAOA;EAGA;IACE;IACA,SAAS;;;iBAII;;;;;;;;EAQf,kBAAkB;EAElB,cACI,iCACA,qCACA,wDACA,8CACA,+CACA;;iBAGW;;;;;EAKf,sBAAsB,eAAe;;;;;;;;;;;;EAarC,uCACE,cAAc,cACd,qBAAqB,0BAEnB,+BAA+B,oDAE/B;;;;;;EAQJ,kBAAkB;;qBAGP;;EAKQ,YAAA,UAAU;MAUlB;;;;MASA,2CAAqC,cAxChC,cAAY,qBACL,4BAEnB,+BAA+B,oDAE/B;;;;EA0CG,sCAAsC,IAAI;MAItC,mBAAmB;EAIvB,mBAAmB,UAAU;EAI7B,uBAAuB,sBAAsB,eAAe;EAS5D,sBAAsB,6BAA6B"}
@@ -2,6 +2,7 @@ import _classPrivateFieldInitSpec from "../../_virtual/_@oxc-project_runtime@0.1
2
2
  import _classPrivateFieldGet2 from "../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/classPrivateFieldGet2.mjs";
3
3
  import _classPrivateFieldSet2 from "../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/classPrivateFieldSet2.mjs";
4
4
  import { X509Certificate } from "./X509Certificate.mjs";
5
+ import { withX509RevocationCheckDefaults } from "./X509ValidationOptions.mjs";
5
6
  //#region src/modules/x509/X509ModuleConfig.ts
6
7
  var _trustedCertificates = /* @__PURE__ */ new WeakMap();
7
8
  var _getTrustedCertificatesForVerification = /* @__PURE__ */ new WeakMap();
@@ -31,7 +32,7 @@ var X509ModuleConfig = class {
31
32
  _classPrivateFieldSet2(_getTrustedCertificatesForVerification, this, fn);
32
33
  }
33
34
  get revocationCheck() {
34
- return _classPrivateFieldGet2(_revocationCheck, this);
35
+ return withX509RevocationCheckDefaults(_classPrivateFieldGet2(_revocationCheck, this));
35
36
  }
36
37
  setRevocationCheck(options) {
37
38
  _classPrivateFieldSet2(_revocationCheck, this, options);
@@ -1 +1 @@
1
- {"version":3,"file":"X509ModuleConfig.mjs","names":[],"sources":["../../../src/modules/x509/X509ModuleConfig.ts"],"sourcesContent":["import type { AgentContext } from '../../agent/context/AgentContext'\nimport type { VerificationTypeMdocReaderAuth } from '../../agent/TrustedIssuersForVerification'\nimport type { JwtPayload } from '../../crypto/jose/jwt/JwtPayload'\nimport type { Mdoc } from '../mdoc/Mdoc'\nimport type { SdJwtVc } from '../sd-jwt-vc/SdJwtVcService'\nimport type { W3cJwtVerifiableCredential } from '../vc/jwt-vc/W3cJwtVerifiableCredential'\nimport type { W3cJwtVerifiablePresentation } from '../vc/jwt-vc/W3cJwtVerifiablePresentation'\nimport { X509Certificate } from './X509Certificate'\nimport { type X509RevocationCheckOptions } from './X509ValidationOptions'\n\nexport type X509VerificationTrustedCertificates = {\n issuance: string[]\n status?: string[]\n}\n\nexport type X509VerificationTypeCredential = {\n type: 'credential'\n credential: SdJwtVc | Mdoc | W3cJwtVerifiableCredential | W3cJwtVerifiablePresentation\n\n /**\n * The `id` of the `DidCommProofRecord` that this verification is bound to.\n */\n didcommProofRecordId?: string\n\n /**\n * The `id` of the `OpenId4VcVerificationSessionRecord` that this verification is bound to.\n */\n openId4VcVerificationSessionId?: string\n}\n\n/**\n * Reader authentication on an incoming mdoc request.\n *\n * There is no separate legacy shape for this verification type: reader authentication is only\n * resolved on the DC API paths that were added after this callback was deprecated, so the type of\n * the `getTrustedIssuersForVerification` callback is reused as-is.\n */\nexport type X509VerificationTypeMdocReaderAuth = VerificationTypeMdocReaderAuth\n\n// NOTE: we should probably move these to the OpenID4VC module\n// but have to think about the typing. Probably the base interface should just contain\n// the `verification` with a `type`. And extension modules can extend the verification\nexport type X509VerificationTypeOauth2SecuredAuthorizationRequest = {\n type: 'oauth2SecuredAuthorizationRequest'\n authorizationRequest: {\n jwt: string\n payload: JwtPayload\n }\n}\n\nexport type X509VerificationTypeOpenId4VciKeyAttestation = {\n type: 'openId4VciKeyAttestation'\n\n /**\n * The `id` of the `OpenId4VcIssuanceSessionRecord` that this key\n * attestation verification is bound to.\n */\n // TODO: should be the record, but we don't have access to the record type here.\n openId4VcIssuanceSessionId: string\n\n // NOTE: it would be more helpful to have the typed JWT payload from openid4vc here?\n keyAttestation: {\n jwt: string\n payload: JwtPayload\n }\n}\n\nexport type X509VerificationTypeOpenId4VciCredentialIssuerMetadata = {\n type: 'openId4VciCredentialIssuerMetadata'\n\n // NOTE: it would be more helpful to have the typed JWT payload from openid4vc here?\n credentialIssuerMetadata: {\n jwt: string\n payload: JwtPayload\n }\n}\n\nexport type X509VerificationTypeOauth2ClientAttestation = {\n type: 'oauth2ClientAttestation'\n\n /**\n * The `id` of the `OpenId4VcIssuanceSessionRecord` that this client\n * attestation verification is bound to.\n */\n // TODO: should be the record, but we don't have access to the record type here.\n openId4VcIssuanceSessionId: string\n\n // NOTE: it would be more helpful to have the typed JWT payload from openid4vc here?\n clientAttestation: {\n jwt: string\n payload: JwtPayload\n }\n}\n\nexport interface X509VerificationContext {\n /**\n * The certificate chain provided with the data to be verified. The trusted certificates\n * are determined before verification and thus it is not verified that the data was actually\n * signed by the private key associated with the leaf certificate in the certificate chain, or\n * whether the certificate chain is valid. However if the certificate\n * does not match, or is not valid, verification will always fail at a later stage\n */\n certificateChain: X509Certificate[]\n\n verification:\n | X509VerificationTypeCredential\n | X509VerificationTypeMdocReaderAuth\n | X509VerificationTypeOauth2SecuredAuthorizationRequest\n | X509VerificationTypeOauth2ClientAttestation\n | X509VerificationTypeOpenId4VciKeyAttestation\n | X509VerificationTypeOpenId4VciCredentialIssuerMetadata\n}\n\nexport interface X509ModuleConfigOptions {\n /**\n *\n * Array of trusted base64-encoded certificate strings in the DER-format.\n */\n trustedCertificates?: Array<string | X509Certificate>\n\n /**\n * Optional callback method that will be called to dynamically get trusted certificates for a verification.\n * It will provide the `agentContext` and `verificationContext` allowing to dynamically set the trusted certificates\n * for a tenant or verification context.\n *\n * If no certificates should be trusted an empty array should be returned. If `undefined` is returned\n * it will fallback to the globally registered trusted certificates\n *\n * @deprecated use the global `getTrustedIssuersForVerification` instead\n * @returns An array of base64-encoded certificate strings or PEM certificate strings.\n */\n getTrustedCertificatesForVerification?(\n agentContext: AgentContext,\n verificationContext: X509VerificationContext\n ):\n | Promise<string[] | undefined | X509VerificationTrustedCertificates[]>\n | string[]\n | X509VerificationTrustedCertificates[]\n | undefined\n\n /**\n * Configuration for certificate revocation checking\n * @default\n * ```\n * {\n * mode: X509RevocationCheckMode.SoftFail, // do not fail on network error\n * checkFullChain: true, // check the leaf and all intermediate CAs\n * timeoutMs: 5000, // 5 seconds\n * maxCrlSizeBytes: 10485760, // 10MB\n * crlCacheExpirySeconds: 3600 // 1 hour\n * }\n * ```\n */\n revocationCheck?: X509RevocationCheckOptions\n}\n\nexport class X509ModuleConfig {\n #trustedCertificates?: X509Certificate[]\n #getTrustedCertificatesForVerification?: X509ModuleConfigOptions['getTrustedCertificatesForVerification']\n #revocationCheck?: X509RevocationCheckOptions\n\n public constructor(options?: X509ModuleConfigOptions) {\n this.setTrustedCertificates(options?.trustedCertificates)\n if (options?.getTrustedCertificatesForVerification) {\n this.setTrustedCertificatesForVerification(options.getTrustedCertificatesForVerification)\n }\n if (options?.revocationCheck) {\n this.#revocationCheck = options.revocationCheck\n }\n }\n\n public get trustedCertificates() {\n // TODO: we should probably update this API to return the instances, but don't want to\n // break too much now\n return this.#trustedCertificates?.map((cert) => cert.toString('pem'))\n }\n\n /**\n * @deprecated use the global `getTrustedIssuersForVerification` instead\n */\n public get getTrustedCertificatesForVerification() {\n return this.#getTrustedCertificatesForVerification\n }\n\n /**\n * @deprecated use the global `getTrustedIssuersForVerification` instead\n */\n public setTrustedCertificatesForVerification(fn: X509ModuleConfigOptions['getTrustedCertificatesForVerification']) {\n this.#getTrustedCertificatesForVerification = fn\n }\n\n public get revocationCheck(): X509RevocationCheckOptions | undefined {\n return this.#revocationCheck\n }\n\n public setRevocationCheck(options?: X509RevocationCheckOptions) {\n this.#revocationCheck = options\n }\n\n public setTrustedCertificates(trustedCertificates?: Array<string | X509Certificate>) {\n const certificateInstances = trustedCertificates?.map((trustedCertificate) =>\n typeof trustedCertificate === 'string'\n ? X509Certificate.fromEncodedCertificate(trustedCertificate)\n : trustedCertificate\n )\n this.#trustedCertificates = trustedCertificates?.length ? certificateInstances : undefined\n }\n\n public addTrustedCertificate(trustedCertificate: string | X509Certificate) {\n const certificateInstance =\n typeof trustedCertificate === 'string'\n ? X509Certificate.fromEncodedCertificate(trustedCertificate)\n : trustedCertificate\n\n if (!this.#trustedCertificates) {\n this.#trustedCertificates = []\n }\n\n this.#trustedCertificates.push(certificateInstance)\n }\n}\n"],"mappings":";;;;;;;;AA4JA,IAAa,mBAAb,MAA8B;CAK5B,YAAmB,SAAmC;;;;EACpD,KAAK,uBAAuB,SAAS,mBAAmB;EACxD,IAAI,SAAS,uCACX,KAAK,sCAAsC,QAAQ,qCAAqC;EAE1F,IAAI,SAAS,iBACX,uBAAA,kBAAA,MAAwB,QAAQ,eAAA;CAEpC;CAEA,IAAW,sBAAsB;EAG/B,OAAA,uBAAA,sBAAO,IAAA,CAAA,EAA2B,KAAK,SAAS,KAAK,SAAS,KAAK,CAAC;CACtE;;;;CAKA,IAAW,wCAAwC;EACjD,OAAA,uBAAA,wCAAO,IAAA;CACT;;;;CAKA,sCAA6C,IAAsE;EACjH,uBAAA,wCAAA,MAA8C,EAAA;CAChD;CAEA,IAAW,kBAA0D;EACnE,OAAA,uBAAA,kBAAO,IAAA;CACT;CAEA,mBAA0B,SAAsC;EAC9D,uBAAA,kBAAA,MAAwB,OAAA;CAC1B;CAEA,uBAA8B,qBAAuD;EACnF,MAAM,uBAAuB,qBAAqB,KAAK,uBACrD,OAAO,uBAAuB,WAC1B,gBAAgB,uBAAuB,kBAAkB,IACzD,kBACN;EACA,uBAAA,sBAAA,MAA4B,qBAAqB,SAAS,uBAAuB,KAAA,CAAA;CACnF;CAEA,sBAA6B,oBAA8C;EACzE,MAAM,sBACJ,OAAO,uBAAuB,WAC1B,gBAAgB,uBAAuB,kBAAkB,IACzD;EAEN,IAAI,CAAA,uBAAA,sBAAC,IAAA,GACH,uBAAA,sBAAA,MAA4B,CAAC,CAAA;EAG/B,uBAAA,sBAAA,IAAA,CAAA,CAA0B,KAAK,mBAAmB;CACpD;AACF"}
1
+ {"version":3,"file":"X509ModuleConfig.mjs","names":[],"sources":["../../../src/modules/x509/X509ModuleConfig.ts"],"sourcesContent":["import type { AgentContext } from '../../agent/context/AgentContext'\nimport type { VerificationTypeMdocReaderAuth } from '../../agent/TrustedIssuersForVerification'\nimport type { JwtPayload } from '../../crypto/jose/jwt/JwtPayload'\nimport type { Mdoc } from '../mdoc/Mdoc'\nimport type { SdJwtVc } from '../sd-jwt-vc/SdJwtVcService'\nimport type { W3cJwtVerifiableCredential } from '../vc/jwt-vc/W3cJwtVerifiableCredential'\nimport type { W3cJwtVerifiablePresentation } from '../vc/jwt-vc/W3cJwtVerifiablePresentation'\nimport { X509Certificate } from './X509Certificate'\nimport {\n withX509RevocationCheckDefaults,\n type X509RevocationCheckOptions,\n type X509RevocationCheckOptionsWithDefaults,\n} from './X509ValidationOptions'\n\nexport type X509VerificationTrustedCertificates = {\n issuance: string[]\n status?: string[]\n}\n\nexport type X509VerificationTypeCredential = {\n type: 'credential'\n credential: SdJwtVc | Mdoc | W3cJwtVerifiableCredential | W3cJwtVerifiablePresentation\n\n /**\n * The `id` of the `DidCommProofRecord` that this verification is bound to.\n */\n didcommProofRecordId?: string\n\n /**\n * The `id` of the `OpenId4VcVerificationSessionRecord` that this verification is bound to.\n */\n openId4VcVerificationSessionId?: string\n}\n\n/**\n * Reader authentication on an incoming mdoc request.\n *\n * There is no separate legacy shape for this verification type: reader authentication is only\n * resolved on the DC API paths that were added after this callback was deprecated, so the type of\n * the `getTrustedIssuersForVerification` callback is reused as-is.\n */\nexport type X509VerificationTypeMdocReaderAuth = VerificationTypeMdocReaderAuth\n\n// NOTE: we should probably move these to the OpenID4VC module\n// but have to think about the typing. Probably the base interface should just contain\n// the `verification` with a `type`. And extension modules can extend the verification\nexport type X509VerificationTypeOauth2SecuredAuthorizationRequest = {\n type: 'oauth2SecuredAuthorizationRequest'\n authorizationRequest: {\n jwt: string\n payload: JwtPayload\n }\n}\n\nexport type X509VerificationTypeOpenId4VciKeyAttestation = {\n type: 'openId4VciKeyAttestation'\n\n /**\n * The `id` of the `OpenId4VcIssuanceSessionRecord` that this key\n * attestation verification is bound to.\n */\n // TODO: should be the record, but we don't have access to the record type here.\n openId4VcIssuanceSessionId: string\n\n // NOTE: it would be more helpful to have the typed JWT payload from openid4vc here?\n keyAttestation: {\n jwt: string\n payload: JwtPayload\n }\n}\n\nexport type X509VerificationTypeOpenId4VciCredentialIssuerMetadata = {\n type: 'openId4VciCredentialIssuerMetadata'\n\n // NOTE: it would be more helpful to have the typed JWT payload from openid4vc here?\n credentialIssuerMetadata: {\n jwt: string\n payload: JwtPayload\n }\n}\n\nexport type X509VerificationTypeOauth2ClientAttestation = {\n type: 'oauth2ClientAttestation'\n\n /**\n * The `id` of the `OpenId4VcIssuanceSessionRecord` that this client\n * attestation verification is bound to.\n */\n // TODO: should be the record, but we don't have access to the record type here.\n openId4VcIssuanceSessionId: string\n\n // NOTE: it would be more helpful to have the typed JWT payload from openid4vc here?\n clientAttestation: {\n jwt: string\n payload: JwtPayload\n }\n}\n\nexport interface X509VerificationContext {\n /**\n * The certificate chain provided with the data to be verified. The trusted certificates\n * are determined before verification and thus it is not verified that the data was actually\n * signed by the private key associated with the leaf certificate in the certificate chain, or\n * whether the certificate chain is valid. However if the certificate\n * does not match, or is not valid, verification will always fail at a later stage\n */\n certificateChain: X509Certificate[]\n\n verification:\n | X509VerificationTypeCredential\n | X509VerificationTypeMdocReaderAuth\n | X509VerificationTypeOauth2SecuredAuthorizationRequest\n | X509VerificationTypeOauth2ClientAttestation\n | X509VerificationTypeOpenId4VciKeyAttestation\n | X509VerificationTypeOpenId4VciCredentialIssuerMetadata\n}\n\nexport interface X509ModuleConfigOptions {\n /**\n *\n * Array of trusted base64-encoded certificate strings in the DER-format.\n */\n trustedCertificates?: Array<string | X509Certificate>\n\n /**\n * Optional callback method that will be called to dynamically get trusted certificates for a verification.\n * It will provide the `agentContext` and `verificationContext` allowing to dynamically set the trusted certificates\n * for a tenant or verification context.\n *\n * If no certificates should be trusted an empty array should be returned. If `undefined` is returned\n * it will fallback to the globally registered trusted certificates\n *\n * @deprecated use the global `getTrustedIssuersForVerification` instead\n * @returns An array of base64-encoded certificate strings or PEM certificate strings.\n */\n getTrustedCertificatesForVerification?(\n agentContext: AgentContext,\n verificationContext: X509VerificationContext\n ):\n | Promise<string[] | undefined | X509VerificationTrustedCertificates[]>\n | string[]\n | X509VerificationTrustedCertificates[]\n | undefined\n\n /**\n * Configuration for certificate revocation checking. Options that are not set use\n * {@link defaultX509RevocationCheckOptions}: `SoftFail` (do not fail on network error) for the\n * leaf and all intermediate CAs, a 5 second timeout, a 10 MB CRL size limit and a 1 hour cache.\n */\n revocationCheck?: X509RevocationCheckOptions\n}\n\nexport class X509ModuleConfig {\n #trustedCertificates?: X509Certificate[]\n #getTrustedCertificatesForVerification?: X509ModuleConfigOptions['getTrustedCertificatesForVerification']\n #revocationCheck?: X509RevocationCheckOptions\n\n public constructor(options?: X509ModuleConfigOptions) {\n this.setTrustedCertificates(options?.trustedCertificates)\n if (options?.getTrustedCertificatesForVerification) {\n this.setTrustedCertificatesForVerification(options.getTrustedCertificatesForVerification)\n }\n if (options?.revocationCheck) {\n this.#revocationCheck = options.revocationCheck\n }\n }\n\n public get trustedCertificates() {\n // TODO: we should probably update this API to return the instances, but don't want to\n // break too much now\n return this.#trustedCertificates?.map((cert) => cert.toString('pem'))\n }\n\n /**\n * @deprecated use the global `getTrustedIssuersForVerification` instead\n */\n public get getTrustedCertificatesForVerification() {\n return this.#getTrustedCertificatesForVerification\n }\n\n /**\n * @deprecated use the global `getTrustedIssuersForVerification` instead\n */\n public setTrustedCertificatesForVerification(fn: X509ModuleConfigOptions['getTrustedCertificatesForVerification']) {\n this.#getTrustedCertificatesForVerification = fn\n }\n\n public get revocationCheck(): X509RevocationCheckOptionsWithDefaults {\n return withX509RevocationCheckDefaults(this.#revocationCheck)\n }\n\n public setRevocationCheck(options?: X509RevocationCheckOptions) {\n this.#revocationCheck = options\n }\n\n public setTrustedCertificates(trustedCertificates?: Array<string | X509Certificate>) {\n const certificateInstances = trustedCertificates?.map((trustedCertificate) =>\n typeof trustedCertificate === 'string'\n ? X509Certificate.fromEncodedCertificate(trustedCertificate)\n : trustedCertificate\n )\n this.#trustedCertificates = trustedCertificates?.length ? certificateInstances : undefined\n }\n\n public addTrustedCertificate(trustedCertificate: string | X509Certificate) {\n const certificateInstance =\n typeof trustedCertificate === 'string'\n ? X509Certificate.fromEncodedCertificate(trustedCertificate)\n : trustedCertificate\n\n if (!this.#trustedCertificates) {\n this.#trustedCertificates = []\n }\n\n this.#trustedCertificates.push(certificateInstance)\n }\n}\n"],"mappings":";;;;;;;;;AAwJA,IAAa,mBAAb,MAA8B;CAK5B,YAAmB,SAAmC;;;;EACpD,KAAK,uBAAuB,SAAS,mBAAmB;EACxD,IAAI,SAAS,uCACX,KAAK,sCAAsC,QAAQ,qCAAqC;EAE1F,IAAI,SAAS,iBACX,uBAAA,kBAAA,MAAwB,QAAQ,eAAA;CAEpC;CAEA,IAAW,sBAAsB;EAG/B,OAAA,uBAAA,sBAAO,IAAA,CAAA,EAA2B,KAAK,SAAS,KAAK,SAAS,KAAK,CAAC;CACtE;;;;CAKA,IAAW,wCAAwC;EACjD,OAAA,uBAAA,wCAAO,IAAA;CACT;;;;CAKA,sCAA6C,IAAsE;EACjH,uBAAA,wCAAA,MAA8C,EAAA;CAChD;CAEA,IAAW,kBAA0D;EACnE,OAAO,gCAAA,uBAAA,kBAAgC,IAAA,CAAqB;CAC9D;CAEA,mBAA0B,SAAsC;EAC9D,uBAAA,kBAAA,MAAwB,OAAA;CAC1B;CAEA,uBAA8B,qBAAuD;EACnF,MAAM,uBAAuB,qBAAqB,KAAK,uBACrD,OAAO,uBAAuB,WAC1B,gBAAgB,uBAAuB,kBAAkB,IACzD,kBACN;EACA,uBAAA,sBAAA,MAA4B,qBAAqB,SAAS,uBAAuB,KAAA,CAAA;CACnF;CAEA,sBAA6B,oBAA8C;EACzE,MAAM,sBACJ,OAAO,uBAAuB,WAC1B,gBAAgB,uBAAuB,kBAAkB,IACzD;EAEN,IAAI,CAAA,uBAAA,sBAAC,IAAA,GACH,uBAAA,sBAAA,MAA4B,CAAC,CAAA;EAG/B,uBAAA,sBAAA,IAAA,CAAA,CAA0B,KAAK,mBAAmB;CACpD;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"X509RevocationService.d.mts","names":[],"sources":["../../../src/modules/x509/X509RevocationService.ts"],"mappings":";;;;;;;;iBA0BiB;EACf;EACA;EACA,QAAQ;EACR;EACA;;qBAmBW;;;;SAIS,2BAClB,cAAc,gBACZ,aAAa,mBAAmB,0BAA0B,wCAC3D,QAAQ;;;;;;;;;;;;;SAqCS,gCAClB,cAAc,cACd,kBAAkB,mBAClB,QAAQ,kBACR,kBAAkB,OACjB,QAAQ;;;;;iBAkDU;;;;iBA4LN;;;;;iBAoBA;;;;iBAaA;;;;iBA0BM;;;;;;;iBAyDN;;;;;iBA2DM;;;;;;;;;;;;;;;;;;;iBAsEA;;;;;;;;;;iBAgDA;;;;;;;iBAuFN;;;;iBAaA;;;;;;;;;;;;SAsCK,+BAClB,cAAc,gBAEZ,KACA,mBACA,WACA,iBACA,oBACC,4CACF,QAAQ"}
1
+ {"version":3,"file":"X509RevocationService.d.mts","names":[],"sources":["../../../src/modules/x509/X509RevocationService.ts"],"mappings":";;;;;;;;iBA8BiB;EACf;EACA;EACA,QAAQ;EACR;EACA;;qBAaW;;;;SAIS,2BAClB,cAAc,gBACZ,aAAa,mBAAmB,0BAA0B,wCAC3D,QAAQ;;;;;;;;;;;;;SA2CS,gCAClB,cAAc,cACd,kBAAkB,mBAClB,QAAQ,kBACR,kBAAkB,OACjB,QAAQ;;;;;iBAkDU;;;;iBA2LN;;;;;iBAoBA;;;;iBAaA;;;;iBA0BM;;;;;;;iBAyDN;;;;;iBA2DM;;;;;;;;;;;;;;;;;;;iBAsEA;;;;;;;;;;iBAgDA;;;;;;;iBAkFN;;;;iBAaA;;;;;;;;;;;;SAsCK,+BAClB,cAAc,gBAEZ,KACA,mBACA,WACA,iBACA,oBACC,4CACF,QAAQ"}
@@ -4,7 +4,7 @@ import { CredoWebCrypto } from "../../crypto/webcrypto/CredoWebCrypto.mjs";
4
4
  import "../../crypto/webcrypto/index.mjs";
5
5
  import { X509CrlUnavailableError, X509Error } from "./X509Error.mjs";
6
6
  import { X509Certificate } from "./X509Certificate.mjs";
7
- import "./X509ValidationOptions.mjs";
7
+ import { withX509RevocationCheckDefaults } from "./X509ValidationOptions.mjs";
8
8
  import { X509ModuleConfig } from "./X509ModuleConfig.mjs";
9
9
  import { validateCriticalCrlExtensionIds } from "./utils/criticalExtensions.mjs";
10
10
  import { X509CertificateRevocationList } from "./X509CertificateRevocationList.mjs";
@@ -13,11 +13,6 @@ import { fetchCrl, getCachedCrlSummary, setCachedCrlSummary } from "./utils/crlF
13
13
  import "./X509CrlDistributionPoint.mjs";
14
14
  //#region src/modules/x509/X509RevocationService.ts
15
15
  var _X509RevocationService;
16
- /**
17
- * Default freshness period for a cached verified CRL summary (1 hour): how long it is served
18
- * without being revalidated against freshly fetched CRL bytes.
19
- */
20
- const DEFAULT_CRL_CACHE_EXPIRY_SECONDS = 3600;
21
16
  let X509RevocationService = _X509RevocationService = class X509RevocationService {
22
17
  /**
23
18
  * Check the revocation status of a single certificate using CRL.
@@ -25,14 +20,14 @@ let X509RevocationService = _X509RevocationService = class X509RevocationService
25
20
  static async checkCertificateRevocation(agentContext, { certificate, issuerCertificate, revocationCheckOptions }) {
26
21
  const parsedCertificate = certificate instanceof X509Certificate ? certificate : X509Certificate.fromEncodedCertificate(certificate);
27
22
  const parsedIssuerCertificate = issuerCertificate instanceof X509Certificate ? issuerCertificate : X509Certificate.fromEncodedCertificate(issuerCertificate);
28
- const options = revocationCheckOptions ?? agentContext.dependencyManager.resolve(X509ModuleConfig).revocationCheck ?? { mode: "SoftFail" };
29
- const mode = options.mode ?? "SoftFail";
23
+ const options = withX509RevocationCheckDefaults(revocationCheckOptions, agentContext.dependencyManager.resolve(X509ModuleConfig).revocationCheck);
24
+ const mode = options.mode;
30
25
  if (mode === "Disabled") return {
31
26
  isValid: true,
32
27
  details: "Revocation checking disabled"
33
28
  };
34
29
  try {
35
- return await _X509RevocationService.checkCrl(agentContext, parsedCertificate, parsedIssuerCertificate, options);
30
+ return await _X509RevocationService.checkCrl(agentContext, parsedCertificate, parsedIssuerCertificate, options, options.verificationDate ?? /* @__PURE__ */ new Date());
36
31
  } catch (error) {
37
32
  return _X509RevocationService.handleRevocationError(error, mode);
38
33
  }
@@ -51,7 +46,7 @@ let X509RevocationService = _X509RevocationService = class X509RevocationService
51
46
  */
52
47
  static async checkCertificateChainRevocation(agentContext, certificateChain, config, verificationDate) {
53
48
  const configuredRevocationCheck = config.revocationCheck;
54
- if (!configuredRevocationCheck || configuredRevocationCheck.mode === "Disabled") return {
49
+ if (configuredRevocationCheck.mode === "Disabled") return {
55
50
  isValid: true,
56
51
  details: "Revocation checking disabled"
57
52
  };
@@ -59,7 +54,7 @@ let X509RevocationService = _X509RevocationService = class X509RevocationService
59
54
  ...configuredRevocationCheck,
60
55
  verificationDate: configuredRevocationCheck.verificationDate ?? verificationDate
61
56
  };
62
- const startIndex = revocationConfig.checkFullChain ?? true ? 1 : certificateChain.length - 1;
57
+ const startIndex = revocationConfig.checkFullChain ? 1 : certificateChain.length - 1;
63
58
  for (let i = startIndex; i < certificateChain.length; i++) {
64
59
  const certificate = certificateChain[i];
65
60
  const issuerCertificate = certificateChain[i - 1];
@@ -84,13 +79,12 @@ let X509RevocationService = _X509RevocationService = class X509RevocationService
84
79
  * Checks the revocation status of a certificate using CRL with proper reason partitioning
85
80
  * Based on RFC 5280 Section 5.2.5
86
81
  */
87
- static async checkCrl(agentContext, certificate, issuerCertificate, options) {
82
+ static async checkCrl(agentContext, certificate, issuerCertificate, options, verificationDate) {
88
83
  const distributionPoints = certificate.crlDistributionPoints;
89
84
  if (distributionPoints.length === 0) return {
90
85
  isValid: true,
91
86
  details: "No CRL distribution points in certificate"
92
87
  };
93
- const verificationDate = options.verificationDate ?? /* @__PURE__ */ new Date();
94
88
  const fullDistributionPoint = distributionPoints.find((dp) => dp.reasons === void 0 && dp.crlIssuer === void 0);
95
89
  if (fullDistributionPoint) return await _X509RevocationService.checkDistributionPoint(agentContext, certificate, issuerCertificate, fullDistributionPoint, verificationDate, options);
96
90
  const requiredReasonsMask = options.requiredReasons ? _X509RevocationService.calculateReasonMask(options.requiredReasons) : _X509RevocationService.calculateAllReasonsInDPs(distributionPoints);
@@ -347,7 +341,7 @@ let X509RevocationService = _X509RevocationService = class X509RevocationService
347
341
  agentContext
348
342
  });
349
343
  reachable = true;
350
- const crlCacheExpirySeconds = options.crlCacheExpirySeconds ?? agentContext.dependencyManager.resolve(X509ModuleConfig).revocationCheck?.crlCacheExpirySeconds ?? DEFAULT_CRL_CACHE_EXPIRY_SECONDS;
344
+ const crlCacheExpirySeconds = options.crlCacheExpirySeconds;
351
345
  const staleAt = verificationDate.getTime() + crlCacheExpirySeconds * 1e3;
352
346
  if (staleSummary && computeCrlSha256(crlData) === staleSummary.crlSha256) {
353
347
  const refreshed = {
@@ -428,11 +422,17 @@ let X509RevocationService = _X509RevocationService = class X509RevocationService
428
422
  * or scoped CRL as-is for inspection.
429
423
  */
430
424
  static async fetchCertificateRevocationList(agentContext, { url, issuerCertificate, timeoutMs, maxCrlSizeBytes, verificationDate = /* @__PURE__ */ new Date() }) {
425
+ const config = agentContext.dependencyManager.resolve(X509ModuleConfig);
426
+ const options = {
427
+ timeoutMs: timeoutMs ?? config.revocationCheck.timeoutMs,
428
+ maxCrlSizeBytes: maxCrlSizeBytes ?? config.revocationCheck.maxCrlSizeBytes,
429
+ crlCacheExpirySeconds: config.revocationCheck.crlCacheExpirySeconds
430
+ };
431
431
  if (!issuerCertificate) {
432
432
  const crlData = await fetchCrl({
433
433
  url,
434
- timeoutMs,
435
- maxSizeBytes: maxCrlSizeBytes,
434
+ timeoutMs: options.timeoutMs,
435
+ maxSizeBytes: options.maxCrlSizeBytes,
436
436
  agentContext
437
437
  });
438
438
  return X509CertificateRevocationList.fromRaw(crlData);
@@ -442,10 +442,7 @@ let X509RevocationService = _X509RevocationService = class X509RevocationService
442
442
  url,
443
443
  issuerCertificate: parsedIssuerCertificate,
444
444
  verificationDate,
445
- options: {
446
- timeoutMs,
447
- maxCrlSizeBytes
448
- },
445
+ options,
449
446
  useCache: false
450
447
  }, new CredoWebCrypto(agentContext));
451
448
  if (!result.success) throw result.reachable ? new X509Error(`CRL from ${url} could not be verified: ${result.error}`) : new X509CrlUnavailableError(result.error);