@bedrock/vc-verifier 9.0.0 → 12.0.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.
@@ -1,488 +0,0 @@
1
- /*!
2
- * Copyright (c) 2019-2022 Digital Bazaar, Inc. All rights reserved.
3
- */
4
- import * as helpers from './helpers.js';
5
- import {agent} from '@bedrock/https-agent';
6
- import {createRequire} from 'node:module';
7
- import {documentLoader as brDocLoader} from '@bedrock/jsonld-document-loader';
8
- import express from 'express';
9
- import {fileURLToPath} from 'node:url';
10
- import fs from 'node:fs';
11
- import {httpClient} from '@digitalbazaar/http-client';
12
- import https from 'node:https';
13
- import {klona} from 'klona';
14
- import {mockData} from './mock.data.js';
15
- import path from 'node:path';
16
- const require = createRequire(import.meta.url);
17
- const {CapabilityAgent} = require('@digitalbazaar/webkms-client');
18
- const {Ed25519Signature2020} = require('@digitalbazaar/ed25519-signature-2020');
19
- const {Ed25519VerificationKey2020} =
20
- require('@digitalbazaar/ed25519-verification-key-2020');
21
- const revocationListCtx = require('vc-revocation-list-context');
22
- const statusListCtx = require('@digitalbazaar/vc-status-list-context');
23
- const vc = require('@digitalbazaar/vc');
24
-
25
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
26
-
27
- const {baseUrl} = mockData;
28
- const serviceType = 'vc-verifier';
29
-
30
- const VC_SL_CONTEXT_URL = statusListCtx.constants.CONTEXT_URL_V1;
31
- const VC_RL_CONTEXT_URL =
32
- revocationListCtx.constants.VC_REVOCATION_LIST_CONTEXT_V1_URL;
33
-
34
- const encodedList100k =
35
- 'H4sIAAAAAAAAA-3BMQEAAADCoPVPbQsvoAAAAAAAAAAAAAAAAP4GcwM92tQwAAA';
36
- const encodedList100KWith50KthRevoked =
37
- 'H4sIAAAAAAAAA-3OMQ0AAAgDsOHfNB72EJJWQRMAAAAAAIDWXAcAAAAAAIDHFrc4zDz' +
38
- 'UMAAA';
39
- const key = fs.readFileSync(__dirname + '/key.pem');
40
- const cert = fs.readFileSync(__dirname + '/cert.pem');
41
-
42
- let slCredential;
43
- let unsignedCredentialSl2021Type;
44
- let revokedSlCredential;
45
- let revokedUnsignedCredential;
46
- let rlCredential;
47
- let unsignedCredentialRL2020Type;
48
- let revokedRlCredential;
49
- let revokedUnsignedCredential2;
50
-
51
- // load docs from test server (e.g., load RL VCs and SL VCs)
52
- let testServerBaseUrl;
53
- async function _documentLoader(url) {
54
- if(url.startsWith(testServerBaseUrl)) {
55
- const response = await httpClient.get(url, {agent});
56
- return {
57
- contextUrl: null,
58
- documentUrl: url,
59
- document: response.data
60
- };
61
- }
62
- return brDocLoader(url);
63
- }
64
-
65
- function _startServer({app}) {
66
- return new Promise(resolve => {
67
- const server = https.createServer({key, cert}, app);
68
- server.listen(() => {
69
- const {port} = server.address();
70
- const BASE_URL = `https://localhost:${port}`;
71
- testServerBaseUrl = BASE_URL;
72
- console.log(`Test server listening at ${BASE_URL}`);
73
-
74
- // Status List 2021 Credential
75
- slCredential = {
76
- '@context': [
77
- 'https://www.w3.org/2018/credentials/v1',
78
- VC_SL_CONTEXT_URL
79
- ],
80
- id: `${BASE_URL}/status/748a7d8e-9111-11ec-a934-10bf48838a41`,
81
- issuer: 'did:key:z6Mktpn6cXks1PBKLMgZH2VaahvCtBMF6K8eCa7HzrnuYLZv',
82
- issuanceDate: '2022-01-10T04:24:12.164Z',
83
- type: ['VerifiableCredential', 'StatusList2021Credential'],
84
- credentialSubject: {
85
- id: `${BASE_URL}/status/748a7d8e-9111-11ec-a934-10bf48838a41#list`,
86
- type: 'StatusList2021',
87
- encodedList: encodedList100k
88
- }
89
- };
90
-
91
- // Unsigned 2021 Credential
92
- unsignedCredentialSl2021Type = {
93
- '@context': [
94
- 'https://www.w3.org/2018/credentials/v1',
95
- VC_SL_CONTEXT_URL,
96
- 'https://w3id.org/security/suites/ed25519-2020/v1'
97
- ],
98
- id: 'urn:uuid:a0418a78-7924-11ea-8a23-10bf48838a41',
99
- type: ['VerifiableCredential', 'example:TestCredential'],
100
- credentialSubject: {
101
- id: 'urn:uuid:4886029a-7925-11ea-9274-10bf48838a41',
102
- 'example:test': 'foo'
103
- },
104
- credentialStatus: {
105
- id: `${BASE_URL}/status/748a7d8e-9111-11ec-a934-10bf48838a41#67342`,
106
- type: 'StatusList2021Entry',
107
- statusPurpose: 'revocation',
108
- statusListIndex: '67342',
109
- statusListCredential: slCredential.id
110
- },
111
- issuer: slCredential.issuer,
112
- };
113
-
114
- // Revoked Status List 2021 Credential
115
- revokedSlCredential = klona(slCredential);
116
-
117
- revokedSlCredential.id =
118
- `${BASE_URL}/status/8ec30054-9111-11ec-9ab5-10bf48838a41`,
119
- revokedSlCredential.credentialSubject.encodedList =
120
- encodedList100KWith50KthRevoked;
121
- revokedSlCredential.credentialSubject.id =
122
- `${BASE_URL}/status/8ec30054-9111-11ec-9ab5-10bf48838a41#list`;
123
-
124
- // Revoked Unsigned 2021 Credential
125
- revokedUnsignedCredential = klona(unsignedCredentialSl2021Type);
126
- revokedUnsignedCredential.credentialStatus.id =
127
- `${revokedSlCredential.id}#50000`;
128
- revokedUnsignedCredential.credentialStatus.statusListIndex = 50000;
129
- revokedUnsignedCredential.credentialStatus.statusListCredential =
130
- `${revokedSlCredential.id}`;
131
- revokedUnsignedCredential.issuer = revokedSlCredential.issuer;
132
-
133
- // Revocation List 2020 Credential
134
- rlCredential = {
135
- '@context': [
136
- 'https://www.w3.org/2018/credentials/v1',
137
- VC_RL_CONTEXT_URL
138
- ],
139
- id: `${BASE_URL}/status/9d5a3fb0-9111-11ec-862d-10bf48838a41`,
140
- issuer: 'did:key:z6Mktpn6cXks1PBKLMgZH2VaahvCtBMF6K8eCa7HzrnuYLZv',
141
- issuanceDate: '2022-01-10T04:24:12.164Z',
142
- type: ['VerifiableCredential', 'RevocationList2020Credential'],
143
- credentialSubject: {
144
- id: `${BASE_URL}/status/9d5a3fb0-9111-11ec-862d-10bf48838a41#list`,
145
- type: 'RevocationList2020',
146
- encodedList: encodedList100k
147
- }
148
- };
149
-
150
- // Unsigned 2020 Credential
151
- unsignedCredentialRL2020Type = {
152
- '@context': [
153
- 'https://www.w3.org/2018/credentials/v1',
154
- VC_RL_CONTEXT_URL,
155
- 'https://w3id.org/security/suites/ed25519-2020/v1'
156
- ],
157
- id: 'urn:uuid:a0418a78-7924-11ea-8a23-10bf48838a41',
158
- type: ['VerifiableCredential', 'example:TestCredential'],
159
- credentialSubject: {
160
- id: 'urn:uuid:4886029a-7925-11ea-9274-10bf48838a41',
161
- 'example:test': 'foo'
162
- },
163
- issuanceDate: '2022-01-11T19:23:24Z',
164
- credentialStatus: {
165
- id: `${BASE_URL}/status/9d5a3fb0-9111-11ec-862d-10bf48838a41#67342`,
166
- type: 'RevocationList2020Status',
167
- revocationListIndex: '67342',
168
- revocationListCredential: rlCredential.id
169
- },
170
- issuer: rlCredential.issuer,
171
- };
172
-
173
- // Revoked Revocation List 2020 Credential
174
- revokedRlCredential = klona(rlCredential);
175
-
176
- revokedRlCredential.id =
177
- `${BASE_URL}/status/a63896b8-9111-11ec-9fd2-10bf48838a41`,
178
- revokedRlCredential.credentialSubject.encodedList =
179
- encodedList100KWith50KthRevoked;
180
- revokedRlCredential.credentialSubject.id =
181
- `${BASE_URL}/status/a63896b8-9111-11ec-9fd2-10bf48838a41#list`;
182
-
183
- // Revoked Unsigned 2020 Credential
184
- revokedUnsignedCredential2 = klona(unsignedCredentialRL2020Type);
185
- revokedUnsignedCredential2.credentialStatus.id =
186
- `${revokedRlCredential.id}#50000`;
187
- revokedUnsignedCredential2.credentialStatus.revocationListIndex = 50000;
188
- revokedUnsignedCredential2.credentialStatus.revocationListCredential =
189
- `${revokedRlCredential.id}`;
190
- revokedUnsignedCredential2.issuer = revokedRlCredential.issuer;
191
-
192
- return resolve(server);
193
- });
194
- });
195
- }
196
-
197
- const app = express();
198
- app.use(express.json());
199
-
200
- // mount the test routes
201
- app.get('/status/748a7d8e-9111-11ec-a934-10bf48838a41',
202
- // eslint-disable-next-line no-unused-vars
203
- (req, res, next) => {
204
- // responds with a valid status list 2021 type credential
205
- res.json(slCredential);
206
- });
207
- app.get('/status/8ec30054-9111-11ec-9ab5-10bf48838a41',
208
- // eslint-disable-next-line no-unused-vars
209
- (req, res, next) => {
210
- // responds with a revoked status list 2021 type credential
211
- res.json(revokedSlCredential);
212
- });
213
- app.get('/status/9d5a3fb0-9111-11ec-862d-10bf48838a41',
214
- // eslint-disable-next-line no-unused-vars
215
- (req, res, next) => {
216
- // responds with a valid revocation list 2020 type credential
217
- res.json(rlCredential);
218
- });
219
- app.get('/status/a63896b8-9111-11ec-9fd2-10bf48838a41',
220
- // eslint-disable-next-line no-unused-vars
221
- (req, res, next) => {
222
- // responds with a revoked revocation list 2020 type credential
223
- res.json(revokedRlCredential);
224
- });
225
- let server;
226
- before(async () => {
227
- server = await _startServer({app});
228
- });
229
- after(async () => {
230
- server.close();
231
- });
232
-
233
- describe('verify credential status', () => {
234
- let keyData;
235
- let keyPair;
236
- let suite;
237
- before(async () => {
238
- keyData = {
239
- id: 'did:key:z6Mktpn6cXks1PBKLMgZH2VaahvCtBMF6K8eCa7HzrnuYLZv#' +
240
- 'z6Mktpn6cXks1PBKLMgZH2VaahvCtBMF6K8eCa7HzrnuYLZv',
241
- controller: 'did:key:z6Mktpn6cXks1PBKLMgZH2VaahvCtBMF6K8eCa7HzrnuYLZv',
242
- type: 'Ed25519VerificationKey2020',
243
- publicKeyMultibase: 'z6Mktpn6cXks1PBKLMgZH2VaahvCtBMF6K8eCa7HzrnuYLZv',
244
- privateKeyMultibase: 'zrv2rP9yjtz3YwCas9m6hnoPxmoqZV72xbCEuomXi4wwSS' +
245
- '4ShekesADYiAMHoxoqfyBDKQowGMvYx9rp6QGJ7Qbk7Y4'
246
- };
247
- keyPair = await Ed25519VerificationKey2020.from(keyData);
248
- suite = new Ed25519Signature2020({key: keyPair});
249
- });
250
- let capabilityAgent;
251
- let verifierConfig;
252
- let verifierId;
253
- let rootZcap;
254
- const zcaps = {};
255
- beforeEach(async () => {
256
- const secret = '53ad64ce-8e1d-11ec-bb12-10bf48838a41';
257
- const handle = 'test';
258
- capabilityAgent = await CapabilityAgent.fromSecret({secret, handle});
259
-
260
- // create keystore for capability agent
261
- const keystoreAgent = await helpers.createKeystoreAgent(
262
- {capabilityAgent});
263
-
264
- // create EDV for storage (creating hmac and kak in the process)
265
- const {
266
- edvConfig,
267
- hmac,
268
- keyAgreementKey
269
- } = await helpers.createEdv({capabilityAgent, keystoreAgent});
270
-
271
- // get service agent to delegate to
272
- const serviceAgentUrl =
273
- `${baseUrl}/service-agents/${encodeURIComponent(serviceType)}`;
274
- const {data: serviceAgent} = await httpClient.get(serviceAgentUrl, {
275
- agent
276
- });
277
-
278
- // delegate edv, hmac, and key agreement key zcaps to service agent
279
- const {id: edvId} = edvConfig;
280
- zcaps.edv = await helpers.delegate({
281
- controller: serviceAgent.id,
282
- delegator: capabilityAgent,
283
- invocationTarget: edvId
284
- });
285
- const {keystoreId} = keystoreAgent;
286
- zcaps.hmac = await helpers.delegate({
287
- capability: `urn:zcap:root:${encodeURIComponent(keystoreId)}`,
288
- controller: serviceAgent.id,
289
- invocationTarget: hmac.id,
290
- delegator: capabilityAgent
291
- });
292
- zcaps.keyAgreementKey = await helpers.delegate({
293
- capability: `urn:zcap:root:${encodeURIComponent(keystoreId)}`,
294
- controller: serviceAgent.id,
295
- invocationTarget: keyAgreementKey.kmsId,
296
- delegator: capabilityAgent
297
- });
298
-
299
- // create verifier instance
300
- verifierConfig = await helpers.createConfig({capabilityAgent, zcaps});
301
- verifierId = verifierConfig.id;
302
- rootZcap = `urn:zcap:root:${encodeURIComponent(verifierId)}`;
303
- });
304
- it('should verify "StatusList2021Credential" type', async () => {
305
- slCredential = await vc.issue({
306
- credential: slCredential,
307
- documentLoader: _documentLoader,
308
- suite
309
- });
310
- const verifiableCredential = await vc.issue({
311
- credential: unsignedCredentialSl2021Type,
312
- documentLoader: _documentLoader,
313
- suite
314
- });
315
- let error;
316
- let result;
317
- try {
318
- const zcapClient = helpers.createZcapClient({capabilityAgent});
319
- result = await zcapClient.write({
320
- url: `${verifierId}/credentials/verify`,
321
- capability: rootZcap,
322
- json: {
323
- options: {
324
- checks: ['proof', 'credentialStatus'],
325
- },
326
- verifiableCredential
327
- }
328
- });
329
- } catch(e) {
330
- error = e;
331
- }
332
- assertNoError(error);
333
- should.exist(result.data.verified);
334
- result.data.verified.should.be.a('boolean');
335
- result.data.verified.should.equal(true);
336
- const {checks} = result.data;
337
- checks.should.be.an('array');
338
- checks.should.have.length(2);
339
- checks.should.be.an('array');
340
- checks.should.eql(['proof', 'credentialStatus']);
341
- should.exist(result.data.results);
342
- result.data.results.should.be.an('array');
343
- result.data.results.should.have.length(1);
344
- const [r] = result.data.results;
345
- r.verified.should.be.a('boolean');
346
- r.verified.should.equal(true);
347
- });
348
- it('should fail to verify a revoked "StatusList2021Credential" type',
349
- async () => {
350
- revokedSlCredential = await vc.issue({
351
- credential: revokedSlCredential,
352
- documentLoader: _documentLoader,
353
- suite
354
- });
355
- const verifiableCredential = await vc.issue({
356
- credential: revokedUnsignedCredential,
357
- documentLoader: _documentLoader,
358
- suite
359
- });
360
- let error;
361
- let result;
362
- try {
363
- const zcapClient = helpers.createZcapClient({capabilityAgent});
364
- result = await zcapClient.write({
365
- url: `${verifierId}/credentials/verify`,
366
- capability: rootZcap,
367
- json: {
368
- options: {
369
- checks: ['credentialStatus'],
370
- },
371
- verifiableCredential
372
- }
373
- });
374
- } catch(e) {
375
- error = e;
376
- }
377
- should.exist(error);
378
- should.not.exist(result);
379
- error.data.verified.should.be.a('boolean');
380
- error.data.verified.should.equal(false);
381
- const {checks, error: {message: errorMsg}} = error.data;
382
- checks.should.be.an('array');
383
- checks.should.have.length(1);
384
- errorMsg.should.equal('The credential failed a status check.');
385
- error.data.statusResult.verified.should.equal(false);
386
- const [{check}] = checks;
387
- check.should.be.an('array');
388
- check.should.eql(['credentialStatus']);
389
- should.exist(error.data.results);
390
- error.data.results.should.be.an('array');
391
- error.data.results.should.have.length(1);
392
- const [r] = error.data.results;
393
- r.verified.should.be.a('boolean');
394
- r.verified.should.equal(true);
395
- });
396
- it('should verify "RevocationList2020Credential" type', async () => {
397
- rlCredential = await vc.issue({
398
- credential: rlCredential,
399
- documentLoader: _documentLoader,
400
- suite
401
- });
402
- const verifiableCredential = await vc.issue({
403
- credential: unsignedCredentialRL2020Type,
404
- documentLoader: _documentLoader,
405
- suite
406
- });
407
- let error;
408
- let result;
409
- try {
410
- const zcapClient = helpers.createZcapClient({capabilityAgent});
411
- result = await zcapClient.write({
412
- url: `${verifierId}/credentials/verify`,
413
- capability: rootZcap,
414
- json: {
415
- options: {
416
- checks: ['proof', 'credentialStatus'],
417
- },
418
- verifiableCredential
419
- }
420
- });
421
- } catch(e) {
422
- error = e;
423
- }
424
- should.not.exist(error);
425
- should.exist(result.data.verified);
426
- result.data.verified.should.be.a('boolean');
427
- result.data.verified.should.equal(true);
428
- const {checks} = result.data;
429
- checks.should.be.an('array');
430
- checks.should.have.length(2);
431
- checks.should.be.an('array');
432
- checks.should.eql(['proof', 'credentialStatus']);
433
- should.exist(result.data.results);
434
- result.data.results.should.be.an('array');
435
- result.data.results.should.have.length(1);
436
- const [r] = result.data.results;
437
- r.verified.should.be.a('boolean');
438
- r.verified.should.equal(true);
439
- });
440
- it('should fail to verify a revoked "RevocationList2020Credential" type',
441
- async () => {
442
- revokedRlCredential = await vc.issue({
443
- credential: revokedRlCredential,
444
- documentLoader: _documentLoader,
445
- suite
446
- });
447
- const verifiableCredential = await vc.issue({
448
- credential: revokedUnsignedCredential2,
449
- documentLoader: _documentLoader,
450
- suite
451
- });
452
- let error;
453
- let result;
454
- try {
455
- const zcapClient = helpers.createZcapClient({capabilityAgent});
456
- result = await zcapClient.write({
457
- url: `${verifierId}/credentials/verify`,
458
- capability: rootZcap,
459
- json: {
460
- options: {
461
- checks: ['credentialStatus'],
462
- },
463
- verifiableCredential
464
- }
465
- });
466
- } catch(e) {
467
- error = e;
468
- }
469
- should.exist(error);
470
- should.not.exist(result);
471
- error.data.verified.should.be.a('boolean');
472
- error.data.verified.should.equal(false);
473
- const {checks, error: {message: errorMsg}} = error.data;
474
- checks.should.be.an('array');
475
- checks.should.have.length(1);
476
- errorMsg.should.equal('The credential failed a status check.');
477
- error.data.statusResult.verified.should.equal(false);
478
- const [{check}] = checks;
479
- check.should.be.an('array');
480
- check.should.eql(['credentialStatus']);
481
- should.exist(error.data.results);
482
- error.data.results.should.be.an('array');
483
- error.data.results.should.have.length(1);
484
- const [r] = error.data.results;
485
- r.verified.should.be.a('boolean');
486
- r.verified.should.equal(true);
487
- });
488
- });
@@ -1,18 +0,0 @@
1
- -----BEGIN CERTIFICATE-----
2
- MIIC8zCCAdugAwIBAgIJAJ+LafmOp1a0MA0GCSqGSIb3DQEBCwUAMCgxJjAkBgNV
3
- BAMMHWJlZHJvY2stdmMtdmVyaWZpZXIubG9jYWxob3N0MB4XDTIyMDIwMzA1MzU1
4
- NloXDTQ5MDYyMTA1MzU1NlowKDEmMCQGA1UEAwwdYmVkcm9jay12Yy12ZXJpZmll
5
- ci5sb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5egV0
6
- Yz8iZziLp5HNSiIfMISiDd/wqArJKJjr9aY96Sa9cVLSBt+4xJrAxKpCVlgAl/6Z
7
- NnVrftZ+SwqBvQ9I2WlodQhu4Gs1ImrSj44P+SooyGO6IT1mhZMt++0oUj/ZjdaI
8
- oFaNjzKoD1N0RLdI5l6lSSbO/E86sXMX9tHGrjSElMO0EF5dXPLMLrRFjRQ4md81
9
- 9aKpH8ObyCI02wRK8j2LI8Cfqka0kxdxQSLQ4z5yDsb3ajd5avJzgCEprOOvwy36
10
- dvtuT11XpstS0Sqgwk1BRhYvYn99H4euSwx9BpoA6GiVM2OaI4SctpvfGxbnhh0Z
11
- 5SU+JaxJxPAnQe9JAgMBAAGjIDAeMBwGA1UdEQQVMBOCEWJlZHJvY2subG9jYWxo
12
- b3N0MA0GCSqGSIb3DQEBCwUAA4IBAQANK3NiEcnhY+bRZymEAJKzy6Ar1vxAsko2
13
- qOtP4/gB9bqBhQLoWRGL66rJ+l2ixNEuK9ammOx6LgRtvDgF/kXovcJyJJtf3FrE
14
- afr9BpWmyIhRW1zGBK/kTz8lB0kHYbE650cAzCK4+pcIxXl3v5HWvAoxUCraVZzB
15
- aggd9ATR0wgGP4dDhUWMDEW9T2GbFSilIW6k7WUpadBUtQb6NzaF3DSUw3jl4LXN
16
- FL/PIWj81f6Uskt0qhDTzVRrn+LgrJklhazvuWpasItEM0WeJRKGp7GcoylASrYx
17
- SwxnpYemqVJ2dTwwkDQfFg/aSyYNwNohywUngRJdDdQOLQQbfrxm
18
- -----END CERTIFICATE-----