Skip to content

Commit 9786c84

Browse files
committed
fix: check signature of fetched credential, w3cjwt support
Signed-off-by: Krishna Waske <[email protected]>
1 parent 96dadd7 commit 9786c84

File tree

4 files changed

+37
-34
lines changed

4 files changed

+37
-34
lines changed

packages/core/src/modules/vc/data-integrity/W3cJsonLdCredentialService.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type {
99
W3cJsonLdVerifyCredentialOptions,
1010
W3cJsonLdVerifyPresentationOptions,
1111
} from '../W3cCredentialServiceOptions'
12-
import type { W3cVerifyCredentialResult, W3cVerifyPresentationResult } from '../models'
12+
import { ClaimFormat, type W3cVerifyCredentialResult, type W3cVerifyPresentationResult } from '../models'
1313
import type { W3cJsonCredential } from '../models/credential/W3cJsonCredential'
1414

1515
import { createWalletKeyPairClass } from '../../../crypto/WalletKeyPair'
@@ -116,7 +116,7 @@ export class W3cJsonLdCredentialService {
116116
// await verifyBitStringCredentialStatus(credential, agentContext)
117117
// Add a verification function that then checks which type of credentailStatus we have
118118
// If the type is supported, we validate it and return the result
119-
await validateStatus(credential.credentialStatus, agentContext)
119+
await validateStatus(credential.credentialStatus, agentContext, ClaimFormat.LdpVc)
120120
}
121121
return {
122122
verified: true,
@@ -275,7 +275,7 @@ export class W3cJsonLdCredentialService {
275275
// await verifyBitStringCredentialStatus(credential, agentContext)
276276
// Add a verification function that then checks which type of credentailStatus we have
277277
// If the type is supported, we validate it and return the result
278-
await validateStatus(credential.credentialStatus, agentContext)
278+
await validateStatus(credential.credentialStatus, agentContext, ClaimFormat.LdpVc)
279279
}
280280
return {
281281
verified: true,

packages/core/src/modules/vc/data-integrity/libraries/credentialStatus.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ import {
99
} from '../../models/credential/w3c-credential-status'
1010
import { W3cCredentialStatusSupportedTypes } from '../../models/credential/w3c-credential-status/W3cCredentialStatus'
1111
import { SingleOrArray } from '../../../../utils'
12+
import { ClaimFormat } from '../../models'
1213

1314
// Function to validate the status using the updated method
1415
export const validateStatus = async (
1516
credentialStatus: SingleOrArray<W3cCredentialStatus>,
16-
agentContext: AgentContext
17+
agentContext: AgentContext,
18+
credentialFormat: ClaimFormat.JwtVc | ClaimFormat.LdpVc
1719
): Promise<boolean> => {
1820

1921
if (Array.isArray(credentialStatus)) {
@@ -27,7 +29,11 @@ export const validateStatus = async (
2729
case W3cCredentialStatusSupportedTypes.BitstringStatusListEntry:
2830
agentContext.config.logger.debug('Credential status type is BitstringStatusListEntry')
2931
try {
30-
await verifyBitStringCredentialStatus(credentialStatus as unknown as BitStringStatusListEntry, agentContext)
32+
await verifyBitStringCredentialStatus(
33+
credentialStatus as unknown as BitStringStatusListEntry,
34+
agentContext,
35+
credentialFormat
36+
)
3137
} catch (errors) {
3238
throw new CredoError(`Error while validating credential status`, errors)
3339
}

packages/core/src/modules/vc/jwt-vc/W3cJwtCredentialService.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type {
88
W3cJwtVerifyCredentialOptions,
99
W3cJwtVerifyPresentationOptions,
1010
} from '../W3cCredentialServiceOptions'
11-
import type { SingleValidationResult, W3cVerifyCredentialResult, W3cVerifyPresentationResult } from '../models'
11+
import { ClaimFormat, type SingleValidationResult, type W3cVerifyCredentialResult, type W3cVerifyPresentationResult } from '../models'
1212

1313
import { JwsService } from '../../../crypto'
1414
import { getJwkFromKey, getJwkClassFromJwaSignatureAlgorithm } from '../../../crypto/jose/jwk'
@@ -23,6 +23,7 @@ import { W3cJwtVerifiableCredential } from './W3cJwtVerifiableCredential'
2323
import { W3cJwtVerifiablePresentation } from './W3cJwtVerifiablePresentation'
2424
import { getJwtPayloadFromCredential } from './credentialTransformer'
2525
import { getJwtPayloadFromPresentation } from './presentationTransformer'
26+
import { validateStatus } from '../data-integrity/libraries/credentialStatus'
2627

2728
/**
2829
* Supports signing and verification of credentials according to the [Verifiable Credential Data Model](https://www.w3.org/TR/vc-data-model)
@@ -193,9 +194,13 @@ export class W3cJwtCredentialService {
193194
isValid: true,
194195
}
195196
} else if (verifyCredentialStatus && credential.credentialStatus) {
197+
// TODO: Add similar verification for JWT VCs
198+
// validationResults.validations.credentialStatus = {
199+
// isValid: false,
200+
// error: new CredoError('Verifying credential status is not supported for JWT VCs'),
201+
// }
196202
validationResults.validations.credentialStatus = {
197-
isValid: false,
198-
error: new CredoError('Verifying credential status is not supported for JWT VCs'),
203+
isValid: await validateStatus(credential.credentialStatus, agentContext, ClaimFormat.JwtVc)
199204
}
200205
}
201206

@@ -376,6 +381,7 @@ export class W3cJwtCredentialService {
376381
}
377382
}
378383

384+
// Already verifying credentialStatus, so might not need to have to check credential status explicitly here
379385
const credentialResult = await this.verifyCredential(agentContext, {
380386
credential,
381387
verifyCredentialStatus: options.verifyCredentialStatus,

packages/core/src/modules/vc/models/credential/w3c-credential-status/bitstring-status-list/VerifyBitStringCredentialStatus.ts

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import type { AgentContext } from '../../../../../../agent/context'
55
import { inflate } from 'pako'
66

77
import { CredoError } from '../../../../../../error'
8+
import { W3cCredentialService } from '../../../../W3cCredentialService'
9+
import { W3cJsonLdVerifyCredentialOptions, W3cJwtVerifyCredentialOptions } from '../../../../W3cCredentialServiceOptions'
10+
import { ClaimFormat } from '../../../ClaimFormat'
811

912
// Function to fetch and parse the bit string status list credential
1013
const fetchBitStringStatusListCredential = async (
@@ -30,7 +33,8 @@ const fetchBitStringStatusListCredential = async (
3033

3134
export const verifyBitStringCredentialStatus = async (
3235
credentialStatus: BitStringStatusListEntry,
33-
agentContext: AgentContext
36+
agentContext: AgentContext,
37+
credentialFormat: ClaimFormat.JwtVc | ClaimFormat.LdpVc
3438
) => {
3539
try {
3640
if (Array.isArray(credentialStatus)) {
@@ -62,7 +66,18 @@ export const verifyBitStringCredentialStatus = async (
6266
`This is the fetched BSLC ${JSON.stringify(bitStringStatusListCredential, null, 2)}`
6367
)
6468

65-
// TODO: Add logic to validate Credential signature
69+
// verify signatures of the credential
70+
const w3cCredentialService = agentContext.dependencyManager.resolve(W3cCredentialService)
71+
72+
let result
73+
if (credentialFormat === ClaimFormat.JwtVc){
74+
result = await w3cCredentialService.verifyCredential(agentContext, bitStringStatusListCredential as unknown as W3cJwtVerifyCredentialOptions)
75+
} else if (credentialFormat === ClaimFormat.LdpVc){
76+
result = await w3cCredentialService.verifyCredential(agentContext, bitStringStatusListCredential as unknown as W3cJsonLdVerifyCredentialOptions)
77+
}
78+
if (result && !result.isValid) {
79+
throw new CredoError(`Failed to validate credential, error = ${result.error}`)
80+
}
6681

6782
// Decode the encoded bit string
6883
let decodedBitStringArray;
@@ -74,30 +89,6 @@ export const verifyBitStringCredentialStatus = async (
7489
} catch(err) {
7590
throw new CredoError('Error decoding Bitstring of fetched Bitstring StatusList Credential')
7691
}
77-
78-
// 1st approach
79-
// agentContext.config.logger.debug(`This is encodedBitString: ${encodedBitString}`)
80-
// const compressedBuffer = Uint8Array.from(atob(encodedBitString), (char) => char.charCodeAt(0))
81-
// agentContext.config.logger.debug('Decoding the encoded bit string for fetched BitString StatusList Credential')
82-
83-
// // Decompress the bit string using pako
84-
// const decodedBitString = ungzip(compressedBuffer, { to: 'string' })
85-
86-
// 2nd approach - worked
87-
// const base64ToUint8Array = (base64: string): Uint8Array => {
88-
// const binaryString = atob(base64.replace(/-/g, '+').replace(/_/g, '/')) // Handle URL-safe Base64
89-
// return new Uint8Array([...binaryString].map((char) => char.charCodeAt(0)))
90-
// }
91-
92-
// const compressedBuffer = base64ToUint8Array(encodedBitString)
93-
94-
// console.debug(`compressedBuffer: ${compressedBuffer}`)
95-
// console.debug('Decoding the encoded bit string for fetched BitString StatusList Credential')
96-
97-
// // Decompress the bit string using pako
98-
// const decodedBitString = new TextDecoder().decode(ungzip(compressedBuffer))
99-
100-
// console.debug(`Decoded BitString: ${decodedBitString}`)
10192

10293
const statusListIndex = Number(credentialStatus.statusListIndex)
10394

0 commit comments

Comments
 (0)