Skip to content

Commit

Permalink
feat: updated oid4vci-holder and siopv2-rp to use credential-validati…
Browse files Browse the repository at this point in the history
…on module for verifying credentials.
  • Loading branch information
sksadjad committed Oct 7, 2024
1 parent b25b66e commit 87081e5
Show file tree
Hide file tree
Showing 9 changed files with 25 additions and 63 deletions.
1 change: 1 addition & 0 deletions packages/credential-validation/agent.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ agent:
- $ref: /keyManager
- $ref: /didManager
- $require: '@veramo/core#Agent'
- $require: '@veramo/credential-w3c#CredentialPlugin'
- $require: '@veramo/data-store#DataStore'
$args:
- $ref: /dbConnection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export type VerifyCredentialArgs = {
credential: OriginalVerifiableCredential
hasher?: Hasher
fetchRemoteContexts: boolean
policies: VerificationPolicies
policies?: VerificationPolicies
}

export type VerificationPolicies = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TAgent } from '@veramo/core'
import { IOID4VCIHolder, SchemaValidation, VerificationResult, verifyCredentialAgainstSchemas } from '../../src'
import { IOID4VCIHolder } from '../../src'
import { AccessTokenResponse, WellKnownEndpoints } from '@sphereon/oid4vci-common'
import {
GET_CREDENTIAL_OFFER_AUTHORIZATION_CODE_HTTPS,
Expand All @@ -13,8 +13,6 @@ import {
WALLET_URL,
} from './MetadataMocks'
import { IMachineStatePersistence } from '@sphereon/ssi-sdk.xstate-machine-persistence'
import { CredentialMapper, OriginalVerifiableCredential, WrappedVerifiableCredential } from '@sphereon/ssi-types'
import * as fs from 'fs'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import nock = require('nock')
Expand Down Expand Up @@ -56,14 +54,6 @@ function succeedWithAFullFlowWithClientSetup() {
})
}

function getFile(path: string) {
return fs.readFileSync(path, 'utf-8')
}

function getFileAsJson(path: string) {
return JSON.parse(getFile(path))
}

export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Promise<boolean>; tearDown: () => Promise<boolean> }): void => {
// fixme: Enable these tests. Not sure why the mocks have been butchered from correct values to values that would never work anyway. Made some quick fixes, but needs more work
describe.skip('OID4VI Holder Agent Plugin', (): void => {
Expand Down Expand Up @@ -120,50 +110,4 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro
).resolves.toEqual(GET_CREDENTIAL_OFFER_PRE_AUTHORIZED_CODE_HTTPS)
})
})

describe('Credential schema validation', () => {
const jwtVc: OriginalVerifiableCredential =
'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sImlkIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzM3MzIiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVW5pdmVyc2l0eURlZ3JlZUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiaHR0cHM6Ly9leGFtcGxlLmVkdS9pc3N1ZXJzLzE0IiwiaXNzdWFuY2VEYXRlIjoiMjAxMC0wMS0wMVQxOToyMzoyNFoiLCJjcmVkZW50aWFsU3ViamVjdCI6eyJpZCI6ImRpZDpleGFtcGxlOmViZmViMWY3MTJlYmM2ZjFjMjc2ZTEyZWMyMSIsImRlZ3JlZSI6eyJ0eXBlIjoiQmFjaGVsb3JEZWdyZWUiLCJuYW1lIjoiQmFjaGVsb3Igb2YgU2NpZW5jZSBhbmQgQXJ0cyJ9fSwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6Imh0dHBzOi8vZXhhbXBsZS5vcmcvZXhhbXBsZXMvZGVncmVlLmpzb24iLCJ0eXBlIjoiSnNvblNjaGVtYVZhbGlkYXRvcjIwMTgifX0sImlzcyI6Imh0dHBzOi8vZXhhbXBsZS5lZHUvaXNzdWVycy8xNCIsIm5iZiI6MTI2MjM3MzgwNCwianRpIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzM3MzIiLCJzdWIiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEifQ.GRJHwxvQfgEOP8TaaBnp2ZCPjFlA_KodpdBupHsRroql10gaE--8oAXR1e-wOuxjFoK-T814h9LKnv71IMI38Q'
const ldpVc: OriginalVerifiableCredential = getFileAsJson('packages/ssi-types/__tests__/vc_vp_examples/vc/vc_driverLicense.json')
const ebsiAuthorisationToOnboardVc: OriginalVerifiableCredential =
'eyJ0eXAiOiJKV1QiLCJraWQiOiIxODNkY2E4NDRiNzM5OGM4MTQ0ZTJiMzk5OWM3MzA2Y2I3OTYzMDJhZWQxNDdkNjY4ZmI2ZmI5YmE0OTZkNTBkIiwiYWxnIjoiRVMyNTZLIn0.eyJpc3N1ZXIiOiJkaWQ6ZWJzaTp6aURuaW94WVlMVzFhM3FVYnFURno0VyIsImlhdCI6MTcxNDQxMzA4OCwianRpIjoidXJuOnV1aWQ6NWZiN2Q5OGItMTA4Yy00YmMwLTlmZmMtYzY5Zjg0ZWQ3ODhmIiwibmJmIjoxNzE0NDEzMDg4LCJleHAiOjE3NDU5NDkwODgsInN1YiI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiaWQiOiJ1cm46dXVpZDo1ZmI3ZDk4Yi0xMDhjLTRiYzAtOWZmYy1jNjlmODRlZDc4OGYiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpYWJsZUF0dGVzdGF0aW9uIiwiVmVyaWZpYWJsZUF1dGhvcmlzYXRpb25Ub09uYm9hcmQiXSwiaXNzdWFuY2VEYXRlIjoiMjAyNC0wNC0yOVQxNzo1MToyOFoiLCJpc3N1ZWQiOiIyMDI0LTA0LTI5VDE3OjUxOjI4WiIsInZhbGlkRnJvbSI6IjIwMjQtMDQtMjlUMTc6NTE6MjhaIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI1LTA0LTI5VDE3OjUxOjI4WiIsImlzc3VlciI6ImRpZDplYnNpOnppRG5pb3hZWUxXMWEzcVVicVRGejRXIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZWJzaTp6ZXliQWlKeHpVVXJXUTFZTTUxU1kzNSIsImFjY3JlZGl0ZWRGb3IiOltdfSwidGVybXNPZlVzZSI6eyJpZCI6ImRpZDplYnNpOnpleWJBaUp4elVVcldRMVlNNTFTWTM1IiwidHlwZSI6Iklzc3VhbmNlQ2VydGlmaWNhdGUifSwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6Imh0dHBzOi8vYXBpLXBpbG90LmVic2kuZXUvdHJ1c3RlZC1zY2hlbWFzLXJlZ2lzdHJ5L3YyL3NjaGVtYXMvejNNZ1VGVWtiNzIydXE0eDNkdjV5QUptbk5tekRGZUs1VUM4eDgzUW9lTEpNIiwidHlwZSI6IkZ1bGxKc29uU2NoZW1hVmFsaWRhdG9yMjAyMSJ9fX0.QWNWTWlrbUpLcFJaLVBGczQ0U3Mxb200Mk4yb3JzWndsTXp3REpHTTMxSUM2WG5ZVXJ0ZlY4RHFTbVQtaXBIMEdLSDZhclFEcGtrbXZTTy1NenYxWEE'
const ebsiKVKRegistrationVc: OriginalVerifiableCredential =
'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRpZDplYnNpOnptS0M5aW4zY3YzeThEUFNFcURVbkcxIzM2WlJCMlFwUzd3aTBUUWMwQVI0NVM4UXpsS2I5UkdUMXRKUndDNGctakEifQ.eyJpc3MiOiJkaWQ6ZWJzaTp6bUtDOWluM2N2M3k4RFBTRXFEVW5HMSIsInN1YiI6ImRpZDpqd2s6ZXlKcmRIa2lPaUpQUzFBaUxDSmpjbllpT2lKRlpESTFOVEU1SWl3aWEybGtJam9pZGtwa1ZUQlBkRzFUUVZVNFZFMXVhVlJxUzJJMFRVZFdNelJaVG1kaWJHNU5NMHBNTWsxTFpsbFNPQ0lzSW5naU9pSXhVRGRIVjBkc09HRnlWM05SUmkxMFFYUTJXVTlPTFd4TkxVOXZTM0ZLVEc1bFZuSmFURWhWU25sdkluMCIsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIiwiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvZXhhbXBsZXMvdjEiXSwiaWQiOiJ1cm46dXVpZDo4OGU3NWVjOS1lMGUxLTQ0NzEtOWIyNi05ZjJhNTk0MmUxNjAiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiVmVyaWZpYWJsZUF0dGVzdGF0aW9uIiwiS1ZLUmVnaXN0cmF0aW9uIl0sImlzc3VlciI6ImRpZDplYnNpOnptS0M5aW4zY3YzeThEUFNFcURVbkcxIiwiaXNzdWVkIjoiMjAyNC0wOS0xOFQxMjozOToyNy4yODMwOTA3NzVaIiwidmFsaWRGcm9tIjoiMjAyNC0wOS0xOFQxMjozOToyNy4yODMwOTA3NzVaIiwiaXNzdWFuY2VEYXRlIjoiMjAyNC0wOS0xOFQxMjozOToyNy4yODMwOTA3NzVaIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6andrOmV5SnJkSGtpT2lKUFMxQWlMQ0pqY25ZaU9pSkZaREkxTlRFNUlpd2lhMmxrSWpvaWRrcGtWVEJQZEcxVFFWVTRWRTF1YVZScVMySTBUVWRXTXpSWlRtZGliRzVOTTBwTU1rMUxabGxTT0NJc0luZ2lPaUl4VURkSFYwZHNPR0Z5VjNOUlJpMTBRWFEyV1U5T0xXeE5MVTl2UzNGS1RHNWxWbkphVEVoVlNubHZJbjAiLCJrdmtOdW1tZXIiOiIyNDEyOTg3NiIsIm5hYW0iOiJEdXRjaENyYWZ0IEZ1cm5pc2hpbmciLCJyZWNodHN2b3JtIjoiQmVzbG90ZW4gVmVubm9vdHNjaGFwIiwic3RhcnRkYXR1bSI6IjIwMjItMDctMDEiLCJlaW5kZGF0dW0iOiIifSwidGVybXNPZlVzZSI6W3siaWQiOiJodHRwczovL2FwaS1waWxvdC5lYnNpLmV1L3RydXN0ZWQtaXNzdWVycy1yZWdpc3RyeS92NS9pc3N1ZXJzL2RpZDplYnNpOnptS0M5aW4zY3YzeThEUFNFcURVbkcxL2F0dHJpYnV0ZXMvZGVhOThhMjIwMTNiMGEyNjgzODNmNWZhZjc4OTJjYjUzMDU4NDI1OGNiOGUzYmZiZTdiMTQ4M2Y3YzY2NjQyMyIsInR5cGUiOiJJc3N1YW5jZUNlcnRpZmljYXRlIn1dLCJjcmVkZW50aWFsU2NoZW1hIjp7ImlkIjoiaHR0cHM6Ly9hcGktcGlsb3QuZWJzaS5ldS90cnVzdGVkLXNjaGVtYXMtcmVnaXN0cnkvdjMvc2NoZW1hcy8weGQyMjA0NjQ3ODE4ZjljMGM5M2Y2NGI3MGYxYzg5MmVhMmE4ZTBhNzQ3Y2VhYTJmNzczNzNiNDE5OTZiYjc2NGQiLCJ0eXBlIjoiRnVsbEpzb25TY2hlbWFWYWxpZGF0b3IyMDIxIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJodHRwczovL3dhbGxldC5hY2MuY3JlZGVuY28uY29tL2FwaS9zdGF0dXMvZGY4MDNkZDQtMzJjNi00YTY5LWFmZTUtZDgwN2M2NzAxZWQ3LzEjNjY5MDQiLCJ0eXBlIjoiU3RhdHVzTGlzdDIwMjFFbnRyeSIsInN0YXR1c1B1cnBvc2UiOiJyZXZvY2F0aW9uIiwic3RhdHVzTGlzdEluZGV4Ijo2NjkwNCwic3RhdHVzTGlzdENyZWRlbnRpYWwiOiJodHRwczovL3dhbGxldC5hY2MuY3JlZGVuY28uY29tL2FwaS9zdGF0dXMvZGY4MDNkZDQtMzJjNi00YTY5LWFmZTUtZDgwN2M2NzAxZWQ3LzEifX0sImp0aSI6InVybjp1dWlkOjg4ZTc1ZWM5LWUwZTEtNDQ3MS05YjI2LTlmMmE1OTQyZTE2MCIsImlhdCI6MTcyNjY2MzE2NywibmJmIjoxNzI2NjYzMTY3fQ.AnfEichO9BbwyCbNH9wImUMShEc9IWYISMfIDXsnqgyH8GijwlioeS75HyJasNWbFXWvSFfKpOkTqXxOji0GGw'

const wrappedJwtVc = CredentialMapper.toWrappedVerifiableCredential(jwtVc) as WrappedVerifiableCredential
const wrappedLdpVc = CredentialMapper.toWrappedVerifiableCredential(ldpVc) as WrappedVerifiableCredential
const wrappedEbsiVerifiableAuthorisationToOnboard = CredentialMapper.toWrappedVerifiableCredential(
ebsiAuthorisationToOnboardVc,
) as WrappedVerifiableCredential
const wrappedEbsiKVKRegistrationVc = CredentialMapper.toWrappedVerifiableCredential(ebsiKVKRegistrationVc) as WrappedVerifiableCredential

it('should validate KVKRegistration ebsi credential against schema', async () => {
/**
* the ebsi vc is different from the schema. it has the `einddatum` value as an empty string, while it should be a valid date like: `2024-09-23`
*/
const resultEbsiVc: VerificationResult = await verifyCredentialAgainstSchemas(wrappedEbsiKVKRegistrationVc, SchemaValidation.WHEN_PRESENT)
expect(resultEbsiVc.result).toBeFalsy()
}, 30000)

it('should validate AuthorisationToOnboard ebsi credential against schema', async () => {
/**
* the ebsi vc is different from the schema. The problem is in the proof section. it has a created of number (epoch) but should be a date-string like `2024-04-29T17:51:28Z` also it expects jws and not jwt
*/
const resultEbsiVc: VerificationResult = await verifyCredentialAgainstSchemas(
wrappedEbsiVerifiableAuthorisationToOnboard,
SchemaValidation.WHEN_PRESENT,
)
expect(resultEbsiVc.result).toBeFalsy()
}, 30000)

it('should not validate jwt VC with dummy schema', async () => {
const result: VerificationResult = await verifyCredentialAgainstSchemas(wrappedJwtVc, SchemaValidation.WHEN_PRESENT)
expect(result.result).toBeFalsy()
}, 30000)

it('should validate ldp VC without schema', async () => {
const result: VerificationResult = await verifyCredentialAgainstSchemas(wrappedLdpVc, SchemaValidation.WHEN_PRESENT)
expect(result.result).toBeTruthy()
}, 30000)
})
}
4 changes: 4 additions & 0 deletions packages/siopv2-oid4vp-op-auth/agent.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ credentialStore:
$require: './packages/data-store/dist#DigitalCredentialStore'
$args:
- $ref: /dbConnection
# Credential Validation
credentialValidation:
$require: ./packages/credential-validation/dist#CredentialValidation

# Agent
agent:
Expand All @@ -129,6 +132,7 @@ agent:
plugins:
- $ref: /didResolver
- $ref: /credentialStore
- $ref: / credentialValidation
- $require: ./packages/siopv2-oid4vp-op-auth/dist#DidAuthSiopOpAuthenticator
$args:
- presentationSignCallback: {}
Expand Down
1 change: 1 addition & 0 deletions packages/siopv2-oid4vp-op-auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@sphereon/ssi-sdk.contact-manager": "workspace:*",
"@sphereon/ssi-sdk.core": "workspace:*",
"@sphereon/ssi-sdk.credential-store": "workspace:*",
"@sphereon/ssi-sdk.credential-validation": "workspace:*",
"@sphereon/ssi-sdk.data-store": "workspace:*",
"@sphereon/ssi-sdk.issuance-branding": "workspace:*",
"@sphereon/ssi-sdk.pd-manager": "workspace:*",
Expand Down
8 changes: 6 additions & 2 deletions packages/siopv2-oid4vp-op-auth/src/session/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Resolvable } from 'did-resolver'
import { EventEmitter } from 'events'
import { IOPOptions, IRequiredContext } from '../types'
import { JwtIssuer } from '@sphereon/oid4vc-common/lib/jwt/JwtIssuer'
import { OriginalVerifiableCredential } from '@sphereon/ssi-types'

export async function createOID4VPPresentationSignCallback({
presentationSignCallback,
Expand Down Expand Up @@ -78,8 +79,11 @@ export async function createOPBuilder({
const wellknownDIDVerifyCallback = opOptions.wellknownDIDVerifyCallback
? opOptions.wellknownDIDVerifyCallback
: async (args: IVerifyCallbackArgs): Promise<IVerifyCredentialResult> => {
const result = await context.agent.verifyCredential({ credential: args.credential, fetchRemoteContexts: true })
return { verified: result.verified }
const result = await context.agent.cvVerifyCredential({
credential: args.credential as OriginalVerifiableCredential,
fetchRemoteContexts: true,
})
return { verified: result.result }
}
builder.withVerifyJwtCallback(
opOptions.verifyJwtCallback
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
Siopv2AuthorizationRequestData,
Siopv2AuthorizationResponseData,
} from './siop-service'
import { ICredentialValidation } from '@sphereon/ssi-sdk.credential-validation'

export const LOGGER_NAMESPACE = 'sphereon:siopv2-oid4vp:op-auth'

Expand Down Expand Up @@ -134,6 +135,7 @@ export type IRequiredContext = IAgentContext<
IKeyManager &
IIdentifierResolution &
ICredentialIssuer &
ICredentialValidation &
ICredentialVerifier &
ICredentialStore &
IPDManager &
Expand Down
9 changes: 6 additions & 3 deletions packages/siopv2-oid4vp-rp-auth/src/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
import { JwsCompactResult } from '@sphereon/ssi-sdk-ext.jwt-service'
import { IVerifySdJwtPresentationResult } from '@sphereon/ssi-sdk.sd-jwt'
import { SigningAlgo } from '@sphereon/oid4vc-common'
import { CredentialMapper, Hasher, PresentationSubmission } from '@sphereon/ssi-types'
import { CredentialMapper, Hasher, OriginalVerifiableCredential, PresentationSubmission } from '@sphereon/ssi-types'
import { IVerifyCallbackArgs, IVerifyCredentialResult, VerifyCallback } from '@sphereon/wellknown-dids-client'
// import { KeyAlgo, SuppliedSigner } from '@sphereon/ssi-sdk.core'
import { TKeyType } from '@veramo/core'
Expand All @@ -49,8 +49,11 @@ function getWellKnownDIDVerifyCallback(siopIdentifierOpts: ISIOPIdentifierOption
return siopIdentifierOpts.wellknownDIDVerifyCallback
? siopIdentifierOpts.wellknownDIDVerifyCallback
: async (args: IVerifyCallbackArgs): Promise<IVerifyCredentialResult> => {
const result = await context.agent.verifyCredential({ credential: args.credential, fetchRemoteContexts: true })
return { verified: result.verified }
const result = await context.agent.cvVerifyCredential({
credential: args.credential as OriginalVerifiableCredential,
fetchRemoteContexts: true,
})
return { verified: result.result }
}
}

Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 87081e5

Please sign in to comment.