@digitalbazaar/oid4-client 5.2.1 → 5.4.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.
@@ -73,14 +73,26 @@ export function fromVpr({
73
73
  if(verifiablePresentationRequest.challenge) {
74
74
  authorizationRequest.nonce = verifiablePresentationRequest.challenge;
75
75
  }
76
- // only a single `DIDAuthentication` query is supported at this time; use
77
- // the last one
76
+ // any DID authentication queries must be merged to a single set of
77
+ // supported values for compatibility purposes
78
78
  const didAuthnQuery = [...groupMap.values()]
79
79
  .filter(g => g.has(DID_AUTHENTICATION))
80
80
  .map(g => g.get(DID_AUTHENTICATION))
81
- .at(-1);
82
- if(didAuthnQuery) {
83
- const [query] = didAuthnQuery;
81
+ .flat();
82
+ if(didAuthnQuery.length > 0) {
83
+ // merge the accepted envelopes and cryptosuites across DID authn queries
84
+ const cryptosuites = new Set();
85
+ const envelopes = new Set();
86
+ for(const query of didAuthnQuery) {
87
+ query.acceptedCryptosuites?.forEach(
88
+ ({cryptosuite}) => cryptosuites.add(cryptosuite));
89
+ query.acceptedEnvelopes?.forEach(envelope => envelopes.add(envelope));
90
+ }
91
+ // convert last DID authn query w/merged cryptosuites and envelopes
92
+ const query = structuredClone(didAuthnQuery.at(-1));
93
+ query.acceptedCryptosuites = [...cryptosuites].map(
94
+ cryptosuite => ({cryptosuite}));
95
+ query.acceptedEnvelopes = [...envelopes];
84
96
  const client_metadata = _fromDIDAuthenticationQuery({query, strict});
85
97
  if(client_metadata) {
86
98
  authorizationRequest.client_metadata = client_metadata;
@@ -258,37 +270,60 @@ function _strictCheckVprGroups({groupMap, queryFormats}) {
258
270
  }
259
271
 
260
272
  function _fromDIDAuthenticationQuery({query, strict = false}) {
273
+ const vp_formats_supported = {};
274
+ const client_metadata = {
275
+ require_signed_request_object: false,
276
+ vp_formats: {},
277
+ vp_formats_supported
278
+ };
279
+
261
280
  const cryptosuites = query.acceptedCryptosuites?.map(
262
281
  ({cryptosuite}) => cryptosuite);
263
- if(!(cryptosuites?.length > 0)) {
282
+ if(cryptosuites?.length > 0) {
283
+ // legacy (before OID4VP 1.0)
284
+ client_metadata.vp_formats.ldp_vp = {
285
+ proof_type: cryptosuites
286
+ };
287
+ // OID4VP 1.0+
288
+ vp_formats_supported.ldp_vc = {
289
+ proof_type_values: ['DataIntegrityProof'],
290
+ cryptosuite_values: cryptosuites
291
+ };
292
+ // compatibility with legacy cryptosuite
293
+ if(cryptosuites.includes('Ed25519Signature2020')) {
294
+ vp_formats_supported.ldp_vc
295
+ .proof_type_values.push('Ed25519Signature2020');
296
+ }
297
+ }
298
+
299
+ if(query.acceptedEnvelopes?.length > 0) {
300
+ for(const envelope of query.acceptedEnvelopes) {
301
+ if(envelope === 'application/jwt') {
302
+ // legacy (before OID4VP 1.0)
303
+ vp_formats_supported.jwt_vp_json = {};
304
+ // OID4VP 1.0+
305
+ vp_formats_supported.jwt_vc_json = {};
306
+ } else if(envelope === 'application/mdl' ||
307
+ envelope === 'application/mdoc') {
308
+ vp_formats_supported.mso_mdoc = {};
309
+ } else if(envelope === 'application/dc+sd-jwt') {
310
+ vp_formats_supported['dc+sd-jwt'] = {};
311
+ }
312
+ // ignore unknown envelope format
313
+ }
314
+ }
315
+
316
+ if(Object.keys(vp_formats_supported) === 0) {
264
317
  if(strict) {
265
318
  const error = new Error(
266
- '"query.acceptedCryptosuites" must be a non-array with specified ' +
267
- `cryptosuites to convert from a "${DID_AUTHENTICATION}" query.`);
319
+ '"query.acceptedCryptosuites" or "query.acceptedEnvelopes" must be a ' +
320
+ 'non-array with specified cryptosuites (or envelopes, respectively) ' +
321
+ `to convert from a "${DID_AUTHENTICATION}" query.`);
268
322
  error.name = 'NotSupportedError';
269
323
  throw error;
270
324
  }
271
325
  return;
272
326
  }
273
- const client_metadata = {
274
- require_signed_request_object: false,
275
- vp_formats: {
276
- ldp_vp: {
277
- proof_type: cryptosuites
278
- }
279
- },
280
- vp_formats_supported: {
281
- ldp_vc: {
282
- proof_type_values: ['DataIntegrityProof']
283
- },
284
- cryptosuite_values: cryptosuites
285
- }
286
- };
287
- // compatibility with legacy cryptosuite
288
- if(cryptosuites.includes('Ed25519Signature2020')) {
289
- client_metadata.vp_formats_supported.ldp_vc
290
- .proof_type_values.push('Ed25519Signature2020');
291
- }
292
327
 
293
328
  return client_metadata;
294
329
  }
@@ -297,9 +332,20 @@ function _toDIDAuthenticationQuery({client_metadata, strict = false}) {
297
332
  const {vp_formats_supported, vp_formats} = client_metadata;
298
333
  const proofTypes = vp_formats_supported?.ldp_vc?.cryptosuite_values ??
299
334
  vp_formats?.ldp_vp?.proof_type;
300
- if(!Array.isArray(proofTypes)) {
335
+ const envelopes = [];
336
+ if(vp_formats_supported?.jwt_vc_json || vp_formats_supported?.jwt_vp_json) {
337
+ envelopes.push('application/jwt');
338
+ }
339
+ if(vp_formats_supported?.mso_mdoc) {
340
+ envelopes.push('application/mdoc');
341
+ }
342
+ if(vp_formats_supported?.['dc+sd-jwt']) {
343
+ envelopes.push('application/dc+sd-jwt');
344
+ }
345
+ if(!(Array.isArray(proofTypes) || envelopes.length > 0)) {
301
346
  if(strict) {
302
347
  const error = new Error(
348
+ '"client_metadata.vp_formats_supported.ldp_vc.cryptosuite_values" or ' +
303
349
  '"client_metadata.vp_formats.ldp_vp.proof_type" must be an array to ' +
304
350
  `convert to "${DID_AUTHENTICATION}" query.`);
305
351
  error.name = 'NotSupportedError';
@@ -307,10 +353,14 @@ function _toDIDAuthenticationQuery({client_metadata, strict = false}) {
307
353
  }
308
354
  return;
309
355
  }
310
- return {
311
- type: DID_AUTHENTICATION,
312
- acceptedCryptosuites: proofTypes.map(cryptosuite => ({cryptosuite}))
313
- };
356
+ const query = {type: DID_AUTHENTICATION};
357
+ if(proofTypes) {
358
+ query.acceptedCryptosuites = proofTypes.map(cryptosuite => ({cryptosuite}));
359
+ }
360
+ if(envelopes.length > 0) {
361
+ query.acceptedEnvelopes = envelopes;
362
+ }
363
+ return query;
314
364
  }
315
365
 
316
366
  function _vprGroupsToQuery({groupMap}) {
@@ -13,6 +13,9 @@ import {
13
13
  const REQUIRED_SIGNED_AUTHZ_REQUEST_CLIENT_ID_SCHEMES = new Set([
14
14
  'x509_san_dns', 'x509_hash', 'did', 'decentralized_identifier'
15
15
  ]);
16
+ const SUPPORTED_AUTHORIZATION_ENCRYPTED_RESPONSE_ENC = new Set([
17
+ 'A256GCM', 'A128GCM'
18
+ ]);
16
19
  const SUPPORTED_CLIENT_ID_SCHEMES = new Set([
17
20
  'redirect_uri',
18
21
  'x509_san_dns', 'x509_hash', 'did', 'decentralized_identifier'
@@ -177,10 +180,12 @@ export async function validate({authorizationRequest, expectedClientId}) {
177
180
  name: 'NotSupportedError'
178
181
  });
179
182
  }
180
- if(authorization_encrypted_response_enc !== 'A256GCM') {
183
+ if(!SUPPORTED_AUTHORIZATION_ENCRYPTED_RESPONSE_ENC.has(
184
+ authorization_encrypted_response_enc)) {
185
+ const supported = [...SUPPORTED_AUTHORIZATION_ENCRYPTED_RESPONSE_ENC];
181
186
  throw createNamedError({
182
187
  message: `"${authorization_encrypted_response_enc}" is not ` +
183
- 'supported; only "A256GCM" is supported.',
188
+ `supported; supported values are: ${supported.join(', ')}`,
184
189
  name: 'NotSupportedError'
185
190
  });
186
191
  }
@@ -239,7 +239,8 @@ async function _encrypt({
239
239
  };
240
240
  const jwt = await new EncryptJWT(claimSet)
241
241
  .setProtectedHeader({
242
- alg: 'ECDH-ES', enc: 'A256GCM',
242
+ alg: 'ECDH-ES',
243
+ enc: encryptionOptions?.enc ?? 'A256GCM',
243
244
  kid: recipientPublicJwk.kid
244
245
  })
245
246
  .setKeyManagementParameters(keyManagementParameters)
@@ -96,7 +96,7 @@ async function _decrypt({jwt, getDecryptParameters}) {
96
96
 
97
97
  return jwtDecrypt(jwt, getKey, {
98
98
  // only supported algorithms at this time:
99
- contentEncryptionAlgorithms: ['A256GCM'],
99
+ contentEncryptionAlgorithms: ['A256GCM', 'A128GCM'],
100
100
  keyManagementAlgorithms: ['ECDH-ES']
101
101
  });
102
102
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitalbazaar/oid4-client",
3
- "version": "5.2.1",
3
+ "version": "5.4.0",
4
4
  "description": "An OID4 (VC + VP) client",
5
5
  "homepage": "https://github.com/digitalbazaar/oid4-client",
6
6
  "author": {