@sphereon/ssi-sdk.siopv2-oid4vp-op-auth 0.34.1-next.91 → 0.36.0
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/dist/index.cjs +278 -178
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -10
- package/dist/index.d.ts +17 -10
- package/dist/index.js +271 -171
- package/dist/index.js.map +1 -1
- package/package.json +23 -22
- package/src/agent/DidAuthSiopOpAuthenticator.ts +5 -22
- package/src/machine/Siopv2Machine.ts +1 -1
- package/src/services/Siopv2MachineService.ts +98 -119
- package/src/session/OID4VP.ts +163 -315
- package/src/session/OpSession.ts +4 -20
- package/src/session/functions.ts +1 -8
- package/src/types/IDidAuthSiopOpAuthenticator.ts +1 -1
- package/src/types/machine/index.ts +1 -1
- package/src/types/siop-service/index.ts +11 -7
- package/src/utils/CredentialUtils.ts +1 -1
- package/src/utils/dcql.ts +7 -3
package/src/session/OID4VP.ts
CHANGED
|
@@ -1,333 +1,181 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// isOID4VCIssuerIdentifier,
|
|
7
|
-
// ManagedIdentifierOptsOrResult,
|
|
8
|
-
// ManagedIdentifierResult,
|
|
9
|
-
// } from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
10
|
-
// import { defaultHasher,
|
|
11
|
-
// // ProofOptions
|
|
12
|
-
// } from '@sphereon/ssi-sdk.core'
|
|
13
|
-
//import { UniqueDigitalCredential, verifiableCredentialForRoleFilter } from '@sphereon/ssi-sdk.credential-store'
|
|
14
|
-
//import { CredentialRole, FindDigitalCredentialArgs } from '@sphereon/ssi-sdk.data-store'
|
|
1
|
+
import type { PartialSdJwtKbJwt } from '@sphereon/pex/dist/main/lib/index.js'
|
|
2
|
+
import { calculateSdHash } from '@sphereon/pex/dist/main/lib/utils/index.js'
|
|
3
|
+
import { isManagedIdentifierDidResult, ManagedIdentifierOptsOrResult } from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
4
|
+
import { UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'
|
|
5
|
+
import { defaultGenerateDigest } from '@sphereon/ssi-sdk.sd-jwt'
|
|
15
6
|
import {
|
|
16
|
-
|
|
7
|
+
CredentialMapper,
|
|
8
|
+
DocumentFormat,
|
|
17
9
|
HasherSync,
|
|
18
|
-
|
|
10
|
+
Loggers,
|
|
11
|
+
OriginalVerifiableCredential,
|
|
12
|
+
SdJwtDecodedVerifiableCredential,
|
|
13
|
+
WrappedVerifiableCredential,
|
|
19
14
|
} from '@sphereon/ssi-types'
|
|
20
|
-
import {
|
|
21
|
-
//DEFAULT_JWT_PROOF_TYPE,
|
|
22
|
-
//IGetPresentationExchangeArgs,
|
|
23
|
-
IOID4VPArgs,
|
|
24
|
-
//VerifiableCredentialsWithDefinition,
|
|
25
|
-
//VerifiablePresentationWithDefinition,
|
|
26
|
-
} from '../types'
|
|
27
|
-
//import { createOID4VPPresentationSignCallback } from './functions'
|
|
28
|
-
import { OpSession } from './OpSession'
|
|
15
|
+
import { LOGGER_NAMESPACE, RequiredContext } from '../types'
|
|
29
16
|
|
|
30
|
-
|
|
17
|
+
const CLOCK_SKEW = 120
|
|
18
|
+
const logger = Loggers.DEFAULT.get(LOGGER_NAMESPACE)
|
|
31
19
|
|
|
32
|
-
export
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
|
|
20
|
+
export interface PresentationBuilderContext {
|
|
21
|
+
nonce: string
|
|
22
|
+
audience: string // clientId or origin
|
|
23
|
+
agent: RequiredContext['agent']
|
|
24
|
+
clockSkew?: number
|
|
25
|
+
hasher?: HasherSync
|
|
26
|
+
}
|
|
36
27
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Extracts the original credential from a UniqueDigitalCredential or WrappedVerifiableCredential
|
|
30
|
+
*/
|
|
31
|
+
function extractOriginalCredential(
|
|
32
|
+
credential: UniqueDigitalCredential | WrappedVerifiableCredential | OriginalVerifiableCredential,
|
|
33
|
+
): OriginalVerifiableCredential {
|
|
34
|
+
if (typeof credential === 'string') {
|
|
35
|
+
return credential
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if ('digitalCredential' in credential) {
|
|
39
|
+
// UniqueDigitalCredential
|
|
40
|
+
const udc = credential as UniqueDigitalCredential
|
|
41
|
+
if (udc.originalVerifiableCredential) {
|
|
42
|
+
return udc.originalVerifiableCredential
|
|
43
|
+
}
|
|
44
|
+
return udc.uniformVerifiableCredential as OriginalVerifiableCredential
|
|
45
|
+
}
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
//
|
|
44
|
-
|
|
47
|
+
if ('original' in credential) {
|
|
48
|
+
// WrappedVerifiableCredential
|
|
49
|
+
return credential.original
|
|
45
50
|
}
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
// Already an OriginalVerifiableCredential
|
|
53
|
+
return credential as OriginalVerifiableCredential
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Gets the issuer/holder identifier from ManagedIdentifierOptsOrResult
|
|
58
|
+
*/
|
|
59
|
+
function getIdentifierString(identifier: ManagedIdentifierOptsOrResult): string {
|
|
60
|
+
// Check if it's a result type (has 'method' and 'opts' properties)
|
|
61
|
+
if ('opts' in identifier && 'method' in identifier) {
|
|
62
|
+
// It's a ManagedIdentifierResult
|
|
63
|
+
if (isManagedIdentifierDidResult(identifier)) {
|
|
64
|
+
return identifier.did
|
|
65
|
+
}
|
|
49
66
|
}
|
|
67
|
+
// For opts types or other result types, use issuer if available, otherwise kid
|
|
68
|
+
return identifier.issuer ?? identifier.kid ?? ''
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Creates a Verifiable Presentation for a given credential in the appropriate format
|
|
73
|
+
* Ensures nonce/aud (or challenge/domain) are set according to OID4VP draft 28
|
|
74
|
+
*/
|
|
75
|
+
export async function createVerifiablePresentationForFormat(
|
|
76
|
+
credential: UniqueDigitalCredential | WrappedVerifiableCredential | OriginalVerifiableCredential,
|
|
77
|
+
identifier: ManagedIdentifierOptsOrResult,
|
|
78
|
+
context: PresentationBuilderContext,
|
|
79
|
+
): Promise<string | object> {
|
|
80
|
+
// FIXME find proper types
|
|
81
|
+
const { nonce, audience, agent, clockSkew = CLOCK_SKEW } = context
|
|
82
|
+
|
|
83
|
+
const originalCredential = extractOriginalCredential(credential)
|
|
84
|
+
const documentFormat = CredentialMapper.detectDocumentType(originalCredential)
|
|
50
85
|
|
|
51
|
-
|
|
52
|
-
// const definitions = await this.session.getPresentationDefinitions()
|
|
53
|
-
// if (definitions) {
|
|
54
|
-
// PresentationExchange.assertValidPresentationDefinitionWithLocations(definitions)
|
|
55
|
-
// }
|
|
56
|
-
// return definitions
|
|
57
|
-
// }
|
|
86
|
+
logger.debug(`Creating VP for format: ${documentFormat}`)
|
|
58
87
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// })
|
|
67
|
-
// }
|
|
88
|
+
switch (documentFormat) {
|
|
89
|
+
case DocumentFormat.SD_JWT_VC: {
|
|
90
|
+
// SD-JWT with KB-JWT
|
|
91
|
+
const decodedSdJwt = await CredentialMapper.decodeSdJwtVcAsync(
|
|
92
|
+
typeof originalCredential === 'string' ? originalCredential : (originalCredential as SdJwtDecodedVerifiableCredential).compactSdJwtVc,
|
|
93
|
+
defaultGenerateDigest,
|
|
94
|
+
)
|
|
68
95
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// credentialsWithDefinitions: VerifiableCredentialsWithDefinition[],
|
|
72
|
-
// opts?: {
|
|
73
|
-
// forceNoCredentialsInVP?: boolean // Allow to create a VP without credentials, like EBSI is using it. Defaults to false
|
|
74
|
-
// restrictToFormats?: Format
|
|
75
|
-
// restrictToDIDMethods?: string[]
|
|
76
|
-
// proofOpts?: ProofOptions
|
|
77
|
-
// idOpts?: ManagedIdentifierOptsOrResult
|
|
78
|
-
// skipDidResolution?: boolean
|
|
79
|
-
// holderDID?: string
|
|
80
|
-
// subjectIsHolder?: boolean
|
|
81
|
-
// hasher?: HasherSync
|
|
82
|
-
// applyFilter?: boolean
|
|
83
|
-
// },
|
|
84
|
-
// ): Promise<VerifiablePresentationWithDefinition[]> {
|
|
85
|
-
// return await Promise.all(credentialsWithDefinitions.map((cred) => this.createVerifiablePresentation(credentialRole, cred, opts)))
|
|
86
|
-
// }
|
|
96
|
+
const hashAlg = decodedSdJwt.signedPayload._sd_alg ?? 'sha-256'
|
|
97
|
+
const sdHash = calculateSdHash(decodedSdJwt.compactSdJwtVc, hashAlg, defaultGenerateDigest)
|
|
87
98
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
// restrictToDIDMethods?: string[]
|
|
95
|
-
// proofOpts?: ProofOptions
|
|
96
|
-
// idOpts?: ManagedIdentifierOptsOrResult
|
|
97
|
-
// skipDidResolution?: boolean
|
|
98
|
-
// holder?: string
|
|
99
|
-
// subjectIsHolder?: boolean
|
|
100
|
-
// applyFilter?: boolean
|
|
101
|
-
// hasher?: HasherSync
|
|
102
|
-
// },
|
|
103
|
-
// ): Promise<VerifiablePresentationWithDefinition> {
|
|
104
|
-
// const { subjectIsHolder, holder, forceNoCredentialsInVP = false } = { ...opts }
|
|
105
|
-
// if (subjectIsHolder && holder) {
|
|
106
|
-
// throw Error('Cannot both have subject is holder and a holderDID value at the same time (programming error)')
|
|
107
|
-
// }
|
|
108
|
-
// if (forceNoCredentialsInVP) {
|
|
109
|
-
// selectedVerifiableCredentials.credentials = []
|
|
110
|
-
// } else if (!selectedVerifiableCredentials?.credentials || selectedVerifiableCredentials.credentials.length === 0) {
|
|
111
|
-
// throw Error('No verifiable verifiableCredentials provided for presentation definition')
|
|
112
|
-
// }
|
|
113
|
-
//
|
|
114
|
-
// // const proofOptions: ProofOptions = {
|
|
115
|
-
// // ...opts?.proofOpts,
|
|
116
|
-
// // challenge: opts?.proofOpts?.nonce ?? opts?.proofOpts?.challenge ?? this.session.nonce,
|
|
117
|
-
// // domain: opts?.proofOpts?.domain ?? (await this.session.getRedirectUri()),
|
|
118
|
-
// // }
|
|
119
|
-
//
|
|
120
|
-
// let idOpts = opts?.idOpts
|
|
121
|
-
// if (!idOpts) {
|
|
122
|
-
// if (opts?.subjectIsHolder) {
|
|
123
|
-
// if (forceNoCredentialsInVP) {
|
|
124
|
-
// return Promise.reject(
|
|
125
|
-
// Error(
|
|
126
|
-
// `Cannot have subject is holder, when force no credentials is being used, as we could never determine the holder then. Please provide holderDID`,
|
|
127
|
-
// ),
|
|
128
|
-
// )
|
|
129
|
-
// }
|
|
130
|
-
// const firstUniqueDC = selectedVerifiableCredentials.credentials[0]
|
|
131
|
-
// // const firstVC = firstUniqueDC.uniformVerifiableCredential!
|
|
132
|
-
// if (typeof firstUniqueDC !== 'object' || !('digitalCredential' in firstUniqueDC)) {
|
|
133
|
-
// return Promise.reject(Error('If no opts provided, credentials should be of type UniqueDigitalCredential'))
|
|
134
|
-
// }
|
|
135
|
-
//
|
|
136
|
-
// idOpts = isOID4VCIssuerIdentifier(firstUniqueDC.digitalCredential.kmsKeyRef)
|
|
137
|
-
// ? await this.session.context.agent.identifierManagedGetByIssuer({
|
|
138
|
-
// identifier: firstUniqueDC.digitalCredential.kmsKeyRef,
|
|
139
|
-
// })
|
|
140
|
-
// : await this.session.context.agent.identifierManagedGetByKid({
|
|
141
|
-
// identifier: firstUniqueDC.digitalCredential.kmsKeyRef,
|
|
142
|
-
// kmsKeyRef: firstUniqueDC.digitalCredential.kmsKeyRef,
|
|
143
|
-
// })
|
|
144
|
-
//
|
|
145
|
-
// /*
|
|
146
|
-
// const holder = CredentialMapper.isSdJwtDecodedCredential(firstVC)
|
|
147
|
-
// ? firstVC.decodedPayload.cnf?.jwk
|
|
148
|
-
// ? //TODO SDK-19: convert the JWK to hex and search for the appropriate key and associated DID
|
|
149
|
-
// //doesn't apply to did:jwk only, as you can represent any DID key as a JWK. So whenever you encounter a JWK it doesn't mean it had to come from a did:jwk in the system. It just can always be represented as a did:jwk
|
|
150
|
-
// `did:jwk:${encodeJoseBlob(firstVC.decodedPayload.cnf?.jwk)}#0`
|
|
151
|
-
// : firstVC.decodedPayload.sub
|
|
152
|
-
// : Array.isArray(firstVC.credentialSubject)
|
|
153
|
-
// ? firstVC.credentialSubject[0].id
|
|
154
|
-
// : firstVC.credentialSubject.id
|
|
155
|
-
// if (holder) {
|
|
156
|
-
// idOpts = { identifier: holder }
|
|
157
|
-
// }
|
|
158
|
-
// */
|
|
159
|
-
// } else if (opts?.holder) {
|
|
160
|
-
// idOpts = { identifier: opts.holder }
|
|
161
|
-
// }
|
|
162
|
-
// }
|
|
163
|
-
//
|
|
164
|
-
// // We are making sure to filter, in case the user submitted all verifiableCredentials in the wallet/agent. We also make sure to get original formats back
|
|
165
|
-
// const vcs = forceNoCredentialsInVP
|
|
166
|
-
// ? selectedVerifiableCredentials
|
|
167
|
-
// : opts?.applyFilter
|
|
168
|
-
// ? await this.filterCredentials(credentialRole, selectedVerifiableCredentials.dcqlQuery, {
|
|
169
|
-
// restrictToFormats: opts?.restrictToFormats,
|
|
170
|
-
// restrictToDIDMethods: opts?.restrictToDIDMethods,
|
|
171
|
-
// filterOpts: {
|
|
172
|
-
// verifiableCredentials: selectedVerifiableCredentials.credentials,
|
|
173
|
-
// },
|
|
174
|
-
// })
|
|
175
|
-
// : {
|
|
176
|
-
// definition: selectedVerifiableCredentials.dcqlQuery,
|
|
177
|
-
// credentials: selectedVerifiableCredentials.credentials,
|
|
178
|
-
// }
|
|
179
|
-
//
|
|
180
|
-
// if (!idOpts) {
|
|
181
|
-
// return Promise.reject(Error(`No identifier options present at this point`))
|
|
182
|
-
// }
|
|
183
|
-
//
|
|
184
|
-
// // const signCallback = await createOID4VPPresentationSignCallback({
|
|
185
|
-
// // presentationSignCallback: this.session.options.presentationSignCallback,
|
|
186
|
-
// // idOpts,
|
|
187
|
-
// // context: this.session.context,
|
|
188
|
-
// // domain: proofOptions.domain,
|
|
189
|
-
// // challenge: proofOptions.challenge,
|
|
190
|
-
// // format: opts?.restrictToFormats ?? selectedVerifiableCredentials.dcqlQuery.dcqlQuery.format,
|
|
191
|
-
// // skipDidResolution: opts?.skipDidResolution ?? false,
|
|
192
|
-
// // })
|
|
193
|
-
// const identifier: ManagedIdentifierResult = await this.session.context.agent.identifierManagedGet(idOpts)
|
|
194
|
-
// const verifiableCredentials = vcs.credentials.map((credential) =>
|
|
195
|
-
// typeof credential === 'object' && 'digitalCredential' in credential ? credential.originalVerifiableCredential! : credential,
|
|
196
|
-
// )
|
|
197
|
-
// // const presentationResult = await this.getPresentationExchange({
|
|
198
|
-
// // verifiableCredentials: verifiableCredentials,
|
|
199
|
-
// // allIdentifiers: this.allIdentifiers,
|
|
200
|
-
// // hasher: opts?.hasher,
|
|
201
|
-
// // }).createVerifiablePresentation(vcs.dcqlQuery.dcqlQuery, verifiableCredentials, signCallback, {
|
|
202
|
-
// // proofOptions,
|
|
203
|
-
// // // fixme: Update to newer siop-vp to not require dids here. But when Veramo is creating the VP it's still looking at this field to pass into didManagerGet
|
|
204
|
-
// // ...(identifier && isManagedIdentifierDidResult(identifier) && { holderDID: identifier.did }),
|
|
205
|
-
// // })
|
|
206
|
-
//
|
|
207
|
-
// const verifiablePresentations = presentationResult.verifiablePresentations.map((verifiablePresentation) =>
|
|
208
|
-
// typeof verifiablePresentation !== 'string' &&
|
|
209
|
-
// 'proof' in verifiablePresentation &&
|
|
210
|
-
// 'jwt' in verifiablePresentation.proof &&
|
|
211
|
-
// verifiablePresentation.proof.jwt
|
|
212
|
-
// ? verifiablePresentation.proof.jwt
|
|
213
|
-
// : verifiablePresentation,
|
|
214
|
-
// )
|
|
215
|
-
//
|
|
216
|
-
// return {
|
|
217
|
-
// ...presentationResult,
|
|
218
|
-
// verifiablePresentations,
|
|
219
|
-
// verifiableCredentials: verifiableCredentials,
|
|
220
|
-
// dcqlQuery: selectedVerifiableCredentials.dcqlQuery,
|
|
221
|
-
// idOpts,
|
|
222
|
-
// }
|
|
223
|
-
// }
|
|
99
|
+
const kbJwtPayload: PartialSdJwtKbJwt['payload'] = {
|
|
100
|
+
iat: Math.floor(Date.now() / 1000 - clockSkew),
|
|
101
|
+
sd_hash: sdHash,
|
|
102
|
+
nonce, // Always use the Authorization Request nonce
|
|
103
|
+
aud: audience, // Always use the Client Identifier or Origin
|
|
104
|
+
}
|
|
224
105
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
// }
|
|
232
|
-
// holderDIDs?: string[]
|
|
233
|
-
// restrictToFormats?: Format
|
|
234
|
-
// restrictToDIDMethods?: string[]
|
|
235
|
-
// },
|
|
236
|
-
// ): Promise<VerifiableCredentialsWithDefinition[]> {
|
|
237
|
-
// const defs = await this.getPresentationDefinitions()
|
|
238
|
-
// const result: VerifiableCredentialsWithDefinition[] = []
|
|
239
|
-
// if (defs) {
|
|
240
|
-
// for (const definition of defs) {
|
|
241
|
-
// result.push(await this.filterCredentials(credentialRole, definition, opts))
|
|
242
|
-
// }
|
|
243
|
-
// }
|
|
244
|
-
// return result
|
|
245
|
-
// }
|
|
106
|
+
const presentationResult = await agent.createSdJwtPresentation({
|
|
107
|
+
presentation: decodedSdJwt.compactSdJwtVc,
|
|
108
|
+
kb: {
|
|
109
|
+
payload: kbJwtPayload as any, // FIXME
|
|
110
|
+
},
|
|
111
|
+
})
|
|
246
112
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
// presentationDefinition: PresentationDefinitionWithLocation,
|
|
250
|
-
// opts?: {
|
|
251
|
-
// filterOpts?: { verifiableCredentials?: (UniqueDigitalCredential | OriginalVerifiableCredential)[]; filter?: FindDigitalCredentialArgs }
|
|
252
|
-
// holderDIDs?: string[]
|
|
253
|
-
// restrictToFormats?: Format
|
|
254
|
-
// restrictToDIDMethods?: string[]
|
|
255
|
-
// },
|
|
256
|
-
// ): Promise<VerifiableCredentialsWithDefinition> {
|
|
257
|
-
// const udcMap = new Map<OriginalVerifiableCredential, UniqueDigitalCredential | OriginalVerifiableCredential>()
|
|
258
|
-
// opts?.filterOpts?.verifiableCredentials?.forEach((credential) => {
|
|
259
|
-
// if (typeof credential === 'object' && 'digitalCredential' in credential) {
|
|
260
|
-
// udcMap.set(credential.originalVerifiableCredential!, credential)
|
|
261
|
-
// } else {
|
|
262
|
-
// udcMap.set(credential, credential)
|
|
263
|
-
// }
|
|
264
|
-
// })
|
|
265
|
-
//
|
|
266
|
-
// const credentials = (
|
|
267
|
-
// await this.filterCredentialsWithSelectionStatus(credentialRole, presentationDefinition, {
|
|
268
|
-
// ...opts,
|
|
269
|
-
// filterOpts: {
|
|
270
|
-
// verifiableCredentials: opts?.filterOpts?.verifiableCredentials?.map((credential) => {
|
|
271
|
-
// if (typeof credential === 'object' && 'digitalCredential' in credential) {
|
|
272
|
-
// return credential.originalVerifiableCredential!
|
|
273
|
-
// } else {
|
|
274
|
-
// return credential
|
|
275
|
-
// }
|
|
276
|
-
// }),
|
|
277
|
-
// },
|
|
278
|
-
// })
|
|
279
|
-
// ).verifiableCredential
|
|
280
|
-
//
|
|
281
|
-
// return {
|
|
282
|
-
// dcqlQuery: presentationDefinition,
|
|
283
|
-
// credentials: credentials?.map((vc) => udcMap.get(vc)!) ?? [],
|
|
284
|
-
// }
|
|
285
|
-
// }
|
|
113
|
+
return presentationResult.presentation
|
|
114
|
+
}
|
|
286
115
|
|
|
287
|
-
|
|
288
|
-
//
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
//
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
//
|
|
302
|
-
//
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
//
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
//
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
//
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
//
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
//
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
116
|
+
case DocumentFormat.JSONLD: {
|
|
117
|
+
// JSON-LD VC - create JSON-LD VP with challenge and domain in proof
|
|
118
|
+
const vcObject = typeof originalCredential === 'string' ? JSON.parse(originalCredential) : originalCredential
|
|
119
|
+
|
|
120
|
+
const vpObject = {
|
|
121
|
+
'@context': ['https://www.w3.org/2018/credentials/v1'],
|
|
122
|
+
type: ['VerifiablePresentation'],
|
|
123
|
+
verifiableCredential: [vcObject],
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Create JSON-LD VP with proof
|
|
127
|
+
return await agent.createVerifiablePresentation({
|
|
128
|
+
presentation: vpObject,
|
|
129
|
+
proofFormat: 'lds',
|
|
130
|
+
challenge: nonce, // Authorization Request nonce as challenge
|
|
131
|
+
domain: audience, // Client Identifier or Origin as domain
|
|
132
|
+
keyRef: identifier.kmsKeyRef || identifier.kid,
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
case DocumentFormat.MSO_MDOC: {
|
|
137
|
+
// ISO mdoc - create mdoc VP token
|
|
138
|
+
// This is a placeholder implementation
|
|
139
|
+
// Full implementation would require:
|
|
140
|
+
// 1. Decode the mdoc using CredentialMapper or mdoc utilities
|
|
141
|
+
// 2. Build proper mdoc VP token with session transcript
|
|
142
|
+
// 3. Include nonce/audience in the session transcript
|
|
143
|
+
logger.warning('mso_mdoc format has basic support - production use requires proper mdoc VP token implementation')
|
|
144
|
+
|
|
145
|
+
return originalCredential
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
default: {
|
|
149
|
+
// JWT VC - create JWT VP with nonce and aud in payload
|
|
150
|
+
const vcJwt = typeof originalCredential === 'string' ? originalCredential : JSON.stringify(originalCredential)
|
|
151
|
+
|
|
152
|
+
const identifierString = getIdentifierString(identifier)
|
|
153
|
+
|
|
154
|
+
// Create VP JWT using agent method
|
|
155
|
+
const vpPayload = {
|
|
156
|
+
iss: identifierString,
|
|
157
|
+
aud: audience, // Client Identifier or Origin
|
|
158
|
+
nonce, // Authorization Request nonce
|
|
159
|
+
vp: {
|
|
160
|
+
'@context': ['https://www.w3.org/2018/credentials/v1'],
|
|
161
|
+
type: ['VerifiablePresentation'],
|
|
162
|
+
holder: identifierString,
|
|
163
|
+
verifiableCredential: [vcJwt],
|
|
164
|
+
},
|
|
165
|
+
iat: Math.floor(Date.now() / 1000 - clockSkew),
|
|
166
|
+
exp: Math.floor(Date.now() / 1000 + 600 + clockSkew), // 10 minutes
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Use the agent's JWT creation capability
|
|
170
|
+
const vpJwt = await agent.createVerifiablePresentation({
|
|
171
|
+
presentation: vpPayload.vp,
|
|
172
|
+
proofFormat: 'jwt',
|
|
173
|
+
domain: audience,
|
|
174
|
+
challenge: nonce,
|
|
175
|
+
keyRef: identifier.kmsKeyRef || identifier.kid,
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
return vpJwt.proof?.jwt || vpJwt
|
|
179
|
+
}
|
|
180
|
+
}
|
|
333
181
|
}
|
package/src/session/OpSession.ts
CHANGED
|
@@ -7,26 +7,18 @@ import {
|
|
|
7
7
|
SupportedVersion,
|
|
8
8
|
URI,
|
|
9
9
|
Verification,
|
|
10
|
-
VerifiedAuthorizationRequest
|
|
10
|
+
VerifiedAuthorizationRequest,
|
|
11
11
|
} from '@sphereon/did-auth-siop'
|
|
12
12
|
import { ResolveOpts } from '@sphereon/did-auth-siop-adapter'
|
|
13
13
|
import { JwtIssuer } from '@sphereon/oid4vc-common'
|
|
14
14
|
import { getAgentDIDMethods, getAgentResolver } from '@sphereon/ssi-sdk-ext.did-utils'
|
|
15
15
|
import { JweAlg, JweEnc } from '@sphereon/ssi-sdk-ext.jwt-service'
|
|
16
16
|
import { encodeBase64url } from '@sphereon/ssi-sdk.core'
|
|
17
|
-
import { parseDid } from '@sphereon/ssi-types'
|
|
17
|
+
import { Loggers, parseDid } from '@sphereon/ssi-types'
|
|
18
18
|
import { IIdentifier, TKeyType } from '@veramo/core'
|
|
19
19
|
import { v4 } from 'uuid'
|
|
20
|
-
import {
|
|
21
|
-
IOPOptions,
|
|
22
|
-
IOpSessionArgs,
|
|
23
|
-
IOpSessionGetOID4VPArgs,
|
|
24
|
-
IOpsSendSiopAuthorizationResponseArgs,
|
|
25
|
-
IRequiredContext
|
|
26
|
-
} from '../types'
|
|
20
|
+
import { IOPOptions, IOpSessionArgs, IOpsSendSiopAuthorizationResponseArgs, IRequiredContext } from '../types'
|
|
27
21
|
import { createOP } from './functions'
|
|
28
|
-
import { OID4VP } from './OID4VP'
|
|
29
|
-
import { Loggers } from '@sphereon/ssi-types'
|
|
30
22
|
|
|
31
23
|
const logger = Loggers.DEFAULT.get('sphereon:oid4vp:OpSession')
|
|
32
24
|
|
|
@@ -213,10 +205,6 @@ export class OpSession {
|
|
|
213
205
|
return Promise.resolve(this.verifiedAuthorizationRequest!.responseURI!)
|
|
214
206
|
}
|
|
215
207
|
|
|
216
|
-
public async getOID4VP(args: IOpSessionGetOID4VPArgs): Promise<OID4VP> {
|
|
217
|
-
return await OID4VP.init(this, args.allIdentifiers ?? [], args.hasher)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
208
|
private async createJarmResponseCallback({
|
|
221
209
|
responseOpts,
|
|
222
210
|
}: {
|
|
@@ -259,11 +247,7 @@ export class OpSession {
|
|
|
259
247
|
}
|
|
260
248
|
|
|
261
249
|
public async sendAuthorizationResponse(args: IOpsSendSiopAuthorizationResponseArgs): Promise<Response> {
|
|
262
|
-
const {
|
|
263
|
-
responseSignerOpts,
|
|
264
|
-
dcqlResponse,
|
|
265
|
-
isFirstParty,
|
|
266
|
-
} = args
|
|
250
|
+
const { responseSignerOpts, dcqlResponse, isFirstParty } = args
|
|
267
251
|
|
|
268
252
|
const resolveOpts: ResolveOpts = this.options.resolveOpts ?? {
|
|
269
253
|
resolver: getAgentResolver(this.context, {
|
package/src/session/functions.ts
CHANGED
|
@@ -60,14 +60,7 @@ export async function createOPBuilder({
|
|
|
60
60
|
const eventEmitter = opOptions.eventEmitter ?? new EventEmitter()
|
|
61
61
|
const builder = OP.builder()
|
|
62
62
|
.withResponseMode(opOptions.responseMode ?? ResponseMode.DIRECT_POST)
|
|
63
|
-
.withSupportedVersions(
|
|
64
|
-
opOptions.supportedVersions ?? [
|
|
65
|
-
SupportedVersion.SIOPv2_ID1,
|
|
66
|
-
SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1,
|
|
67
|
-
SupportedVersion.SIOPv2_D11,
|
|
68
|
-
SupportedVersion.SIOPv2_D12_OID4VP_D18,
|
|
69
|
-
],
|
|
70
|
-
)
|
|
63
|
+
.withSupportedVersions(opOptions.supportedVersions ?? [SupportedVersion.OID4VP_v1, SupportedVersion.SIOPv2_OID4VP_D28])
|
|
71
64
|
.withExpiresIn(opOptions.expiresIn ?? 300)
|
|
72
65
|
.withEventEmitter(eventEmitter)
|
|
73
66
|
.withRegistration({
|
|
@@ -12,7 +12,7 @@ import { DIDDocument } from '@sphereon/did-uni-client'
|
|
|
12
12
|
import { IIdentifierResolution, ManagedIdentifierOptsOrResult } from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
13
13
|
import { IJwtService } from '@sphereon/ssi-sdk-ext.jwt-service'
|
|
14
14
|
import { ICredentialStore } from '@sphereon/ssi-sdk.credential-store'
|
|
15
|
-
import { Party } from '@sphereon/ssi-sdk.data-store'
|
|
15
|
+
import { Party } from '@sphereon/ssi-sdk.data-store-types'
|
|
16
16
|
import { IPDManager } from '@sphereon/ssi-sdk.pd-manager'
|
|
17
17
|
import { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt'
|
|
18
18
|
import { HasherSync, PresentationSubmission, W3CVerifiablePresentation } from '@sphereon/ssi-types'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { VerifiedAuthorizationRequest } from '@sphereon/did-auth-siop'
|
|
2
2
|
import { ManagedIdentifierOptsOrResult } from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
3
|
-
import { DidAuthConfig, Party } from '@sphereon/ssi-sdk.data-store'
|
|
3
|
+
import { DidAuthConfig, Party } from '@sphereon/ssi-sdk.data-store-types'
|
|
4
4
|
import { BaseActionObject, Interpreter, ResolveTypegenMeta, ServiceMap, State, StateMachine, TypegenDisabled } from 'xstate'
|
|
5
5
|
import { ErrorDetails } from '../error'
|
|
6
6
|
import { SelectableCredentialsMap, Siopv2AuthorizationRequestData, Siopv2AuthorizationResponseData } from '../siop-service'
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
PresentationSignCallback,
|
|
3
|
-
RPRegistrationMetadataPayload,
|
|
4
|
-
VerifiedAuthorizationRequest,
|
|
5
|
-
} from '@sphereon/did-auth-siop'
|
|
1
|
+
import { PresentationSignCallback, RPRegistrationMetadataPayload, VerifiedAuthorizationRequest } from '@sphereon/did-auth-siop'
|
|
6
2
|
import { IIdentifierResolution, ManagedIdentifierOptsOrResult } from '@sphereon/ssi-sdk-ext.identifier-resolution'
|
|
7
3
|
import { IContactManager } from '@sphereon/ssi-sdk.contact-manager'
|
|
8
4
|
import { ICredentialStore, UniqueDigitalCredential } from '@sphereon/ssi-sdk.credential-store'
|
|
9
|
-
import { DidAuthConfig, ICredentialLocaleBranding, Identity, Party } from '@sphereon/ssi-sdk.data-store'
|
|
5
|
+
import { DidAuthConfig, ICredentialLocaleBranding, Identity, Party } from '@sphereon/ssi-sdk.data-store-types'
|
|
10
6
|
import { IIssuanceBranding } from '@sphereon/ssi-sdk.issuance-branding'
|
|
7
|
+
import { ISDJwtPlugin } from '@sphereon/ssi-sdk.sd-jwt'
|
|
11
8
|
import { IAgentContext, IDIDManager, IIdentifier, IResolver } from '@veramo/core'
|
|
12
9
|
import { IDidAuthSiopOpAuthenticator } from '../IDidAuthSiopOpAuthenticator'
|
|
13
10
|
import { Siopv2MachineContext, Siopv2MachineInterpreter, Siopv2MachineState } from '../machine'
|
|
@@ -90,5 +87,12 @@ export type OnIdentifierCreatedArgs = {
|
|
|
90
87
|
}
|
|
91
88
|
|
|
92
89
|
export type RequiredContext = IAgentContext<
|
|
93
|
-
IContactManager &
|
|
90
|
+
IContactManager &
|
|
91
|
+
IDidAuthSiopOpAuthenticator &
|
|
92
|
+
IDIDManager &
|
|
93
|
+
IResolver &
|
|
94
|
+
IIdentifierResolution &
|
|
95
|
+
ICredentialStore &
|
|
96
|
+
IIssuanceBranding &
|
|
97
|
+
ISDJwtPlugin
|
|
94
98
|
>
|
|
@@ -25,7 +25,7 @@ const getCredentialFromProofOrWrapped = (cred: any, hasher?: HasherSync): Origin
|
|
|
25
25
|
return cred.proof.jwt
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
return CredentialMapper.toWrappedVerifiableCredential(cred as OriginalVerifiableCredential, { hasher }).original
|
|
28
|
+
return CredentialMapper.toWrappedVerifiableCredential(cred as OriginalVerifiableCredential, { hasher }).original as OriginalVerifiableCredential // FIXME SSISDK-59
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export const isUniqueDigitalCredential = (credential: InputCredential): credential is UniqueDigitalCredential => {
|