From d3c2062bffe01c1534124537e0b13122c2a93adf Mon Sep 17 00:00:00 2001 From: PatStLouis Date: Sun, 17 Nov 2024 17:58:31 +0000 Subject: [PATCH 01/12] Add an algorithm test file and helper functions for ecdsa-jcs-2019 Signed-off-by: PatStLouis --- tests/90-algorithms-jcs.js | 194 +++++++++++++++++++++++++++++++++++++ tests/helpers.js | 1 + 2 files changed, 195 insertions(+) create mode 100644 tests/90-algorithms-jcs.js diff --git a/tests/90-algorithms-jcs.js b/tests/90-algorithms-jcs.js new file mode 100644 index 00000000..ae279fe4 --- /dev/null +++ b/tests/90-algorithms-jcs.js @@ -0,0 +1,194 @@ +/*! + * Copyright 2024 Digital Bazaar, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +import { + config, + createInitialVc, + createValidCredential, + getProofs, + isValidDatetime, + isValidUtf8, + setupReportableTestSuite, + setupRow +} from '../helpers.js'; +import chai from 'chai'; +import {endpoints} from 'vc-test-suite-implementations'; + +const should = chai.should(); + +const cryptosuite = 'ecdsa-jcs-2019'; +const {tags} = config.suites[ + cryptosuite +]; +const {match: issuers} = endpoints.filterByTag({ + tags: [...tags], + property: 'issuers' +}); + +describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { + setupReportableTestSuite(this); + this.implemented = [...issuers.keys()]; + let validCredential; + before(async function() { + validCredential = await createValidCredential(); + }); + for(const [columnId, {endpoints}] of issuers) { + describe(columnId, function() { + const [issuer] = endpoints; + let issuedVc; + let proofs; + let jcs2019Proofs = []; + before(async function() { + issuedVc = await createInitialVc({issuer, vc: validCredential}); + proofs = getProofs(issuedVc); + if(proofs?.length) { + jcs2019Proofs = proofs.filter( + proof => proof?.cryptosuite === cryptosuite); + } + }); + beforeEach(setupRow); + const assertBefore = () => { + should.exist(issuedVc, 'Expected issuer to have issued a ' + + 'credential.'); + should.exist(proofs, 'Expected credential to have a proof.'); + jcs2019Proofs.length.should.be.gte(1, 'Expected at least one ' + + 'ecdsa-jcs-2019 cryptosuite.'); + }; + it('The proof options MUST contain a type identifier for the ' + + 'cryptographic suite (type) and MAY contain a cryptosuite ' + + 'identifier (cryptosuite).', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019'; + assertBefore(); + for(const proof of jcs2019Proofs) { + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + } + }); + it('The transformation options MUST contain a type identifier ' + + 'for the cryptographic suite (type) and a cryptosuite identifier ' + + '(cryptosuite).', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; + assertBefore(); + for(const proof of jcs2019Proofs) { + should.exist(proof.type, 'Expected a type identifier on ' + + 'the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + } + }); + it('Whenever this algorithm encodes strings, ' + + 'it MUST use UTF-8 encoding.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; + assertBefore(); + for(const proof of jcs2019Proofs) { + should.exist(proof?.proofValue, + 'Expected proofValue to exist.'); + isValidUtf8(proof.proofValue).should.equal( + true, + 'Expected proofValue value to be a valid UTF-8 encoded string.' + ); + } + }); + it('If options.type is not set to the string DataIntegrityProof or ' + + 'options.cryptosuite is not set to the string ecdsa-jcs-2019, ' + + 'an error MUST be raised and SHOULD convey an error type ' + + 'of PROOF_TRANSFORMATION_ERROR.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; + assertBefore(); + for(const proof of jcs2019Proofs) { + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + proof.type.should.equal('DataIntegrityProof', + 'Expected DataIntegrityProof type.'); + proof.cryptosuite.should.equal('ecdsa-jcs-2019', + 'Expected ecdsa-jcs-2019 cryptosuite.'); + } + }); + }); + } +}); + +describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { + setupReportableTestSuite(this); + this.implemented = [...issuers.keys()]; + let validCredential; + before(async function() { + validCredential = await createValidCredential(); + }); + for(const [columnId, {endpoints}] of issuers) { + describe(columnId, function() { + const [issuer] = endpoints; + let issuedVc; + let proofs; + let jcs2019Proofs = []; + before(async function() { + issuedVc = await createInitialVc({issuer, vc: validCredential}); + proofs = getProofs(issuedVc); + if(proofs?.length) { + jcs2019Proofs = proofs.filter( + proof => proof?.cryptosuite === cryptosuite); + } + }); + beforeEach(setupRow); + const assertBefore = () => { + should.exist(issuedVc, 'Expected issuer to have issued a ' + + 'credential.'); + should.exist(proofs, 'Expected credential to have a proof.'); + jcs2019Proofs.length.should.be.gte(1, 'Expected at least one ' + + 'ecdsa-jcs-2019 cryptosuite.'); + }; + it('The proof options MUST contain a type identifier for the ' + + 'cryptographic suite (type) and MUST contain a cryptosuite ' + + 'identifier (cryptosuite).', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; + assertBefore(); + for(const proof of jcs2019Proofs) { + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + } + }); + it('If proofConfig.type is not set to DataIntegrityProof ' + + 'and/or proofConfig.cryptosuite is not set to ecdsa-jcs-2019, ' + + 'an error MUST be raised and SHOULD convey an error type ' + + 'of PROOF_GENERATION_ERROR.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; + assertBefore(); + for(const proof of jcs2019Proofs) { + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + proof.type.should.equal('DataIntegrityProof', + 'Expected DataIntegrityProof type.'); + proof.cryptosuite.should.equal('ecdsa-jcs-2019', + 'Expected ecdsa-jcs-2019 cryptosuite.'); + } + }); + it('If proofConfig.created is set and if the value is not a ' + + 'valid [XMLSCHEMA11-2] datetime, an error MUST be raised and ' + + 'SHOULD convey an error type of PROOF_GENERATION_ERROR.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; + for(const proof of jcs2019Proofs) { + if(proof?.created) { + isValidDatetime(proof.created).should.equal( + true, + 'Expected created value to be a valid datetime string.' + ); + } + } + }); + }); + } +}); diff --git a/tests/helpers.js b/tests/helpers.js index 3d1f9fcf..cb3bb490 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -6,6 +6,7 @@ import * as bs58 from 'base58-universal'; import * as bs64 from 'base64url-universal'; import {createRequire} from 'node:module'; import {isUtf8} from 'node:buffer'; +import {isUtf8} from 'node:buffer'; import {klona} from 'klona'; import {readFileSync} from 'fs'; import {v4 as uuidv4} from 'uuid'; From c6be6617dd3b96de36d6f70863117c0658a91a9c Mon Sep 17 00:00:00 2001 From: PatStLouis Date: Sun, 17 Nov 2024 18:16:50 +0000 Subject: [PATCH 02/12] add proof serialization section Signed-off-by: PatStLouis --- tests/90-algorithms-jcs.js | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/90-algorithms-jcs.js b/tests/90-algorithms-jcs.js index ae279fe4..f5640da8 100644 --- a/tests/90-algorithms-jcs.js +++ b/tests/90-algorithms-jcs.js @@ -192,3 +192,48 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { }); } }); + +describe('ecdsa-jcs-2019 - Algorithms - Proof Serialization', function() { + setupReportableTestSuite(this); + this.implemented = [...issuers.keys()]; + let validCredential; + before(async function() { + validCredential = await createValidCredential(); + }); + for(const [columnId, {endpoints}] of issuers) { + describe(columnId, function() { + const [issuer] = endpoints; + let issuedVc; + let proofs; + let jcs2019Proofs = []; + before(async function() { + issuedVc = await createInitialVc({issuer, vc: validCredential}); + proofs = getProofs(issuedVc); + if(proofs?.length) { + jcs2019Proofs = proofs.filter( + proof => proof?.cryptosuite === cryptosuite); + } + }); + beforeEach(setupRow); + const assertBefore = () => { + should.exist(issuedVc, 'Expected issuer to have issued a ' + + 'credential.'); + should.exist(proofs, 'Expected credential to have a proof.'); + jcs2019Proofs.length.should.be.gte(1, 'Expected at least one ' + + 'ecdsa-jcs-2019 cryptosuite.'); + }; + it('The proof options MUST contain a type identifier for the ' + + 'cryptographic suite (type) and MAY contain a cryptosuite identifier ' + + '(cryptosuite).', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019'; + assertBefore(); + for(const proof of jcs2019Proofs) { + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + } + }); + }); + } +}); + From bc09fb11604de002fe71038856b7cf9c10e8ffce Mon Sep 17 00:00:00 2001 From: PatStLouis Date: Tue, 19 Nov 2024 02:17:03 +0000 Subject: [PATCH 03/12] add missing helper functions Signed-off-by: PatStLouis --- tests/90-algorithms-jcs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/90-algorithms-jcs.js b/tests/90-algorithms-jcs.js index f5640da8..21e8b4c1 100644 --- a/tests/90-algorithms-jcs.js +++ b/tests/90-algorithms-jcs.js @@ -11,7 +11,7 @@ import { isValidUtf8, setupReportableTestSuite, setupRow -} from '../helpers.js'; +} from './helpers.js'; import chai from 'chai'; import {endpoints} from 'vc-test-suite-implementations'; From 4a72c6e9f830d680ad2cadea3f319d1b3ce47caa Mon Sep 17 00:00:00 2001 From: PatStLouis Date: Tue, 19 Nov 2024 06:46:23 +0000 Subject: [PATCH 04/12] add create tests Signed-off-by: PatStLouis --- tests/90-algorithms-jcs.js | 111 +++++++++++++++++++++---------------- tests/helpers.js | 12 ++++ 2 files changed, 76 insertions(+), 47 deletions(-) diff --git a/tests/90-algorithms-jcs.js b/tests/90-algorithms-jcs.js index 21e8b4c1..2541a7b0 100644 --- a/tests/90-algorithms-jcs.js +++ b/tests/90-algorithms-jcs.js @@ -3,6 +3,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ import { + assertIssuedVc, config, createInitialVc, createValidCredential, @@ -26,6 +27,42 @@ const {match: issuers} = endpoints.filterByTag({ property: 'issuers' }); +describe('ecdsa-jcs-2019 - Algorithms - Create Proof', function() { + setupReportableTestSuite(this); + this.implemented = [...issuers.keys()]; + let validCredential; + before(async function() { + validCredential = await createValidCredential(); + }); + for(const [columnId, {endpoints}] of issuers) { + describe(columnId, function() { + const [issuer] = endpoints; + let issuedVc; + let proofs; + let filteredProofs = []; + before(async function() { + issuedVc = await createInitialVc({issuer, vc: validCredential}); + proofs = getProofs(issuedVc); + if(proofs?.length) { + filteredProofs = proofs.filter( + proof => proof?.cryptosuite === cryptosuite); + } + }); + beforeEach(setupRow); + it('If unsecuredDocument.@context is present, ' + + 'set proof.@context to unsecuredDocument.@context.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#create-proof-ecdsa-jcs-2019'; + assertIssuedVc(issuedVc, proofs, filteredProofs); + for(const proof of filteredProofs) { + proof.should.have('@context', + 'Expected proof to have context.'); + } + }); + }); + } +}); + describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { setupReportableTestSuite(this); this.implemented = [...issuers.keys()]; @@ -38,30 +75,23 @@ describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { const [issuer] = endpoints; let issuedVc; let proofs; - let jcs2019Proofs = []; + let filteredProofs = []; before(async function() { issuedVc = await createInitialVc({issuer, vc: validCredential}); proofs = getProofs(issuedVc); if(proofs?.length) { - jcs2019Proofs = proofs.filter( + filteredProofs = proofs.filter( proof => proof?.cryptosuite === cryptosuite); } }); beforeEach(setupRow); - const assertBefore = () => { - should.exist(issuedVc, 'Expected issuer to have issued a ' + - 'credential.'); - should.exist(proofs, 'Expected credential to have a proof.'); - jcs2019Proofs.length.should.be.gte(1, 'Expected at least one ' + - 'ecdsa-jcs-2019 cryptosuite.'); - }; it('The proof options MUST contain a type identifier for the ' + - 'cryptographic suite (type) and MAY contain a cryptosuite ' + - 'identifier (cryptosuite).', + 'cryptographic suite (type) and MAY contain a cryptosuite ' + + 'identifier (cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019'; - assertBefore(); - for(const proof of jcs2019Proofs) { + assertIssuedVc(issuedVc, proofs, filteredProofs); + for(const proof of filteredProofs) { should.exist(proof.type, 'Expected a type identifier on the proof.'); } @@ -71,8 +101,8 @@ describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; - assertBefore(); - for(const proof of jcs2019Proofs) { + assertIssuedVc(issuedVc, proofs, filteredProofs); + for(const proof of filteredProofs) { should.exist(proof.type, 'Expected a type identifier on ' + 'the proof.'); should.exist(proof.cryptosuite, @@ -83,8 +113,8 @@ describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { 'it MUST use UTF-8 encoding.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; - assertBefore(); - for(const proof of jcs2019Proofs) { + assertIssuedVc(issuedVc, proofs, filteredProofs); + for(const proof of filteredProofs) { should.exist(proof?.proofValue, 'Expected proofValue to exist.'); isValidUtf8(proof.proofValue).should.equal( @@ -94,13 +124,13 @@ describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { } }); it('If options.type is not set to the string DataIntegrityProof or ' + - 'options.cryptosuite is not set to the string ecdsa-jcs-2019, ' + - 'an error MUST be raised and SHOULD convey an error type ' + - 'of PROOF_TRANSFORMATION_ERROR.', + 'options.cryptosuite is not set to the string ecdsa-jcs-2019, ' + + 'an error MUST be raised and SHOULD convey an error type ' + + 'of PROOF_TRANSFORMATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; - assertBefore(); - for(const proof of jcs2019Proofs) { + assertIssuedVc(issuedVc, proofs, filteredProofs); + for(const proof of filteredProofs) { should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -127,30 +157,23 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { const [issuer] = endpoints; let issuedVc; let proofs; - let jcs2019Proofs = []; + let filteredProofs = []; before(async function() { issuedVc = await createInitialVc({issuer, vc: validCredential}); proofs = getProofs(issuedVc); if(proofs?.length) { - jcs2019Proofs = proofs.filter( + filteredProofs = proofs.filter( proof => proof?.cryptosuite === cryptosuite); } }); beforeEach(setupRow); - const assertBefore = () => { - should.exist(issuedVc, 'Expected issuer to have issued a ' + - 'credential.'); - should.exist(proofs, 'Expected credential to have a proof.'); - jcs2019Proofs.length.should.be.gte(1, 'Expected at least one ' + - 'ecdsa-jcs-2019 cryptosuite.'); - }; it('The proof options MUST contain a type identifier for the ' + 'cryptographic suite (type) and MUST contain a cryptosuite ' + 'identifier (cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; - assertBefore(); - for(const proof of jcs2019Proofs) { + assertIssuedVc(issuedVc, proofs, filteredProofs); + for(const proof of filteredProofs) { should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -163,8 +186,8 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { 'of PROOF_GENERATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; - assertBefore(); - for(const proof of jcs2019Proofs) { + assertIssuedVc(issuedVc, proofs, filteredProofs); + for(const proof of filteredProofs) { should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -180,7 +203,8 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { 'SHOULD convey an error type of PROOF_GENERATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; - for(const proof of jcs2019Proofs) { + assertIssuedVc(issuedVc, proofs, filteredProofs); + for(const proof of filteredProofs) { if(proof?.created) { isValidDatetime(proof.created).should.equal( true, @@ -205,30 +229,23 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Serialization', function() { const [issuer] = endpoints; let issuedVc; let proofs; - let jcs2019Proofs = []; + let filteredProofs = []; before(async function() { issuedVc = await createInitialVc({issuer, vc: validCredential}); proofs = getProofs(issuedVc); if(proofs?.length) { - jcs2019Proofs = proofs.filter( + filteredProofs = proofs.filter( proof => proof?.cryptosuite === cryptosuite); } }); beforeEach(setupRow); - const assertBefore = () => { - should.exist(issuedVc, 'Expected issuer to have issued a ' + - 'credential.'); - should.exist(proofs, 'Expected credential to have a proof.'); - jcs2019Proofs.length.should.be.gte(1, 'Expected at least one ' + - 'ecdsa-jcs-2019 cryptosuite.'); - }; it('The proof options MUST contain a type identifier for the ' + 'cryptographic suite (type) and MAY contain a cryptosuite identifier ' + '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019'; - assertBefore(); - for(const proof of jcs2019Proofs) { + assertIssuedVc(issuedVc, proofs, filteredProofs); + for(const proof of filteredProofs) { should.exist(proof.type, 'Expected a type identifier on the proof.'); } diff --git a/tests/helpers.js b/tests/helpers.js index cb3bb490..da77789d 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -4,6 +4,7 @@ */ import * as bs58 from 'base58-universal'; import * as bs64 from 'base64url-universal'; +import chai from 'chai'; import {createRequire} from 'node:module'; import {isUtf8} from 'node:buffer'; import {isUtf8} from 'node:buffer'; @@ -11,6 +12,8 @@ import {klona} from 'klona'; import {readFileSync} from 'fs'; import {v4 as uuidv4} from 'uuid'; +const should = chai.should(); + export const require = createRequire(import.meta.url); // takes a multibase string starting with z lops the z off @@ -283,3 +286,12 @@ export function setupRow() { rowId: this.currentTest.title }; } + +export function assertIssuedVc(issuedVc, proofs, filteredProofs) { + should.exist(issuedVc, + 'Expected issuer to have issued a credential.'); + should.exist(proofs, + 'Expected credential to have a proof.'); + filteredProofs.length.should.be.gte(1, + 'Expected at least one filtered cryptosuite proof.'); +} From a1e8a1ce30c334c10f7d7817c327c0344074fe5c Mon Sep 17 00:00:00 2001 From: PatStLouis Date: Tue, 19 Nov 2024 19:07:34 +0000 Subject: [PATCH 05/12] add create proof algorithm Signed-off-by: PatStLouis --- package.json | 3 + tests/30-rdfc-interop.js | 4 +- tests/40-sd-create.js | 4 +- tests/60-sd-interop.js | 4 +- tests/90-algorithms-jcs.js | 265 ++++++++----------------------------- tests/assertions.js | 88 ++++++++++++ tests/helpers.js | 13 +- 7 files changed, 160 insertions(+), 221 deletions(-) diff --git a/package.json b/package.json index 7799a75f..6e2c0913 100644 --- a/package.json +++ b/package.json @@ -55,9 +55,12 @@ "base58-universal": "^2.0.0", "base64url-universal": "^2.0.0", "chai": "^4.3.7", + "chai-string": "^1.5.0", "data-integrity-test-suite-assertion": "github:w3c-ccg/data-integrity-test-suite-assertion", "jsonld-document-loader": "^2.0.0", + "json-canon": "^1.0.1", "klona": "^2.0.6", + "multibase": "^4.0.6", "mocha": "^10.2.0", "uuid": "^9.0.0", "varint": "^6.0.0", diff --git a/tests/30-rdfc-interop.js b/tests/30-rdfc-interop.js index cbe6a6be..4561ec99 100644 --- a/tests/30-rdfc-interop.js +++ b/tests/30-rdfc-interop.js @@ -3,9 +3,9 @@ * SPDX-License-Identifier: BSD-3-Clause */ import chai from 'chai'; -import {createInitialVc} from './helpers.js'; import {endpoints} from 'vc-test-suite-implementations'; import {getSuiteConfig} from './test-config.js'; +import {secureCredential} from './helpers.js'; import {verificationSuccess} from './assertions.js'; const { @@ -81,7 +81,7 @@ const { } let issuedVc; before(async function() { - issuedVc = await createInitialVc({ + issuedVc = await secureCredential({ issuer: issuerEndpoint, vc: credentials.interop[vcVersion].document, vcVersion diff --git a/tests/40-sd-create.js b/tests/40-sd-create.js index 23181536..b20fe775 100644 --- a/tests/40-sd-create.js +++ b/tests/40-sd-create.js @@ -4,7 +4,7 @@ */ import * as ecdsaSd2023Cryptosuite from '@digitalbazaar/ecdsa-sd-2023-cryptosuite'; -import {createInitialVc, endpointCheck} from './helpers.js'; +import {endpointCheck, secureCredential} from './helpers.js'; import { shouldBeBs58, shouldBeBs64UrlNoPad, @@ -51,7 +51,7 @@ describe('ecdsa-sd-2023 (create)', function() { let proofs; const verificationMethodDocuments = []; before(async function() { - issuedVc = await createInitialVc({ + issuedVc = await secureCredential({ issuer, vc: credentials.create[vcVersion].document, mandatoryPointers: diff --git a/tests/60-sd-interop.js b/tests/60-sd-interop.js index 2e738910..9618076d 100644 --- a/tests/60-sd-interop.js +++ b/tests/60-sd-interop.js @@ -2,7 +2,7 @@ * Copyright 2023 Digital Bazaar, Inc. * SPDX-License-Identifier: BSD-3-Clause */ -import {createDisclosedVc, createInitialVc} from './helpers.js'; +import {createDisclosedVc, secureCredential} from './helpers.js'; import chai from 'chai'; import {endpoints} from 'vc-test-suite-implementations'; import {getSuiteConfig} from './test-config.js'; @@ -83,7 +83,7 @@ const { } let disclosedCredential; before(async function() { - const issuedVc = await createInitialVc({ + const issuedVc = await secureCredential({ issuer: issuerEndpoint, vc: credentials.interop[vcVersion].document, mandatoryPointers: credentials.interop[vcVersion].mandatoryPointers, diff --git a/tests/90-algorithms-jcs.js b/tests/90-algorithms-jcs.js index 2541a7b0..bcbe4d46 100644 --- a/tests/90-algorithms-jcs.js +++ b/tests/90-algorithms-jcs.js @@ -3,254 +3,101 @@ * SPDX-License-Identifier: BSD-3-Clause */ import { - assertIssuedVc, - config, - createInitialVc, - createValidCredential, + assertDataIntegrityProof, + assertSecuredCredential +} from './assertions.js'; +import { + baseCredential, getProofs, - isValidDatetime, - isValidUtf8, + secureCredential, setupReportableTestSuite, setupRow } from './helpers.js'; +import canonicalize from 'json-canon'; import chai from 'chai'; import {endpoints} from 'vc-test-suite-implementations'; +import {expect} from 'chai'; const should = chai.should(); -const cryptosuite = 'ecdsa-jcs-2019'; -const {tags} = config.suites[ - cryptosuite +const cryptosuites = [ + 'ecdsa-jcs-2019', ]; + const {match: issuers} = endpoints.filterByTag({ - tags: [...tags], + tags: cryptosuites, property: 'issuers' }); -describe('ecdsa-jcs-2019 - Algorithms - Create Proof', function() { - setupReportableTestSuite(this); - this.implemented = [...issuers.keys()]; - let validCredential; - before(async function() { - validCredential = await createValidCredential(); - }); - for(const [columnId, {endpoints}] of issuers) { - describe(columnId, function() { - const [issuer] = endpoints; - let issuedVc; - let proofs; - let filteredProofs = []; - before(async function() { - issuedVc = await createInitialVc({issuer, vc: validCredential}); - proofs = getProofs(issuedVc); - if(proofs?.length) { - filteredProofs = proofs.filter( - proof => proof?.cryptosuite === cryptosuite); - } - }); - beforeEach(setupRow); - it('If unsecuredDocument.@context is present, ' + - 'set proof.@context to unsecuredDocument.@context.', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#create-proof-ecdsa-jcs-2019'; - assertIssuedVc(issuedVc, proofs, filteredProofs); - for(const proof of filteredProofs) { - proof.should.have('@context', - 'Expected proof to have context.'); - } - }); - }); - } -}); - -describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { - setupReportableTestSuite(this); - this.implemented = [...issuers.keys()]; - let validCredential; - before(async function() { - validCredential = await createValidCredential(); - }); - for(const [columnId, {endpoints}] of issuers) { - describe(columnId, function() { - const [issuer] = endpoints; - let issuedVc; - let proofs; - let filteredProofs = []; - before(async function() { - issuedVc = await createInitialVc({issuer, vc: validCredential}); - proofs = getProofs(issuedVc); - if(proofs?.length) { - filteredProofs = proofs.filter( - proof => proof?.cryptosuite === cryptosuite); - } - }); - beforeEach(setupRow); - it('The proof options MUST contain a type identifier for the ' + - 'cryptographic suite (type) and MAY contain a cryptosuite ' + - 'identifier (cryptosuite).', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019'; - assertIssuedVc(issuedVc, proofs, filteredProofs); - for(const proof of filteredProofs) { - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - } - }); - it('The transformation options MUST contain a type identifier ' + - 'for the cryptographic suite (type) and a cryptosuite identifier ' + - '(cryptosuite).', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; - assertIssuedVc(issuedVc, proofs, filteredProofs); - for(const proof of filteredProofs) { - should.exist(proof.type, 'Expected a type identifier on ' + - 'the proof.'); - should.exist(proof.cryptosuite, - 'Expected a cryptosuite identifier on the proof.'); - } - }); - it('Whenever this algorithm encodes strings, ' + - 'it MUST use UTF-8 encoding.', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; - assertIssuedVc(issuedVc, proofs, filteredProofs); - for(const proof of filteredProofs) { - should.exist(proof?.proofValue, - 'Expected proofValue to exist.'); - isValidUtf8(proof.proofValue).should.equal( - true, - 'Expected proofValue value to be a valid UTF-8 encoded string.' - ); - } - }); - it('If options.type is not set to the string DataIntegrityProof or ' + - 'options.cryptosuite is not set to the string ecdsa-jcs-2019, ' + - 'an error MUST be raised and SHOULD convey an error type ' + - 'of PROOF_TRANSFORMATION_ERROR.', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; - assertIssuedVc(issuedVc, proofs, filteredProofs); - for(const proof of filteredProofs) { - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - should.exist(proof.cryptosuite, - 'Expected a cryptosuite identifier on the proof.'); - proof.type.should.equal('DataIntegrityProof', - 'Expected DataIntegrityProof type.'); - proof.cryptosuite.should.equal('ecdsa-jcs-2019', - 'Expected ecdsa-jcs-2019 cryptosuite.'); - } - }); - }); - } +const {match: verifiers} = endpoints.filterByTag({ + tags: cryptosuites, + property: 'verifiers' }); -describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { +describe('Create Proof (ecdsa-jcs-2019)', function() { setupReportableTestSuite(this); this.implemented = [...issuers.keys()]; - let validCredential; - before(async function() { - validCredential = await createValidCredential(); - }); for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; - let issuedVc; - let proofs; - let filteredProofs = []; + let securedCredential; + let proof; before(async function() { - issuedVc = await createInitialVc({issuer, vc: validCredential}); - proofs = getProofs(issuedVc); - if(proofs?.length) { - filteredProofs = proofs.filter( - proof => proof?.cryptosuite === cryptosuite); - } + securedCredential = await secureCredential( + {issuer, vc: baseCredential()}); + proof = getProofs(securedCredential)[0]; }); beforeEach(setupRow); - it('The proof options MUST contain a type identifier for the ' + - 'cryptographic suite (type) and MUST contain a cryptosuite ' + - 'identifier (cryptosuite).', + it('The following algorithm specifies how to create a ' + + 'data integrity proof given an unsecured data document. ' + + 'Required inputs are an unsecured data document ' + + '(map unsecuredDocument), and a set of proof options ' + + '(map options). A data integrity proof (map), or an error, ' + + 'is produced as output.', async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; - assertIssuedVc(issuedVc, proofs, filteredProofs); - for(const proof of filteredProofs) { - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - should.exist(proof.cryptosuite, - 'Expected a cryptosuite identifier on the proof.'); - } + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#create-proof-ecdsa-jcs-2019'; + assertSecuredCredential(securedCredential); + assertDataIntegrityProof(proof, 'ecdsa-jcs-2019'); }); - it('If proofConfig.type is not set to DataIntegrityProof ' + - 'and/or proofConfig.cryptosuite is not set to ecdsa-jcs-2019, ' + - 'an error MUST be raised and SHOULD convey an error type ' + - 'of PROOF_GENERATION_ERROR.', + it('If unsecuredDocument.@context is present, ' + + 'set proof.@context to unsecuredDocument.@context.', async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; - assertIssuedVc(issuedVc, proofs, filteredProofs); - for(const proof of filteredProofs) { - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - should.exist(proof.cryptosuite, - 'Expected a cryptosuite identifier on the proof.'); - proof.type.should.equal('DataIntegrityProof', - 'Expected DataIntegrityProof type.'); - proof.cryptosuite.should.equal('ecdsa-jcs-2019', - 'Expected ecdsa-jcs-2019 cryptosuite.'); - } + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#create-proof-ecdsa-jcs-2019'; + should.exist(proof['@context'], + 'Expected proof to have context.'); + canonicalize(proof['@context']).should.equal( + canonicalize(securedCredential['@context']), + 'Expected proof context to match document context.' + ); }); - it('If proofConfig.created is set and if the value is not a ' + - 'valid [XMLSCHEMA11-2] datetime, an error MUST be raised and ' + - 'SHOULD convey an error type of PROOF_GENERATION_ERROR.', + it('Let proof.proofValue be a base58-btc-encoded ' + + 'Multibase value of the proofBytes.', async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; - assertIssuedVc(issuedVc, proofs, filteredProofs); - for(const proof of filteredProofs) { - if(proof?.created) { - isValidDatetime(proof.created).should.equal( - true, - 'Expected created value to be a valid datetime string.' - ); - } - } + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#create-proof-ecdsa-jcs-2019'; + should.exist(proof.proofValue, + 'Expected proof to have proofValue.'); + expect(proof.proofValue.startsWith('z')).to.be.true; }); }); } }); -describe('ecdsa-jcs-2019 - Algorithms - Proof Serialization', function() { +describe('Algorithms - Verify Proof (ecdsa-jcs-2019)', function() { setupReportableTestSuite(this); - this.implemented = [...issuers.keys()]; - let validCredential; - before(async function() { - validCredential = await createValidCredential(); - }); - for(const [columnId, {endpoints}] of issuers) { + for(const [columnId, {endpoints}] of verifiers) { describe(columnId, function() { - const [issuer] = endpoints; - let issuedVc; - let proofs; - let filteredProofs = []; + const [issuer] = issuers.get(columnId).endpoints; + const [verifier] = endpoints; + let securedCredential; before(async function() { - issuedVc = await createInitialVc({issuer, vc: validCredential}); - proofs = getProofs(issuedVc); - if(proofs?.length) { - filteredProofs = proofs.filter( - proof => proof?.cryptosuite === cryptosuite); - } + securedCredential = await secureCredential( + {issuer, vc: baseCredential()}); }); beforeEach(setupRow); - it('The proof options MUST contain a type identifier for the ' + - 'cryptographic suite (type) and MAY contain a cryptosuite identifier ' + - '(cryptosuite).', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019'; - assertIssuedVc(issuedVc, proofs, filteredProofs); - for(const proof of filteredProofs) { - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - } - }); + it('', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#verify-proof-ecdsa-rdfc-2019'; + }); }); } }); - diff --git a/tests/assertions.js b/tests/assertions.js index 5072e82f..3d3d70e1 100644 --- a/tests/assertions.js +++ b/tests/assertions.js @@ -5,6 +5,9 @@ import { getBs58Bytes, getBs64UrlBytes, + getProofs, + isValidDatetime, + isValidUtf8, multibaseMultikeyHeaderP256, multibaseMultikeyHeaderP384, } from './helpers.js'; @@ -182,3 +185,88 @@ export function itRejectsInvalidCryptosuite(expectedValidSuites, { await verificationFail({credential, verifier: endpoint}); }); } + +export function assertSecuredCredential(securedCredential) { + should.exist(securedCredential, + 'Expected issuer to have issued a credential.'); + const proofs = getProofs(securedCredential); + should.exist(proofs, + 'Expected credential to have a proof.'); + proofs.length.should.equal(1, + 'Expected credential to have a single proof.'); +} + +export function assertDataIntegrityProof(proof, cryptosuite) { + if(proof?.id) { + } + should.exist(proof.type, + 'Expected a type on the proof.'); + proof.type.should.equal('DataIntegrityProof', + 'Expected DataIntegrityProof type.'); + isValidUtf8(proof.type).should.equal( + true, + 'Expected type value to be a valid UTF-8 encoded string.' + ); + should.exist(proof.proofPurpose, + 'Expected a proofPurpose on the proof.'); + isValidUtf8(proof.proofPurpose).should.equal( + true, + 'Expected proofPurpose value to be a valid UTF-8 encoded string.' + ); + if(proof?.verificationMethod) { + isValidUtf8(proof.verificationMethod).should.equal( + true, + 'Expected verificationMethod value to be a valid UTF-8 encoded string.' + ); + } + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + proof.cryptosuite.should.equal(cryptosuite, + `Expected {cryptosuite} cryptosuite.`); + isValidUtf8(proof.cryptosuite).should.equal( + true, + 'Expected cryptosuite value to be a valid UTF-8 encoded string.' + ); + if(proof?.created) { + isValidDatetime(proof.created).should.equal( + true, + 'Expected created value to be a valid datetime string.' + ); + isValidUtf8(proof.created).should.equal( + true, + 'Expected created value to be a valid UTF-8 encoded string.' + ); + } + if(proof?.expires) { + isValidDatetime(proof.expires).should.equal( + true, + 'Expected created value to be a valid datetime string.' + ); + isValidUtf8(proof.expires).should.equal( + true, + 'Expected expires value to be a valid UTF-8 encoded string.' + ); + } + if(proof?.domain) { + isValidUtf8(proof.domain).should.equal( + true, + 'Expected domain value to be a valid UTF-8 encoded string.' + ); + } + if(proof?.challenge) { + isValidUtf8(proof.challenge).should.equal( + true, + 'Expected challenge value to be a valid UTF-8 encoded string.' + ); + } + should.exist(proof.proofValue, + 'Expected proof to have proofValue.'); + isValidUtf8(proof.proofValue).should.equal( + true, + 'Expected proofValue value to be a valid UTF-8 encoded string.' + ); + if(proof?.previousProof) { + } + if(proof?.nonce) { + } +} diff --git a/tests/helpers.js b/tests/helpers.js index da77789d..5a6f69ad 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -43,7 +43,7 @@ export const ISOTimeStamp = ({date = new Date()} = {}) => { export const config = JSON.parse(readFileSync('./config/runner.json')); -export const createInitialVc = async ({ +export const secureCredential = async ({ issuer, vc, mandatoryPointers, @@ -251,7 +251,7 @@ export function getProofs(issuedVc) { return proofs; } -export function createValidCredential(version = 2) { +export function baseCredential(version = 2) { let credential = { type: ['VerifiableCredential'], id: `urn:uuid:${uuidv4()}`, @@ -287,11 +287,12 @@ export function setupRow() { }; } -export function assertIssuedVc(issuedVc, proofs, filteredProofs) { - should.exist(issuedVc, +export function assertSecuredCredential(securedCredential) { + should.exist(securedCredential, 'Expected issuer to have issued a credential.'); + const proofs = getProofs(securedCredential); should.exist(proofs, 'Expected credential to have a proof.'); - filteredProofs.length.should.be.gte(1, - 'Expected at least one filtered cryptosuite proof.'); + proofs.length.should.equal(1, + 'Expected credential to have a single proof.'); } From f952c000d6ef82965b963aaf711defec37109ecf Mon Sep 17 00:00:00 2001 From: PatStLouis Date: Wed, 20 Nov 2024 04:20:23 +0000 Subject: [PATCH 06/12] add db vectors and improve code handling Signed-off-by: PatStLouis --- tests/90-algorithms-jcs.js | 169 ++++++++++++++++++++++++++++++++++--- tests/assertions.js | 9 ++ tests/helpers.js | 20 ++++- tests/vectors.js | 73 ++++++++++++++++ 4 files changed, 260 insertions(+), 11 deletions(-) create mode 100644 tests/vectors.js diff --git a/tests/90-algorithms-jcs.js b/tests/90-algorithms-jcs.js index bcbe4d46..62337e34 100644 --- a/tests/90-algorithms-jcs.js +++ b/tests/90-algorithms-jcs.js @@ -3,18 +3,23 @@ * SPDX-License-Identifier: BSD-3-Clause */ import { + assertAllUtf8, assertDataIntegrityProof, assertSecuredCredential } from './assertions.js'; import { - baseCredential, + generateCredential, getProofs, + isValidDatetime, secureCredential, setupReportableTestSuite, - setupRow + setupRow, + verifyFail, + verifySuccess } from './helpers.js'; import canonicalize from 'json-canon'; import chai from 'chai'; +import {ecdsaJcsVectors} from './vectors.js'; import {endpoints} from 'vc-test-suite-implementations'; import {expect} from 'chai'; @@ -34,7 +39,7 @@ const {match: verifiers} = endpoints.filterByTag({ property: 'verifiers' }); -describe('Create Proof (ecdsa-jcs-2019)', function() { +describe('Algorithms - Create Proof (ecdsa-jcs-2019)', function() { setupReportableTestSuite(this); this.implemented = [...issuers.keys()]; for(const [columnId, {endpoints}] of issuers) { @@ -44,7 +49,7 @@ describe('Create Proof (ecdsa-jcs-2019)', function() { let proof; before(async function() { securedCredential = await secureCredential( - {issuer, vc: baseCredential()}); + {issuer, vc: generateCredential()}); proof = getProofs(securedCredential)[0]; }); beforeEach(setupRow); @@ -86,18 +91,162 @@ describe('Algorithms - Verify Proof (ecdsa-jcs-2019)', function() { setupReportableTestSuite(this); for(const [columnId, {endpoints}] of verifiers) { describe(columnId, function() { - const [issuer] = issuers.get(columnId).endpoints; const [verifier] = endpoints; + beforeEach(setupRow); + it('The following algorithm specifies how to verify a ' + + 'data integrity proof given an secured data document. ' + + 'Required inputs are an secured data document (map securedDocument). ' + + 'This algorithm returns a verification result.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#verify-proof-ecdsa-rdfc-2019'; + for(const curve of verifier.settings.supportedEcdsaKeyTypes) { + const testVector = structuredClone(ecdsaJcsVectors[curve]); + await verifySuccess(verifier, testVector); + + // Slice the proof + testVector.proof.proofValue = + testVector.proof.proofValue.slice(0, -1); + await verifyFail(verifier, testVector); + } + }); + }); + } +}); + +describe('Algorithms - Transformation', function() { + setupReportableTestSuite(this); + this.implemented = [...issuers.keys()]; + for(const [columnId, {endpoints}] of issuers) { + describe(columnId, function() { + const [issuer] = endpoints; let securedCredential; + let proof; before(async function() { securedCredential = await secureCredential( - {issuer, vc: baseCredential()}); + {issuer, vc: generateCredential()}); + proof = getProofs(securedCredential)[0]; }); beforeEach(setupRow); - it('', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#verify-proof-ecdsa-rdfc-2019'; - }); + it('The proof options MUST contain a type identifier for the ' + + 'cryptographic suite (type) and MAY contain a cryptosuite ' + + 'identifier (cryptosuite).', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019'; + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + }); + it('The transformation options MUST contain a type identifier ' + + 'for the cryptographic suite (type) and a cryptosuite identifier ' + + '(cryptosuite).', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; + should.exist(proof.type, 'Expected a type identifier on ' + + 'the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + }); + it('Whenever this algorithm encodes strings, ' + + 'it MUST use UTF-8 encoding.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; + assertAllUtf8(proof); + }); + it('If options.type is not set to the string DataIntegrityProof or ' + + 'options.cryptosuite is not set to the string ecdsa-jcs-2019, ' + + 'an error MUST be raised and SHOULD convey an error type ' + + 'of PROOF_TRANSFORMATION_ERROR.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + proof.type.should.equal('DataIntegrityProof', + 'Expected DataIntegrityProof type.'); + proof.cryptosuite.should.equal('ecdsa-jcs-2019', + 'Expected ecdsa-jcs-2019 cryptosuite.'); + }); + }); + } +}); + +describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { + setupReportableTestSuite(this); + this.implemented = [...issuers.keys()]; + for(const [columnId, {endpoints}] of issuers) { + describe(columnId, function() { + const [issuer] = endpoints; + let securedCredential; + let proof; + before(async function() { + securedCredential = await secureCredential( + {issuer, vc: generateCredential()}); + proof = getProofs(securedCredential)[0]; + }); + beforeEach(setupRow); + it('The proof options MUST contain a type identifier for the ' + + 'cryptographic suite (type) and MUST contain a cryptosuite ' + + 'identifier (cryptosuite).', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + }); + it('If proofConfig.type is not set to DataIntegrityProof ' + + 'and/or proofConfig.cryptosuite is not set to ecdsa-jcs-2019, ' + + 'an error MUST be raised and SHOULD convey an error type ' + + 'of PROOF_GENERATION_ERROR.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + proof.type.should.equal('DataIntegrityProof', + 'Expected DataIntegrityProof type.'); + proof.cryptosuite.should.equal('ecdsa-jcs-2019', + 'Expected ecdsa-jcs-2019 cryptosuite.'); + }); + it('If proofConfig.created is set and if the value is not a ' + + 'valid [XMLSCHEMA11-2] datetime, an error MUST be raised and ' + + 'SHOULD convey an error type of PROOF_GENERATION_ERROR.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; + if(proof?.created) { + isValidDatetime(proof.created).should.equal( + true, + 'Expected created value to be a valid datetime string.' + ); + } + }); + }); + } +}); + +describe('ecdsa-jcs-2019 - Algorithms - Proof Serialization', function() { + setupReportableTestSuite(this); + this.implemented = [...issuers.keys()]; + for(const [columnId, {endpoints}] of issuers) { + describe(columnId, function() { + const [issuer] = endpoints; + let securedCredential; + let proof; + before(async function() { + securedCredential = await secureCredential( + {issuer, vc: generateCredential()}); + proof = getProofs(securedCredential)[0]; + }); + beforeEach(setupRow); + it('The proof options MUST contain a type identifier for the ' + + 'cryptographic suite (type) and MAY contain a cryptosuite identifier ' + + '(cryptosuite).', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019'; + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + }); }); } }); diff --git a/tests/assertions.js b/tests/assertions.js index 3d3d70e1..0c4ff092 100644 --- a/tests/assertions.js +++ b/tests/assertions.js @@ -196,6 +196,15 @@ export function assertSecuredCredential(securedCredential) { 'Expected credential to have a single proof.'); } +export function assertAllUtf8(proof) { + for(const [key, value] of Object.entries(proof)) { + isValidUtf8(value).should.equal( + true, + `Expected ${key} value to be a valid UTF-8 encoded string.` + ); + } +} + export function assertDataIntegrityProof(proof, cryptosuite) { if(proof?.id) { } diff --git a/tests/helpers.js b/tests/helpers.js index 5a6f69ad..ffd301d0 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -251,7 +251,7 @@ export function getProofs(issuedVc) { return proofs; } -export function baseCredential(version = 2) { +export function generateCredential(version = 2) { let credential = { type: ['VerifiableCredential'], id: `urn:uuid:${uuidv4()}`, @@ -273,6 +273,7 @@ export function baseCredential(version = 2) { 'https://www.w3.org/ns/credentials/v2' ] }, credential); + credential.credentialSubject.name = 'Alice'; } else { return null; } @@ -296,3 +297,20 @@ export function assertSecuredCredential(securedCredential) { proofs.length.should.equal(1, 'Expected credential to have a single proof.'); } + +export async function verifySuccess(verifier, securedCredential) { + const body = { + verifiableCredential: securedCredential + }; + const response = await verifier.post({json: body}); + should.exist(response.result, 'Expected a result from verifier.'); +} + +export async function verifyFail(verifier, securedCredential) { + const body = { + verifiableCredential: securedCredential + }; + const response = await verifier.post({json: body}); + should.exist(response.error, 'Expected an error from verifier.'); +} + diff --git a/tests/vectors.js b/tests/vectors.js new file mode 100644 index 00000000..3f05f26e --- /dev/null +++ b/tests/vectors.js @@ -0,0 +1,73 @@ +/*! + * Copyright (c) 2024 Digital Bazaar, Inc. All rights reserved. + */ +/* Note: This file contains data generated from the vc-di-ecdsa specification +test vectors. */ + +/* eslint-disable max-len */ +/* eslint-disable quote-props */ +/* eslint-disable quotes */ +export const ecdsaJcsVectors = { + 'P-256': { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://www.w3.org/ns/credentials/examples/v2" + ], + "id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33", + "type": [ + "VerifiableCredential", + "AlumniCredential" + ], + "name": "Alumni Credential", + "description": "A minimum viable example of an Alumni Credential.", + "issuer": "https://vc.example/issuers/5678", + "validFrom": "2023-01-01T00:00:00Z", + "credentialSubject": { + "id": "did:example:abcdefgh", + "alumniOf": "The School of Examples" + }, + "proof": { + "type": "DataIntegrityProof", + "created": "2023-02-24T23:36:38Z", + "verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP", + "cryptosuite": "ecdsa-jcs-2019", + "proofPurpose": "assertionMethod", + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://www.w3.org/ns/credentials/examples/v2" + ], + "proofValue": "z48fSpWLud2PXMmBjRnacU3oE4WMHX4J1hx7qjc2K31x1aoVfLPCcpEincvjUg8ptbDnrYgcytmSj51Uj2Ap3a7WB" + } + }, + 'P-384': { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://www.w3.org/ns/credentials/examples/v2" + ], + "id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33", + "type": [ + "VerifiableCredential", + "AlumniCredential" + ], + "name": "Alumni Credential", + "description": "A minimum viable example of an Alumni Credential.", + "issuer": "https://vc.example/issuers/5678", + "validFrom": "2023-01-01T00:00:00Z", + "credentialSubject": { + "id": "did:example:abcdefgh", + "alumniOf": "The School of Examples" + }, + "proof": { + "type": "DataIntegrityProof", + "created": "2023-02-24T23:36:38Z", + "verificationMethod": "did:key:z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ#z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ", + "cryptosuite": "ecdsa-jcs-2019", + "proofPurpose": "assertionMethod", + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://www.w3.org/ns/credentials/examples/v2" + ], + "proofValue": "zasuhHXVzmepTMgSuyWvCCY3gYbLpANXDYWSuemx7WjopwRr6DDN532dKSMoxqNeQm7BWZxqyurFLSPBDmzaHe57k7JgGRaNtJhjfYjgww19nPWdP7dYqqf1X1LvNEcZJP75" + } + } +}; From 6bce372d300a276376bcdda7b399a19394f182a8 Mon Sep 17 00:00:00 2001 From: PatStLouis Date: Wed, 20 Nov 2024 05:13:49 +0000 Subject: [PATCH 07/12] Add comments to the code Signed-off-by: PatStLouis --- tests/90-algorithms-jcs.js | 48 +++++++++++++++++++++----------------- tests/helpers.js | 2 +- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/tests/90-algorithms-jcs.js b/tests/90-algorithms-jcs.js index 62337e34..ed594cf0 100644 --- a/tests/90-algorithms-jcs.js +++ b/tests/90-algorithms-jcs.js @@ -14,7 +14,7 @@ import { secureCredential, setupReportableTestSuite, setupRow, - verifyFail, + verifyError, verifySuccess } from './helpers.js'; import canonicalize from 'json-canon'; @@ -53,21 +53,20 @@ describe('Algorithms - Create Proof (ecdsa-jcs-2019)', function() { proof = getProofs(securedCredential)[0]; }); beforeEach(setupRow); - it('The following algorithm specifies how to create a ' + - 'data integrity proof given an unsecured data document. ' + - 'Required inputs are an unsecured data document ' + - '(map unsecuredDocument), and a set of proof options ' + - '(map options). A data integrity proof (map), or an error, ' + - 'is produced as output.', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#create-proof-ecdsa-jcs-2019'; - assertSecuredCredential(securedCredential); - assertDataIntegrityProof(proof, 'ecdsa-jcs-2019'); - }); + it('A data integrity proof (map), or an error, is produced as output.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#create-proof-ecdsa-jcs-2019'; + assertSecuredCredential(securedCredential); + assertDataIntegrityProof(proof, 'ecdsa-jcs-2019'); + // Since we are not sending proof options, we only do a positive test + }); it('If unsecuredDocument.@context is present, ' + 'set proof.@context to unsecuredDocument.@context.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#create-proof-ecdsa-jcs-2019'; + // NOTE, for backwards compatibility reason, this step is not mandatory + // This feature is designed to be used with proof sets/chains, + // when adding new context in subsequent proofs should.exist(proof['@context'], 'Expected proof to have context.'); canonicalize(proof['@context']).should.equal( @@ -79,6 +78,8 @@ describe('Algorithms - Create Proof (ecdsa-jcs-2019)', function() { 'Multibase value of the proofBytes.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#create-proof-ecdsa-jcs-2019'; + // Shallow multibase test + // TODO try decoding should.exist(proof.proofValue, 'Expected proof to have proofValue.'); expect(proof.proofValue.startsWith('z')).to.be.true; @@ -100,13 +101,16 @@ describe('Algorithms - Verify Proof (ecdsa-jcs-2019)', function() { async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#verify-proof-ecdsa-rdfc-2019'; for(const curve of verifier.settings.supportedEcdsaKeyTypes) { + // Send a valid VC and an invalid VC to the verifier + // Check for success/error on response const testVector = structuredClone(ecdsaJcsVectors[curve]); await verifySuccess(verifier, testVector); // Slice the proof testVector.proof.proofValue = testVector.proof.proofValue.slice(0, -1); - await verifyFail(verifier, testVector); + await verifyError(verifier, testVector); + // TODO, create a verifyProblemDetails function } }); }); @@ -136,12 +140,12 @@ describe('Algorithms - Transformation', function() { 'Expected a type identifier on the proof.'); }); it('The transformation options MUST contain a type identifier ' + - 'for the cryptographic suite (type) and a cryptosuite identifier ' + - '(cryptosuite).', + 'for the cryptographic suite (type) and a cryptosuite identifier ' + + '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; - should.exist(proof.type, 'Expected a type identifier on ' + - 'the proof.'); + should.exist(proof.type, + 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, 'Expected a cryptosuite identifier on the proof.'); }); @@ -195,9 +199,9 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { 'Expected a cryptosuite identifier on the proof.'); }); it('If proofConfig.type is not set to DataIntegrityProof ' + - 'and/or proofConfig.cryptosuite is not set to ecdsa-jcs-2019, ' + - 'an error MUST be raised and SHOULD convey an error type ' + - 'of PROOF_GENERATION_ERROR.', + 'and/or proofConfig.cryptosuite is not set to ecdsa-jcs-2019, ' + + 'an error MUST be raised and SHOULD convey an error type ' + + 'of PROOF_GENERATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; should.exist(proof.type, @@ -210,8 +214,8 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { 'Expected ecdsa-jcs-2019 cryptosuite.'); }); it('If proofConfig.created is set and if the value is not a ' + - 'valid [XMLSCHEMA11-2] datetime, an error MUST be raised and ' + - 'SHOULD convey an error type of PROOF_GENERATION_ERROR.', + 'valid [XMLSCHEMA11-2] datetime, an error MUST be raised and ' + + 'SHOULD convey an error type of PROOF_GENERATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; if(proof?.created) { diff --git a/tests/helpers.js b/tests/helpers.js index ffd301d0..bdb5db99 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -306,7 +306,7 @@ export async function verifySuccess(verifier, securedCredential) { should.exist(response.result, 'Expected a result from verifier.'); } -export async function verifyFail(verifier, securedCredential) { +export async function verifyError(verifier, securedCredential) { const body = { verifiableCredential: securedCredential }; From 1db0e436deae5d2ce62bcc342e5689cd1dbe5a74 Mon Sep 17 00:00:00 2001 From: PatStLouis Date: Wed, 20 Nov 2024 05:35:13 +0000 Subject: [PATCH 08/12] improve proof handling when asserting a secured credential Signed-off-by: PatStLouis --- tests/90-algorithms-jcs.js | 28 +++++--- tests/90-algorithms-rdfc.js | 134 +++++++++++++++++++++++------------- tests/helpers.js | 13 ++-- 3 files changed, 115 insertions(+), 60 deletions(-) diff --git a/tests/90-algorithms-jcs.js b/tests/90-algorithms-jcs.js index ed594cf0..f3cd5574 100644 --- a/tests/90-algorithms-jcs.js +++ b/tests/90-algorithms-jcs.js @@ -11,6 +11,7 @@ import { generateCredential, getProofs, isValidDatetime, + proofExists, secureCredential, setupReportableTestSuite, setupRow, @@ -46,17 +47,18 @@ describe('Algorithms - Create Proof (ecdsa-jcs-2019)', function() { describe(columnId, function() { const [issuer] = endpoints; let securedCredential; - let proof; + let proofs; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); - proof = getProofs(securedCredential)[0]; + proofs = getProofs(securedCredential); }); beforeEach(setupRow); it('A data integrity proof (map), or an error, is produced as output.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#create-proof-ecdsa-jcs-2019'; assertSecuredCredential(securedCredential); + const proof = proofExists(proofs); assertDataIntegrityProof(proof, 'ecdsa-jcs-2019'); // Since we are not sending proof options, we only do a positive test }); @@ -67,6 +69,7 @@ describe('Algorithms - Create Proof (ecdsa-jcs-2019)', function() { // NOTE, for backwards compatibility reason, this step is not mandatory // This feature is designed to be used with proof sets/chains, // when adding new context in subsequent proofs + const proof = proofExists(proofs); should.exist(proof['@context'], 'Expected proof to have context.'); canonicalize(proof['@context']).should.equal( @@ -80,6 +83,7 @@ describe('Algorithms - Create Proof (ecdsa-jcs-2019)', function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#create-proof-ecdsa-jcs-2019'; // Shallow multibase test // TODO try decoding + const proof = proofExists(proofs); should.exist(proof.proofValue, 'Expected proof to have proofValue.'); expect(proof.proofValue.startsWith('z')).to.be.true; @@ -124,11 +128,11 @@ describe('Algorithms - Transformation', function() { describe(columnId, function() { const [issuer] = endpoints; let securedCredential; - let proof; + let proofs; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); - proof = getProofs(securedCredential)[0]; + proofs = getProofs(securedCredential); }); beforeEach(setupRow); it('The proof options MUST contain a type identifier for the ' + @@ -136,6 +140,7 @@ describe('Algorithms - Transformation', function() { 'identifier (cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019'; + const proof = proofExists(proofs); should.exist(proof.type, 'Expected a type identifier on the proof.'); }); @@ -144,6 +149,7 @@ describe('Algorithms - Transformation', function() { '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; + const proof = proofExists(proofs); should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -153,6 +159,7 @@ describe('Algorithms - Transformation', function() { 'it MUST use UTF-8 encoding.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; + const proof = proofExists(proofs); assertAllUtf8(proof); }); it('If options.type is not set to the string DataIntegrityProof or ' + @@ -161,6 +168,7 @@ describe('Algorithms - Transformation', function() { 'of PROOF_TRANSFORMATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; + const proof = proofExists(proofs); should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -181,11 +189,11 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { describe(columnId, function() { const [issuer] = endpoints; let securedCredential; - let proof; + let proofs; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); - proof = getProofs(securedCredential)[0]; + proofs = getProofs(securedCredential); }); beforeEach(setupRow); it('The proof options MUST contain a type identifier for the ' + @@ -193,6 +201,7 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { 'identifier (cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; + const proof = proofExists(proofs); should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -204,6 +213,7 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { 'of PROOF_GENERATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; + const proof = proofExists(proofs); should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -218,6 +228,7 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { 'SHOULD convey an error type of PROOF_GENERATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; + const proof = proofExists(proofs); if(proof?.created) { isValidDatetime(proof.created).should.equal( true, @@ -236,11 +247,11 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Serialization', function() { describe(columnId, function() { const [issuer] = endpoints; let securedCredential; - let proof; + let proofs; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); - proof = getProofs(securedCredential)[0]; + proofs = getProofs(securedCredential); }); beforeEach(setupRow); it('The proof options MUST contain a type identifier for the ' + @@ -248,6 +259,7 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Serialization', function() { '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019'; + const proof = proofExists(proofs); should.exist(proof.type, 'Expected a type identifier on the proof.'); }); diff --git a/tests/90-algorithms-rdfc.js b/tests/90-algorithms-rdfc.js index cab9baf2..a1cdce00 100644 --- a/tests/90-algorithms-rdfc.js +++ b/tests/90-algorithms-rdfc.js @@ -8,7 +8,8 @@ import { createValidCredential, getProofs, isValidDatetime, - isValidUtf8, + proofExists, + secureCredential, setupReportableTestSuite, setupRow } from './helpers.js'; @@ -36,16 +37,12 @@ describe('ecdsa-rdfc-2019 - Algorithms - Transformation', function() { for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; - let issuedVc; + let securedCredential; let proofs; - let rdfc2019Proofs = []; before(async function() { - issuedVc = await createInitialVc({issuer, vc: validCredential}); - proofs = getProofs(issuedVc); - if(proofs?.length) { - rdfc2019Proofs = proofs.filter( - proof => proof?.cryptosuite === cryptosuite); - } + securedCredential = await secureCredential( + {issuer, vc: generateCredential()}); + proofs = getProofs(securedCredential); }); beforeEach(setupRow); const assertBefore = () => { @@ -60,27 +57,18 @@ describe('ecdsa-rdfc-2019 - Algorithms - Transformation', function() { '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; - assertBefore(); - for(const proof of rdfc2019Proofs) { - should.exist(proof.type, 'Expected a type identifier on ' + - 'the proof.'); - should.exist(proof.cryptosuite, - 'Expected a cryptosuite identifier on the proof.'); - } + const proof = proofExists(proofs); + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); }); it('Whenever this algorithm encodes strings, ' + 'it MUST use UTF-8 encoding.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; - assertBefore(); - for(const proof of rdfc2019Proofs) { - should.exist(proof?.proofValue, - 'Expected proofValue to exist.'); - isValidUtf8(proof.proofValue).should.equal( - true, - 'Expected proofValue value to be a valid UTF-8 encoded string.' - ); - } + const proof = proofExists(proofs); + assertAllUtf8(proof); }); it('If options.type is not set to the string DataIntegrityProof or ' + 'options.cryptosuite is not set to the string ecdsa-rdfc-2019, ' + @@ -88,16 +76,72 @@ describe('ecdsa-rdfc-2019 - Algorithms - Transformation', function() { 'of PROOF_TRANSFORMATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; - assertBefore(); - for(const proof of rdfc2019Proofs) { - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - should.exist(proof.cryptosuite, - 'Expected a cryptosuite identifier on the proof.'); - proof.type.should.equal('DataIntegrityProof', - 'Expected DataIntegrityProof type.'); - proof.cryptosuite.should.equal('ecdsa-rdfc-2019', - 'Expected ecdsa-rdfc-2019 cryptosuite.'); + const proof = proofExists(proofs); + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + proof.type.should.equal('DataIntegrityProof', + 'Expected DataIntegrityProof type.'); + proof.cryptosuite.should.equal('ecdsa-rdfc-2019', + 'Expected ecdsa-rdfc-2019 cryptosuite.'); + }); + }); + } +}); + +describe('Algorithms - Proof Configuration (ecdsa-rdfc-2019)', function() { + setupReportableTestSuite(this); + this.implemented = [...issuers.keys()]; + for(const [columnId, {endpoints}] of issuers) { + describe(columnId, function() { + const [issuer] = endpoints; + let securedCredential; + let proofs; + before(async function() { + securedCredential = await secureCredential( + {issuer, vc: generateCredential()}); + proofs = getProofs(securedCredential); + }); + beforeEach(setupRow); + it('The proof options MUST contain a type identifier for the ' + + 'cryptographic suite (type) and MUST contain a cryptosuite ' + + 'identifier (cryptosuite).', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; + const proof = proofExists(proofs); + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + }); + it('If proofConfig.type is not set to DataIntegrityProof ' + + 'and/or proofConfig.cryptosuite is not set to ecdsa-rdfc-2019, ' + + 'an error MUST be raised and SHOULD convey an error type ' + + 'of PROOF_GENERATION_ERROR.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; + const proof = proofExists(proofs); + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + proof.type.should.equal('DataIntegrityProof', + 'Expected DataIntegrityProof type.'); + proof.cryptosuite.should.equal('ecdsa-rdfc-2019', + 'Expected ecdsa-rdfc-2019 cryptosuite.'); + }); + it('If proofConfig.created is set and if the value is not a ' + + 'valid [XMLSCHEMA11-2] datetime, an error MUST be raised and ' + + 'SHOULD convey an error type of PROOF_GENERATION_ERROR.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; + const proof = proofExists(proofs); + if(proof?.created) { + isValidDatetime(proof.created).should.equal( + true, + 'Expected created value to be a valid datetime string.' + ); } }); }); @@ -114,16 +158,12 @@ describe('ecdsa-rdfc-2019 - Algorithms - Proof Configuration', function() { for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; - let issuedVc; + let securedCredential; let proofs; - let rdfc2019Proofs = []; before(async function() { - issuedVc = await createInitialVc({issuer, vc: validCredential}); - proofs = getProofs(issuedVc); - if(proofs?.length) { - rdfc2019Proofs = proofs.filter( - proof => proof?.cryptosuite === cryptosuite); - } + securedCredential = await secureCredential( + {issuer, vc: generateCredential()}); + proofs = getProofs(securedCredential); }); beforeEach(setupRow); const assertBefore = () => { @@ -216,11 +256,9 @@ describe('ecdsa-rdfc-2019 - Algorithms - Proof Serialization', function() { '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-rdfc-2019'; - assertBefore(); - for(const proof of rdfc2019Proofs) { - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - } + const proof = proofExists(proofs); + should.exist(proof.type, + 'Expected a type identifier on the proof.'); }); }); } diff --git a/tests/helpers.js b/tests/helpers.js index bdb5db99..2199100c 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -288,14 +288,19 @@ export function setupRow() { }; } +export function proofExists(proofs) { + should.exist(proofs, + 'Expected credential to have a proof.'); + proofs.length.should.be.gte(1, + 'Expected credential to have at least one proof.'); + return proofs[0]; +} + export function assertSecuredCredential(securedCredential) { should.exist(securedCredential, 'Expected issuer to have issued a credential.'); const proofs = getProofs(securedCredential); - should.exist(proofs, - 'Expected credential to have a proof.'); - proofs.length.should.equal(1, - 'Expected credential to have a single proof.'); + proofExists(proofs); } export async function verifySuccess(verifier, securedCredential) { From 7bb2c588c580f6af6edfcdcaf83eac1cd541c726 Mon Sep 17 00:00:00 2001 From: PatStLouis Date: Wed, 20 Nov 2024 05:39:58 +0000 Subject: [PATCH 09/12] improve proof selection when asserting issued credentials Signed-off-by: PatStLouis --- tests/90-algorithms-jcs.js | 52 ++++-------- tests/90-algorithms-rdfc.js | 152 ++++++------------------------------ tests/helpers.js | 14 +--- 3 files changed, 43 insertions(+), 175 deletions(-) diff --git a/tests/90-algorithms-jcs.js b/tests/90-algorithms-jcs.js index f3cd5574..4ac18127 100644 --- a/tests/90-algorithms-jcs.js +++ b/tests/90-algorithms-jcs.js @@ -4,12 +4,10 @@ */ import { assertAllUtf8, - assertDataIntegrityProof, - assertSecuredCredential + assertDataIntegrityProof } from './assertions.js'; import { generateCredential, - getProofs, isValidDatetime, proofExists, secureCredential, @@ -47,18 +45,15 @@ describe('Algorithms - Create Proof (ecdsa-jcs-2019)', function() { describe(columnId, function() { const [issuer] = endpoints; let securedCredential; - let proofs; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); - proofs = getProofs(securedCredential); }); beforeEach(setupRow); it('A data integrity proof (map), or an error, is produced as output.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#create-proof-ecdsa-jcs-2019'; - assertSecuredCredential(securedCredential); - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); assertDataIntegrityProof(proof, 'ecdsa-jcs-2019'); // Since we are not sending proof options, we only do a positive test }); @@ -69,7 +64,7 @@ describe('Algorithms - Create Proof (ecdsa-jcs-2019)', function() { // NOTE, for backwards compatibility reason, this step is not mandatory // This feature is designed to be used with proof sets/chains, // when adding new context in subsequent proofs - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); should.exist(proof['@context'], 'Expected proof to have context.'); canonicalize(proof['@context']).should.equal( @@ -83,7 +78,7 @@ describe('Algorithms - Create Proof (ecdsa-jcs-2019)', function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#create-proof-ecdsa-jcs-2019'; // Shallow multibase test // TODO try decoding - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); should.exist(proof.proofValue, 'Expected proof to have proofValue.'); expect(proof.proofValue.startsWith('z')).to.be.true; @@ -121,35 +116,24 @@ describe('Algorithms - Verify Proof (ecdsa-jcs-2019)', function() { } }); -describe('Algorithms - Transformation', function() { +describe('Algorithms - Transformation (ecdsa-jcs-2019)', function() { setupReportableTestSuite(this); this.implemented = [...issuers.keys()]; for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; let securedCredential; - let proofs; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); - proofs = getProofs(securedCredential); }); beforeEach(setupRow); - it('The proof options MUST contain a type identifier for the ' + - 'cryptographic suite (type) and MAY contain a cryptosuite ' + - 'identifier (cryptosuite).', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019'; - const proof = proofExists(proofs); - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - }); it('The transformation options MUST contain a type identifier ' + 'for the cryptographic suite (type) and a cryptosuite identifier ' + '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -159,7 +143,7 @@ describe('Algorithms - Transformation', function() { 'it MUST use UTF-8 encoding.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); assertAllUtf8(proof); }); it('If options.type is not set to the string DataIntegrityProof or ' + @@ -168,7 +152,7 @@ describe('Algorithms - Transformation', function() { 'of PROOF_TRANSFORMATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -182,26 +166,24 @@ describe('Algorithms - Transformation', function() { } }); -describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { +describe('Algorithms - Proof Configuration (ecdsa-jcs-2019)', function() { setupReportableTestSuite(this); this.implemented = [...issuers.keys()]; for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; let securedCredential; - let proofs; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); - proofs = getProofs(securedCredential); }); beforeEach(setupRow); it('The proof options MUST contain a type identifier for the ' + - 'cryptographic suite (type) and MUST contain a cryptosuite ' + - 'identifier (cryptosuite).', + 'cryptographic suite (type) and MUST contain a cryptosuite ' + + 'identifier (cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -213,7 +195,7 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { 'of PROOF_GENERATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -228,7 +210,7 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { 'SHOULD convey an error type of PROOF_GENERATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); if(proof?.created) { isValidDatetime(proof.created).should.equal( true, @@ -240,18 +222,16 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { } }); -describe('ecdsa-jcs-2019 - Algorithms - Proof Serialization', function() { +describe('Algorithms - Proof Serialization (ecdsa-jcs-2019)', function() { setupReportableTestSuite(this); this.implemented = [...issuers.keys()]; for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; let securedCredential; - let proofs; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); - proofs = getProofs(securedCredential); }); beforeEach(setupRow); it('The proof options MUST contain a type identifier for the ' + @@ -259,7 +239,7 @@ describe('ecdsa-jcs-2019 - Algorithms - Proof Serialization', function() { '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); should.exist(proof.type, 'Expected a type identifier on the proof.'); }); diff --git a/tests/90-algorithms-rdfc.js b/tests/90-algorithms-rdfc.js index a1cdce00..aea1789e 100644 --- a/tests/90-algorithms-rdfc.js +++ b/tests/90-algorithms-rdfc.js @@ -3,80 +3,67 @@ * SPDX-License-Identifier: BSD-3-Clause */ import { - config, - createInitialVc, - createValidCredential, - getProofs, + generateCredential, isValidDatetime, proofExists, secureCredential, setupReportableTestSuite, setupRow } from './helpers.js'; +import { + assertAllUtf8 +} from './assertions.js'; import chai from 'chai'; import {endpoints} from 'vc-test-suite-implementations'; const should = chai.should(); -const cryptosuite = 'ecdsa-rdfc-2019'; -const {tags} = config.suites[ - cryptosuite +const cryptosuites = [ + 'ecdsa-rdfc-2019', ]; + const {match: issuers} = endpoints.filterByTag({ - tags: [...tags], + tags: cryptosuites, property: 'issuers' }); -describe('ecdsa-rdfc-2019 - Algorithms - Transformation', function() { +describe('Algorithms - Transformation (ecdsa-rdfc-2019)', function() { setupReportableTestSuite(this); this.implemented = [...issuers.keys()]; - let validCredential; - before(async function() { - validCredential = await createValidCredential(); - }); for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; let securedCredential; - let proofs; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); - proofs = getProofs(securedCredential); }); beforeEach(setupRow); - const assertBefore = () => { - should.exist(issuedVc, 'Expected issuer to have issued a ' + - 'credential.'); - should.exist(proofs, 'Expected credential to have a proof.'); - rdfc2019Proofs.length.should.be.gte(1, 'Expected at least one ' + - 'ecdsa-rdfc-2019 cryptosuite.'); - }; it('The transformation options MUST contain a type identifier ' + - 'for the cryptographic suite (type) and a cryptosuite identifier ' + - '(cryptosuite).', + 'for the cryptographic suite (type) and a cryptosuite identifier ' + + '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, 'Expected a cryptosuite identifier on the proof.'); }); it('Whenever this algorithm encodes strings, ' + - 'it MUST use UTF-8 encoding.', + 'it MUST use UTF-8 encoding.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); assertAllUtf8(proof); }); it('If options.type is not set to the string DataIntegrityProof or ' + - 'options.cryptosuite is not set to the string ecdsa-rdfc-2019, ' + - 'an error MUST be raised and SHOULD convey an error type ' + - 'of PROOF_TRANSFORMATION_ERROR.', + 'options.cryptosuite is not set to the string ecdsa-rdfc-2019, ' + + 'an error MUST be raised and SHOULD convey an error type ' + + 'of PROOF_TRANSFORMATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -97,11 +84,9 @@ describe('Algorithms - Proof Configuration (ecdsa-rdfc-2019)', function() { describe(columnId, function() { const [issuer] = endpoints; let securedCredential; - let proofs; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); - proofs = getProofs(securedCredential); }); beforeEach(setupRow); it('The proof options MUST contain a type identifier for the ' + @@ -109,7 +94,7 @@ describe('Algorithms - Proof Configuration (ecdsa-rdfc-2019)', function() { 'identifier (cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -121,7 +106,7 @@ describe('Algorithms - Proof Configuration (ecdsa-rdfc-2019)', function() { 'of PROOF_GENERATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -136,7 +121,7 @@ describe('Algorithms - Proof Configuration (ecdsa-rdfc-2019)', function() { 'SHOULD convey an error type of PROOF_GENERATION_ERROR.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); if(proof?.created) { isValidDatetime(proof.created).should.equal( true, @@ -148,115 +133,24 @@ describe('Algorithms - Proof Configuration (ecdsa-rdfc-2019)', function() { } }); -describe('ecdsa-rdfc-2019 - Algorithms - Proof Configuration', function() { +describe('Algorithms - Proof Serialization (ecdsa-rdfc-2019)', function() { setupReportableTestSuite(this); this.implemented = [...issuers.keys()]; - let validCredential; - before(async function() { - validCredential = await createValidCredential(); - }); for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; let securedCredential; - let proofs; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); - proofs = getProofs(securedCredential); - }); - beforeEach(setupRow); - const assertBefore = () => { - should.exist(issuedVc, 'Expected issuer to have issued a ' + - 'credential.'); - should.exist(proofs, 'Expected credential to have a proof.'); - rdfc2019Proofs.length.should.be.gte(1, 'Expected at least one ' + - 'ecdsa-rdfc-2019 cryptosuite.'); - }; - it('The proof options MUST contain a type identifier for the ' + - 'cryptographic suite (type) and MUST contain a cryptosuite ' + - 'identifier (cryptosuite).', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; - assertBefore(); - for(const proof of rdfc2019Proofs) { - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - should.exist(proof.cryptosuite, - 'Expected a cryptosuite identifier on the proof.'); - } - }); - it('If proofConfig.type is not set to DataIntegrityProof ' + - 'and/or proofConfig.cryptosuite is not set to ecdsa-rdfc-2019, ' + - 'an error MUST be raised and SHOULD convey an error type ' + - 'of PROOF_GENERATION_ERROR.', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; - assertBefore(); - for(const proof of rdfc2019Proofs) { - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - should.exist(proof.cryptosuite, - 'Expected a cryptosuite identifier on the proof.'); - proof.type.should.equal('DataIntegrityProof', - 'Expected DataIntegrityProof type.'); - proof.cryptosuite.should.equal('ecdsa-rdfc-2019', - 'Expected ecdsa-rdfc-2019 cryptosuite.'); - } - }); - it('If proofConfig.created is set and if the value is not a ' + - 'valid [XMLSCHEMA11-2] datetime, an error MUST be raised and ' + - 'SHOULD convey an error type of PROOF_GENERATION_ERROR.', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; - for(const proof of rdfc2019Proofs) { - if(proof?.created) { - isValidDatetime(proof.created).should.equal( - true, - 'Expected created value to be a valid datetime string.' - ); - } - } - }); - }); - } -}); - -describe('ecdsa-rdfc-2019 - Algorithms - Proof Serialization', function() { - setupReportableTestSuite(this); - this.implemented = [...issuers.keys()]; - let validCredential; - before(async function() { - validCredential = await createValidCredential(); - }); - for(const [columnId, {endpoints}] of issuers) { - describe(columnId, function() { - const [issuer] = endpoints; - let issuedVc; - let proofs; - let rdfc2019Proofs = []; - before(async function() { - issuedVc = await createInitialVc({issuer, vc: validCredential}); - proofs = getProofs(issuedVc); - if(proofs?.length) { - rdfc2019Proofs = proofs.filter( - proof => proof?.cryptosuite === cryptosuite); - } }); beforeEach(setupRow); - const assertBefore = () => { - should.exist(issuedVc, 'Expected issuer to have issued a ' + - 'credential.'); - should.exist(proofs, 'Expected credential to have a proof.'); - rdfc2019Proofs.length.should.be.gte(1, 'Expected at least one ' + - 'ecdsa-rdfc-2019 cryptosuite.'); - }; it('The proof options MUST contain a type identifier for the ' + 'cryptographic suite (type) and MAY contain a cryptosuite identifier ' + '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-rdfc-2019'; - const proof = proofExists(proofs); + const proof = proofExists(securedCredential); should.exist(proof.type, 'Expected a type identifier on the proof.'); }); diff --git a/tests/helpers.js b/tests/helpers.js index 2199100c..4ee64466 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -7,7 +7,6 @@ import * as bs64 from 'base64url-universal'; import chai from 'chai'; import {createRequire} from 'node:module'; import {isUtf8} from 'node:buffer'; -import {isUtf8} from 'node:buffer'; import {klona} from 'klona'; import {readFileSync} from 'fs'; import {v4 as uuidv4} from 'uuid'; @@ -288,7 +287,10 @@ export function setupRow() { }; } -export function proofExists(proofs) { +export function proofExists(securedCredential) { + should.exist(securedCredential, + 'Expected issuer to have issued a credential.'); + const proofs = getProofs(securedCredential); should.exist(proofs, 'Expected credential to have a proof.'); proofs.length.should.be.gte(1, @@ -296,13 +298,6 @@ export function proofExists(proofs) { return proofs[0]; } -export function assertSecuredCredential(securedCredential) { - should.exist(securedCredential, - 'Expected issuer to have issued a credential.'); - const proofs = getProofs(securedCredential); - proofExists(proofs); -} - export async function verifySuccess(verifier, securedCredential) { const body = { verifiableCredential: securedCredential @@ -318,4 +313,3 @@ export async function verifyError(verifier, securedCredential) { const response = await verifier.post({json: body}); should.exist(response.error, 'Expected an error from verifier.'); } - From e5732ef2b42f4eb18a077027dbe74b7fc84dd562 Mon Sep 17 00:00:00 2001 From: PatStLouis Date: Tue, 19 Nov 2024 19:07:34 +0000 Subject: [PATCH 10/12] add create proof algorithm Signed-off-by: PatStLouis --- tests/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/helpers.js b/tests/helpers.js index 4ee64466..2fe728a8 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -42,7 +42,7 @@ export const ISOTimeStamp = ({date = new Date()} = {}) => { export const config = JSON.parse(readFileSync('./config/runner.json')); -export const secureCredential = async ({ +export const createInitialVc = async ({ issuer, vc, mandatoryPointers, From f2256c25ba0ac47aa82c2ff7eed5eeebab3a780c Mon Sep 17 00:00:00 2001 From: PatStLouis Date: Wed, 20 Nov 2024 05:35:13 +0000 Subject: [PATCH 11/12] improve proof handling when asserting a secured credential Signed-off-by: PatStLouis --- tests/90-algorithms-rdfc.js | 187 ++++++++++++++++++++++++++++++++++++ tests/helpers.js | 17 ++++ 2 files changed, 204 insertions(+) diff --git a/tests/90-algorithms-rdfc.js b/tests/90-algorithms-rdfc.js index aea1789e..a0d57bde 100644 --- a/tests/90-algorithms-rdfc.js +++ b/tests/90-algorithms-rdfc.js @@ -5,8 +5,17 @@ import { generateCredential, isValidDatetime, +<<<<<<< HEAD proofExists, secureCredential, +======= +<<<<<<< HEAD + isValidUtf8, +======= + proofExists, + secureCredential, +>>>>>>> 265e798 (improve proof handling when asserting a secured credential) +>>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) setupReportableTestSuite, setupRow } from './helpers.js'; @@ -33,10 +42,32 @@ describe('Algorithms - Transformation (ecdsa-rdfc-2019)', function() { for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; +<<<<<<< HEAD let securedCredential; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); +======= +<<<<<<< HEAD + let issuedVc; + let proofs; + let rdfc2019Proofs = []; + before(async function() { + issuedVc = await createInitialVc({issuer, vc: validCredential}); + proofs = getProofs(issuedVc); + if(proofs?.length) { + rdfc2019Proofs = proofs.filter( + proof => proof?.cryptosuite === cryptosuite); + } +======= + let securedCredential; + let proofs; + before(async function() { + securedCredential = await secureCredential( + {issuer, vc: generateCredential()}); + proofs = getProofs(securedCredential); +>>>>>>> 265e798 (improve proof handling when asserting a secured credential) +>>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) }); beforeEach(setupRow); it('The transformation options MUST contain a type identifier ' + @@ -44,16 +75,34 @@ describe('Algorithms - Transformation (ecdsa-rdfc-2019)', function() { '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; +<<<<<<< HEAD const proof = proofExists(securedCredential); +======= +<<<<<<< HEAD + assertBefore(); + for(const proof of rdfc2019Proofs) { + should.exist(proof.type, 'Expected a type identifier on ' + + 'the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + } +======= + const proof = proofExists(proofs); +>>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, 'Expected a cryptosuite identifier on the proof.'); +<<<<<<< HEAD +======= +>>>>>>> 265e798 (improve proof handling when asserting a secured credential) +>>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) }); it('Whenever this algorithm encodes strings, ' + 'it MUST use UTF-8 encoding.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; +<<<<<<< HEAD const proof = proofExists(securedCredential); assertAllUtf8(proof); }); @@ -124,11 +173,113 @@ describe('Algorithms - Proof Configuration (ecdsa-rdfc-2019)', function() { const proof = proofExists(securedCredential); if(proof?.created) { isValidDatetime(proof.created).should.equal( +======= +<<<<<<< HEAD + assertBefore(); + for(const proof of rdfc2019Proofs) { + should.exist(proof?.proofValue, + 'Expected proofValue to exist.'); + isValidUtf8(proof.proofValue).should.equal( +>>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) + true, + 'Expected created value to be a valid datetime string.' + ); + } +======= + const proof = proofExists(proofs); + assertAllUtf8(proof); +>>>>>>> 265e798 (improve proof handling when asserting a secured credential) + }); +<<<<<<< HEAD +======= + it('If options.type is not set to the string DataIntegrityProof or ' + + 'options.cryptosuite is not set to the string ecdsa-rdfc-2019, ' + + 'an error MUST be raised and SHOULD convey an error type ' + + 'of PROOF_TRANSFORMATION_ERROR.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; +<<<<<<< HEAD + assertBefore(); + for(const proof of rdfc2019Proofs) { + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + proof.type.should.equal('DataIntegrityProof', + 'Expected DataIntegrityProof type.'); + proof.cryptosuite.should.equal('ecdsa-rdfc-2019', + 'Expected ecdsa-rdfc-2019 cryptosuite.'); +======= + const proof = proofExists(proofs); + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + proof.type.should.equal('DataIntegrityProof', + 'Expected DataIntegrityProof type.'); + proof.cryptosuite.should.equal('ecdsa-rdfc-2019', + 'Expected ecdsa-rdfc-2019 cryptosuite.'); + }); + }); + } +}); + +describe('Algorithms - Proof Configuration (ecdsa-rdfc-2019)', function() { + setupReportableTestSuite(this); + this.implemented = [...issuers.keys()]; + for(const [columnId, {endpoints}] of issuers) { + describe(columnId, function() { + const [issuer] = endpoints; + let securedCredential; + let proofs; + before(async function() { + securedCredential = await secureCredential( + {issuer, vc: generateCredential()}); + proofs = getProofs(securedCredential); + }); + beforeEach(setupRow); + it('The proof options MUST contain a type identifier for the ' + + 'cryptographic suite (type) and MUST contain a cryptosuite ' + + 'identifier (cryptosuite).', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; + const proof = proofExists(proofs); + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + }); + it('If proofConfig.type is not set to DataIntegrityProof ' + + 'and/or proofConfig.cryptosuite is not set to ecdsa-rdfc-2019, ' + + 'an error MUST be raised and SHOULD convey an error type ' + + 'of PROOF_GENERATION_ERROR.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; + const proof = proofExists(proofs); + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + should.exist(proof.cryptosuite, + 'Expected a cryptosuite identifier on the proof.'); + proof.type.should.equal('DataIntegrityProof', + 'Expected DataIntegrityProof type.'); + proof.cryptosuite.should.equal('ecdsa-rdfc-2019', + 'Expected ecdsa-rdfc-2019 cryptosuite.'); + }); + it('If proofConfig.created is set and if the value is not a ' + + 'valid [XMLSCHEMA11-2] datetime, an error MUST be raised and ' + + 'SHOULD convey an error type of PROOF_GENERATION_ERROR.', + async function() { + this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; + const proof = proofExists(proofs); + if(proof?.created) { + isValidDatetime(proof.created).should.equal( true, 'Expected created value to be a valid datetime string.' ); +>>>>>>> 265e798 (improve proof handling when asserting a secured credential) } }); +>>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) }); } }); @@ -139,10 +290,32 @@ describe('Algorithms - Proof Serialization (ecdsa-rdfc-2019)', function() { for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; +<<<<<<< HEAD + let securedCredential; + before(async function() { + securedCredential = await secureCredential( + {issuer, vc: generateCredential()}); +======= +<<<<<<< HEAD + let issuedVc; + let proofs; + let rdfc2019Proofs = []; + before(async function() { + issuedVc = await createInitialVc({issuer, vc: validCredential}); + proofs = getProofs(issuedVc); + if(proofs?.length) { + rdfc2019Proofs = proofs.filter( + proof => proof?.cryptosuite === cryptosuite); + } +======= let securedCredential; + let proofs; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); + proofs = getProofs(securedCredential); +>>>>>>> 265e798 (improve proof handling when asserting a secured credential) +>>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) }); beforeEach(setupRow); it('The proof options MUST contain a type identifier for the ' + @@ -150,9 +323,23 @@ describe('Algorithms - Proof Serialization (ecdsa-rdfc-2019)', function() { '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-rdfc-2019'; +<<<<<<< HEAD const proof = proofExists(securedCredential); should.exist(proof.type, 'Expected a type identifier on the proof.'); +======= +<<<<<<< HEAD + assertBefore(); + for(const proof of rdfc2019Proofs) { + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + } +======= + const proof = proofExists(proofs); + should.exist(proof.type, + 'Expected a type identifier on the proof.'); +>>>>>>> 265e798 (improve proof handling when asserting a secured credential) +>>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) }); }); } diff --git a/tests/helpers.js b/tests/helpers.js index 2fe728a8..c57dfaa2 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -287,10 +287,16 @@ export function setupRow() { }; } +<<<<<<< HEAD export function proofExists(securedCredential) { should.exist(securedCredential, 'Expected issuer to have issued a credential.'); const proofs = getProofs(securedCredential); +======= +<<<<<<< HEAD +======= +export function proofExists(proofs) { +>>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) should.exist(proofs, 'Expected credential to have a proof.'); proofs.length.should.be.gte(1, @@ -298,6 +304,17 @@ export function proofExists(securedCredential) { return proofs[0]; } +<<<<<<< HEAD +======= +export function assertSecuredCredential(securedCredential) { + should.exist(securedCredential, + 'Expected issuer to have issued a credential.'); + const proofs = getProofs(securedCredential); + proofExists(proofs); +} + +>>>>>>> 265e798 (improve proof handling when asserting a secured credential) +>>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) export async function verifySuccess(verifier, securedCredential) { const body = { verifiableCredential: securedCredential From 60ed0b668ad514a13565d391ff99f4ebff2ae9f0 Mon Sep 17 00:00:00 2001 From: PatStLouis Date: Wed, 20 Nov 2024 06:47:49 +0000 Subject: [PATCH 12/12] Rebase with main Signed-off-by: PatStLouis --- tests/90-algorithms-rdfc.js | 187 ------------------------------------ tests/helpers.js | 19 +--- 2 files changed, 1 insertion(+), 205 deletions(-) diff --git a/tests/90-algorithms-rdfc.js b/tests/90-algorithms-rdfc.js index a0d57bde..aea1789e 100644 --- a/tests/90-algorithms-rdfc.js +++ b/tests/90-algorithms-rdfc.js @@ -5,17 +5,8 @@ import { generateCredential, isValidDatetime, -<<<<<<< HEAD proofExists, secureCredential, -======= -<<<<<<< HEAD - isValidUtf8, -======= - proofExists, - secureCredential, ->>>>>>> 265e798 (improve proof handling when asserting a secured credential) ->>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) setupReportableTestSuite, setupRow } from './helpers.js'; @@ -42,32 +33,10 @@ describe('Algorithms - Transformation (ecdsa-rdfc-2019)', function() { for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; -<<<<<<< HEAD let securedCredential; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); -======= -<<<<<<< HEAD - let issuedVc; - let proofs; - let rdfc2019Proofs = []; - before(async function() { - issuedVc = await createInitialVc({issuer, vc: validCredential}); - proofs = getProofs(issuedVc); - if(proofs?.length) { - rdfc2019Proofs = proofs.filter( - proof => proof?.cryptosuite === cryptosuite); - } -======= - let securedCredential; - let proofs; - before(async function() { - securedCredential = await secureCredential( - {issuer, vc: generateCredential()}); - proofs = getProofs(securedCredential); ->>>>>>> 265e798 (improve proof handling when asserting a secured credential) ->>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) }); beforeEach(setupRow); it('The transformation options MUST contain a type identifier ' + @@ -75,34 +44,16 @@ describe('Algorithms - Transformation (ecdsa-rdfc-2019)', function() { '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; -<<<<<<< HEAD const proof = proofExists(securedCredential); -======= -<<<<<<< HEAD - assertBefore(); - for(const proof of rdfc2019Proofs) { - should.exist(proof.type, 'Expected a type identifier on ' + - 'the proof.'); - should.exist(proof.cryptosuite, - 'Expected a cryptosuite identifier on the proof.'); - } -======= - const proof = proofExists(proofs); ->>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, 'Expected a cryptosuite identifier on the proof.'); -<<<<<<< HEAD -======= ->>>>>>> 265e798 (improve proof handling when asserting a secured credential) ->>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) }); it('Whenever this algorithm encodes strings, ' + 'it MUST use UTF-8 encoding.', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; -<<<<<<< HEAD const proof = proofExists(securedCredential); assertAllUtf8(proof); }); @@ -173,113 +124,11 @@ describe('Algorithms - Proof Configuration (ecdsa-rdfc-2019)', function() { const proof = proofExists(securedCredential); if(proof?.created) { isValidDatetime(proof.created).should.equal( -======= -<<<<<<< HEAD - assertBefore(); - for(const proof of rdfc2019Proofs) { - should.exist(proof?.proofValue, - 'Expected proofValue to exist.'); - isValidUtf8(proof.proofValue).should.equal( ->>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) - true, - 'Expected created value to be a valid datetime string.' - ); - } -======= - const proof = proofExists(proofs); - assertAllUtf8(proof); ->>>>>>> 265e798 (improve proof handling when asserting a secured credential) - }); -<<<<<<< HEAD -======= - it('If options.type is not set to the string DataIntegrityProof or ' + - 'options.cryptosuite is not set to the string ecdsa-rdfc-2019, ' + - 'an error MUST be raised and SHOULD convey an error type ' + - 'of PROOF_TRANSFORMATION_ERROR.', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; -<<<<<<< HEAD - assertBefore(); - for(const proof of rdfc2019Proofs) { - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - should.exist(proof.cryptosuite, - 'Expected a cryptosuite identifier on the proof.'); - proof.type.should.equal('DataIntegrityProof', - 'Expected DataIntegrityProof type.'); - proof.cryptosuite.should.equal('ecdsa-rdfc-2019', - 'Expected ecdsa-rdfc-2019 cryptosuite.'); -======= - const proof = proofExists(proofs); - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - should.exist(proof.cryptosuite, - 'Expected a cryptosuite identifier on the proof.'); - proof.type.should.equal('DataIntegrityProof', - 'Expected DataIntegrityProof type.'); - proof.cryptosuite.should.equal('ecdsa-rdfc-2019', - 'Expected ecdsa-rdfc-2019 cryptosuite.'); - }); - }); - } -}); - -describe('Algorithms - Proof Configuration (ecdsa-rdfc-2019)', function() { - setupReportableTestSuite(this); - this.implemented = [...issuers.keys()]; - for(const [columnId, {endpoints}] of issuers) { - describe(columnId, function() { - const [issuer] = endpoints; - let securedCredential; - let proofs; - before(async function() { - securedCredential = await secureCredential( - {issuer, vc: generateCredential()}); - proofs = getProofs(securedCredential); - }); - beforeEach(setupRow); - it('The proof options MUST contain a type identifier for the ' + - 'cryptographic suite (type) and MUST contain a cryptosuite ' + - 'identifier (cryptosuite).', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; - const proof = proofExists(proofs); - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - should.exist(proof.cryptosuite, - 'Expected a cryptosuite identifier on the proof.'); - }); - it('If proofConfig.type is not set to DataIntegrityProof ' + - 'and/or proofConfig.cryptosuite is not set to ecdsa-rdfc-2019, ' + - 'an error MUST be raised and SHOULD convey an error type ' + - 'of PROOF_GENERATION_ERROR.', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; - const proof = proofExists(proofs); - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - should.exist(proof.cryptosuite, - 'Expected a cryptosuite identifier on the proof.'); - proof.type.should.equal('DataIntegrityProof', - 'Expected DataIntegrityProof type.'); - proof.cryptosuite.should.equal('ecdsa-rdfc-2019', - 'Expected ecdsa-rdfc-2019 cryptosuite.'); - }); - it('If proofConfig.created is set and if the value is not a ' + - 'valid [XMLSCHEMA11-2] datetime, an error MUST be raised and ' + - 'SHOULD convey an error type of PROOF_GENERATION_ERROR.', - async function() { - this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; - const proof = proofExists(proofs); - if(proof?.created) { - isValidDatetime(proof.created).should.equal( true, 'Expected created value to be a valid datetime string.' ); ->>>>>>> 265e798 (improve proof handling when asserting a secured credential) } }); ->>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) }); } }); @@ -290,32 +139,10 @@ describe('Algorithms - Proof Serialization (ecdsa-rdfc-2019)', function() { for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; -<<<<<<< HEAD - let securedCredential; - before(async function() { - securedCredential = await secureCredential( - {issuer, vc: generateCredential()}); -======= -<<<<<<< HEAD - let issuedVc; - let proofs; - let rdfc2019Proofs = []; - before(async function() { - issuedVc = await createInitialVc({issuer, vc: validCredential}); - proofs = getProofs(issuedVc); - if(proofs?.length) { - rdfc2019Proofs = proofs.filter( - proof => proof?.cryptosuite === cryptosuite); - } -======= let securedCredential; - let proofs; before(async function() { securedCredential = await secureCredential( {issuer, vc: generateCredential()}); - proofs = getProofs(securedCredential); ->>>>>>> 265e798 (improve proof handling when asserting a secured credential) ->>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) }); beforeEach(setupRow); it('The proof options MUST contain a type identifier for the ' + @@ -323,23 +150,9 @@ describe('Algorithms - Proof Serialization (ecdsa-rdfc-2019)', function() { '(cryptosuite).', async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-rdfc-2019'; -<<<<<<< HEAD const proof = proofExists(securedCredential); should.exist(proof.type, 'Expected a type identifier on the proof.'); -======= -<<<<<<< HEAD - assertBefore(); - for(const proof of rdfc2019Proofs) { - should.exist(proof.type, - 'Expected a type identifier on the proof.'); - } -======= - const proof = proofExists(proofs); - should.exist(proof.type, - 'Expected a type identifier on the proof.'); ->>>>>>> 265e798 (improve proof handling when asserting a secured credential) ->>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) }); }); } diff --git a/tests/helpers.js b/tests/helpers.js index c57dfaa2..4ee64466 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -42,7 +42,7 @@ export const ISOTimeStamp = ({date = new Date()} = {}) => { export const config = JSON.parse(readFileSync('./config/runner.json')); -export const createInitialVc = async ({ +export const secureCredential = async ({ issuer, vc, mandatoryPointers, @@ -287,16 +287,10 @@ export function setupRow() { }; } -<<<<<<< HEAD export function proofExists(securedCredential) { should.exist(securedCredential, 'Expected issuer to have issued a credential.'); const proofs = getProofs(securedCredential); -======= -<<<<<<< HEAD -======= -export function proofExists(proofs) { ->>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) should.exist(proofs, 'Expected credential to have a proof.'); proofs.length.should.be.gte(1, @@ -304,17 +298,6 @@ export function proofExists(proofs) { return proofs[0]; } -<<<<<<< HEAD -======= -export function assertSecuredCredential(securedCredential) { - should.exist(securedCredential, - 'Expected issuer to have issued a credential.'); - const proofs = getProofs(securedCredential); - proofExists(proofs); -} - ->>>>>>> 265e798 (improve proof handling when asserting a secured credential) ->>>>>>> ec4cd6a (improve proof handling when asserting a secured credential) export async function verifySuccess(verifier, securedCredential) { const body = { verifiableCredential: securedCredential