@bedrock/vc-verifier 23.5.1 → 23.6.1

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.
@@ -0,0 +1,54 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Digital Bazaar, Inc. All rights reserved.
3
+ */
4
+ import {oid4vp} from '@digitalbazaar/oid4-client';
5
+
6
+ // returns session transcript bytes
7
+ export async function getEncodedSessionTranscript({
8
+ options, domain, challenge
9
+ } = {}) {
10
+ const {mdl} = options;
11
+
12
+ if(!mdl?.sessionTranscript) {
13
+ // no `mdl` session transcript given
14
+ return undefined;
15
+ }
16
+
17
+ const {sessionTranscript} = mdl;
18
+
19
+ // if `mdl.sessionTranscript` is a base64url string, decode and return it
20
+ if(typeof sessionTranscript === 'string') {
21
+ return Buffer.from(sessionTranscript, 'base64url');
22
+ }
23
+
24
+ // backwards compatibility case: `sessionTranscript` is an object with
25
+ // Annex B parameters; convert it
26
+ if(sessionTranscript && typeof sessionTranscript === 'object') {
27
+ const handover = {
28
+ type: 'AnnexBHandover',
29
+ responseUri: domain,
30
+ ...sessionTranscript
31
+ };
32
+
33
+ // `mdocGeneratedNonce` and `verifierGeneratedNonce` are
34
+ // base64url strings that must be converted to UTF-8 strings; the others
35
+ // are passthrough strings
36
+ for(const prop of ['mdocGeneratedNonce', 'verifierGeneratedNonce']) {
37
+ if(handover[prop]) {
38
+ handover[prop] = Buffer
39
+ .from(handover[prop], 'base64url')
40
+ .toString('utf8');
41
+ }
42
+ }
43
+
44
+ // add `challenge` as `verifierGeneratedNonce` if not specified
45
+ if(!handover.verifierGeneratedNonce) {
46
+ handover.verifierGeneratedNonce = challenge;
47
+ }
48
+
49
+ return oid4vp.mdl.encodeSessionTranscript({handover});
50
+ }
51
+
52
+ // no acceptable session transcript
53
+ return undefined;
54
+ }
package/lib/mdl.js CHANGED
@@ -1,12 +1,13 @@
1
1
  /*
2
- * Copyright (c) 2025 Digital Bazaar, Inc. All rights reserved.
2
+ * Copyright (c) 2025-2026 Digital Bazaar, Inc. All rights reserved.
3
3
  */
4
4
  import * as bedrock from '@bedrock/core';
5
5
  import {addDocumentRoutes, documentStores} from '@bedrock/service-agent';
6
6
  import {
7
7
  createMdlCaStoreBody, updateMdlCaStoreBody
8
8
  } from '../schemas/bedrock-vc-verifier.js';
9
- import {DataItem, Verifier} from '@auth0/mdl';
9
+ import {getEncodedSessionTranscript} from './iso18013-7.js';
10
+ import {Verifier} from '@auth0/mdl';
10
11
 
11
12
  const {util: {BedrockError}} = bedrock;
12
13
 
@@ -51,14 +52,23 @@ export async function verifyEnvelopedPresentation({
51
52
  // decoded `contents` is the mDL device response
52
53
  const deviceResponse = Buffer.from(contents, 'base64url');
53
54
 
54
- // session transcription must be provided modulo:
55
+ // session transcription must be provided as base64url string or as an
56
+ // object in `options.mdl.sessionTranscript` with Annex B parameters modulo:
55
57
  // `domain` which is used as the `responseUri`
56
58
  // `challenge` which is used as the `verifierGeneratedNonce`
57
- const sessionTranscript = {
58
- ..._getSessionTranscriptFromOptions({options}),
59
- responseUri: domain,
60
- verifierGeneratedNonce: challenge
61
- };
59
+ const encodedSessionTranscript = await getEncodedSessionTranscript({
60
+ options, domain, challenge
61
+ });
62
+ if(!encodedSessionTranscript) {
63
+ throw new BedrockError(
64
+ 'No usable mdoc session transcript provided in verification options.', {
65
+ name: 'DataError',
66
+ details: {
67
+ httpStatusCode: 400,
68
+ public: true
69
+ },
70
+ });
71
+ }
62
72
 
63
73
  // fetch CA store(s)
64
74
  const {documentStore} = await documentStores.get({config, serviceType});
@@ -71,18 +81,32 @@ export async function verifyEnvelopedPresentation({
71
81
  doc.content.trustedCertificates.forEach(caStore.add, caStore);
72
82
  }
73
83
 
74
- return verifyPresentation({
75
- deviceResponse, sessionTranscript, trustedCertificates: [...caStore]
84
+ return _verifyDeviceResponse({
85
+ deviceResponse, encodedSessionTranscript, trustedCertificates: [...caStore]
76
86
  });
77
87
  }
78
88
 
79
- export async function verifyPresentation({
80
- deviceResponse, sessionTranscript, trustedCertificates
89
+ async function _getCAStoreDocument({documentStore, url}) {
90
+ const doc = await documentStore.get({id: url});
91
+ if(doc.meta.type !== MDL_CA_STORE_TYPE) {
92
+ // wrong meta type; treat as not found error
93
+ throw new BedrockError(`Document "${url}" not found.`, {
94
+ name: 'NotFoundError',
95
+ details: {
96
+ url,
97
+ httpStatusCode: 404,
98
+ public: true
99
+ }
100
+ });
101
+ }
102
+ return doc;
103
+ }
104
+
105
+ async function _verifyDeviceResponse({
106
+ deviceResponse, encodedSessionTranscript, trustedCertificates
81
107
  } = {}) {
82
108
  try {
83
109
  const verifier = new Verifier(trustedCertificates);
84
- const encodedSessionTranscript = _encodeSessionTranscript(
85
- sessionTranscript);
86
110
 
87
111
  // uncomment to debug
88
112
  /*
@@ -133,61 +157,3 @@ export async function verifyPresentation({
133
157
  return {verified: false, error};
134
158
  }
135
159
  }
136
-
137
- // returns a full or partial session transcript
138
- function _getSessionTranscriptFromOptions({options}) {
139
- if(!options.mdl?.sessionTranscript) {
140
- // no `mdl` session transcription options given
141
- return {};
142
- }
143
-
144
- // `mdocGeneratedNonce` and `verifierGeneratedNonce` are base64url-encoded
145
- // values; the others are passthrough strings
146
- const sessionTranscript = {...options.mdl.sessionTranscript};
147
- if(sessionTranscript.mdocGeneratedNonce) {
148
- sessionTranscript.mdocGeneratedNonce = Buffer
149
- .from(sessionTranscript.mdocGeneratedNonce, 'base64url')
150
- // note: ISO 18013-7 requires `verifierGeneratedNonce` to be a string
151
- .toString('utf8');
152
- }
153
- if(sessionTranscript.verifierGeneratedNonce) {
154
- sessionTranscript.verifierGeneratedNonce = Buffer
155
- .from(sessionTranscript.verifierGeneratedNonce, 'base64url')
156
- // note: ISO 18013-7 requires `verifierGeneratedNonce` to be a string
157
- .toString('utf8');
158
- }
159
- return sessionTranscript;
160
- }
161
-
162
- function _encodeSessionTranscript(sessionTranscript) {
163
- const {
164
- mdocGeneratedNonce,
165
- clientId,
166
- responseUri,
167
- verifierGeneratedNonce
168
- } = sessionTranscript;
169
- const encoded = DataItem.fromData([
170
- // deviceEngagementBytes
171
- null,
172
- // eReaderKeyBytes
173
- null,
174
- [mdocGeneratedNonce, clientId, responseUri, verifierGeneratedNonce],
175
- ]);
176
- return DataItem.fromData(encoded).buffer;
177
- }
178
-
179
- async function _getCAStoreDocument({documentStore, url}) {
180
- const doc = await documentStore.get({id: url});
181
- if(doc.meta.type !== MDL_CA_STORE_TYPE) {
182
- // wrong meta type; treat as not found error
183
- throw new BedrockError(`Document "${url}" not found.`, {
184
- name: 'NotFoundError',
185
- details: {
186
- url,
187
- httpStatusCode: 404,
188
- public: true
189
- }
190
- });
191
- }
192
- return doc;
193
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrock/vc-verifier",
3
- "version": "23.5.1",
3
+ "version": "23.6.1",
4
4
  "type": "module",
5
5
  "description": "Bedrock VC Verifier",
6
6
  "main": "./lib/index.js",
@@ -41,6 +41,7 @@
41
41
  "@digitalbazaar/eddsa-2022-cryptosuite": "^1.0.0",
42
42
  "@digitalbazaar/eddsa-jcs-2022-cryptosuite": "^1.0.0",
43
43
  "@digitalbazaar/eddsa-rdfc-2022-cryptosuite": "^1.2.0",
44
+ "@digitalbazaar/oid4-client": "^5.8.0",
44
45
  "@digitalbazaar/pdf417-dl-canonicalizer": "^1.2.1",
45
46
  "@digitalbazaar/vc": "^7.2.0",
46
47
  "@digitalbazaar/vc-bitstring-status-list": "^2.0.1",
@@ -178,7 +178,7 @@ const envelopedVerifiablePresentation = {
178
178
  export const verifyOptions = {
179
179
  title: 'Verify Options',
180
180
  type: 'object',
181
- oneOf: [{
181
+ anyOf: [{
182
182
  required: ['didResolver']
183
183
  }, {
184
184
  required: ['documentLoader']