@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.
- package/build/agent/TrustedIssuerContext.d.mts +11 -1
- package/build/agent/TrustedIssuerContext.d.mts.map +1 -1
- package/build/agent/TrustedIssuerContext.mjs +7 -0
- package/build/agent/TrustedIssuerContext.mjs.map +1 -1
- package/build/agent/TrustedIssuersForVerification.d.mts +11 -1
- package/build/agent/TrustedIssuersForVerification.d.mts.map +1 -1
- package/build/index.d.mts +3 -3
- package/build/index.mjs +2 -2
- package/build/modules/dcql/DcqlService.d.mts.map +1 -1
- package/build/modules/dcql/DcqlService.mjs +24 -12
- package/build/modules/dcql/DcqlService.mjs.map +1 -1
- package/build/modules/dids/domain/verificationMethod/JsonWebKey2020.d.mts +24 -24
- package/build/modules/dids/methods/jwk/DidJwk.d.mts +24 -24
- package/build/modules/dids/services/DidResolverService.d.mts +4 -0
- package/build/modules/dids/services/DidResolverService.d.mts.map +1 -1
- package/build/modules/dids/services/DidResolverService.mjs +21 -5
- package/build/modules/dids/services/DidResolverService.mjs.map +1 -1
- package/build/modules/kms/KeyManagementApi.d.mts +14 -14
- package/build/modules/kms/jwk/jwa.d.mts +1 -1
- package/build/modules/kms/jwk/knownJwk.d.mts +4 -4
- package/build/modules/kms/jwk/kty/ec/P256PublicJwk.d.mts +1 -1
- package/build/modules/kms/jwk/kty/ec/P384PublicJwk.d.mts +1 -1
- package/build/modules/kms/jwk/kty/ec/P521PublicJwk.d.mts +1 -1
- package/build/modules/kms/jwk/kty/ec/Secp256k1PublicJwk.d.mts +1 -1
- package/build/modules/kms/jwk/kty/okp/Ed25519PublicJwk.d.mts +2 -2
- package/build/modules/kms/jwk/kty/okp/X25519PublicJwk.d.mts +1 -1
- package/build/modules/kms/jwk/kty/okp/okpJwk.d.mts +2 -2
- package/build/modules/kms/options/KmsCreateKeyOptions.d.mts +3 -3
- package/build/modules/kms/options/KmsSignOptions.d.mts +1 -1
- package/build/modules/kms/options/KmsVerifyOptions.d.mts +2 -2
- package/build/modules/mdoc/repository/MdocRecord.d.mts +1 -1
- package/build/modules/sd-jwt-vc/repository/SdJwtVcRecord.d.mts +1 -1
- package/build/modules/sd-jwt-vc/utils.mjs +4 -4
- package/build/modules/sd-jwt-vc/utils.mjs.map +1 -1
- package/build/modules/vc/W3cCredentialServiceOptions.d.mts +5 -5
- package/build/modules/vc/W3cCredentialServiceOptions.d.mts.map +1 -1
- package/build/modules/vc/W3cV2CredentialService.d.mts +5 -1
- package/build/modules/vc/W3cV2CredentialService.d.mts.map +1 -1
- package/build/modules/vc/W3cV2CredentialService.mjs +72 -26
- package/build/modules/vc/W3cV2CredentialService.mjs.map +1 -1
- package/build/modules/vc/W3cV2CredentialServiceOptions.d.mts +14 -6
- package/build/modules/vc/W3cV2CredentialServiceOptions.d.mts.map +1 -1
- package/build/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.d.mts +0 -18
- package/build/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.d.mts.map +1 -1
- package/build/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.mjs +38 -36
- package/build/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.mjs.map +1 -1
- package/build/modules/vc/data-integrity/v2-di-utils.mjs +17 -35
- package/build/modules/vc/data-integrity/v2-di-utils.mjs.map +1 -1
- package/build/modules/vc/jwt-vc/W3cJwtCredentialService.d.mts +0 -23
- package/build/modules/vc/jwt-vc/W3cJwtCredentialService.d.mts.map +1 -1
- package/build/modules/vc/jwt-vc/W3cJwtCredentialService.mjs +17 -68
- package/build/modules/vc/jwt-vc/W3cJwtCredentialService.mjs.map +1 -1
- package/build/modules/vc/jwt-vc/W3cV2JwtCredentialService.d.mts.map +1 -1
- package/build/modules/vc/jwt-vc/W3cV2JwtCredentialService.mjs +11 -17
- package/build/modules/vc/jwt-vc/W3cV2JwtCredentialService.mjs.map +1 -1
- package/build/modules/vc/linked-data-proofs/W3cJsonLdCredentialService.d.mts +5 -0
- package/build/modules/vc/linked-data-proofs/W3cJsonLdCredentialService.d.mts.map +1 -1
- package/build/modules/vc/linked-data-proofs/W3cJsonLdCredentialService.mjs +18 -4
- package/build/modules/vc/linked-data-proofs/W3cJsonLdCredentialService.mjs.map +1 -1
- package/build/modules/vc/models/W3cV2VerifyResult.d.mts +6 -0
- package/build/modules/vc/models/W3cV2VerifyResult.d.mts.map +1 -1
- package/build/modules/vc/resolveSigner.mjs +74 -0
- package/build/modules/vc/resolveSigner.mjs.map +1 -0
- package/build/modules/vc/sd-jwt-vc/W3cV2SdJwtCredentialService.d.mts.map +1 -1
- package/build/modules/vc/sd-jwt-vc/W3cV2SdJwtCredentialService.mjs +16 -18
- package/build/modules/vc/sd-jwt-vc/W3cV2SdJwtCredentialService.mjs.map +1 -1
- package/build/modules/vc/sd-jwt-vc/disclosureFrame.d.mts +1 -1
- package/build/modules/vc/sd-jwt-vc/disclosureFrame.d.mts.map +1 -1
- package/build/modules/vc/sd-jwt-vc/disclosureFrame.mjs +2 -1
- package/build/modules/vc/sd-jwt-vc/disclosureFrame.mjs.map +1 -1
- package/build/modules/vc/v2-jwt-utils.mjs +54 -55
- package/build/modules/vc/v2-jwt-utils.mjs.map +1 -1
- package/build/modules/x509/X509ModuleConfig.d.mts +5 -13
- package/build/modules/x509/X509ModuleConfig.d.mts.map +1 -1
- package/build/modules/x509/X509ModuleConfig.mjs +2 -1
- package/build/modules/x509/X509ModuleConfig.mjs.map +1 -1
- package/build/modules/x509/X509RevocationService.d.mts.map +1 -1
- package/build/modules/x509/X509RevocationService.mjs +17 -20
- package/build/modules/x509/X509RevocationService.mjs.map +1 -1
- package/build/modules/x509/X509Service.mjs +1 -1
- package/build/modules/x509/X509Service.mjs.map +1 -1
- package/build/modules/x509/X509ServiceOptions.d.mts +4 -6
- package/build/modules/x509/X509ServiceOptions.d.mts.map +1 -1
- package/build/modules/x509/X509ValidationOptions.d.mts +19 -2
- package/build/modules/x509/X509ValidationOptions.d.mts.map +1 -1
- package/build/modules/x509/X509ValidationOptions.mjs +21 -1
- package/build/modules/x509/X509ValidationOptions.mjs.map +1 -1
- package/build/modules/x509/index.d.mts +2 -2
- package/build/modules/x509/index.mjs +2 -2
- package/build/modules/x509/utils/crlFetcher.mjs +1 -11
- package/build/modules/x509/utils/crlFetcher.mjs.map +1 -1
- 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
|
|
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
|
-
|
|
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)
|
|
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
|
|
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
|
-
|
|
77
|
+
const holder = await extractKeyFromHolderBinding(agentContext, holderBinding, options);
|
|
78
|
+
holders.set(holder.publicJwk.fingerprint, holder);
|
|
61
79
|
}
|
|
62
|
-
|
|
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
|
-
*
|
|
69
|
-
*
|
|
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
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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,
|
|
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
|
-
* @
|
|
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():
|
|
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":";;;;;;;;;;
|
|
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 {
|
|
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":";;;;;;;;
|
|
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
|
|
29
|
-
const mode = options.mode
|
|
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 (
|
|
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
|
|
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
|
|
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);
|