@credo-ts/core 0.7.3 → 0.7.4-alpha-20261028231852
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/crypto/webcrypto/CredoWalletWebCrypto.d.mts +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/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/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/models/credential/W3cV2EnvelopedVerifiableCredential.d.mts +1 -1
- package/build/modules/vc/models/credential/W3cV2EnvelopedVerifiableCredential.d.mts.map +1 -1
- package/build/modules/vc/models/credential/W3cV2VerifiableCredential.d.mts +1 -1
- package/build/modules/vc/models/credential/W3cV2VerifiableCredential.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,7 +4,11 @@ import { asArray } from "../../utils/array.mjs";
|
|
|
4
4
|
import { injectable } from "../../plugins/index.mjs";
|
|
5
5
|
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.mjs";
|
|
6
6
|
import __decorate from "../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorate.mjs";
|
|
7
|
+
import { getPublicJwkFromVerificationMethod } from "../dids/domain/key-type/keyDidMapping.mjs";
|
|
8
|
+
import "../dids/index.mjs";
|
|
7
9
|
import "./models/ClaimFormat.mjs";
|
|
10
|
+
import "./resolveSigner.mjs";
|
|
11
|
+
import { extractKeyFromHolderBinding, parseHolderBindingFromCredential } from "../sd-jwt-vc/utils.mjs";
|
|
8
12
|
import { W3cV2JwtVerifiableCredential } from "./jwt-vc/W3cV2JwtVerifiableCredential.mjs";
|
|
9
13
|
import { W3cV2DataIntegrityVerifiableCredential } from "./data-integrity/W3cV2DataIntegrityVerifiableCredential.mjs";
|
|
10
14
|
import { W3cV2DataIntegrityVerifiablePresentation } from "./data-integrity/W3cV2DataIntegrityVerifiablePresentation.mjs";
|
|
@@ -13,10 +17,10 @@ import { W3cV2EnvelopedVerifiableCredential } from "./models/credential/W3cV2Env
|
|
|
13
17
|
import { W3cV2EnvelopedVerifiablePresentation } from "./models/presentation/W3cV2EnvelopedVerifiablePresentation.mjs";
|
|
14
18
|
import { W3cV2JwtVerifiablePresentation } from "./jwt-vc/W3cV2JwtVerifiablePresentation.mjs";
|
|
15
19
|
import { W3cV2SdJwtVerifiablePresentation } from "./sd-jwt-vc/W3cV2SdJwtVerifiablePresentation.mjs";
|
|
16
|
-
import {
|
|
20
|
+
import { getSignerForJwt } from "./v2-jwt-utils.mjs";
|
|
17
21
|
import { W3cV2JwtCredentialService } from "./jwt-vc/W3cV2JwtCredentialService.mjs";
|
|
18
22
|
import "./jwt-vc/index.mjs";
|
|
19
|
-
import {
|
|
23
|
+
import { resolveDataIntegritySigner } from "./data-integrity/v2-di-utils.mjs";
|
|
20
24
|
import { W3cV2DataIntegrityCredentialService } from "./data-integrity/W3cV2DataIntegrityCredentialService.mjs";
|
|
21
25
|
import "./data-integrity/index.mjs";
|
|
22
26
|
import { W3cV2SdJwtCredentialService } from "./sd-jwt-vc/W3cV2SdJwtCredentialService.mjs";
|
|
@@ -117,7 +121,7 @@ let W3cV2CredentialService = class W3cV2CredentialService {
|
|
|
117
121
|
credentialEntries: []
|
|
118
122
|
};
|
|
119
123
|
let entries = [];
|
|
120
|
-
let
|
|
124
|
+
let signer;
|
|
121
125
|
if (presentation instanceof W3cV2JwtVerifiablePresentation) {
|
|
122
126
|
const presentationResult = await this.w3cV2JwtCredentialService.verifyPresentation(agentContext, {
|
|
123
127
|
...options,
|
|
@@ -126,12 +130,11 @@ let W3cV2CredentialService = class W3cV2CredentialService {
|
|
|
126
130
|
validationResults.presentation = presentationResult.presentation;
|
|
127
131
|
if (!presentationResult.presentation.isValid) {
|
|
128
132
|
validationResults.isValid = false;
|
|
133
|
+
validationResults.error = presentationResult.error;
|
|
129
134
|
return validationResults;
|
|
130
135
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
else try {
|
|
134
|
-
signerId = (await getVerificationMethodForJwt(agentContext, presentation, ["authentication"])).controller;
|
|
136
|
+
try {
|
|
137
|
+
signer = await getSignerForJwt(agentContext, presentation, ["authentication"]);
|
|
135
138
|
} catch (error) {
|
|
136
139
|
validationResults.isValid = false;
|
|
137
140
|
validationResults.error = error;
|
|
@@ -146,12 +149,11 @@ let W3cV2CredentialService = class W3cV2CredentialService {
|
|
|
146
149
|
validationResults.presentation = presentationResult.presentation;
|
|
147
150
|
if (!presentationResult.presentation.isValid) {
|
|
148
151
|
validationResults.isValid = false;
|
|
152
|
+
validationResults.error = presentationResult.error;
|
|
149
153
|
return validationResults;
|
|
150
154
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
else try {
|
|
154
|
-
signerId = (await getVerificationMethodForJwt(agentContext, presentation, ["authentication"])).controller;
|
|
155
|
+
try {
|
|
156
|
+
signer = await getSignerForJwt(agentContext, presentation, ["authentication"]);
|
|
155
157
|
} catch (error) {
|
|
156
158
|
validationResults.isValid = false;
|
|
157
159
|
validationResults.error = error;
|
|
@@ -166,11 +168,11 @@ let W3cV2CredentialService = class W3cV2CredentialService {
|
|
|
166
168
|
validationResults.presentation = presentationResult.presentation;
|
|
167
169
|
if (!presentationResult.presentation.isValid) {
|
|
168
170
|
validationResults.isValid = false;
|
|
171
|
+
validationResults.error = presentationResult.error;
|
|
169
172
|
return validationResults;
|
|
170
173
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
signerId = await getSignerForDataIntegrityProof(agentContext, presentation.securedPresentation, "authentication");
|
|
174
|
+
try {
|
|
175
|
+
signer = await resolveDataIntegritySigner(agentContext, presentation.securedPresentation, "authentication", presentation.resolvedPresentation.holderId);
|
|
174
176
|
} catch (error) {
|
|
175
177
|
validationResults.isValid = false;
|
|
176
178
|
validationResults.error = error;
|
|
@@ -178,24 +180,67 @@ let W3cV2CredentialService = class W3cV2CredentialService {
|
|
|
178
180
|
}
|
|
179
181
|
entries = this.extractCredentialEntriesFromPresentation(presentation);
|
|
180
182
|
} else throw new CredoError("Unsupported credential type in options. Presentation must be either a W3cV2JwtVerifiablePresentation, a W3cV2SdJwtVerifiablePresentation, or a W3cV2DataIntegrityVerifiablePresentation");
|
|
181
|
-
validationResults.credentialEntries = (await Promise.all(entries.map((entry) => this.verifyPresentationEntry(agentContext, entry,
|
|
183
|
+
validationResults.credentialEntries = (await Promise.all(entries.map((entry) => this.verifyPresentationEntry(agentContext, entry, signer, options.trustedIssuers, {
|
|
184
|
+
nonce: options.challenge,
|
|
185
|
+
audience: options.domain
|
|
186
|
+
})))).flat();
|
|
182
187
|
validationResults.isValid = validationResults.presentation.isValid && validationResults.credentialEntries.every((entry) => entry.isValid);
|
|
183
188
|
return validationResults;
|
|
184
189
|
}
|
|
185
|
-
async verifyPresentationEntry(agentContext, entry,
|
|
190
|
+
async verifyPresentationEntry(agentContext, entry, signer, trustedIssuers, presentationBinding) {
|
|
186
191
|
if (entry instanceof W3cV2DataIntegrityVerifiablePresentation) return [this.createInvalidCredentialEntryResult(new CredoError("Nested verifiable presentation entries are not supported in VC 2.0 presentations."))];
|
|
187
192
|
if (entry instanceof W3cV2DataIntegrityVerifiableCredential) {
|
|
188
|
-
const credentialResult = await this.w3cV2DataIntegrityCredentialService.verifyCredential(agentContext, {
|
|
189
|
-
|
|
193
|
+
const credentialResult = await this.w3cV2DataIntegrityCredentialService.verifyCredential(agentContext, {
|
|
194
|
+
credential: entry,
|
|
195
|
+
trustedIssuers
|
|
196
|
+
});
|
|
197
|
+
return [this.mergeHolderValidations(credentialResult, signer, entry.resolvedCredential?.credentialSubjectIds ?? [], { isValid: true })];
|
|
190
198
|
}
|
|
191
199
|
if (entry instanceof W3cV2EnvelopedVerifiablePresentation) return [this.createInvalidCredentialEntryResult(new CredoError("Nested verifiable presentation entries are not supported in VC 2.0 presentations."))];
|
|
192
200
|
if (!(entry instanceof W3cV2EnvelopedVerifiableCredential)) return [this.createInvalidCredentialEntryResult(new CredoError("Unsupported credential entry type in presentation."))];
|
|
193
201
|
const enclosed = entry.envelopedCredential;
|
|
194
202
|
let credentialResult;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
203
|
+
let claims;
|
|
204
|
+
if (enclosed instanceof W3cV2JwtVerifiableCredential) {
|
|
205
|
+
credentialResult = await this.w3cV2JwtCredentialService.verifyCredential(agentContext, {
|
|
206
|
+
credential: enclosed,
|
|
207
|
+
trustedIssuers
|
|
208
|
+
});
|
|
209
|
+
claims = enclosed.jwt.payload.toJson();
|
|
210
|
+
} else if (enclosed instanceof W3cV2SdJwtVerifiableCredential) {
|
|
211
|
+
const { nonce, audience } = presentationBinding;
|
|
212
|
+
if (enclosed.sdJwt.kbJwt && !audience) return [this.createInvalidCredentialEntryResult(new CredoError("Credential has a KB-JWT, but no domain is provided to verify its audience"))];
|
|
213
|
+
credentialResult = await this.w3cV2SdJwtCredentialService.verifyCredential(agentContext, {
|
|
214
|
+
credential: enclosed,
|
|
215
|
+
trustedIssuers,
|
|
216
|
+
keyBinding: enclosed.sdJwt.kbJwt && audience ? {
|
|
217
|
+
nonce,
|
|
218
|
+
audience
|
|
219
|
+
} : void 0
|
|
220
|
+
});
|
|
221
|
+
claims = enclosed.sdJwt.prettyClaims;
|
|
222
|
+
} else return [this.createInvalidCredentialEntryResult(new CredoError(`Credential entry uses '${this.getClaimFormat(enclosed) ?? "an unsupported enclosed credential format"}'.`))];
|
|
223
|
+
return [this.mergeHolderValidations(credentialResult, signer, entry.resolvedCredential.credentialSubjectIds, await this.verifyHolderBinding(agentContext, claims, signer))];
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* A credential bound to a key with `cnf` must be presented with that key.
|
|
227
|
+
*/
|
|
228
|
+
async verifyHolderBinding(agentContext, claims, signer) {
|
|
229
|
+
try {
|
|
230
|
+
const holderBinding = parseHolderBindingFromCredential(claims);
|
|
231
|
+
if (!holderBinding) return { isValid: true };
|
|
232
|
+
const { publicJwk } = await extractKeyFromHolderBinding(agentContext, holderBinding, { didPurposes: ["authentication"] });
|
|
233
|
+
if (publicJwk.equals(getPublicJwkFromVerificationMethod(signer.verificationMethod))) return { isValid: true };
|
|
234
|
+
return {
|
|
235
|
+
isValid: false,
|
|
236
|
+
error: new CredoError(`Credential is bound to a different key than verification method ${signer.verificationMethod.id} that signed the presentation`)
|
|
237
|
+
};
|
|
238
|
+
} catch (error) {
|
|
239
|
+
return {
|
|
240
|
+
isValid: false,
|
|
241
|
+
error
|
|
242
|
+
};
|
|
243
|
+
}
|
|
199
244
|
}
|
|
200
245
|
extractCredentialEntriesFromPresentation(presentation) {
|
|
201
246
|
return this.extractCredentialEntriesFromResolvedPresentation(presentation.resolvedPresentation);
|
|
@@ -215,18 +260,19 @@ let W3cV2CredentialService = class W3cV2CredentialService {
|
|
|
215
260
|
const candidate = value;
|
|
216
261
|
return typeof candidate.claimFormat === "string" ? candidate.claimFormat : void 0;
|
|
217
262
|
}
|
|
218
|
-
|
|
219
|
-
const presentationAuthenticatesCredentialSubject = credentialSubjectIds.some((subjectId) =>
|
|
263
|
+
mergeHolderValidations(credentialResult, signer, credentialSubjectIds, holderBinding) {
|
|
264
|
+
const presentationAuthenticatesCredentialSubject = credentialSubjectIds.some((subjectId) => signer.signer === subjectId);
|
|
220
265
|
const credentialSubjectAuthentication = credentialSubjectIds.length > 0 && !presentationAuthenticatesCredentialSubject ? {
|
|
221
266
|
isValid: false,
|
|
222
267
|
error: new CredoError("Credential has one or more credentialSubject ids, but presentation does not authenticate credential subject")
|
|
223
268
|
} : { isValid: true };
|
|
224
269
|
return {
|
|
225
270
|
...credentialResult,
|
|
226
|
-
isValid: credentialResult.isValid && credentialSubjectAuthentication.isValid,
|
|
271
|
+
isValid: credentialResult.isValid && credentialSubjectAuthentication.isValid && holderBinding.isValid,
|
|
227
272
|
validations: {
|
|
228
273
|
...credentialResult.validations,
|
|
229
|
-
credentialSubjectAuthentication
|
|
274
|
+
credentialSubjectAuthentication,
|
|
275
|
+
holderBinding
|
|
230
276
|
}
|
|
231
277
|
};
|
|
232
278
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"W3cV2CredentialService.mjs","names":[],"sources":["../../../src/modules/vc/W3cV2CredentialService.ts"],"sourcesContent":["import type { AgentContext } from '../../agent/context'\nimport { CredoError } from '../../error'\nimport { injectable } from '../../plugins'\nimport type { Query, QueryOptions } from '../../storage/StorageService'\nimport { asArray } from '../../utils/array'\nimport {\n W3cV2DataIntegrityCredentialService,\n type W3cV2DataIntegrityResolvedPresentation,\n W3cV2DataIntegrityVerifiableCredential,\n W3cV2DataIntegrityVerifiablePresentation,\n} from './data-integrity'\nimport { getSignerForDataIntegrityProof } from './data-integrity/v2-di-utils'\nimport { W3cV2JwtVerifiableCredential, W3cV2JwtVerifiablePresentation } from './jwt-vc'\nimport { W3cV2JwtCredentialService } from './jwt-vc/W3cV2JwtCredentialService'\nimport type {\n W3cV2PresentationCredentialEntry,\n W3cV2PresentationCredentialEntryResult,\n W3cV2VerifiableCredential,\n W3cV2VerifiablePresentation,\n W3cV2VerifyCredentialResult,\n W3cV2VerifyPresentationResult,\n} from './models'\nimport {\n ClaimFormat,\n decodeW3cV2VerifiablePresentation,\n W3cV2EnvelopedVerifiableCredential,\n W3cV2EnvelopedVerifiablePresentation,\n} from './models'\nimport { decodeW3cV2VerifiableCredential } from './models/credential/W3cV2VerifiableCredential'\nimport type { W3cV2Presentation } from './models/presentation/W3cV2Presentation'\nimport { W3cV2CredentialRecord, W3cV2CredentialRepository } from './repository'\nimport {\n W3cV2SdJwtCredentialService,\n W3cV2SdJwtVerifiableCredential,\n W3cV2SdJwtVerifiablePresentation,\n} from './sd-jwt-vc'\nimport { getVerificationMethodForJwt } from './v2-jwt-utils'\nimport type {\n W3cV2DiSignCredentialOptions,\n W3cV2DiSignPresentationOptions,\n W3cV2DiVerifyCredentialOptions,\n W3cV2DiVerifyPresentationOptions,\n W3cV2JwtVerifyCredentialOptions,\n W3cV2JwtVerifyPresentationOptions,\n W3cV2SdJwtVerifyCredentialOptions,\n W3cV2SdJwtVerifyPresentationOptions,\n W3cV2SignCredentialOptions,\n W3cV2SignPresentationOptions,\n W3cV2StoreCredentialOptions,\n W3cV2VerifyCredentialOptions,\n W3cV2VerifyPresentationOptions,\n} from './W3cV2CredentialServiceOptions'\n\n@injectable()\nexport class W3cV2CredentialService {\n private w3cV2CredentialRepository: W3cV2CredentialRepository\n private w3cV2SdJwtCredentialService: W3cV2SdJwtCredentialService\n private w3cV2JwtCredentialService: W3cV2JwtCredentialService\n private w3cV2DataIntegrityCredentialService: W3cV2DataIntegrityCredentialService\n\n public constructor(\n w3cV2CredentialRepository: W3cV2CredentialRepository,\n w3cV2SdJwtCredentialService: W3cV2SdJwtCredentialService,\n w3cV2JwtCredentialService: W3cV2JwtCredentialService,\n w3cV2DataIntegrityCredentialService: W3cV2DataIntegrityCredentialService\n ) {\n this.w3cV2CredentialRepository = w3cV2CredentialRepository\n this.w3cV2SdJwtCredentialService = w3cV2SdJwtCredentialService\n this.w3cV2JwtCredentialService = w3cV2JwtCredentialService\n this.w3cV2DataIntegrityCredentialService = w3cV2DataIntegrityCredentialService\n }\n\n /**\n * Signs a credential\n *\n * @param credential the credential to be signed\n * @returns the signed credential\n */\n public async signCredential<Format extends ClaimFormat.JwtW3cVc | ClaimFormat.SdJwtW3cVc | ClaimFormat.DiVc>(\n agentContext: AgentContext,\n options: W3cV2SignCredentialOptions<Format>\n ): Promise<W3cV2VerifiableCredential<Format>> {\n if (options.format === ClaimFormat.JwtW3cVc) {\n const signed = await this.w3cV2JwtCredentialService.signCredential(agentContext, options)\n return signed as W3cV2VerifiableCredential<Format>\n }\n if (options.format === ClaimFormat.SdJwtW3cVc) {\n const signed = await this.w3cV2SdJwtCredentialService.signCredential(agentContext, options)\n return signed as W3cV2VerifiableCredential<Format>\n }\n if (options.format === ClaimFormat.DiVc) {\n const signed = await this.w3cV2DataIntegrityCredentialService.signCredential(\n agentContext,\n options as W3cV2DiSignCredentialOptions\n )\n return signed as W3cV2VerifiableCredential<Format>\n }\n throw new CredoError(`Unsupported format in options. Format must be either 'vc+jwt', 'vc+sd-jwt', or 'di_vc'`)\n }\n\n /**\n * Verifies the signature(s) of a credential\n */\n public async verifyCredential(\n agentContext: AgentContext,\n options: W3cV2VerifyCredentialOptions\n ): Promise<W3cV2VerifyCredentialResult> {\n const credential =\n typeof options.credential === 'string' ? decodeW3cV2VerifiableCredential(options.credential) : options.credential\n\n if (credential instanceof W3cV2JwtVerifiableCredential) {\n return this.w3cV2JwtCredentialService.verifyCredential(agentContext, {\n ...options,\n credential,\n } as W3cV2JwtVerifyCredentialOptions)\n }\n\n if (credential instanceof W3cV2SdJwtVerifiableCredential) {\n return this.w3cV2SdJwtCredentialService.verifyCredential(agentContext, {\n ...options,\n credential,\n } as W3cV2SdJwtVerifyCredentialOptions)\n }\n\n if (credential instanceof W3cV2DataIntegrityVerifiableCredential) {\n return this.w3cV2DataIntegrityCredentialService.verifyCredential(agentContext, {\n ...options,\n credential,\n } as W3cV2DiVerifyCredentialOptions)\n }\n\n throw new CredoError(\n 'Unsupported credential type in options. Credential must be either a W3cV2JwtVerifiableCredential, a W3cV2SdJwtVerifiableCredential, or a W3cV2DataIntegrityVerifiableCredential'\n )\n }\n\n /**\n * Signs a presentation including the credentials it includes\n *\n * @param presentation the presentation to be signed\n * @returns the signed presentation\n */\n public async signPresentation<Format extends ClaimFormat.JwtW3cVp | ClaimFormat.SdJwtW3cVp | ClaimFormat.DiVp>(\n agentContext: AgentContext,\n options: W3cV2SignPresentationOptions<Format>\n ): Promise<W3cV2VerifiablePresentation<Format>> {\n if (options.format === ClaimFormat.JwtW3cVp) {\n const signed = await this.w3cV2JwtCredentialService.signPresentation(agentContext, options)\n return signed as W3cV2VerifiablePresentation<Format>\n }\n if (options.format === ClaimFormat.SdJwtW3cVp) {\n const signed = await this.w3cV2SdJwtCredentialService.signPresentation(agentContext, options)\n return signed as W3cV2VerifiablePresentation<Format>\n }\n if (options.format === ClaimFormat.DiVp) {\n const signed = await this.w3cV2DataIntegrityCredentialService.signPresentation(\n agentContext,\n options as W3cV2DiSignPresentationOptions\n )\n return signed as W3cV2VerifiablePresentation<Format>\n }\n throw new CredoError(`Unsupported format in options. Format must be either 'vp+jwt', 'vp+sd-jwt', or 'di_vp'`)\n }\n\n /**\n * Verifies a W3C V2 verifiable presentation and each enclosed credential entry.\n *\n * Flow:\n * 1. Verifies the outer VP using the format-specific service (`vp+jwt` or `vp+sd-jwt`).\n * 2. Derives the presenter identifier (holder id, or JWT verification method controller fallback).\n * 3. Recursively walks enclosed entries and verifies each credential entry with the matching\n * credential verifier (`vc+jwt` or `vc+sd-jwt`) based on the actual enclosed format.\n * 4. Adds `credentialSubjectAuthentication` validation to each credential result by checking\n * whether the authenticated presenter matches at least one credentialSubject id.\n *\n * Current support and constraints:\n * - Compact string presentations are accepted for `vp+jwt` and `vp+sd-jwt` and normalized\n * to typed presentation instances before routing.\n * - `di_vp` routes through the DI credential service for outer-VP verification.\n * - `di_vc` entries route through the DI credential service for entry verification.\n * - Nested VP entries are treated as invalid. VC 2.0 verifiable presentations support VC entries,\n * not VP-within-VP entries.\n *\n * Return semantics:\n * - `presentation` contains the outer VP verification result.\n * - `credentialEntries` contains one result per traversed credential entry, including unsupported\n * entries as invalid results.\n * - Top-level `isValid` is true only if the outer VP and all credential entry validations are valid.\n *\n * @param agentContext The framework agent context used for resolution and cryptographic checks.\n * @param options Verification input containing the presentation to verify.\n * @returns Aggregated presentation and credential-entry verification result.\n */\n public async verifyPresentation(\n agentContext: AgentContext,\n options: W3cV2VerifyPresentationOptions\n ): Promise<W3cV2VerifyPresentationResult> {\n const presentation =\n typeof options.presentation === 'string'\n ? decodeW3cV2VerifiablePresentation(options.presentation)\n : options.presentation\n\n const validationResults: W3cV2VerifyPresentationResult = {\n isValid: false,\n presentation: {\n isValid: false,\n validations: {},\n },\n credentialEntries: [],\n }\n\n let entries: W3cV2PresentationCredentialEntry[] = []\n let signerId: string | undefined\n\n // Phase 1: verify the outer secured VP envelope and derive the authenticated presenter.\n if (presentation instanceof W3cV2JwtVerifiablePresentation) {\n const presentationResult = await this.w3cV2JwtCredentialService.verifyPresentation(agentContext, {\n ...options,\n presentation,\n } as W3cV2JwtVerifyPresentationOptions)\n validationResults.presentation = presentationResult.presentation\n\n if (!presentationResult.presentation.isValid) {\n validationResults.isValid = false\n return validationResults\n }\n\n const holderId = presentation.resolvedPresentation.holderId\n if (holderId) {\n signerId = holderId\n } else {\n try {\n const verificationMethod = await getVerificationMethodForJwt(agentContext, presentation, ['authentication'])\n signerId = verificationMethod.controller\n } catch (error) {\n validationResults.isValid = false\n validationResults.error = error\n return validationResults\n }\n }\n entries = this.extractCredentialEntriesFromPresentation(presentation)\n } else if (presentation instanceof W3cV2SdJwtVerifiablePresentation) {\n const presentationResult = await this.w3cV2SdJwtCredentialService.verifyPresentation(agentContext, {\n ...options,\n presentation,\n } as W3cV2SdJwtVerifyPresentationOptions)\n validationResults.presentation = presentationResult.presentation\n\n if (!presentationResult.presentation.isValid) {\n validationResults.isValid = false\n return validationResults\n }\n\n const holderId = presentation.resolvedPresentation.holderId\n if (holderId) {\n signerId = holderId\n } else {\n try {\n const verificationMethod = await getVerificationMethodForJwt(agentContext, presentation, ['authentication'])\n signerId = verificationMethod.controller\n } catch (error) {\n validationResults.isValid = false\n validationResults.error = error\n return validationResults\n }\n }\n entries = this.extractCredentialEntriesFromPresentation(presentation)\n } else if (presentation instanceof W3cV2DataIntegrityVerifiablePresentation) {\n const presentationResult = await this.w3cV2DataIntegrityCredentialService.verifyPresentation(agentContext, {\n ...options,\n presentation,\n } as W3cV2DiVerifyPresentationOptions)\n validationResults.presentation = presentationResult.presentation\n\n if (!presentationResult.presentation.isValid) {\n validationResults.isValid = false\n return validationResults\n }\n\n signerId = presentation.resolvedPresentation.holderId\n if (!signerId) {\n try {\n // The holder is optional in VCDM 2.0, so fall back to the identity that authenticated the\n // presentation, mirroring how the JWT and SD-JWT branches above derive their signer.\n // No expected controller is passed: with no declared holder there is nothing to\n // disambiguate against, so an ambiguous proof set is rejected rather than guessed at.\n signerId = await getSignerForDataIntegrityProof(\n agentContext,\n presentation.securedPresentation,\n 'authentication'\n )\n } catch (error) {\n validationResults.isValid = false\n validationResults.error = error\n return validationResults\n }\n }\n\n entries = this.extractCredentialEntriesFromPresentation(presentation)\n } else {\n throw new CredoError(\n 'Unsupported credential type in options. Presentation must be either a W3cV2JwtVerifiablePresentation, a W3cV2SdJwtVerifiablePresentation, or a W3cV2DataIntegrityVerifiablePresentation'\n )\n }\n\n // Phase 2: walk enclosed credential entries and verify recursively by entry format.\n validationResults.credentialEntries = (\n await Promise.all(entries.map((entry) => this.verifyPresentationEntry(agentContext, entry, signerId)))\n ).flat()\n\n validationResults.isValid =\n validationResults.presentation.isValid && validationResults.credentialEntries.every((entry) => entry.isValid)\n\n return validationResults\n }\n\n private async verifyPresentationEntry(\n agentContext: AgentContext,\n entry: W3cV2PresentationCredentialEntry,\n signerId: string\n ): Promise<W3cV2PresentationCredentialEntryResult[]> {\n if (entry instanceof W3cV2DataIntegrityVerifiablePresentation) {\n return [\n this.createInvalidCredentialEntryResult(\n new CredoError('Nested verifiable presentation entries are not supported in VC 2.0 presentations.')\n ),\n ]\n }\n\n if (entry instanceof W3cV2DataIntegrityVerifiableCredential) {\n const credentialResult = await this.w3cV2DataIntegrityCredentialService.verifyCredential(agentContext, {\n credential: entry,\n } as W3cV2DiVerifyCredentialOptions)\n\n return [\n this.mergeCredentialSubjectAuthenticationValidation(\n credentialResult,\n signerId,\n entry.resolvedCredential?.credentialSubjectIds ?? []\n ),\n ]\n }\n\n if (entry instanceof W3cV2EnvelopedVerifiablePresentation) {\n return [\n this.createInvalidCredentialEntryResult(\n new CredoError('Nested verifiable presentation entries are not supported in VC 2.0 presentations.')\n ),\n ]\n }\n\n if (!(entry instanceof W3cV2EnvelopedVerifiableCredential)) {\n return [\n this.createInvalidCredentialEntryResult(new CredoError('Unsupported credential entry type in presentation.')),\n ]\n }\n\n const enclosed = entry.envelopedCredential\n let credentialResult: W3cV2VerifyCredentialResult\n\n if (enclosed instanceof W3cV2JwtVerifiableCredential) {\n credentialResult = await this.w3cV2JwtCredentialService.verifyCredential(agentContext, {\n credential: enclosed,\n } as W3cV2JwtVerifyCredentialOptions)\n } else if (enclosed instanceof W3cV2SdJwtVerifiableCredential) {\n credentialResult = await this.w3cV2SdJwtCredentialService.verifyCredential(agentContext, {\n credential: enclosed,\n } as W3cV2SdJwtVerifyCredentialOptions)\n } else {\n return [\n this.createInvalidCredentialEntryResult(\n new CredoError(\n `Credential entry uses '${this.getClaimFormat(enclosed) ?? 'an unsupported enclosed credential format'}'.`\n )\n ),\n ]\n }\n\n return [\n this.mergeCredentialSubjectAuthenticationValidation(\n credentialResult,\n signerId,\n entry.resolvedCredential.credentialSubjectIds\n ),\n ]\n }\n\n private extractCredentialEntriesFromPresentation(\n presentation:\n | W3cV2JwtVerifiablePresentation\n | W3cV2SdJwtVerifiablePresentation\n | W3cV2DataIntegrityVerifiablePresentation\n ): W3cV2PresentationCredentialEntry[] {\n return this.extractCredentialEntriesFromResolvedPresentation(presentation.resolvedPresentation)\n }\n\n private extractCredentialEntriesFromResolvedPresentation(\n resolvedPresentation: Pick<W3cV2Presentation, 'verifiableCredential'> | W3cV2DataIntegrityResolvedPresentation\n ): W3cV2PresentationCredentialEntry[] {\n return asArray(resolvedPresentation.verifiableCredential) as W3cV2PresentationCredentialEntry[]\n }\n\n private createInvalidCredentialEntryResult(error: Error): W3cV2PresentationCredentialEntryResult {\n return {\n isValid: false,\n error,\n validations: {},\n }\n }\n\n private getClaimFormat(value: unknown): string | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined\n\n const candidate = value as { claimFormat?: unknown }\n return typeof candidate.claimFormat === 'string' ? candidate.claimFormat : undefined\n }\n\n private mergeCredentialSubjectAuthenticationValidation(\n credentialResult: W3cV2VerifyCredentialResult,\n signerId: string,\n credentialSubjectIds: string[]\n ) {\n const presentationAuthenticatesCredentialSubject = credentialSubjectIds.some((subjectId) => signerId === subjectId)\n\n const credentialSubjectAuthentication =\n credentialSubjectIds.length > 0 && !presentationAuthenticatesCredentialSubject\n ? {\n isValid: false,\n error: new CredoError(\n 'Credential has one or more credentialSubject ids, but presentation does not authenticate credential subject'\n ),\n }\n : {\n isValid: true,\n }\n\n return {\n ...credentialResult,\n isValid: credentialResult.isValid && credentialSubjectAuthentication.isValid,\n validations: {\n ...credentialResult.validations,\n credentialSubjectAuthentication,\n },\n }\n }\n\n /**\n * Writes a credential to storage\n *\n * @param record the credential to be stored\n * @returns the credential record that was written to storage\n */\n public async storeCredential(\n agentContext: AgentContext,\n options: W3cV2StoreCredentialOptions\n ): Promise<W3cV2CredentialRecord> {\n // Store the w3cV2 credential record\n await this.w3cV2CredentialRepository.save(agentContext, options.record)\n\n return options.record\n }\n\n public async removeCredentialRecord(agentContext: AgentContext, id: string) {\n await this.w3cV2CredentialRepository.deleteById(agentContext, id)\n }\n\n public async getAllCredentialRecords(agentContext: AgentContext): Promise<W3cV2CredentialRecord[]> {\n return await this.w3cV2CredentialRepository.getAll(agentContext)\n }\n\n public async getCredentialRecordById(agentContext: AgentContext, id: string): Promise<W3cV2CredentialRecord> {\n return await this.w3cV2CredentialRepository.getById(agentContext, id)\n }\n\n public async findCredentialsByQuery(\n agentContext: AgentContext,\n query: Query<W3cV2CredentialRecord>,\n queryOptions?: QueryOptions\n ): Promise<W3cV2VerifiableCredential[]> {\n const result = await this.w3cV2CredentialRepository.findByQuery(agentContext, query, queryOptions)\n return result.map((record) => record.firstCredential)\n }\n\n public async findCredentialRecordByQuery(\n agentContext: AgentContext,\n query: Query<W3cV2CredentialRecord>\n ): Promise<W3cV2VerifiableCredential | undefined> {\n const result = await this.w3cV2CredentialRepository.findSingleByQuery(agentContext, query)\n return result?.firstCredential\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"W3cV2CredentialService.mjs","names":[],"sources":["../../../src/modules/vc/W3cV2CredentialService.ts"],"sourcesContent":["import type { AgentContext } from '../../agent/context'\nimport type { GetTrustedIssuersForCredential, TrustedIssuerDid } from '../../agent/TrustedIssuersForVerification'\nimport { CredoError } from '../../error'\nimport { injectable } from '../../plugins'\nimport type { Query, QueryOptions } from '../../storage/StorageService'\nimport { asArray } from '../../utils/array'\nimport { getPublicJwkFromVerificationMethod } from '../dids'\nimport { extractKeyFromHolderBinding, parseHolderBindingFromCredential } from '../sd-jwt-vc/utils'\nimport {\n W3cV2DataIntegrityCredentialService,\n type W3cV2DataIntegrityResolvedPresentation,\n W3cV2DataIntegrityVerifiableCredential,\n W3cV2DataIntegrityVerifiablePresentation,\n} from './data-integrity'\nimport { resolveDataIntegritySigner } from './data-integrity/v2-di-utils'\nimport { W3cV2JwtVerifiableCredential, W3cV2JwtVerifiablePresentation } from './jwt-vc'\nimport { W3cV2JwtCredentialService } from './jwt-vc/W3cV2JwtCredentialService'\nimport type {\n W3cV2PresentationCredentialEntry,\n W3cV2PresentationCredentialEntryResult,\n W3cV2VerifiableCredential,\n W3cV2VerifiablePresentation,\n W3cV2VerifyCredentialResult,\n W3cV2VerifyPresentationResult,\n} from './models'\nimport {\n ClaimFormat,\n decodeW3cV2VerifiablePresentation,\n W3cV2EnvelopedVerifiableCredential,\n W3cV2EnvelopedVerifiablePresentation,\n} from './models'\nimport { decodeW3cV2VerifiableCredential } from './models/credential/W3cV2VerifiableCredential'\nimport type { W3cV2Presentation } from './models/presentation/W3cV2Presentation'\nimport type { SingleValidationResult } from './models/W3cVerifyResult'\nimport { W3cV2CredentialRecord, W3cV2CredentialRepository } from './repository'\nimport { type ResolvedSigner } from './resolveSigner'\nimport {\n W3cV2SdJwtCredentialService,\n W3cV2SdJwtVerifiableCredential,\n W3cV2SdJwtVerifiablePresentation,\n} from './sd-jwt-vc'\nimport { getSignerForJwt } from './v2-jwt-utils'\nimport type {\n W3cV2DiSignCredentialOptions,\n W3cV2DiSignPresentationOptions,\n W3cV2DiVerifyCredentialOptions,\n W3cV2DiVerifyPresentationOptions,\n W3cV2JwtVerifyCredentialOptions,\n W3cV2JwtVerifyPresentationOptions,\n W3cV2SdJwtVerifyCredentialOptions,\n W3cV2SdJwtVerifyPresentationOptions,\n W3cV2SignCredentialOptions,\n W3cV2SignPresentationOptions,\n W3cV2StoreCredentialOptions,\n W3cV2VerifyCredentialOptions,\n W3cV2VerifyPresentationOptions,\n} from './W3cV2CredentialServiceOptions'\n\n@injectable()\nexport class W3cV2CredentialService {\n private w3cV2CredentialRepository: W3cV2CredentialRepository\n private w3cV2SdJwtCredentialService: W3cV2SdJwtCredentialService\n private w3cV2JwtCredentialService: W3cV2JwtCredentialService\n private w3cV2DataIntegrityCredentialService: W3cV2DataIntegrityCredentialService\n\n public constructor(\n w3cV2CredentialRepository: W3cV2CredentialRepository,\n w3cV2SdJwtCredentialService: W3cV2SdJwtCredentialService,\n w3cV2JwtCredentialService: W3cV2JwtCredentialService,\n w3cV2DataIntegrityCredentialService: W3cV2DataIntegrityCredentialService\n ) {\n this.w3cV2CredentialRepository = w3cV2CredentialRepository\n this.w3cV2SdJwtCredentialService = w3cV2SdJwtCredentialService\n this.w3cV2JwtCredentialService = w3cV2JwtCredentialService\n this.w3cV2DataIntegrityCredentialService = w3cV2DataIntegrityCredentialService\n }\n\n /**\n * Signs a credential\n *\n * @param credential the credential to be signed\n * @returns the signed credential\n */\n public async signCredential<Format extends ClaimFormat.JwtW3cVc | ClaimFormat.SdJwtW3cVc | ClaimFormat.DiVc>(\n agentContext: AgentContext,\n options: W3cV2SignCredentialOptions<Format>\n ): Promise<W3cV2VerifiableCredential<Format>> {\n if (options.format === ClaimFormat.JwtW3cVc) {\n const signed = await this.w3cV2JwtCredentialService.signCredential(agentContext, options)\n return signed as W3cV2VerifiableCredential<Format>\n }\n if (options.format === ClaimFormat.SdJwtW3cVc) {\n const signed = await this.w3cV2SdJwtCredentialService.signCredential(agentContext, options)\n return signed as W3cV2VerifiableCredential<Format>\n }\n if (options.format === ClaimFormat.DiVc) {\n const signed = await this.w3cV2DataIntegrityCredentialService.signCredential(\n agentContext,\n options as W3cV2DiSignCredentialOptions\n )\n return signed as W3cV2VerifiableCredential<Format>\n }\n throw new CredoError(`Unsupported format in options. Format must be either 'vc+jwt', 'vc+sd-jwt', or 'di_vc'`)\n }\n\n /**\n * Verifies the signature(s) of a credential\n */\n public async verifyCredential(\n agentContext: AgentContext,\n options: W3cV2VerifyCredentialOptions\n ): Promise<W3cV2VerifyCredentialResult> {\n const credential =\n typeof options.credential === 'string' ? decodeW3cV2VerifiableCredential(options.credential) : options.credential\n\n if (credential instanceof W3cV2JwtVerifiableCredential) {\n return this.w3cV2JwtCredentialService.verifyCredential(agentContext, {\n ...options,\n credential,\n } as W3cV2JwtVerifyCredentialOptions)\n }\n\n if (credential instanceof W3cV2SdJwtVerifiableCredential) {\n return this.w3cV2SdJwtCredentialService.verifyCredential(agentContext, {\n ...options,\n credential,\n } as W3cV2SdJwtVerifyCredentialOptions)\n }\n\n if (credential instanceof W3cV2DataIntegrityVerifiableCredential) {\n return this.w3cV2DataIntegrityCredentialService.verifyCredential(agentContext, {\n ...options,\n credential,\n } as W3cV2DiVerifyCredentialOptions)\n }\n\n throw new CredoError(\n 'Unsupported credential type in options. Credential must be either a W3cV2JwtVerifiableCredential, a W3cV2SdJwtVerifiableCredential, or a W3cV2DataIntegrityVerifiableCredential'\n )\n }\n\n /**\n * Signs a presentation including the credentials it includes\n *\n * @param presentation the presentation to be signed\n * @returns the signed presentation\n */\n public async signPresentation<Format extends ClaimFormat.JwtW3cVp | ClaimFormat.SdJwtW3cVp | ClaimFormat.DiVp>(\n agentContext: AgentContext,\n options: W3cV2SignPresentationOptions<Format>\n ): Promise<W3cV2VerifiablePresentation<Format>> {\n if (options.format === ClaimFormat.JwtW3cVp) {\n const signed = await this.w3cV2JwtCredentialService.signPresentation(agentContext, options)\n return signed as W3cV2VerifiablePresentation<Format>\n }\n if (options.format === ClaimFormat.SdJwtW3cVp) {\n const signed = await this.w3cV2SdJwtCredentialService.signPresentation(agentContext, options)\n return signed as W3cV2VerifiablePresentation<Format>\n }\n if (options.format === ClaimFormat.DiVp) {\n const signed = await this.w3cV2DataIntegrityCredentialService.signPresentation(\n agentContext,\n options as W3cV2DiSignPresentationOptions\n )\n return signed as W3cV2VerifiablePresentation<Format>\n }\n throw new CredoError(`Unsupported format in options. Format must be either 'vp+jwt', 'vp+sd-jwt', or 'di_vp'`)\n }\n\n /**\n * Verifies a W3C V2 verifiable presentation and each enclosed credential entry.\n *\n * Flow:\n * 1. Verifies the outer VP using the format-specific service (`vp+jwt` or `vp+sd-jwt`).\n * 2. Derives the presenter identifier (holder id, or JWT verification method controller fallback).\n * 3. Recursively walks enclosed entries and verifies each credential entry with the matching\n * credential verifier (`vc+jwt` or `vc+sd-jwt`) based on the actual enclosed format.\n * 4. Adds `credentialSubjectAuthentication` validation to each credential result by checking\n * whether the authenticated presenter matches at least one credentialSubject id.\n *\n * Current support and constraints:\n * - Compact string presentations are accepted for `vp+jwt` and `vp+sd-jwt` and normalized\n * to typed presentation instances before routing.\n * - `di_vp` routes through the DI credential service for outer-VP verification.\n * - `di_vc` entries route through the DI credential service for entry verification.\n * - Nested VP entries are treated as invalid. VC 2.0 verifiable presentations support VC entries,\n * not VP-within-VP entries.\n *\n * Return semantics:\n * - `presentation` contains the outer VP verification result.\n * - `credentialEntries` contains one result per traversed credential entry, including unsupported\n * entries as invalid results.\n * - Top-level `isValid` is true only if the outer VP and all credential entry validations are valid.\n *\n * @param agentContext The framework agent context used for resolution and cryptographic checks.\n * @param options Verification input containing the presentation to verify.\n * @returns Aggregated presentation and credential-entry verification result.\n */\n public async verifyPresentation(\n agentContext: AgentContext,\n options: W3cV2VerifyPresentationOptions\n ): Promise<W3cV2VerifyPresentationResult> {\n const presentation =\n typeof options.presentation === 'string'\n ? decodeW3cV2VerifiablePresentation(options.presentation)\n : options.presentation\n\n const validationResults: W3cV2VerifyPresentationResult = {\n isValid: false,\n presentation: {\n isValid: false,\n validations: {},\n },\n credentialEntries: [],\n }\n\n let entries: W3cV2PresentationCredentialEntry[] = []\n let signer: ResolvedSigner\n\n // Phase 1: verify the outer secured VP envelope and derive the authenticated presenter.\n if (presentation instanceof W3cV2JwtVerifiablePresentation) {\n const presentationResult = await this.w3cV2JwtCredentialService.verifyPresentation(agentContext, {\n ...options,\n presentation,\n } as W3cV2JwtVerifyPresentationOptions)\n validationResults.presentation = presentationResult.presentation\n\n if (!presentationResult.presentation.isValid) {\n validationResults.isValid = false\n validationResults.error = presentationResult.error\n return validationResults\n }\n\n try {\n signer = await getSignerForJwt(agentContext, presentation, ['authentication'])\n } catch (error) {\n validationResults.isValid = false\n validationResults.error = error\n return validationResults\n }\n entries = this.extractCredentialEntriesFromPresentation(presentation)\n } else if (presentation instanceof W3cV2SdJwtVerifiablePresentation) {\n const presentationResult = await this.w3cV2SdJwtCredentialService.verifyPresentation(agentContext, {\n ...options,\n presentation,\n } as W3cV2SdJwtVerifyPresentationOptions)\n validationResults.presentation = presentationResult.presentation\n\n if (!presentationResult.presentation.isValid) {\n validationResults.isValid = false\n validationResults.error = presentationResult.error\n return validationResults\n }\n\n try {\n signer = await getSignerForJwt(agentContext, presentation, ['authentication'])\n } catch (error) {\n validationResults.isValid = false\n validationResults.error = error\n return validationResults\n }\n entries = this.extractCredentialEntriesFromPresentation(presentation)\n } else if (presentation instanceof W3cV2DataIntegrityVerifiablePresentation) {\n const presentationResult = await this.w3cV2DataIntegrityCredentialService.verifyPresentation(agentContext, {\n ...options,\n presentation,\n } as W3cV2DiVerifyPresentationOptions)\n validationResults.presentation = presentationResult.presentation\n\n if (!presentationResult.presentation.isValid) {\n validationResults.isValid = false\n validationResults.error = presentationResult.error\n return validationResults\n }\n\n try {\n // Without a holder there is nothing to disambiguate a proof set against, so an ambiguous\n // proof set is rejected rather than guessed at.\n signer = await resolveDataIntegritySigner(\n agentContext,\n presentation.securedPresentation,\n 'authentication',\n presentation.resolvedPresentation.holderId\n )\n } catch (error) {\n validationResults.isValid = false\n validationResults.error = error\n return validationResults\n }\n\n entries = this.extractCredentialEntriesFromPresentation(presentation)\n } else {\n throw new CredoError(\n 'Unsupported credential type in options. Presentation must be either a W3cV2JwtVerifiablePresentation, a W3cV2SdJwtVerifiablePresentation, or a W3cV2DataIntegrityVerifiablePresentation'\n )\n }\n\n // Phase 2: walk enclosed credential entries and verify recursively by entry format.\n validationResults.credentialEntries = (\n await Promise.all(\n entries.map((entry) =>\n this.verifyPresentationEntry(agentContext, entry, signer, options.trustedIssuers, {\n nonce: options.challenge,\n audience: options.domain,\n })\n )\n )\n ).flat()\n\n validationResults.isValid =\n validationResults.presentation.isValid && validationResults.credentialEntries.every((entry) => entry.isValid)\n\n return validationResults\n }\n\n private async verifyPresentationEntry(\n agentContext: AgentContext,\n entry: W3cV2PresentationCredentialEntry,\n signer: ResolvedSigner,\n trustedIssuers: TrustedIssuerDid[] | GetTrustedIssuersForCredential | undefined,\n presentationBinding: { nonce: string; audience?: string }\n ): Promise<W3cV2PresentationCredentialEntryResult[]> {\n if (entry instanceof W3cV2DataIntegrityVerifiablePresentation) {\n return [\n this.createInvalidCredentialEntryResult(\n new CredoError('Nested verifiable presentation entries are not supported in VC 2.0 presentations.')\n ),\n ]\n }\n\n if (entry instanceof W3cV2DataIntegrityVerifiableCredential) {\n const credentialResult = await this.w3cV2DataIntegrityCredentialService.verifyCredential(agentContext, {\n credential: entry,\n trustedIssuers,\n } as W3cV2DiVerifyCredentialOptions)\n\n return [\n this.mergeHolderValidations(credentialResult, signer, entry.resolvedCredential?.credentialSubjectIds ?? [], {\n isValid: true,\n }),\n ]\n }\n\n if (entry instanceof W3cV2EnvelopedVerifiablePresentation) {\n return [\n this.createInvalidCredentialEntryResult(\n new CredoError('Nested verifiable presentation entries are not supported in VC 2.0 presentations.')\n ),\n ]\n }\n\n if (!(entry instanceof W3cV2EnvelopedVerifiableCredential)) {\n return [\n this.createInvalidCredentialEntryResult(new CredoError('Unsupported credential entry type in presentation.')),\n ]\n }\n\n const enclosed = entry.envelopedCredential\n let credentialResult: W3cV2VerifyCredentialResult\n let claims: Record<string, unknown>\n\n if (enclosed instanceof W3cV2JwtVerifiableCredential) {\n credentialResult = await this.w3cV2JwtCredentialService.verifyCredential(agentContext, {\n credential: enclosed,\n trustedIssuers,\n } as W3cV2JwtVerifyCredentialOptions)\n claims = enclosed.jwt.payload.toJson()\n } else if (enclosed instanceof W3cV2SdJwtVerifiableCredential) {\n // The presentation proves possession of the key. A KB-JWT is optional, but must match the presentation.\n const { nonce, audience } = presentationBinding\n if (enclosed.sdJwt.kbJwt && !audience) {\n return [\n this.createInvalidCredentialEntryResult(\n new CredoError('Credential has a KB-JWT, but no domain is provided to verify its audience')\n ),\n ]\n }\n\n credentialResult = await this.w3cV2SdJwtCredentialService.verifyCredential(agentContext, {\n credential: enclosed,\n trustedIssuers,\n keyBinding: enclosed.sdJwt.kbJwt && audience ? { nonce, audience } : undefined,\n } as W3cV2SdJwtVerifyCredentialOptions)\n claims = enclosed.sdJwt.prettyClaims\n } else {\n return [\n this.createInvalidCredentialEntryResult(\n new CredoError(\n `Credential entry uses '${this.getClaimFormat(enclosed) ?? 'an unsupported enclosed credential format'}'.`\n )\n ),\n ]\n }\n\n return [\n this.mergeHolderValidations(\n credentialResult,\n signer,\n entry.resolvedCredential.credentialSubjectIds,\n await this.verifyHolderBinding(agentContext, claims, signer)\n ),\n ]\n }\n\n /**\n * A credential bound to a key with `cnf` must be presented with that key.\n */\n private async verifyHolderBinding(\n agentContext: AgentContext,\n claims: Record<string, unknown>,\n signer: ResolvedSigner\n ): Promise<SingleValidationResult> {\n try {\n const holderBinding = parseHolderBindingFromCredential(claims)\n if (!holderBinding) return { isValid: true }\n\n // The presentation signer is resolved under `authentication`, so the holder key must be too\n const { publicJwk } = await extractKeyFromHolderBinding(agentContext, holderBinding, {\n didPurposes: ['authentication'],\n })\n if (publicJwk.equals(getPublicJwkFromVerificationMethod(signer.verificationMethod))) return { isValid: true }\n\n return {\n isValid: false,\n error: new CredoError(\n `Credential is bound to a different key than verification method ${signer.verificationMethod.id} that signed the presentation`\n ),\n }\n } catch (error) {\n return { isValid: false, error }\n }\n }\n\n private extractCredentialEntriesFromPresentation(\n presentation:\n | W3cV2JwtVerifiablePresentation\n | W3cV2SdJwtVerifiablePresentation\n | W3cV2DataIntegrityVerifiablePresentation\n ): W3cV2PresentationCredentialEntry[] {\n return this.extractCredentialEntriesFromResolvedPresentation(presentation.resolvedPresentation)\n }\n\n private extractCredentialEntriesFromResolvedPresentation(\n resolvedPresentation: Pick<W3cV2Presentation, 'verifiableCredential'> | W3cV2DataIntegrityResolvedPresentation\n ): W3cV2PresentationCredentialEntry[] {\n return asArray(resolvedPresentation.verifiableCredential) as W3cV2PresentationCredentialEntry[]\n }\n\n private createInvalidCredentialEntryResult(error: Error): W3cV2PresentationCredentialEntryResult {\n return {\n isValid: false,\n error,\n validations: {},\n }\n }\n\n private getClaimFormat(value: unknown): string | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined\n\n const candidate = value as { claimFormat?: unknown }\n return typeof candidate.claimFormat === 'string' ? candidate.claimFormat : undefined\n }\n\n private mergeHolderValidations(\n credentialResult: W3cV2VerifyCredentialResult,\n signer: ResolvedSigner,\n credentialSubjectIds: string[],\n holderBinding: SingleValidationResult\n ) {\n const presentationAuthenticatesCredentialSubject = credentialSubjectIds.some(\n (subjectId) => signer.signer === subjectId\n )\n\n const credentialSubjectAuthentication =\n credentialSubjectIds.length > 0 && !presentationAuthenticatesCredentialSubject\n ? {\n isValid: false,\n error: new CredoError(\n 'Credential has one or more credentialSubject ids, but presentation does not authenticate credential subject'\n ),\n }\n : {\n isValid: true,\n }\n\n return {\n ...credentialResult,\n isValid: credentialResult.isValid && credentialSubjectAuthentication.isValid && holderBinding.isValid,\n validations: {\n ...credentialResult.validations,\n credentialSubjectAuthentication,\n holderBinding,\n },\n }\n }\n\n /**\n * Writes a credential to storage\n *\n * @param record the credential to be stored\n * @returns the credential record that was written to storage\n */\n public async storeCredential(\n agentContext: AgentContext,\n options: W3cV2StoreCredentialOptions\n ): Promise<W3cV2CredentialRecord> {\n // Store the w3cV2 credential record\n await this.w3cV2CredentialRepository.save(agentContext, options.record)\n\n return options.record\n }\n\n public async removeCredentialRecord(agentContext: AgentContext, id: string) {\n await this.w3cV2CredentialRepository.deleteById(agentContext, id)\n }\n\n public async getAllCredentialRecords(agentContext: AgentContext): Promise<W3cV2CredentialRecord[]> {\n return await this.w3cV2CredentialRepository.getAll(agentContext)\n }\n\n public async getCredentialRecordById(agentContext: AgentContext, id: string): Promise<W3cV2CredentialRecord> {\n return await this.w3cV2CredentialRepository.getById(agentContext, id)\n }\n\n public async findCredentialsByQuery(\n agentContext: AgentContext,\n query: Query<W3cV2CredentialRecord>,\n queryOptions?: QueryOptions\n ): Promise<W3cV2VerifiableCredential[]> {\n const result = await this.w3cV2CredentialRepository.findByQuery(agentContext, query, queryOptions)\n return result.map((record) => record.firstCredential)\n }\n\n public async findCredentialRecordByQuery(\n agentContext: AgentContext,\n query: Query<W3cV2CredentialRecord>\n ): Promise<W3cV2VerifiableCredential | undefined> {\n const result = await this.w3cV2CredentialRepository.findSingleByQuery(agentContext, query)\n return result?.firstCredential\n }\n}\n"],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ import "./repository/index.mjs";
|
|
|
17
17
|
import "./sd-jwt-vc/index.mjs";
|
|
18
18
|
import "./jwt-vc/index.mjs";
|
|
19
19
|
import "./data-integrity/index.mjs";
|
|
20
|
-
import { TrustedIssuerDid } from "../../agent/TrustedIssuersForVerification.mjs";
|
|
20
|
+
import { GetTrustedIssuersForCredential, TrustedIssuerDid } from "../../agent/TrustedIssuersForVerification.mjs";
|
|
21
21
|
import "../../crypto/index.mjs";
|
|
22
22
|
import "../kms/index.mjs";
|
|
23
23
|
//#region src/modules/vc/W3cV2CredentialServiceOptions.d.ts
|
|
@@ -100,12 +100,20 @@ interface W3cV2VerifyCredentialOptionsBase<Credential = unknown> {
|
|
|
100
100
|
*/
|
|
101
101
|
verifyCredentialStatus?: boolean;
|
|
102
102
|
/**
|
|
103
|
-
* Trusted issuers for the verification.
|
|
103
|
+
* Trusted issuers for the verification, or a callback that resolves them for each credential.
|
|
104
104
|
*/
|
|
105
|
-
trustedIssuers?: TrustedIssuerDid[];
|
|
105
|
+
trustedIssuers?: TrustedIssuerDid[] | GetTrustedIssuersForCredential;
|
|
106
106
|
}
|
|
107
107
|
export interface W3cV2JwtVerifyCredentialOptions extends W3cV2VerifyCredentialOptionsBase<W3cV2JwtVerifiableCredential | string> {}
|
|
108
|
-
export interface W3cV2SdJwtVerifyCredentialOptions extends W3cV2VerifyCredentialOptionsBase<W3cV2SdJwtVerifiableCredential | string> {
|
|
108
|
+
export interface W3cV2SdJwtVerifyCredentialOptions extends W3cV2VerifyCredentialOptionsBase<W3cV2SdJwtVerifiableCredential | string> {
|
|
109
|
+
/**
|
|
110
|
+
* Requires a KB-JWT with this `nonce`, and with this `aud` when `audience` is set.
|
|
111
|
+
*/
|
|
112
|
+
keyBinding?: {
|
|
113
|
+
nonce: string;
|
|
114
|
+
audience: string | string[];
|
|
115
|
+
};
|
|
116
|
+
}
|
|
109
117
|
interface W3cV2SignPresentationOptionsBase<Format extends ClaimFormat = ClaimFormat> {
|
|
110
118
|
/**
|
|
111
119
|
* The format of the presentation to be signed.
|
|
@@ -154,9 +162,9 @@ interface W3cV2VerifyPresentationOptionsBase<Presentation = unknown> {
|
|
|
154
162
|
*/
|
|
155
163
|
domain?: string;
|
|
156
164
|
/**
|
|
157
|
-
* Trusted issuers for the verification.
|
|
165
|
+
* Trusted issuers for the verification, or a callback that resolves them for each credential.
|
|
158
166
|
*/
|
|
159
|
-
trustedIssuers?: TrustedIssuerDid[];
|
|
167
|
+
trustedIssuers?: TrustedIssuerDid[] | GetTrustedIssuersForCredential;
|
|
160
168
|
}
|
|
161
169
|
export interface W3cV2JwtVerifyPresentationOptions extends W3cV2VerifyPresentationOptionsBase<W3cV2JwtVerifiablePresentation | string> {}
|
|
162
170
|
export interface W3cV2SdJwtVerifyPresentationOptions extends W3cV2VerifyPresentationOptionsBase<W3cV2SdJwtVerifiablePresentation | string> {}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"W3cV2CredentialServiceOptions.d.mts","names":[],"sources":["../../../src/modules/vc/W3cV2CredentialServiceOptions.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;KAUK;GACF,YAAY,WAAW;GACvB,YAAY,aAAa;GACzB,YAAY,OAAO;;KAGjB;GACF,YAAY,WAAW;GACvB,YAAY,aAAa;GACzB,YAAY,OAAO;;KAGjB;GACF,YAAY,WAAW;GACvB,YAAY,aAAa;GACzB,YAAY,OAAO;;YAGV,2BACV,qBAAqB,8DACnB,qBAAqB,qCACrB,mCAAmC,UACnC,yCAAyC;YAEjC,6BACV,qBAAqB,gEACnB,qBAAqB,uCACrB,qCAAqC,UACrC,2CAA2C;YAEnC,6BACV,qBAAqB,gEACnB,qBAAqB,uCACrB,qCAAqC,UACrC,2CAA2C;YAEnC,iCACR,oCACA,sCACA;UAEM,+BAA+B,eAAe,cAAc;;;;;;EAMpE,QAAQ;;;;EAKR,YAAY;;;;;;EAOZ;;iBAGe,sCAAsC,+BAA+B,YAAY;;;;EAIhG,KAAK;;;;;EAML,SAAS;;iBAGM,wCAAwC,+BAA+B,YAAY;;;;EAIlG,KAAK;;;;;;EAOL,mBAAmB,QAAQ;;;;;EAM3B,SAAS;;;;;EAMT,kBAAkB;;UAGV,iCAAiC;EACzC,YAAY;;;;;;EAOZ;;;;EAKA,iBAAiB;;
|
|
1
|
+
{"version":3,"file":"W3cV2CredentialServiceOptions.d.mts","names":[],"sources":["../../../src/modules/vc/W3cV2CredentialServiceOptions.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;KAUK;GACF,YAAY,WAAW;GACvB,YAAY,aAAa;GACzB,YAAY,OAAO;;KAGjB;GACF,YAAY,WAAW;GACvB,YAAY,aAAa;GACzB,YAAY,OAAO;;KAGjB;GACF,YAAY,WAAW;GACvB,YAAY,aAAa;GACzB,YAAY,OAAO;;YAGV,2BACV,qBAAqB,8DACnB,qBAAqB,qCACrB,mCAAmC,UACnC,yCAAyC;YAEjC,6BACV,qBAAqB,gEACnB,qBAAqB,uCACrB,qCAAqC,UACrC,2CAA2C;YAEnC,6BACV,qBAAqB,gEACnB,qBAAqB,uCACrB,qCAAqC,UACrC,2CAA2C;YAEnC,iCACR,oCACA,sCACA;UAEM,+BAA+B,eAAe,cAAc;;;;;;EAMpE,QAAQ;;;;EAKR,YAAY;;;;;;EAOZ;;iBAGe,sCAAsC,+BAA+B,YAAY;;;;EAIhG,KAAK;;;;;EAML,SAAS;;iBAGM,wCAAwC,+BAA+B,YAAY;;;;EAIlG,KAAK;;;;;;EAOL,mBAAmB,QAAQ;;;;;EAM3B,SAAS;;;;;EAMT,kBAAkB;;UAGV,iCAAiC;EACzC,YAAY;;;;;;EAOZ;;;;EAKA,iBAAiB,qBAAqB;;iBAGvB,wCACP,iCAAiC;iBAE1B,0CACP,iCAAiC;;;;EAIzC;IACE;IACA;;;UAIM,iCAAiC,eAAe,cAAc;;;;;;EAMtE,QAAQ;;;;EAKR,cAAc;;;;EAKd;;;;EAKA;;iBAGe,wCAAwC,iCAAiC,YAAY;iBAErF,0CAA0C,iCAAiC,YAAY;;;;;;EAMtG,mBAAmB,QAAQ;;;;;EAM3B,kBAAkB;;UAGV,mCAAmC;;;;EAI3C,cAAc;;;;EAKd;;;;EAKA;;;;EAKA,iBAAiB,qBAAqB;;iBAGvB,0CACP,mCAAmC;iBAE5B,4CACP,mCAAmC;iBAE5B;EACf,QAAQ;;iBAGO;EACf,YAAY;;;;EAKZ,oBAAoB;;;;;iBAML,qCAAqC,+BAA+B,YAAY;;;;EAI/F;;;;;iBAMe,uCACP,iCAAiC;;;;iBAK1B,uCAAuC,iCAAiC,YAAY;;;;;;EAMnG;;;;EAKA;;;;;iBAMe,yCACP,mCAAmC"}
|
|
@@ -17,24 +17,6 @@ export declare class W3cV2DataIntegrityCredentialService {
|
|
|
17
17
|
verifyCredential(agentContext: AgentContext, options: W3cV2DiVerifyCredentialOptions): Promise<W3cV2VerifyCredentialResult>;
|
|
18
18
|
signPresentation(agentContext: AgentContext, options: W3cV2DiSignPresentationOptions): Promise<W3cV2VerifiablePresentation<ClaimFormat.DiVp>>;
|
|
19
19
|
verifyPresentation(agentContext: AgentContext, options: W3cV2DiVerifyPresentationOptions): Promise<W3cV2VerifyPresentationResult>;
|
|
20
|
-
/**
|
|
21
|
-
* Checks that a secured document was signed by the identity it names as responsible for it —
|
|
22
|
-
* the `issuer` of a credential, or the `holder` of a presentation.
|
|
23
|
-
*
|
|
24
|
-
* Mirrors the equivalent checks in the JWT and SD-JWT services — though those compare key
|
|
25
|
-
* fingerprints for the issuer, whereas Data Integrity proofs name a verification method, so the
|
|
26
|
-
* comparison here is by controller for both roles. It implements the association described in
|
|
27
|
-
* VC-DATA-INTEGRITY §"Relationship to Verifiable Credentials": that the `controller` of the
|
|
28
|
-
* proof's verification method matches the identifier used for the `issuer` or `holder`, and that
|
|
29
|
-
* the verification method is expressed under a verification relationship acceptable for the
|
|
30
|
-
* proof's purpose. The latter is enforced by dereferencing the key with `purpose`.
|
|
31
|
-
*
|
|
32
|
-
* Verifying the proof only establishes that *someone* signed; without this comparison a document
|
|
33
|
-
* could name one party and be signed by an unrelated one.
|
|
34
|
-
*
|
|
35
|
-
* @param expectedSigner the `issuer` or `holder`. `Holder` is optional in
|
|
36
|
-
* VCDM 2.0 so when undefined there is no claim to contradict, so the validation passes.
|
|
37
|
-
*/
|
|
38
20
|
private verifySignerIsExpectedParty;
|
|
39
21
|
private invalidResult;
|
|
40
22
|
private invalidValidation;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"W3cV2DataIntegrityCredentialService.d.mts","names":[],"sources":["../../../../src/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.ts"],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"W3cV2DataIntegrityCredentialService.d.mts","names":[],"sources":["../../../../src/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.ts"],"mappings":";;;;;;;;;;;qBAgCa;UACH;UACA;EAGN,YAAA,2BAA2B,8BAC3B,kBAAkB;EAMP,eACX,cAAc,cACd,SAAS,+BACR,QAAQ,0BAA0B,YAAY;EAgCpC,iBACX,cAAc,cACd,SAAS,iCACR,QAAQ;EA6DE,iBACX,cAAc,cACd,SAAS,iCACR,QAAQ,4BAA4B,YAAY;EAuCtC,mBACX,cAAc,cACd,SAAS,mCACR,QAAQ;UA8CG;UAmBN;UAoBA;UAOA"}
|
|
@@ -7,7 +7,9 @@ import { injectable } from "../../../plugins/index.mjs";
|
|
|
7
7
|
import __decorateMetadata from "../../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.mjs";
|
|
8
8
|
import __decorate from "../../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorate.mjs";
|
|
9
9
|
import { CREDENTIALS_CONTEXT_V2_URL } from "../constants.mjs";
|
|
10
|
+
import { TrustedIssuerContext } from "../../../agent/TrustedIssuerContext.mjs";
|
|
10
11
|
import { validateVc2ContextBaseline, validateVc2CredentialStatus } from "../validators.mjs";
|
|
12
|
+
import { validateSignerIsExpectedParty } from "../resolveSigner.mjs";
|
|
11
13
|
import { W3cV2Credential } from "../models/credential/W3cV2Credential.mjs";
|
|
12
14
|
import { W3cV2DataIntegrityVerifiableCredential } from "./W3cV2DataIntegrityVerifiableCredential.mjs";
|
|
13
15
|
import { W3cV2DataIntegrityVerifiablePresentation } from "./W3cV2DataIntegrityVerifiablePresentation.mjs";
|
|
@@ -16,7 +18,7 @@ import { createW3cDataIntegrityCredoError } from "../../w3c-di/W3cDataIntegrityE
|
|
|
16
18
|
import { W3cDataIntegrityProofService } from "../../w3c-di/W3cDataIntegrityProofService.mjs";
|
|
17
19
|
import "../../w3c-di/internal.mjs";
|
|
18
20
|
import { W3cV2DataIntegrityContextValidator } from "./W3cV2DataIntegrityContextValidator.mjs";
|
|
19
|
-
import {
|
|
21
|
+
import { resolveDataIntegritySigner } from "./v2-di-utils.mjs";
|
|
20
22
|
//#region src/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.ts
|
|
21
23
|
let W3cV2DataIntegrityCredentialService = class W3cV2DataIntegrityCredentialService {
|
|
22
24
|
constructor(dataIntegrityProofService, contextValidator) {
|
|
@@ -52,15 +54,34 @@ let W3cV2DataIntegrityCredentialService = class W3cV2DataIntegrityCredentialServ
|
|
|
52
54
|
credentialFormat: "DI",
|
|
53
55
|
verifyCredentialStatus: options.verifyCredentialStatus
|
|
54
56
|
});
|
|
55
|
-
const issuerIsSigner = await this.verifySignerIsExpectedParty(agentContext, securedCredential, "assertionMethod", options.credential.resolvedCredential.issuerId,
|
|
57
|
+
const { validation: issuerIsSigner, signer: issuer } = await this.verifySignerIsExpectedParty(agentContext, securedCredential, "assertionMethod", options.credential.resolvedCredential.issuerId, "issuer");
|
|
58
|
+
const validations = {
|
|
59
|
+
dataModel: { isValid: true },
|
|
60
|
+
signature: { isValid: true },
|
|
61
|
+
credentialStatus,
|
|
62
|
+
issuerIsSigner
|
|
63
|
+
};
|
|
64
|
+
if (issuer && issuerIsSigner.isValid) try {
|
|
65
|
+
await TrustedIssuerContext.ensureTrustedCredentialSigner(agentContext, {
|
|
66
|
+
signer: {
|
|
67
|
+
method: "did",
|
|
68
|
+
didUrl: issuer.verificationMethod.id
|
|
69
|
+
},
|
|
70
|
+
verification: {
|
|
71
|
+
type: "credential",
|
|
72
|
+
credential: options.credential
|
|
73
|
+
}
|
|
74
|
+
}, options.trustedIssuers);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
return {
|
|
77
|
+
isValid: false,
|
|
78
|
+
validations,
|
|
79
|
+
error
|
|
80
|
+
};
|
|
81
|
+
}
|
|
56
82
|
return {
|
|
57
83
|
isValid: credentialStatus.isValid && issuerIsSigner.isValid,
|
|
58
|
-
validations
|
|
59
|
-
dataModel: { isValid: true },
|
|
60
|
-
signature: { isValid: true },
|
|
61
|
-
credentialStatus,
|
|
62
|
-
issuerIsSigner
|
|
63
|
-
}
|
|
84
|
+
validations
|
|
64
85
|
};
|
|
65
86
|
}
|
|
66
87
|
async signPresentation(agentContext, options) {
|
|
@@ -101,7 +122,7 @@ let W3cV2DataIntegrityCredentialService = class W3cV2DataIntegrityCredentialServ
|
|
|
101
122
|
if (!verificationResult.verified) return this.invalidResult(verificationResult.errors, "presentation");
|
|
102
123
|
const presentationContextResult = await this.contextValidator.validate(agentContext, securedPresentation);
|
|
103
124
|
if (!presentationContextResult.validated) return this.invalidResult(presentationContextResult.errors, "presentation");
|
|
104
|
-
const holderIsSigner = await this.verifySignerIsExpectedParty(agentContext, options.presentation.securedPresentation, "authentication", options.presentation.resolvedPresentation.holderId,
|
|
125
|
+
const { validation: holderIsSigner } = await this.verifySignerIsExpectedParty(agentContext, options.presentation.securedPresentation, "authentication", options.presentation.resolvedPresentation.holderId, "holder");
|
|
105
126
|
return {
|
|
106
127
|
isValid: holderIsSigner.isValid,
|
|
107
128
|
presentation: {
|
|
@@ -115,38 +136,19 @@ let W3cV2DataIntegrityCredentialService = class W3cV2DataIntegrityCredentialServ
|
|
|
115
136
|
credentialEntries: []
|
|
116
137
|
};
|
|
117
138
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
* the `issuer` of a credential, or the `holder` of a presentation.
|
|
121
|
-
*
|
|
122
|
-
* Mirrors the equivalent checks in the JWT and SD-JWT services — though those compare key
|
|
123
|
-
* fingerprints for the issuer, whereas Data Integrity proofs name a verification method, so the
|
|
124
|
-
* comparison here is by controller for both roles. It implements the association described in
|
|
125
|
-
* VC-DATA-INTEGRITY §"Relationship to Verifiable Credentials": that the `controller` of the
|
|
126
|
-
* proof's verification method matches the identifier used for the `issuer` or `holder`, and that
|
|
127
|
-
* the verification method is expressed under a verification relationship acceptable for the
|
|
128
|
-
* proof's purpose. The latter is enforced by dereferencing the key with `purpose`.
|
|
129
|
-
*
|
|
130
|
-
* Verifying the proof only establishes that *someone* signed; without this comparison a document
|
|
131
|
-
* could name one party and be signed by an unrelated one.
|
|
132
|
-
*
|
|
133
|
-
* @param expectedSigner the `issuer` or `holder`. `Holder` is optional in
|
|
134
|
-
* VCDM 2.0 so when undefined there is no claim to contradict, so the validation passes.
|
|
135
|
-
*/
|
|
136
|
-
async verifySignerIsExpectedParty(agentContext, securedDocument, purpose, expectedSigner, describeMismatch) {
|
|
137
|
-
if (!expectedSigner) return { isValid: true };
|
|
139
|
+
async verifySignerIsExpectedParty(agentContext, securedDocument, purpose, expectedSigner, role) {
|
|
140
|
+
if (!expectedSigner) return { validation: { isValid: true } };
|
|
138
141
|
try {
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
142
|
+
const signer = await resolveDataIntegritySigner(agentContext, securedDocument, purpose, expectedSigner);
|
|
143
|
+
return {
|
|
144
|
+
validation: validateSignerIsExpectedParty(signer, expectedSigner, role),
|
|
145
|
+
signer
|
|
143
146
|
};
|
|
144
|
-
return { isValid: true };
|
|
145
147
|
} catch (error) {
|
|
146
|
-
return {
|
|
148
|
+
return { validation: {
|
|
147
149
|
isValid: false,
|
|
148
150
|
error
|
|
149
|
-
};
|
|
151
|
+
} };
|
|
150
152
|
}
|
|
151
153
|
}
|
|
152
154
|
invalidResult(errors, target) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"W3cV2DataIntegrityCredentialService.mjs","names":["createDataIntegrityCredoError"],"sources":["../../../../src/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.ts"],"sourcesContent":["import type { AgentContext } from '../../../agent/context'\nimport { CredoError } from '../../../error'\nimport { injectable } from '../../../plugins'\nimport { JsonTransformer, MessageValidator } from '../../../utils'\nimport {\n createW3cDataIntegrityCredoError as createDataIntegrityCredoError,\n type W3cDataIntegrityIssueList as DataIntegrityIssueList,\n W3cDataIntegrityProofService as DataIntegrityProofService,\n} from '../../w3c-di/internal'\nimport { CREDENTIALS_CONTEXT_V2_URL } from '../constants'\nimport { ClaimFormat } from '../models/ClaimFormat'\nimport { W3cV2Credential } from '../models/credential/W3cV2Credential'\nimport type { W3cV2VerifiableCredential } from '../models/credential/W3cV2VerifiableCredential'\nimport { W3cV2Presentation } from '../models/presentation/W3cV2Presentation'\nimport type { W3cV2VerifiablePresentation } from '../models/presentation/W3cV2VerifiablePresentation'\nimport type { W3cV2VerifyCredentialResult, W3cV2VerifyPresentationResult } from '../models/W3cV2VerifyResult'\nimport type { SingleValidationResult } from '../models/W3cVerifyResult'\nimport { validateVc2ContextBaseline, validateVc2CredentialStatus } from '../validators'\nimport type {\n W3cV2DiSignCredentialOptions,\n W3cV2DiSignPresentationOptions,\n W3cV2DiVerifyCredentialOptions,\n W3cV2DiVerifyPresentationOptions,\n} from '../W3cV2CredentialServiceOptions'\nimport { getVerificationMethodForDataIntegrityProof } from './v2-di-utils'\nimport { W3cV2DataIntegrityContextValidator } from './W3cV2DataIntegrityContextValidator'\nimport { W3cV2DataIntegrityVerifiableCredential } from './W3cV2DataIntegrityVerifiableCredential'\nimport { W3cV2DataIntegrityVerifiablePresentation } from './W3cV2DataIntegrityVerifiablePresentation'\n\n@injectable()\nexport class W3cV2DataIntegrityCredentialService {\n private dataIntegrityProofService: DataIntegrityProofService\n private contextValidator: W3cV2DataIntegrityContextValidator\n\n public constructor(\n dataIntegrityProofService: DataIntegrityProofService,\n contextValidator: W3cV2DataIntegrityContextValidator\n ) {\n this.dataIntegrityProofService = dataIntegrityProofService\n this.contextValidator = contextValidator\n }\n\n public async signCredential(\n agentContext: AgentContext,\n options: W3cV2DiSignCredentialOptions\n ): Promise<W3cV2VerifiableCredential<ClaimFormat.DiVc>> {\n const unsecuredCredential = JsonTransformer.toJSON(options.credential)\n if (unsecuredCredential['@context'] === undefined || unsecuredCredential['@context'] === null) {\n unsecuredCredential['@context'] = [CREDENTIALS_CONTEXT_V2_URL]\n }\n\n MessageValidator.validateSync(JsonTransformer.fromJSON(unsecuredCredential, W3cV2Credential, { validate: false }))\n\n const contextValidation = validateVc2ContextBaseline(unsecuredCredential['@context'])\n if (!contextValidation.isValid) {\n throw contextValidation.error ?? new CredoError('VC2 credential @context validation failed')\n }\n\n const proofResult = await this.dataIntegrityProofService.createProof(agentContext, {\n unsecuredDocument: unsecuredCredential,\n verificationMethod: options.verificationMethod,\n proofPurpose: 'assertionMethod',\n cryptosuite: options.cryptosuite,\n })\n\n if (!proofResult.created) {\n throw createDataIntegrityCredoError(proofResult.errors)\n }\n\n return new W3cV2DataIntegrityVerifiableCredential({\n securedCredential: {\n ...unsecuredCredential,\n proof: proofResult.proof,\n },\n })\n }\n\n public async verifyCredential(\n agentContext: AgentContext,\n options: W3cV2DiVerifyCredentialOptions\n ): Promise<W3cV2VerifyCredentialResult> {\n const securedCredential = options.credential.securedCredential\n const verificationResult = Array.isArray(securedCredential.proof)\n ? await this.dataIntegrityProofService.verifyProofSetAndChain(agentContext, securedCredential as never, {\n expectedProofPurpose: 'assertionMethod',\n })\n : await this.dataIntegrityProofService.verifyProof(agentContext, securedCredential as never, {\n expectedProofPurpose: 'assertionMethod',\n })\n\n if (!verificationResult.verified) {\n return this.invalidResult(verificationResult.errors, 'credential')\n }\n\n const contextResult = await this.contextValidator.validate(agentContext, securedCredential)\n if (!contextResult.validated) {\n return this.invalidResult(contextResult.errors as DataIntegrityIssueList, 'credential')\n }\n\n const credentialStatus = validateVc2CredentialStatus({\n credentialStatus: securedCredential.credentialStatus,\n credentialFormat: 'DI',\n verifyCredentialStatus: options.verifyCredentialStatus,\n })\n\n const issuerIsSigner = await this.verifySignerIsExpectedParty(\n agentContext,\n securedCredential,\n 'assertionMethod',\n options.credential.resolvedCredential.issuerId,\n (verificationMethodId, issuerId) =>\n `Credential is signed using verification method ${verificationMethodId}, while the issuer of the credential is '${issuerId}'`\n )\n\n const isValid = credentialStatus.isValid && issuerIsSigner.isValid\n\n return {\n isValid,\n validations: {\n dataModel: { isValid: true },\n signature: { isValid: true },\n credentialStatus,\n issuerIsSigner,\n },\n }\n }\n\n public async signPresentation(\n agentContext: AgentContext,\n options: W3cV2DiSignPresentationOptions\n ): Promise<W3cV2VerifiablePresentation<ClaimFormat.DiVp>> {\n const unsecuredPresentation = JsonTransformer.toJSON(options.presentation)\n if (unsecuredPresentation['@context'] === undefined || unsecuredPresentation['@context'] === null) {\n unsecuredPresentation['@context'] = [CREDENTIALS_CONTEXT_V2_URL]\n }\n\n MessageValidator.validateSync(\n JsonTransformer.fromJSON(unsecuredPresentation, W3cV2Presentation, { validate: false })\n )\n\n const contextValidation = validateVc2ContextBaseline(unsecuredPresentation['@context'])\n if (!contextValidation.isValid) {\n throw contextValidation.error ?? new CredoError('VC2 presentation @context validation failed')\n }\n\n const proofResult = await this.dataIntegrityProofService.createProof(agentContext, {\n unsecuredDocument: unsecuredPresentation,\n verificationMethod: options.verificationMethod,\n proofPurpose: 'authentication',\n cryptosuite: options.cryptosuite,\n challenge: options.challenge,\n domain: options.domain,\n })\n\n if (!proofResult.created) {\n throw createDataIntegrityCredoError(proofResult.errors)\n }\n\n const securedPresentation = {\n ...unsecuredPresentation,\n proof: proofResult.proof,\n }\n\n return new W3cV2DataIntegrityVerifiablePresentation({\n securedPresentation,\n resolvedPresentation: JsonTransformer.fromJSON(securedPresentation, W3cV2Presentation, { validate: false }),\n })\n }\n\n public async verifyPresentation(\n agentContext: AgentContext,\n options: W3cV2DiVerifyPresentationOptions\n ): Promise<W3cV2VerifyPresentationResult> {\n const securedPresentation = options.presentation.securedPresentation\n\n const verificationResult = Array.isArray(securedPresentation.proof)\n ? await this.dataIntegrityProofService.verifyProofSetAndChain(agentContext, securedPresentation as never, {\n expectedProofPurpose: 'authentication',\n challenge: options.challenge,\n domain: options.domain,\n })\n : await this.dataIntegrityProofService.verifyProof(agentContext, securedPresentation as never, {\n expectedProofPurpose: 'authentication',\n challenge: options.challenge,\n domain: options.domain,\n })\n\n if (!verificationResult.verified) {\n return this.invalidResult(verificationResult.errors, 'presentation')\n }\n\n const presentationContextResult = await this.contextValidator.validate(agentContext, securedPresentation)\n if (!presentationContextResult.validated) {\n return this.invalidResult(presentationContextResult.errors as DataIntegrityIssueList, 'presentation')\n }\n\n const holderIsSigner = await this.verifySignerIsExpectedParty(\n agentContext,\n options.presentation.securedPresentation,\n 'authentication',\n options.presentation.resolvedPresentation.holderId,\n (verificationMethodId, holderId) =>\n `Presentation is signed using verification method ${verificationMethodId}, while the holder of the presentation is '${holderId}'`\n )\n\n return {\n isValid: holderIsSigner.isValid,\n presentation: {\n isValid: holderIsSigner.isValid,\n validations: {\n dataModel: { isValid: true },\n holderIsSigner,\n presentationSignature: { isValid: true },\n },\n },\n credentialEntries: [],\n }\n }\n\n /**\n * Checks that a secured document was signed by the identity it names as responsible for it —\n * the `issuer` of a credential, or the `holder` of a presentation.\n *\n * Mirrors the equivalent checks in the JWT and SD-JWT services — though those compare key\n * fingerprints for the issuer, whereas Data Integrity proofs name a verification method, so the\n * comparison here is by controller for both roles. It implements the association described in\n * VC-DATA-INTEGRITY §\"Relationship to Verifiable Credentials\": that the `controller` of the\n * proof's verification method matches the identifier used for the `issuer` or `holder`, and that\n * the verification method is expressed under a verification relationship acceptable for the\n * proof's purpose. The latter is enforced by dereferencing the key with `purpose`.\n *\n * Verifying the proof only establishes that *someone* signed; without this comparison a document\n * could name one party and be signed by an unrelated one.\n *\n * @param expectedSigner the `issuer` or `holder`. `Holder` is optional in\n * VCDM 2.0 so when undefined there is no claim to contradict, so the validation passes.\n */\n private async verifySignerIsExpectedParty(\n agentContext: AgentContext,\n securedDocument: { proof: unknown },\n purpose: 'assertionMethod' | 'authentication',\n expectedSigner: string | undefined,\n describeMismatch: (verificationMethodId: string, expectedSigner: string) => string\n ): Promise<SingleValidationResult> {\n if (!expectedSigner) {\n return { isValid: true }\n }\n\n try {\n const verificationMethod = await getVerificationMethodForDataIntegrityProof(\n agentContext,\n securedDocument,\n purpose,\n expectedSigner\n )\n\n // NOTE: as in the JWT service's holder check, this compares verificationMethod.controller\n // rather than verificationMethod.id, since issuer and holder identify an entity rather than\n // a specific key.\n if (verificationMethod.controller !== expectedSigner) {\n return {\n isValid: false,\n error: new CredoError(describeMismatch(verificationMethod.id, expectedSigner)),\n }\n }\n\n return { isValid: true }\n } catch (error) {\n return { isValid: false, error }\n }\n }\n\n private invalidResult(errors: DataIntegrityIssueList, target: 'credential'): W3cV2VerifyCredentialResult\n private invalidResult(errors: DataIntegrityIssueList, target: 'presentation'): W3cV2VerifyPresentationResult\n private invalidResult(\n errors: DataIntegrityIssueList,\n target: 'credential' | 'presentation'\n ): W3cV2VerifyCredentialResult | W3cV2VerifyPresentationResult {\n const invalidValidation = this.invalidValidation(errors)\n\n if (target === 'credential') {\n return {\n isValid: false,\n validations: {\n signature: invalidValidation,\n },\n }\n }\n\n return this.invalidPresentationResult('presentationSignature', invalidValidation.error)\n }\n\n private invalidValidation(errors: DataIntegrityIssueList) {\n return {\n isValid: false,\n error: createDataIntegrityCredoError(errors),\n } as const\n }\n\n private invalidPresentationResult(\n field: 'dataModel' | 'presentationSignature',\n error: Error\n ): W3cV2VerifyPresentationResult {\n return {\n isValid: false,\n presentation: {\n isValid: false,\n validations: {\n [field]: {\n isValid: false,\n error,\n },\n },\n },\n credentialEntries: [],\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"W3cV2DataIntegrityCredentialService.mjs","names":["createDataIntegrityCredoError"],"sources":["../../../../src/modules/vc/data-integrity/W3cV2DataIntegrityCredentialService.ts"],"sourcesContent":["import type { AgentContext } from '../../../agent/context'\nimport { TrustedIssuerContext } from '../../../agent/TrustedIssuerContext'\nimport { CredoError } from '../../../error'\nimport { injectable } from '../../../plugins'\nimport { JsonTransformer, MessageValidator } from '../../../utils'\nimport {\n createW3cDataIntegrityCredoError as createDataIntegrityCredoError,\n type W3cDataIntegrityIssueList as DataIntegrityIssueList,\n W3cDataIntegrityProofService as DataIntegrityProofService,\n} from '../../w3c-di/internal'\nimport { CREDENTIALS_CONTEXT_V2_URL } from '../constants'\nimport { ClaimFormat } from '../models/ClaimFormat'\nimport { W3cV2Credential } from '../models/credential/W3cV2Credential'\nimport type { W3cV2VerifiableCredential } from '../models/credential/W3cV2VerifiableCredential'\nimport { W3cV2Presentation } from '../models/presentation/W3cV2Presentation'\nimport type { W3cV2VerifiablePresentation } from '../models/presentation/W3cV2VerifiablePresentation'\nimport type { W3cV2VerifyCredentialResult, W3cV2VerifyPresentationResult } from '../models/W3cV2VerifyResult'\nimport type { SingleValidationResult } from '../models/W3cVerifyResult'\nimport { type ResolvedSigner, validateSignerIsExpectedParty } from '../resolveSigner'\nimport { validateVc2ContextBaseline, validateVc2CredentialStatus } from '../validators'\nimport type {\n W3cV2DiSignCredentialOptions,\n W3cV2DiSignPresentationOptions,\n W3cV2DiVerifyCredentialOptions,\n W3cV2DiVerifyPresentationOptions,\n} from '../W3cV2CredentialServiceOptions'\nimport { resolveDataIntegritySigner } from './v2-di-utils'\nimport { W3cV2DataIntegrityContextValidator } from './W3cV2DataIntegrityContextValidator'\nimport { W3cV2DataIntegrityVerifiableCredential } from './W3cV2DataIntegrityVerifiableCredential'\nimport { W3cV2DataIntegrityVerifiablePresentation } from './W3cV2DataIntegrityVerifiablePresentation'\n\n@injectable()\nexport class W3cV2DataIntegrityCredentialService {\n private dataIntegrityProofService: DataIntegrityProofService\n private contextValidator: W3cV2DataIntegrityContextValidator\n\n public constructor(\n dataIntegrityProofService: DataIntegrityProofService,\n contextValidator: W3cV2DataIntegrityContextValidator\n ) {\n this.dataIntegrityProofService = dataIntegrityProofService\n this.contextValidator = contextValidator\n }\n\n public async signCredential(\n agentContext: AgentContext,\n options: W3cV2DiSignCredentialOptions\n ): Promise<W3cV2VerifiableCredential<ClaimFormat.DiVc>> {\n const unsecuredCredential = JsonTransformer.toJSON(options.credential)\n if (unsecuredCredential['@context'] === undefined || unsecuredCredential['@context'] === null) {\n unsecuredCredential['@context'] = [CREDENTIALS_CONTEXT_V2_URL]\n }\n\n MessageValidator.validateSync(JsonTransformer.fromJSON(unsecuredCredential, W3cV2Credential, { validate: false }))\n\n const contextValidation = validateVc2ContextBaseline(unsecuredCredential['@context'])\n if (!contextValidation.isValid) {\n throw contextValidation.error ?? new CredoError('VC2 credential @context validation failed')\n }\n\n const proofResult = await this.dataIntegrityProofService.createProof(agentContext, {\n unsecuredDocument: unsecuredCredential,\n verificationMethod: options.verificationMethod,\n proofPurpose: 'assertionMethod',\n cryptosuite: options.cryptosuite,\n })\n\n if (!proofResult.created) {\n throw createDataIntegrityCredoError(proofResult.errors)\n }\n\n return new W3cV2DataIntegrityVerifiableCredential({\n securedCredential: {\n ...unsecuredCredential,\n proof: proofResult.proof,\n },\n })\n }\n\n public async verifyCredential(\n agentContext: AgentContext,\n options: W3cV2DiVerifyCredentialOptions\n ): Promise<W3cV2VerifyCredentialResult> {\n const securedCredential = options.credential.securedCredential\n const verificationResult = Array.isArray(securedCredential.proof)\n ? await this.dataIntegrityProofService.verifyProofSetAndChain(agentContext, securedCredential as never, {\n expectedProofPurpose: 'assertionMethod',\n })\n : await this.dataIntegrityProofService.verifyProof(agentContext, securedCredential as never, {\n expectedProofPurpose: 'assertionMethod',\n })\n\n if (!verificationResult.verified) {\n return this.invalidResult(verificationResult.errors, 'credential')\n }\n\n const contextResult = await this.contextValidator.validate(agentContext, securedCredential)\n if (!contextResult.validated) {\n return this.invalidResult(contextResult.errors as DataIntegrityIssueList, 'credential')\n }\n\n const credentialStatus = validateVc2CredentialStatus({\n credentialStatus: securedCredential.credentialStatus,\n credentialFormat: 'DI',\n verifyCredentialStatus: options.verifyCredentialStatus,\n })\n\n const { validation: issuerIsSigner, signer: issuer } = await this.verifySignerIsExpectedParty(\n agentContext,\n securedCredential,\n 'assertionMethod',\n options.credential.resolvedCredential.issuerId,\n 'issuer'\n )\n\n const validations = {\n dataModel: { isValid: true },\n signature: { isValid: true },\n credentialStatus,\n issuerIsSigner,\n }\n\n if (issuer && issuerIsSigner.isValid) {\n try {\n await TrustedIssuerContext.ensureTrustedCredentialSigner(\n agentContext,\n {\n signer: { method: 'did', didUrl: issuer.verificationMethod.id },\n verification: { type: 'credential', credential: options.credential },\n },\n options.trustedIssuers\n )\n } catch (error) {\n return { isValid: false, validations, error }\n }\n }\n\n return {\n isValid: credentialStatus.isValid && issuerIsSigner.isValid,\n validations,\n }\n }\n\n public async signPresentation(\n agentContext: AgentContext,\n options: W3cV2DiSignPresentationOptions\n ): Promise<W3cV2VerifiablePresentation<ClaimFormat.DiVp>> {\n const unsecuredPresentation = JsonTransformer.toJSON(options.presentation)\n if (unsecuredPresentation['@context'] === undefined || unsecuredPresentation['@context'] === null) {\n unsecuredPresentation['@context'] = [CREDENTIALS_CONTEXT_V2_URL]\n }\n\n MessageValidator.validateSync(\n JsonTransformer.fromJSON(unsecuredPresentation, W3cV2Presentation, { validate: false })\n )\n\n const contextValidation = validateVc2ContextBaseline(unsecuredPresentation['@context'])\n if (!contextValidation.isValid) {\n throw contextValidation.error ?? new CredoError('VC2 presentation @context validation failed')\n }\n\n const proofResult = await this.dataIntegrityProofService.createProof(agentContext, {\n unsecuredDocument: unsecuredPresentation,\n verificationMethod: options.verificationMethod,\n proofPurpose: 'authentication',\n cryptosuite: options.cryptosuite,\n challenge: options.challenge,\n domain: options.domain,\n })\n\n if (!proofResult.created) {\n throw createDataIntegrityCredoError(proofResult.errors)\n }\n\n const securedPresentation = {\n ...unsecuredPresentation,\n proof: proofResult.proof,\n }\n\n return new W3cV2DataIntegrityVerifiablePresentation({\n securedPresentation,\n resolvedPresentation: JsonTransformer.fromJSON(securedPresentation, W3cV2Presentation, { validate: false }),\n })\n }\n\n public async verifyPresentation(\n agentContext: AgentContext,\n options: W3cV2DiVerifyPresentationOptions\n ): Promise<W3cV2VerifyPresentationResult> {\n const securedPresentation = options.presentation.securedPresentation\n\n const verificationResult = Array.isArray(securedPresentation.proof)\n ? await this.dataIntegrityProofService.verifyProofSetAndChain(agentContext, securedPresentation as never, {\n expectedProofPurpose: 'authentication',\n challenge: options.challenge,\n domain: options.domain,\n })\n : await this.dataIntegrityProofService.verifyProof(agentContext, securedPresentation as never, {\n expectedProofPurpose: 'authentication',\n challenge: options.challenge,\n domain: options.domain,\n })\n\n if (!verificationResult.verified) {\n return this.invalidResult(verificationResult.errors, 'presentation')\n }\n\n const presentationContextResult = await this.contextValidator.validate(agentContext, securedPresentation)\n if (!presentationContextResult.validated) {\n return this.invalidResult(presentationContextResult.errors as DataIntegrityIssueList, 'presentation')\n }\n\n const { validation: holderIsSigner } = await this.verifySignerIsExpectedParty(\n agentContext,\n options.presentation.securedPresentation,\n 'authentication',\n options.presentation.resolvedPresentation.holderId,\n 'holder'\n )\n\n return {\n isValid: holderIsSigner.isValid,\n presentation: {\n isValid: holderIsSigner.isValid,\n validations: {\n dataModel: { isValid: true },\n holderIsSigner,\n presentationSignature: { isValid: true },\n },\n },\n credentialEntries: [],\n }\n }\n\n private async verifySignerIsExpectedParty(\n agentContext: AgentContext,\n securedDocument: { proof: unknown },\n purpose: 'assertionMethod' | 'authentication',\n expectedSigner: string | undefined,\n role: 'issuer' | 'holder'\n ): Promise<{ validation: SingleValidationResult; signer?: ResolvedSigner }> {\n if (!expectedSigner) {\n return { validation: { isValid: true } }\n }\n\n try {\n const signer = await resolveDataIntegritySigner(agentContext, securedDocument, purpose, expectedSigner)\n return { validation: validateSignerIsExpectedParty(signer, expectedSigner, role), signer }\n } catch (error) {\n return { validation: { isValid: false, error } }\n }\n }\n\n private invalidResult(errors: DataIntegrityIssueList, target: 'credential'): W3cV2VerifyCredentialResult\n private invalidResult(errors: DataIntegrityIssueList, target: 'presentation'): W3cV2VerifyPresentationResult\n private invalidResult(\n errors: DataIntegrityIssueList,\n target: 'credential' | 'presentation'\n ): W3cV2VerifyCredentialResult | W3cV2VerifyPresentationResult {\n const invalidValidation = this.invalidValidation(errors)\n\n if (target === 'credential') {\n return {\n isValid: false,\n validations: {\n signature: invalidValidation,\n },\n }\n }\n\n return this.invalidPresentationResult('presentationSignature', invalidValidation.error)\n }\n\n private invalidValidation(errors: DataIntegrityIssueList) {\n return {\n isValid: false,\n error: createDataIntegrityCredoError(errors),\n } as const\n }\n\n private invalidPresentationResult(\n field: 'dataModel' | 'presentationSignature',\n error: Error\n ): W3cV2VerifyPresentationResult {\n return {\n isValid: false,\n presentation: {\n isValid: false,\n validations: {\n [field]: {\n isValid: false,\n error,\n },\n },\n },\n credentialEntries: [],\n }\n }\n}\n"],"mappings":"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"}
|