@pagopa/io-react-native-wallet 2.0.0-next.2 → 2.0.0-next.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/credential/issuance/03-start-user-authorization.js +38 -24
- package/lib/commonjs/credential/issuance/03-start-user-authorization.js.map +1 -1
- package/lib/commonjs/credential/issuance/04-complete-user-authorization.js +75 -57
- package/lib/commonjs/credential/issuance/04-complete-user-authorization.js.map +1 -1
- package/lib/commonjs/credential/issuance/05-authorize-access.js +6 -10
- package/lib/commonjs/credential/issuance/05-authorize-access.js.map +1 -1
- package/lib/commonjs/credential/issuance/06-obtain-credential.js +43 -11
- package/lib/commonjs/credential/issuance/06-obtain-credential.js.map +1 -1
- package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js +51 -48
- package/lib/commonjs/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
- package/lib/commonjs/credential/issuance/README.md +77 -45
- package/lib/commonjs/credential/issuance/const.js +1 -1
- package/lib/commonjs/credential/issuance/types.js +17 -10
- package/lib/commonjs/credential/issuance/types.js.map +1 -1
- package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js +6 -13
- package/lib/commonjs/credential/presentation/07-evaluate-dcql-query.js.map +1 -1
- package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js +10 -11
- package/lib/commonjs/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
- package/lib/commonjs/credential/presentation/types.js +1 -1
- package/lib/commonjs/credential/presentation/types.js.map +1 -1
- package/lib/commonjs/credential/status/README.md +0 -1
- package/lib/commonjs/sd-jwt/__test__/index.test.js +11 -15
- package/lib/commonjs/sd-jwt/__test__/index.test.js.map +1 -1
- package/lib/commonjs/sd-jwt/__test__/types.test.js +5 -2
- package/lib/commonjs/sd-jwt/__test__/types.test.js.map +1 -1
- package/lib/commonjs/sd-jwt/__test__/utils.test.js +37 -0
- package/lib/commonjs/sd-jwt/__test__/utils.test.js.map +1 -0
- package/lib/commonjs/sd-jwt/index.js +26 -1
- package/lib/commonjs/sd-jwt/index.js.map +1 -1
- package/lib/commonjs/sd-jwt/types.js +71 -8
- package/lib/commonjs/sd-jwt/types.js.map +1 -1
- package/lib/commonjs/sd-jwt/utils.js +64 -0
- package/lib/commonjs/sd-jwt/utils.js.map +1 -0
- package/lib/commonjs/trust/types.js +18 -13
- package/lib/commonjs/trust/types.js.map +1 -1
- package/lib/commonjs/utils/par.js +32 -22
- package/lib/commonjs/utils/par.js.map +1 -1
- package/lib/commonjs/utils/pop.js +1 -1
- package/lib/commonjs/utils/pop.js.map +1 -1
- package/lib/commonjs/wallet-instance-attestation/types.js +4 -1
- package/lib/commonjs/wallet-instance-attestation/types.js.map +1 -1
- package/lib/module/credential/issuance/03-start-user-authorization.js +38 -24
- package/lib/module/credential/issuance/03-start-user-authorization.js.map +1 -1
- package/lib/module/credential/issuance/04-complete-user-authorization.js +76 -58
- package/lib/module/credential/issuance/04-complete-user-authorization.js.map +1 -1
- package/lib/module/credential/issuance/05-authorize-access.js +6 -10
- package/lib/module/credential/issuance/05-authorize-access.js.map +1 -1
- package/lib/module/credential/issuance/06-obtain-credential.js +44 -12
- package/lib/module/credential/issuance/06-obtain-credential.js.map +1 -1
- package/lib/module/credential/issuance/07-verify-and-parse-credential.js +51 -48
- package/lib/module/credential/issuance/07-verify-and-parse-credential.js.map +1 -1
- package/lib/module/credential/issuance/README.md +77 -45
- package/lib/module/credential/issuance/const.js +1 -1
- package/lib/module/credential/issuance/types.js +13 -8
- package/lib/module/credential/issuance/types.js.map +1 -1
- package/lib/module/credential/presentation/07-evaluate-dcql-query.js +6 -13
- package/lib/module/credential/presentation/07-evaluate-dcql-query.js.map +1 -1
- package/lib/module/credential/presentation/07-evaluate-input-descriptor.js +10 -11
- package/lib/module/credential/presentation/07-evaluate-input-descriptor.js.map +1 -1
- package/lib/module/credential/presentation/types.js +1 -1
- package/lib/module/credential/presentation/types.js.map +1 -1
- package/lib/module/credential/status/README.md +0 -1
- package/lib/module/sd-jwt/__test__/index.test.js +11 -16
- package/lib/module/sd-jwt/__test__/index.test.js.map +1 -1
- package/lib/module/sd-jwt/__test__/types.test.js +5 -2
- package/lib/module/sd-jwt/__test__/types.test.js.map +1 -1
- package/lib/module/sd-jwt/__test__/utils.test.js +35 -0
- package/lib/module/sd-jwt/__test__/utils.test.js.map +1 -0
- package/lib/module/sd-jwt/index.js +7 -1
- package/lib/module/sd-jwt/index.js.map +1 -1
- package/lib/module/sd-jwt/types.js +70 -7
- package/lib/module/sd-jwt/types.js.map +1 -1
- package/lib/module/sd-jwt/utils.js +57 -0
- package/lib/module/sd-jwt/utils.js.map +1 -0
- package/lib/module/trust/types.js +18 -13
- package/lib/module/trust/types.js.map +1 -1
- package/lib/module/utils/par.js +29 -20
- package/lib/module/utils/par.js.map +1 -1
- package/lib/module/utils/pop.js +1 -1
- package/lib/module/utils/pop.js.map +1 -1
- package/lib/module/wallet-instance-attestation/types.js +4 -1
- package/lib/module/wallet-instance-attestation/types.js.map +1 -1
- package/lib/typescript/client/generated/wallet-provider.d.ts +12 -12
- package/lib/typescript/credential/issuance/01-start-flow.d.ts +2 -2
- package/lib/typescript/credential/issuance/01-start-flow.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts +7 -6
- package/lib/typescript/credential/issuance/03-start-user-authorization.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts +7 -14
- package/lib/typescript/credential/issuance/04-complete-user-authorization.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/05-authorize-access.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/06-obtain-credential.d.ts +10 -5
- package/lib/typescript/credential/issuance/06-obtain-credential.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts +3 -2
- package/lib/typescript/credential/issuance/07-verify-and-parse-credential.d.ts.map +1 -1
- package/lib/typescript/credential/issuance/const.d.ts +1 -1
- package/lib/typescript/credential/issuance/types.d.ts +49 -26
- package/lib/typescript/credential/issuance/types.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/01-start-flow.d.ts +2 -2
- package/lib/typescript/credential/presentation/07-evaluate-dcql-query.d.ts +4 -3
- package/lib/typescript/credential/presentation/07-evaluate-dcql-query.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/07-evaluate-input-descriptor.d.ts +9 -5
- package/lib/typescript/credential/presentation/07-evaluate-input-descriptor.d.ts.map +1 -1
- package/lib/typescript/credential/presentation/types.d.ts +3 -4
- package/lib/typescript/credential/presentation/types.d.ts.map +1 -1
- package/lib/typescript/credential/status/types.d.ts +4 -4
- package/lib/typescript/pid/sd-jwt/types.d.ts +7 -7
- package/lib/typescript/sd-jwt/__test__/utils.test.d.ts +2 -0
- package/lib/typescript/sd-jwt/__test__/utils.test.d.ts.map +1 -0
- package/lib/typescript/sd-jwt/index.d.ts +69 -28
- package/lib/typescript/sd-jwt/index.d.ts.map +1 -1
- package/lib/typescript/sd-jwt/types.d.ts +264 -31
- package/lib/typescript/sd-jwt/types.d.ts.map +1 -1
- package/lib/typescript/sd-jwt/utils.d.ts +18 -0
- package/lib/typescript/sd-jwt/utils.d.ts.map +1 -0
- package/lib/typescript/trust/build-chain.d.ts +30 -14
- package/lib/typescript/trust/build-chain.d.ts.map +1 -1
- package/lib/typescript/trust/types.d.ts +322 -158
- package/lib/typescript/trust/types.d.ts.map +1 -1
- package/lib/typescript/utils/par.d.ts +29 -13
- package/lib/typescript/utils/par.d.ts.map +1 -1
- package/lib/typescript/wallet-instance-attestation/types.d.ts +9 -9
- package/lib/typescript/wallet-instance-attestation/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/credential/issuance/01-start-flow.ts +2 -2
- package/src/credential/issuance/03-start-user-authorization.ts +57 -38
- package/src/credential/issuance/04-complete-user-authorization.ts +79 -85
- package/src/credential/issuance/05-authorize-access.ts +5 -11
- package/src/credential/issuance/06-obtain-credential.ts +56 -23
- package/src/credential/issuance/07-verify-and-parse-credential.ts +54 -62
- package/src/credential/issuance/README.md +77 -45
- package/src/credential/issuance/const.ts +1 -1
- package/src/credential/issuance/types.ts +19 -8
- package/src/credential/presentation/07-evaluate-dcql-query.ts +16 -17
- package/src/credential/presentation/07-evaluate-input-descriptor.ts +19 -16
- package/src/credential/presentation/types.ts +1 -2
- package/src/credential/status/README.md +0 -1
- package/src/sd-jwt/__test__/index.test.ts +8 -29
- package/src/sd-jwt/__test__/types.test.ts +6 -2
- package/src/sd-jwt/__test__/utils.test.ts +37 -0
- package/src/sd-jwt/index.ts +7 -1
- package/src/sd-jwt/types.ts +68 -7
- package/src/sd-jwt/utils.ts +73 -0
- package/src/trust/types.ts +23 -17
- package/src/utils/par.ts +37 -21
- package/src/utils/pop.ts +1 -1
- package/src/wallet-instance-attestation/types.ts +3 -1
@@ -6,7 +6,7 @@ There's a fork in the flow which is based on the type of the credential that is
|
|
6
6
|
This is due to the fact that eID credentials require a different authorization flow than other credentials, which is accomplished by a strong authentication method like SPID or CIE.
|
7
7
|
Credentials instead require a simpler authorization flow and they require other credentials to be presented in order to be issued.
|
8
8
|
|
9
|
-
The supported credentials are defined in the entity configuration of the issuer which is evaluted and parsed in the `evaluateIssuerTrust` step.
|
9
|
+
The supported credentials are defined in the entity configuration of the issuer which is evaluted and parsed in the `evaluateIssuerTrust` step. Available credentials are identified with a unique `credential_configuration_id`, that must be used when requesting authorization. The Authorization Server returns an array of **credential identifiers** that map to the `credential_configuration_id` provided: to obtain the credential, one of the credential identifiers (or all of them) must be requested to the credential endpoint.
|
10
10
|
|
11
11
|
## Sequence Diagram
|
12
12
|
|
@@ -96,17 +96,13 @@ const walletInstanceAttestation =
|
|
96
96
|
appFetch,
|
97
97
|
});
|
98
98
|
|
99
|
-
const
|
100
|
-
|
101
|
-
const eid = {
|
99
|
+
const pid = {
|
102
100
|
credential: "example",
|
103
101
|
parsedCredential: "example"
|
104
102
|
keyTag: "example";
|
105
|
-
credentialType: "
|
103
|
+
credentialType: "PersonIdentificationData";
|
106
104
|
};
|
107
105
|
|
108
|
-
const eidCryptoContext = createCryptoContextFor(eid.keyTag);
|
109
|
-
|
110
106
|
// Create credential crypto context
|
111
107
|
const credentialKeyTag = uuidv4().toString();
|
112
108
|
await generate(credentialKeyTag); // Let's assume this function generates a new hardware-backed key pair
|
@@ -115,22 +111,26 @@ const credentialCryptoContext = createCryptoContextFor(credentialKeyTag);
|
|
115
111
|
// Start the issuance flow
|
116
112
|
const startFlow: Credential.Issuance.StartFlow = () => ({
|
117
113
|
issuerUrl: WALLET_EAA_PROVIDER_BASE_URL,
|
118
|
-
|
114
|
+
credentialId: "someCredentialId",
|
119
115
|
});
|
120
116
|
|
121
|
-
const { issuerUrl } = startFlow();
|
117
|
+
const { issuerUrl, credentialId } = startFlow();
|
122
118
|
|
123
119
|
// Evaluate issuer trust
|
124
120
|
const { issuerConf } = await Credential.Issuance.evaluateIssuerTrust(issuerUrl);
|
125
121
|
|
126
122
|
// Start user authorization
|
127
|
-
const { issuerRequestUri, clientId, codeVerifier
|
128
|
-
await Credential.Issuance.startUserAuthorization(
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
123
|
+
const { issuerRequestUri, clientId, codeVerifier } =
|
124
|
+
await Credential.Issuance.startUserAuthorization(
|
125
|
+
issuerConf,
|
126
|
+
[credentialId],
|
127
|
+
{
|
128
|
+
walletInstanceAttestation,
|
129
|
+
redirectUri: REDIRECT_URI,
|
130
|
+
wiaCryptoContext,
|
131
|
+
appFetch,
|
132
|
+
}
|
133
|
+
);
|
134
134
|
|
135
135
|
const requestObject =
|
136
136
|
await Credential.Issuance.getRequestedCredentialToBePresented(
|
@@ -140,13 +140,12 @@ const requestObject =
|
|
140
140
|
appFetch
|
141
141
|
);
|
142
142
|
|
143
|
-
// The app here should ask the user to confirm the required data contained in the requestObject
|
144
|
-
|
145
143
|
// Complete the user authorization via form_post.jwt mode
|
146
144
|
const { code } =
|
147
145
|
await Credential.Issuance.completeUserAuthorizationWithFormPostJwtMode(
|
148
146
|
requestObject,
|
149
|
-
|
147
|
+
pid.credential,
|
148
|
+
{ wiaCryptoContext, pidCryptoContext: createCryptoContextFor(pid.keyTag) }
|
150
149
|
);
|
151
150
|
|
152
151
|
// Generate the DPoP context which will be used for the whole issuance flow
|
@@ -157,7 +156,7 @@ const { accessToken } = await Credential.Issuance.authorizeAccess(
|
|
157
156
|
issuerConf,
|
158
157
|
code,
|
159
158
|
clientId,
|
160
|
-
redirectUri,
|
159
|
+
redirectUri: REDIRECT_URI,
|
161
160
|
codeVerifier,
|
162
161
|
{
|
163
162
|
walletInstanceAttestation,
|
@@ -167,12 +166,19 @@ const { accessToken } = await Credential.Issuance.authorizeAccess(
|
|
167
166
|
}
|
168
167
|
);
|
169
168
|
|
170
|
-
//
|
171
|
-
const {
|
169
|
+
// For simplicity, in this example flow we work on a single credential.
|
170
|
+
const { credential_configuration_id, credential_identifiers } =
|
171
|
+
accessToken.authorization_details[0]!;
|
172
|
+
|
173
|
+
// Obtain the credential
|
174
|
+
const { credential } = await Credential.Issuance.obtainCredential(
|
172
175
|
issuerConf,
|
173
176
|
accessToken,
|
174
177
|
clientId,
|
175
|
-
|
178
|
+
{
|
179
|
+
credential_configuration_id,
|
180
|
+
credential_identifier: credential_identifiers[0],
|
181
|
+
},
|
176
182
|
{
|
177
183
|
credentialCryptoContext,
|
178
184
|
dPopCryptoContext,
|
@@ -184,22 +190,29 @@ const { credential, format } = await Credential.Issuance.obtainCredential(
|
|
184
190
|
* Parse and verify the credential. The ignoreMissingAttributes flag must be set to false or omitted in production.
|
185
191
|
* WARNING: includeUndefinedAttributes should not be set to true in production in order to get only claims explicitly declared by the issuer.
|
186
192
|
*/
|
187
|
-
const { parsedCredential } =
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
193
|
+
const { parsedCredential } =
|
194
|
+
await Credential.Issuance.verifyAndParseCredential(
|
195
|
+
issuerConf,
|
196
|
+
credential,
|
197
|
+
credential_configuration_id,
|
198
|
+
{
|
199
|
+
credentialCryptoContext,
|
200
|
+
ignoreMissingAttributes: true,
|
201
|
+
includeUndefinedAttributes: false
|
202
|
+
}
|
203
|
+
);
|
204
|
+
|
205
|
+
const credentialType =
|
206
|
+
issuerConf.openid_credential_issuer.credential_configurations_supported[
|
207
|
+
credential_configuration_id
|
208
|
+
].scope;
|
197
209
|
|
198
210
|
return {
|
199
211
|
parsedCredential,
|
200
212
|
credential,
|
201
213
|
keyTag: credentialKeyTag,
|
202
214
|
credentialType,
|
215
|
+
credentialConfigurationId: credential_configuration_id,
|
203
216
|
};
|
204
217
|
```
|
205
218
|
|
@@ -251,11 +264,10 @@ const credentialCryptoContext = createCryptoContextFor(credentialKeyTag);
|
|
251
264
|
// Start the issuance flow
|
252
265
|
const startFlow: Credential.Issuance.StartFlow = () => ({
|
253
266
|
issuerUrl: WALLET_EID_PROVIDER_BASE_URL,
|
254
|
-
|
255
|
-
appFetch,
|
267
|
+
credentialId: "dc_sd_jwt_PersonIdentificationData",
|
256
268
|
});
|
257
269
|
|
258
|
-
const { issuerUrl } = startFlow();
|
270
|
+
const { issuerUrl, credentialId } = startFlow();
|
259
271
|
|
260
272
|
// Evaluate issuer trust
|
261
273
|
const { issuerConf } = await Credential.Issuance.evaluateIssuerTrust(
|
@@ -265,12 +277,16 @@ const { issuerConf } = await Credential.Issuance.evaluateIssuerTrust(
|
|
265
277
|
|
266
278
|
// Start user authorization
|
267
279
|
const { issuerRequestUri, clientId, codeVerifier, credentialDefinition } =
|
268
|
-
await Credential.Issuance.startUserAuthorization(
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
280
|
+
await Credential.Issuance.startUserAuthorization(
|
281
|
+
issuerConf,
|
282
|
+
[credentialId], // Request authorization for one or more credentials
|
283
|
+
{
|
284
|
+
walletInstanceAttestation,
|
285
|
+
redirectUri,
|
286
|
+
wiaCryptoContext,
|
287
|
+
appFetch,
|
288
|
+
}
|
289
|
+
);
|
274
290
|
|
275
291
|
// Complete the authorization process with query mode with the authorizationContext which opens the browser
|
276
292
|
const { code } =
|
@@ -301,12 +317,27 @@ const { accessToken } = await Credential.Issuance.authorizeAccess(
|
|
301
317
|
}
|
302
318
|
);
|
303
319
|
|
320
|
+
|
321
|
+
const [pidCredentialDefinition] = credentialDefinition;
|
322
|
+
|
323
|
+
// Extract the credential_identifier(s) from the access token
|
324
|
+
// For each one of them, a credential can be obtained by calling `obtainCredential`
|
325
|
+
const { credential_configuration_id, credential_identifiers } =
|
326
|
+
accessToken.authorization_details.find(
|
327
|
+
(authDetails) =>
|
328
|
+
authDetails.credential_configuration_id ===
|
329
|
+
pidCredentialDefinition.credential_configuration_id
|
330
|
+
);
|
331
|
+
|
304
332
|
// Obtain che eID credential
|
305
333
|
const { credential, format } = await Credential.Issuance.obtainCredential(
|
306
334
|
issuerConf,
|
307
335
|
accessToken,
|
308
336
|
clientId,
|
309
|
-
|
337
|
+
{
|
338
|
+
credential_configuration_id,
|
339
|
+
credential_identifier: credential_identifiers.at(0),
|
340
|
+
},
|
310
341
|
{
|
311
342
|
credentialCryptoContext,
|
312
343
|
dPopCryptoContext,
|
@@ -318,15 +349,16 @@ const { credential, format } = await Credential.Issuance.obtainCredential(
|
|
318
349
|
const { parsedCredential, issuedAt, expiration } = await Credential.Issuance.verifyAndParseCredential(
|
319
350
|
issuerConf,
|
320
351
|
credential,
|
321
|
-
|
352
|
+
credential_configuration_id,
|
322
353
|
{ credentialCryptoContext }
|
323
354
|
);
|
324
355
|
|
325
356
|
return {
|
326
357
|
parsedCredential,
|
327
358
|
credential,
|
359
|
+
credentialConfigurationId: credential_configuration_id
|
360
|
+
credentialType: "PersonIdentificationData",
|
328
361
|
keyTag: credentialKeyTag,
|
329
|
-
credentialType,
|
330
362
|
issuedAt,
|
331
363
|
expiration
|
332
364
|
};
|
@@ -1,14 +1,18 @@
|
|
1
|
-
import { AuthorizationDetail } from "../../utils/par";
|
2
1
|
import * as z from "zod";
|
3
|
-
|
2
|
+
|
3
|
+
export type AuthorizationDetail = z.infer<typeof AuthorizationDetail>;
|
4
|
+
export const AuthorizationDetail = z.object({
|
5
|
+
type: z.literal("openid_credential"),
|
6
|
+
credential_configuration_id: z.string(),
|
7
|
+
credential_identifiers: z.array(z.string()),
|
8
|
+
});
|
4
9
|
|
5
10
|
export type TokenResponse = z.infer<typeof TokenResponse>;
|
6
11
|
|
7
12
|
export const TokenResponse = z.object({
|
8
13
|
access_token: z.string(),
|
14
|
+
refresh_token: z.string().optional(),
|
9
15
|
authorization_details: z.array(AuthorizationDetail),
|
10
|
-
c_nonce: z.string(),
|
11
|
-
c_nonce_expires_in: z.number(),
|
12
16
|
expires_in: z.number(),
|
13
17
|
token_type: z.string(),
|
14
18
|
});
|
@@ -16,10 +20,12 @@ export const TokenResponse = z.object({
|
|
16
20
|
export type CredentialResponse = z.infer<typeof CredentialResponse>;
|
17
21
|
|
18
22
|
export const CredentialResponse = z.object({
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
+
credentials: z.array(
|
24
|
+
z.object({
|
25
|
+
credential: z.string(),
|
26
|
+
})
|
27
|
+
),
|
28
|
+
notification_id: z.string().optional(),
|
23
29
|
});
|
24
30
|
|
25
31
|
/**
|
@@ -30,3 +36,8 @@ export const ResponseUriResultShape = z.object({
|
|
30
36
|
});
|
31
37
|
|
32
38
|
export type ResponseMode = "query" | "form_post.jwt";
|
39
|
+
|
40
|
+
export type NonceResponse = z.infer<typeof NonceResponse>;
|
41
|
+
export const NonceResponse = z.object({
|
42
|
+
c_nonce: z.string(),
|
43
|
+
});
|
@@ -2,9 +2,9 @@ import { DcqlQuery, DcqlError, DcqlQueryResult } from "dcql";
|
|
2
2
|
import { isValiError } from "valibot";
|
3
3
|
import { decode, prepareVpToken } from "../../sd-jwt";
|
4
4
|
import type { Disclosure } from "../../sd-jwt/types";
|
5
|
-
import { createCryptoContextFor } from "../../utils/crypto";
|
6
5
|
import type { RemotePresentation } from "./types";
|
7
6
|
import { CredentialsNotFoundError, type NotFoundDetail } from "./errors";
|
7
|
+
import type { CryptoContext } from "@pagopa/io-react-native-jwt";
|
8
8
|
|
9
9
|
/**
|
10
10
|
* The purpose for the credential request by the RP.
|
@@ -15,13 +15,13 @@ type CredentialPurpose = {
|
|
15
15
|
};
|
16
16
|
|
17
17
|
export type EvaluateDcqlQuery = (
|
18
|
-
credentialsSdJwt: [
|
18
|
+
credentialsSdJwt: [CryptoContext, string /* credential */][],
|
19
19
|
query: DcqlQuery.Input
|
20
20
|
) => {
|
21
21
|
id: string;
|
22
22
|
vct: string;
|
23
23
|
credential: string;
|
24
|
-
|
24
|
+
cryptoContext: CryptoContext;
|
25
25
|
requiredDisclosures: Disclosure[];
|
26
26
|
purposes: CredentialPurpose[];
|
27
27
|
}[];
|
@@ -30,7 +30,7 @@ export type PrepareRemotePresentations = (
|
|
30
30
|
credentials: {
|
31
31
|
id: string;
|
32
32
|
credential: string;
|
33
|
-
|
33
|
+
cryptoContext: CryptoContext;
|
34
34
|
requestedClaims: string[];
|
35
35
|
}[],
|
36
36
|
nonce: string,
|
@@ -55,11 +55,6 @@ const mapCredentialToObject = (jwt: string) => {
|
|
55
55
|
const { sdJwt, disclosures } = decode(jwt);
|
56
56
|
const credentialFormat = sdJwt.header.typ;
|
57
57
|
|
58
|
-
// TODO [SIW-2082]: support MDOC credentials
|
59
|
-
if (credentialFormat !== "vc+sd-jwt") {
|
60
|
-
throw new Error(`Unsupported credential format: ${credentialFormat}`);
|
61
|
-
}
|
62
|
-
|
63
58
|
return {
|
64
59
|
vct: sdJwt.payload.vct,
|
65
60
|
credential_format: credentialFormat,
|
@@ -100,7 +95,10 @@ const extractMissingCredentials = (
|
|
100
95
|
): NotFoundDetail[] => {
|
101
96
|
return getDcqlQueryFailedMatches(queryResult).map(([id]) => {
|
102
97
|
const credential = originalQuery.credentials.find((c) => c.id === id);
|
103
|
-
if (
|
98
|
+
if (
|
99
|
+
credential?.format !== "dc+sd-jwt" &&
|
100
|
+
credential?.format !== "vc+sd-jwt"
|
101
|
+
) {
|
104
102
|
throw new Error("Unsupported format"); // TODO [SIW-2082]: support MDOC credentials
|
105
103
|
}
|
106
104
|
return { id, vctValues: credential.meta?.vct_values };
|
@@ -114,7 +112,6 @@ export const evaluateDcqlQuery: EvaluateDcqlQuery = (
|
|
114
112
|
const credentials = credentialsSdJwt.map(([, credential]) =>
|
115
113
|
mapCredentialToObject(credential)
|
116
114
|
);
|
117
|
-
|
118
115
|
try {
|
119
116
|
// Validate the query
|
120
117
|
const parsedQuery = DcqlQuery.parse(query);
|
@@ -131,11 +128,14 @@ export const evaluateDcqlQuery: EvaluateDcqlQuery = (
|
|
131
128
|
// Build an object vct:credentialJwt to map matched credentials to their JWT
|
132
129
|
const credentialsSdJwtByVct = credentials.reduce(
|
133
130
|
(acc, c, i) => ({ ...acc, [c.vct]: credentialsSdJwt[i]! }),
|
134
|
-
{} as Record<string, [
|
131
|
+
{} as Record<string, [CryptoContext, string /* credential */]>
|
135
132
|
);
|
136
133
|
|
137
134
|
return getDcqlQueryMatches(queryResult).map(([id, match]) => {
|
138
|
-
if (
|
135
|
+
if (
|
136
|
+
match.output.credential_format !== "dc+sd-jwt" &&
|
137
|
+
match.output.credential_format !== "vc+sd-jwt"
|
138
|
+
) {
|
139
139
|
throw new Error("Unsupported format"); // TODO [SIW-2082]: support MDOC credentials
|
140
140
|
}
|
141
141
|
const { vct, claims } = match.output;
|
@@ -147,12 +147,12 @@ export const evaluateDcqlQuery: EvaluateDcqlQuery = (
|
|
147
147
|
required: Boolean(credentialSet.required),
|
148
148
|
}));
|
149
149
|
|
150
|
-
const [
|
150
|
+
const [cryptoContext, credential] = credentialsSdJwtByVct[vct]!;
|
151
151
|
const requiredDisclosures = Object.values(claims) as Disclosure[];
|
152
152
|
return {
|
153
153
|
id,
|
154
154
|
vct,
|
155
|
-
|
155
|
+
cryptoContext,
|
156
156
|
credential,
|
157
157
|
requiredDisclosures,
|
158
158
|
// When it is a match but no credential_sets are found, the credential is required by default
|
@@ -185,14 +185,13 @@ export const prepareRemotePresentations: PrepareRemotePresentations = async (
|
|
185
185
|
const { vp_token } = await prepareVpToken(nonce, clientId, [
|
186
186
|
item.credential,
|
187
187
|
item.requestedClaims,
|
188
|
-
|
188
|
+
item.cryptoContext,
|
189
189
|
]);
|
190
190
|
|
191
191
|
return {
|
192
192
|
credentialId: item.id,
|
193
193
|
requestedClaims: item.requestedClaims,
|
194
194
|
vpToken: vp_token,
|
195
|
-
format: "vc+sd-jwt",
|
196
195
|
};
|
197
196
|
})
|
198
197
|
);
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import { InputDescriptor, type LegacyRemotePresentation } from "./types";
|
2
2
|
import { SdJwt4VC, type DisclosureWithEncoded } from "../../sd-jwt/types";
|
3
3
|
import { decode, prepareVpToken } from "../../sd-jwt";
|
4
|
-
import { createCryptoContextFor } from "../../utils/crypto";
|
5
4
|
import { JSONPath } from "jsonpath-plus";
|
6
5
|
import { CredentialsNotFoundError, MissingDataError } from "./errors";
|
7
6
|
import Ajv from "ajv";
|
7
|
+
import type { CryptoContext } from "@pagopa/io-react-native-jwt";
|
8
8
|
|
9
9
|
const ajv = new Ajv({ allErrors: true });
|
10
10
|
const INDEX_CLAIM_NAME = 1;
|
@@ -23,13 +23,16 @@ export type EvaluateInputDescriptorSdJwt4VC = (
|
|
23
23
|
|
24
24
|
export type EvaluateInputDescriptors = (
|
25
25
|
descriptors: InputDescriptor[],
|
26
|
-
credentialsSdJwt: [
|
26
|
+
credentialsSdJwt: [
|
27
|
+
CryptoContext /* cryptoContext */,
|
28
|
+
string /* credential */,
|
29
|
+
][]
|
27
30
|
) => Promise<
|
28
31
|
{
|
29
32
|
evaluatedDisclosure: EvaluatedDisclosures;
|
30
33
|
inputDescriptor: InputDescriptor;
|
31
34
|
credential: string;
|
32
|
-
|
35
|
+
cryptoContext: CryptoContext;
|
33
36
|
}[]
|
34
37
|
>;
|
35
38
|
|
@@ -41,7 +44,7 @@ export type PrepareLegacyRemotePresentations = (
|
|
41
44
|
requestedClaims: string[];
|
42
45
|
inputDescriptor: InputDescriptor;
|
43
46
|
credential: string;
|
44
|
-
|
47
|
+
cryptoContext: CryptoContext;
|
45
48
|
}[],
|
46
49
|
nonce: string,
|
47
50
|
client_id: string
|
@@ -247,7 +250,7 @@ export const evaluateInputDescriptorForSdJwt4VC: EvaluateInputDescriptorSdJwt4VC
|
|
247
250
|
};
|
248
251
|
|
249
252
|
type DecodedCredentialSdJwt = {
|
250
|
-
|
253
|
+
cryptoContext: CryptoContext;
|
251
254
|
credential: string;
|
252
255
|
sdJwt: SdJwt4VC;
|
253
256
|
disclosures: DisclosureWithEncoded[];
|
@@ -264,11 +267,11 @@ export const findCredentialSdJwt = (
|
|
264
267
|
decodedSdJwtCredentials: DecodedCredentialSdJwt[]
|
265
268
|
): {
|
266
269
|
matchedEvaluation: EvaluatedDisclosures;
|
267
|
-
matchedKeyTag: string;
|
268
270
|
matchedCredential: string;
|
271
|
+
cryptoContext: CryptoContext;
|
269
272
|
} => {
|
270
273
|
for (const {
|
271
|
-
|
274
|
+
cryptoContext,
|
272
275
|
credential,
|
273
276
|
sdJwt,
|
274
277
|
disclosures,
|
@@ -282,7 +285,7 @@ export const findCredentialSdJwt = (
|
|
282
285
|
|
283
286
|
return {
|
284
287
|
matchedEvaluation: evaluatedDisclosure,
|
285
|
-
|
288
|
+
cryptoContext,
|
286
289
|
matchedCredential: credential,
|
287
290
|
};
|
288
291
|
} catch {
|
@@ -319,14 +322,14 @@ export const evaluateInputDescriptors: EvaluateInputDescriptors = async (
|
|
319
322
|
) => {
|
320
323
|
// We need decode SD-JWT credentials for evaluation
|
321
324
|
const decodedSdJwtCredentials =
|
322
|
-
credentialsSdJwt?.map(([
|
325
|
+
credentialsSdJwt?.map(([cryptoContext, credential]) => {
|
323
326
|
const { sdJwt, disclosures } = decode(credential);
|
324
|
-
return {
|
327
|
+
return { cryptoContext, credential, sdJwt, disclosures };
|
325
328
|
}) || [];
|
326
329
|
|
327
330
|
return Promise.all(
|
328
331
|
inputDescriptors.map(async (descriptor) => {
|
329
|
-
if (descriptor.format?.["
|
332
|
+
if (descriptor.format?.["dc+sd-jwt"]) {
|
330
333
|
if (!decodedSdJwtCredentials.length) {
|
331
334
|
throw new CredentialsNotFoundError([
|
332
335
|
{
|
@@ -336,14 +339,14 @@ export const evaluateInputDescriptors: EvaluateInputDescriptors = async (
|
|
336
339
|
]);
|
337
340
|
}
|
338
341
|
|
339
|
-
const { matchedEvaluation,
|
342
|
+
const { matchedEvaluation, cryptoContext, matchedCredential } =
|
340
343
|
findCredentialSdJwt(descriptor, decodedSdJwtCredentials);
|
341
344
|
|
342
345
|
return {
|
343
346
|
evaluatedDisclosure: matchedEvaluation,
|
344
347
|
inputDescriptor: descriptor,
|
345
348
|
credential: matchedCredential,
|
346
|
-
|
349
|
+
cryptoContext,
|
347
350
|
};
|
348
351
|
}
|
349
352
|
|
@@ -379,18 +382,18 @@ export const prepareLegacyRemotePresentations: PrepareLegacyRemotePresentations
|
|
379
382
|
credentialAndDescriptors.map(async (item) => {
|
380
383
|
const descriptor = item.inputDescriptor;
|
381
384
|
|
382
|
-
if (descriptor.format?.["
|
385
|
+
if (descriptor.format?.["dc+sd-jwt"]) {
|
383
386
|
const { vp_token } = await prepareVpToken(nonce, client_id, [
|
384
387
|
item.credential,
|
385
388
|
item.requestedClaims,
|
386
|
-
|
389
|
+
item.cryptoContext,
|
387
390
|
]);
|
388
391
|
|
389
392
|
return {
|
390
393
|
requestedClaims: item.requestedClaims,
|
391
394
|
inputDescriptor: descriptor,
|
392
395
|
vpToken: vp_token,
|
393
|
-
format: "
|
396
|
+
format: "dc+sd-jwt",
|
394
397
|
};
|
395
398
|
}
|
396
399
|
|
@@ -30,7 +30,6 @@ export type LegacyRemotePresentation = {
|
|
30
30
|
export type RemotePresentation = {
|
31
31
|
requestedClaims: string[];
|
32
32
|
credentialId: string;
|
33
|
-
format: string;
|
34
33
|
vpToken: string;
|
35
34
|
};
|
36
35
|
|
@@ -97,7 +96,7 @@ export const RequestObject = z.object({
|
|
97
96
|
state: z.string().optional(),
|
98
97
|
nonce: z.string(),
|
99
98
|
response_uri: z.string(),
|
100
|
-
|
99
|
+
request_uri_method: z.string().optional(),
|
101
100
|
response_type: z.literal("vp_token"),
|
102
101
|
response_mode: z.literal("direct_post.jwt"),
|
103
102
|
client_id: z.string(),
|
@@ -3,39 +3,14 @@ import { decode, disclose } from "../index";
|
|
3
3
|
|
4
4
|
import { encodeBase64, decodeBase64 } from "@pagopa/io-react-native-jwt";
|
5
5
|
import { SdJwt4VC } from "../types";
|
6
|
+
import { pid } from "../__mocks__/sd-jwt";
|
6
7
|
|
7
|
-
|
8
|
-
// but adapted to adhere to format declared in https://italia.github.io/eudi-wallet-it-docs/versione-corrente/en/pid-eaa-data-model.html#id2
|
9
|
-
// In short, the token is a Frankenstein composed as follows:
|
10
|
-
// - the header is taken from the italian specification, with kid and alg valued according to the signing keys
|
11
|
-
// - disclosures are taken from the SD-JWT-4-VC standard
|
12
|
-
// - payload is taken from the italian specification, but _sd are compiled with:
|
13
|
-
// - "address" is used as verification._sd
|
14
|
-
// - all others disclosures are in claims._sd
|
15
|
-
const token =
|
16
|
-
"eyJraWQiOiItRl82VWdhOG4zVmVnalkyVTdZVUhLMXpMb2FELU5QVGM2M1JNSVNuTGF3IiwidHlwIjoidmMrc2Qtand0IiwiYWxnIjoiRVMyNTYifQ.eyJfc2QiOlsiMHExRDVKbWF2NnBRYUVoX0pfRmN2X3VOTk1RSWdDeWhRT3hxbFk0bDNxVSIsIktDSi1BVk52ODhkLXhqNnNVSUFPSnhGbmJVaDNySFhES2tJSDFsRnFiUnMiLCJNOWxvOVl4RE5JWHJBcTJxV2VpQ0E0MHpwSl96WWZGZFJfNEFFQUxjUnRVIiwiY3pnalVrMG5xUkNzd1NoQ2hDamRTNkExLXY0N2RfcVRDU0ZJdklIaE1vSSIsIm5HblFyN2NsbTN0ZlRwOHlqTF91SHJEU090elIyUFZiOFM3R2VMZEFxQlEiLCJ4TklWd2xwU3NhWjhDSlNmMGd6NXhfNzVWUldXYzZWMW1scGVqZENycVVzIl0sInN1YiI6IjIxNmY4OTQ2LTllY2ItNDgxOS05MzA5LWMwNzZmMzRhN2UxMSIsIl9zZF9hbGciOiJzaGEtMjU2IiwidmN0IjoiUGVyc29uSWRlbnRpZmljYXRpb25EYXRhIiwiaXNzIjoiaHR0cHM6Ly9wcmUuZWlkLndhbGxldC5pcHpzLml0IiwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2Iiwia2lkIjoiUnYzVy1FaUtwdkJUeWs1eVp4dnJldi03TURCNlNselVDQm9fQ1FqamRkVSIsIngiOiIwV294N1F0eVBxQnlnMzVNSF9YeUNjbmQ1TGUtSm0wQVhIbFVnREJBMDNZIiwieSI6ImVFaFZ2ZzFKUHFOZDNEVFNhNG1HREdCbHdZNk5QLUVaYkxiTkZYU1h3SWcifX0sImV4cCI6MTc1MTU0NjU3Niwic3RhdHVzIjp7InN0YXR1c19hdHRlc3RhdGlvbiI6eyJjcmVkZW50aWFsX2hhc2hfYWxnIjoic2hhLTI1NiJ9fX0.qXHA2oqr8trX4fGxpxpUft2GX380TM3pzfo1MYAsDjUC8HsODA-4rdRWAvDe2zYP57x4tJU7eiABkd1Kmln9yQ~WyJrSkRFUDhFYU5URU1CRE9aelp6VDR3IiwidW5pcXVlX2lkIiwiVElOSVQtTFZMREFBODVUNTBHNzAyQiJd~WyJ6SUF5VUZ2UGZJcEUxekJxeEk1aGFRIiwiYmlydGhfZGF0ZSIsIjE5ODUtMTItMTAiXQ~WyJHcjNSM3MyOTBPa1FVbS1ORlR1OTZBIiwidGF4X2lkX2NvZGUiLCJUSU5JVC1MVkxEQUE4NVQ1MEc3MDJCIl0~WyJHeE9SYWxNQWVsZlowZWRGSmpqWVV3IiwiZ2l2ZW5fbmFtZSIsIkFkYSJd~WyJfdlY1UklrbDBJT0VYS290czlrdDF3IiwiZmFtaWx5X25hbWUiLCJMb3ZlbGFjZSJd~WyJDajV0Y2NSNzJKd3J6ZTJUVzRhLXdnIiwiaWF0IiwxNzIwMDEwNTc1XQ";
|
17
|
-
|
18
|
-
const unsigned =
|
19
|
-
"eyJraWQiOiItRl82VWdhOG4zVmVnalkyVTdZVUhLMXpMb2FELU5QVGM2M1JNSVNuTGF3IiwidHlwIjoidmMrc2Qtand0IiwiYWxnIjoiRVMyNTYifQ.eyJfc2QiOlsiMHExRDVKbWF2NnBRYUVoX0pfRmN2X3VOTk1RSWdDeWhRT3hxbFk0bDNxVSIsIktDSi1BVk52ODhkLXhqNnNVSUFPSnhGbmJVaDNySFhES2tJSDFsRnFiUnMiLCJNOWxvOVl4RE5JWHJBcTJxV2VpQ0E0MHpwSl96WWZGZFJfNEFFQUxjUnRVIiwiY3pnalVrMG5xUkNzd1NoQ2hDamRTNkExLXY0N2RfcVRDU0ZJdklIaE1vSSIsIm5HblFyN2NsbTN0ZlRwOHlqTF91SHJEU090elIyUFZiOFM3R2VMZEFxQlEiLCJ4TklWd2xwU3NhWjhDSlNmMGd6NXhfNzVWUldXYzZWMW1scGVqZENycVVzIl0sInN1YiI6IjIxNmY4OTQ2LTllY2ItNDgxOS05MzA5LWMwNzZmMzRhN2UxMSIsIl9zZF9hbGciOiJzaGEtMjU2IiwidmN0IjoiUGVyc29uSWRlbnRpZmljYXRpb25EYXRhIiwiaXNzIjoiaHR0cHM6Ly9wcmUuZWlkLndhbGxldC5pcHpzLml0IiwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2Iiwia2lkIjoiUnYzVy1FaUtwdkJUeWs1eVp4dnJldi03TURCNlNselVDQm9fQ1FqamRkVSIsIngiOiIwV294N1F0eVBxQnlnMzVNSF9YeUNjbmQ1TGUtSm0wQVhIbFVnREJBMDNZIiwieSI6ImVFaFZ2ZzFKUHFOZDNEVFNhNG1HREdCbHdZNk5QLUVaYkxiTkZYU1h3SWcifX0sImV4cCI6MTc1MTU0NjU3Niwic3RhdHVzIjp7InN0YXR1c19hdHRlc3RhdGlvbiI6eyJjcmVkZW50aWFsX2hhc2hfYWxnIjoic2hhLTI1NiJ9fX0";
|
20
|
-
|
21
|
-
const signature =
|
22
|
-
"qXHA2oqr8trX4fGxpxpUft2GX380TM3pzfo1MYAsDjUC8HsODA-4rdRWAvDe2zYP57x4tJU7eiABkd1Kmln9yQ";
|
23
|
-
|
24
|
-
const signed = `${unsigned}.${signature}`;
|
25
|
-
|
26
|
-
const tokenizedDisclosures = [
|
27
|
-
"WyJrSkRFUDhFYU5URU1CRE9aelp6VDR3IiwidW5pcXVlX2lkIiwiVElOSVQtTFZMREFBODVUNTBHNzAyQiJd",
|
28
|
-
"WyJ6SUF5VUZ2UGZJcEUxekJxeEk1aGFRIiwiYmlydGhfZGF0ZSIsIjE5ODUtMTItMTAiXQ",
|
29
|
-
"WyJHcjNSM3MyOTBPa1FVbS1ORlR1OTZBIiwidGF4X2lkX2NvZGUiLCJUSU5JVC1MVkxEQUE4NVQ1MEc3MDJCIl0",
|
30
|
-
"WyJHeE9SYWxNQWVsZlowZWRGSmpqWVV3IiwiZ2l2ZW5fbmFtZSIsIkFkYSJd",
|
31
|
-
"WyJfdlY1UklrbDBJT0VYS290czlrdDF3IiwiZmFtaWx5X25hbWUiLCJMb3ZlbGFjZSJd",
|
32
|
-
"WyJDajV0Y2NSNzJKd3J6ZTJUVzRhLXdnIiwiaWF0IiwxNzIwMDEwNTc1XQ",
|
33
|
-
];
|
8
|
+
const { token, signed, tokenizedDisclosures } = pid;
|
34
9
|
|
35
10
|
const sdJwt = {
|
36
11
|
header: {
|
37
12
|
kid: "-F_6Uga8n3VegjY2U7YUHK1zLoaD-NPTc63RMISnLaw",
|
38
|
-
typ: "
|
13
|
+
typ: "dc+sd-jwt",
|
39
14
|
alg: "ES256",
|
40
15
|
},
|
41
16
|
payload: {
|
@@ -50,7 +25,11 @@ const sdJwt = {
|
|
50
25
|
sub: "216f8946-9ecb-4819-9309-c076f34a7e11",
|
51
26
|
_sd_alg: "sha-256",
|
52
27
|
vct: "PersonIdentificationData",
|
28
|
+
"vct#integrity":
|
29
|
+
"13e25888ac7b8a3a6d61440da787fccc81654e61085732bcacd89b36aec32675",
|
53
30
|
iss: "https://pre.eid.wallet.ipzs.it",
|
31
|
+
issuing_country: "IT",
|
32
|
+
issuing_authority: "Istituto Poligrafico e Zecca dello Stato",
|
54
33
|
cnf: {
|
55
34
|
jwk: {
|
56
35
|
kty: "EC",
|
@@ -62,7 +41,7 @@ const sdJwt = {
|
|
62
41
|
},
|
63
42
|
exp: 1751546576,
|
64
43
|
status: {
|
65
|
-
|
44
|
+
status_assertion: {
|
66
45
|
credential_hash_alg: "sha-256",
|
67
46
|
},
|
68
47
|
},
|
@@ -5,7 +5,7 @@ describe("SdJwt4VC", () => {
|
|
5
5
|
// example provided at https://italia.github.io/eidas-it-wallet-docs/en/pid-data-model.html
|
6
6
|
const token = {
|
7
7
|
header: {
|
8
|
-
typ: "
|
8
|
+
typ: "dc+sd-jwt",
|
9
9
|
alg: "RS512",
|
10
10
|
kid: "dB67gL7ck3TFiIAf7N6_7SHvqk0MDYMEQcoGGlkUAAw",
|
11
11
|
},
|
@@ -21,7 +21,11 @@ describe("SdJwt4VC", () => {
|
|
21
21
|
sub: "216f8946-9ecb-4819-9309-c076f34a7e11",
|
22
22
|
_sd_alg: "sha-256",
|
23
23
|
vct: "PersonIdentificationData",
|
24
|
+
"vct#integrity":
|
25
|
+
"13e25888ac7b8a3a6d61440da787fccc81654e61085732bcacd89b36aec32675",
|
24
26
|
iss: "https://pidprovider.example.com",
|
27
|
+
issuing_country: "IT",
|
28
|
+
issuing_authority: "Istituto Poligrafico e Zecca dello Stato",
|
25
29
|
cnf: {
|
26
30
|
jwk: {
|
27
31
|
kty: "EC",
|
@@ -33,7 +37,7 @@ describe("SdJwt4VC", () => {
|
|
33
37
|
},
|
34
38
|
exp: 1751107255,
|
35
39
|
status: {
|
36
|
-
|
40
|
+
status_assertion: {
|
37
41
|
credential_hash_alg: "sha-256",
|
38
42
|
},
|
39
43
|
},
|