From 0b7bc09afa799bf3e3cf11bf01f36ba2d7c6758f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 7 Nov 2024 11:15:56 -0500 Subject: [PATCH 01/35] Add non-suite specific algorithm statements & start ecdsa-rdfc-2019. --- tests/suites/algorithms.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/suites/algorithms.js diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js new file mode 100644 index 00000000..d2429bfd --- /dev/null +++ b/tests/suites/algorithms.js @@ -0,0 +1,36 @@ +/*! + * Copyright 2024 Digital Bazaar, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + +export function algorithmSuite({ + suiteName +}) { + it('When generating ECDSA signatures, the signature value MUST be ' + + 'expressed according to section 7 of [RFC4754] (sometimes referred to ' + + 'as the IEEE P1363 format) and encoded according to the specific ' + + 'cryptosuite proof generation algorithm.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=When%20generating%20ECDSA%20signatures%2C%20the%20signature%20value%20MUST%20be%20expressed%20according%20to%20section%207%20of%20%5BRFC4754%5D%20(sometimes%20referred%20to%20as%20the%20IEEE%20P1363%20format)%20and%20encoded%20according%20to%20the%20specific%20cryptosuite%20proof%20generation%20algorithm'; + }); + it('For P-256 keys, the default hashing function, SHA-2 with 256 bits of ' + + 'output, MUST be used.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D256%20keys%2C%20the%20default%20hashing%20function%2C%20SHA%2D2%20with%20256%20bits%20of%20output%2C%20MUST%20be%20used.'; + }); + it('For P-384 keys, SHA-2 with 384-bits of output MUST be used, specified ' + + 'via the RDFC-1.0 implementation-specific parameter.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D384%20keys%2C%20SHA%2D2%20with%20384%2Dbits%20of%20output%20MUST%20be%20used%2C%20specified%20via%20the%20RDFC%2D1.0%20implementation%2Dspecific%20parameter.'; + }); +} + +export function ecdsaRdfc2019Algorithms({ + suiteName, + vcVersion +}) { + return describe(`${suiteName} - Algorithms - VC ${vcVersion}`, function() { + 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://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; + }); + }); +} From 96690e1c7124f309583c6d8abfd03498f986fb43 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 8 Nov 2024 14:40:24 +0000 Subject: [PATCH 02/35] Add basic matrix and row info to rdfc2019 algorithms. --- tests/suites/algorithms.js | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index d2429bfd..42d46101 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -23,14 +23,31 @@ export function algorithmSuite({ } export function ecdsaRdfc2019Algorithms({ + endpoints, suiteName, + keyType, vcVersion }) { return describe(`${suiteName} - Algorithms - VC ${vcVersion}`, function() { - 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://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; - }); + this.matrix = true; + this.report = true; + this.implemented = [...endpoints]; + this.rowLabel = 'Test Name'; + this.columnLabel = 'Implementation'; + for(const [name, {endpoints: issuers}] of endpoints) { + describe(`${name}: ${keyType}`, function() { + beforeEach(function() { + this.currentTest.cell = { + rowId: this.currentTest.title, + columnId: this.currentTest.parent.title + }; + }); + 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://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; + }); + }); + } }); } From 2279c6758d1ae0dd9df641765f837d1f44594cad Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 8 Nov 2024 15:50:15 +0000 Subject: [PATCH 03/35] Add the ecdsa-rdfc-2019 algorithm statements. --- tests/suites/algorithms.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 42d46101..034f8e28 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -47,6 +47,34 @@ export function ecdsaRdfc2019Algorithms({ '(cryptosuite).', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; }); + it('Whenever this algorithm encodes strings, it MUST use UTF-8 ' + + 'encoding. (proof.type)', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; + }); + it('If options.type is not set to the string DataIntegrityProof ' + + 'and options.cryptosuite is not set to the string ecdsa-rdfc-2019, ' + + 'an error MUST be raised ', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019:~:text=If%20options.type%20is%20not%20set%20to%20the%20string%20DataIntegrityProof%20and%20options.cryptosuite%20is%20not%20set%20to%20the%20string%20ecdsa%2Drdfc%2D2019%2C%20an%20error%20MUST%20be%20raised'; + }); + 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://w3c.github.io/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; + }); + 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', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019:~:text=If%20proofConfig.type%20is%20not%20set%20to%20DataIntegrityProof%20and/or%20proofConfig.cryptosuite%20is%20not%20set%20to%20ecdsa%2Drdfc%2D2019%2C%20an%20error%20MUST%20be%20raised'; + }); + it('If proofConfig.created is set and if the value is not a valid ' + + '[XMLSCHEMA11-2] datetime, an error MUST be raised', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#proof-configuration-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://w3c.github.io/vc-di-ecdsa/#proof-serialization-ecdsa-rdfc-2019'; + }); }); } }); From ed9cfaf02bcb6a73371f14bdea9418fda239f6a5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 8 Nov 2024 16:38:39 +0000 Subject: [PATCH 04/35] Add setup code and first test for well formed utf strings. --- tests/suites/algorithms.js | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 034f8e28..08d4250b 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -2,6 +2,8 @@ * Copyright 2024 Digital Bazaar, Inc. * SPDX-License-Identifier: BSD-3-Clause */ +import {createInitialVc, endpointCheck} from '../helpers.js'; +import {expect} from 'chai'; export function algorithmSuite({ suiteName @@ -23,9 +25,11 @@ export function algorithmSuite({ } export function ecdsaRdfc2019Algorithms({ + credential, endpoints, - suiteName, + mandatoryPointers, keyType, + suiteName, vcVersion }) { return describe(`${suiteName} - Algorithms - VC ${vcVersion}`, function() { @@ -35,7 +39,28 @@ export function ecdsaRdfc2019Algorithms({ this.rowLabel = 'Test Name'; this.columnLabel = 'Implementation'; for(const [name, {endpoints: issuers}] of endpoints) { + const [issuer] = issuers; + // does the endpoint support this test? + if(!endpointCheck({endpoint: issuer, keyType, vcVersion})) { + continue; + } describe(`${name}: ${keyType}`, function() { + let securedCredential = null; + let proofs = []; + before(async function() { + securedCredential = await createInitialVc({ + issuer, + vcVersion, + vc: credential, + mandatoryPointers + }); + if(securedCredential) { + proofs = Array.isArray(securedCredential.proof) ? + securedCredential?.proof : [securedCredential?.proof]; + // only test proofs that match the relevant cryptosuite + proofs = proofs.filter(p => p?.cryptosuite === suiteName); + } + }); beforeEach(function() { this.currentTest.cell = { rowId: this.currentTest.title, @@ -50,6 +75,14 @@ export function ecdsaRdfc2019Algorithms({ it('Whenever this algorithm encodes strings, it MUST use UTF-8 ' + 'encoding. (proof.type)', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; + for(const proof of proofs) { + expect(proof?.type).to.exist; + expect(proof.type).to.be.a('string'); + expect( + proof.type.isWellFormed(), + 'Expected string to be a well formed UTF string' + ).to.be.true; + } }); it('If options.type is not set to the string DataIntegrityProof ' + 'and options.cryptosuite is not set to the string ecdsa-rdfc-2019, ' + From 7b9c7a0500ac3f5b9f9dfc71cc089283170a47c9 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 8 Nov 2024 18:37:23 +0000 Subject: [PATCH 05/35] Create common algorithms assertions. --- tests/suites/algorithms.js | 81 +++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 08d4250b..31f9a646 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -8,25 +8,60 @@ import {expect} from 'chai'; export function algorithmSuite({ suiteName }) { - it('When generating ECDSA signatures, the signature value MUST be ' + - 'expressed according to section 7 of [RFC4754] (sometimes referred to ' + - 'as the IEEE P1363 format) and encoded according to the specific ' + - 'cryptosuite proof generation algorithm.', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=When%20generating%20ECDSA%20signatures%2C%20the%20signature%20value%20MUST%20be%20expressed%20according%20to%20section%207%20of%20%5BRFC4754%5D%20(sometimes%20referred%20to%20as%20the%20IEEE%20P1363%20format)%20and%20encoded%20according%20to%20the%20specific%20cryptosuite%20proof%20generation%20algorithm'; - }); - it('For P-256 keys, the default hashing function, SHA-2 with 256 bits of ' + - 'output, MUST be used.', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D256%20keys%2C%20the%20default%20hashing%20function%2C%20SHA%2D2%20with%20256%20bits%20of%20output%2C%20MUST%20be%20used.'; - }); - it('For P-384 keys, SHA-2 with 384-bits of output MUST be used, specified ' + - 'via the RDFC-1.0 implementation-specific parameter.', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D384%20keys%2C%20SHA%2D2%20with%20384%2Dbits%20of%20output%20MUST%20be%20used%2C%20specified%20via%20the%20RDFC%2D1.0%20implementation%2Dspecific%20parameter.'; - }); +} + +export function commonAlgorithms({ + credential, + issuers, + mandatoryPointers, + keyType, + suiteName, + vcVersion +}) { + for(const [name, {endpoints}] of issuers) { + const [issuer] = endpoints; + // does the endpoint support this test? + if(!endpointCheck({endpoint: issuer, keyType, vcVersion})) { + continue; + } + describe(`${name}: ${keyType}`, function() { + let securedCredential = null; + let proofs = []; + before(async function() { + securedCredential = await createInitialVc({ + issuer, + vcVersion, + vc: credential, + mandatoryPointers + }); + if(securedCredential) { + proofs = Array.isArray(securedCredential.proof) ? + securedCredential?.proof : [securedCredential?.proof]; + // only test proofs that match the relevant cryptosuite + proofs = proofs.filter(p => p?.cryptosuite === suiteName); + } + }); + it('When generating ECDSA signatures, the signature value MUST be ' + + 'expressed according to section 7 of [RFC4754] (sometimes referred to ' + + 'as the IEEE P1363 format) and encoded according to the specific ' + + 'cryptosuite proof generation algorithm.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=When%20generating%20ECDSA%20signatures%2C%20the%20signature%20value%20MUST%20be%20expressed%20according%20to%20section%207%20of%20%5BRFC4754%5D%20(sometimes%20referred%20to%20as%20the%20IEEE%20P1363%20format)%20and%20encoded%20according%20to%20the%20specific%20cryptosuite%20proof%20generation%20algorithm'; + }); + it('For P-256 keys, the default hashing function, SHA-2 with 256 bits of ' + + 'output, MUST be used.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D256%20keys%2C%20the%20default%20hashing%20function%2C%20SHA%2D2%20with%20256%20bits%20of%20output%2C%20MUST%20be%20used.'; + }); + it('For P-384 keys, SHA-2 with 384-bits of output MUST be used, specified ' + + 'via the RDFC-1.0 implementation-specific parameter.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D384%20keys%2C%20SHA%2D2%20with%20384%2Dbits%20of%20output%20MUST%20be%20used%2C%20specified%20via%20the%20RDFC%2D1.0%20implementation%2Dspecific%20parameter.'; + }); + }); + } } export function ecdsaRdfc2019Algorithms({ credential, - endpoints, + verifiers, mandatoryPointers, keyType, suiteName, @@ -35,13 +70,13 @@ export function ecdsaRdfc2019Algorithms({ return describe(`${suiteName} - Algorithms - VC ${vcVersion}`, function() { this.matrix = true; this.report = true; - this.implemented = [...endpoints]; + this.implemented = [...verifiers]; this.rowLabel = 'Test Name'; this.columnLabel = 'Implementation'; - for(const [name, {endpoints: issuers}] of endpoints) { - const [issuer] = issuers; + for(const [name, {endpoints}] of verifiers) { + const [verifier] = endpoints; // does the endpoint support this test? - if(!endpointCheck({endpoint: issuer, keyType, vcVersion})) { + if(!endpointCheck({endpoint: verifier, keyType, vcVersion})) { continue; } describe(`${name}: ${keyType}`, function() { @@ -75,14 +110,6 @@ export function ecdsaRdfc2019Algorithms({ it('Whenever this algorithm encodes strings, it MUST use UTF-8 ' + 'encoding. (proof.type)', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; - for(const proof of proofs) { - expect(proof?.type).to.exist; - expect(proof.type).to.be.a('string'); - expect( - proof.type.isWellFormed(), - 'Expected string to be a well formed UTF string' - ).to.be.true; - } }); it('If options.type is not set to the string DataIntegrityProof ' + 'and options.cryptosuite is not set to the string ecdsa-rdfc-2019, ' + From ea3e4c90da2abf575ac55c2cb9d6f832b84dd4da Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 8 Nov 2024 15:21:35 -0500 Subject: [PATCH 06/35] Use verificationSucess to test common algorithm tests. --- tests/suites/algorithms.js | 55 ++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 31f9a646..65ea44f2 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -2,8 +2,14 @@ * Copyright 2024 Digital Bazaar, Inc. * SPDX-License-Identifier: BSD-3-Clause */ +import { + assertions, + generators, + issueCloned +} from 'data-integrity-test-suite-assertion'; import {createInitialVc, endpointCheck} from '../helpers.js'; import {expect} from 'chai'; +import {localVerifier} from '../vc-verifier/index.js'; export function algorithmSuite({ suiteName @@ -15,9 +21,11 @@ export function commonAlgorithms({ issuers, mandatoryPointers, keyType, + cryptosuite, suiteName, vcVersion }) { + const verifier = localVerifier({cryptosuite}); for(const [name, {endpoints}] of issuers) { const [issuer] = endpoints; // does the endpoint support this test? @@ -26,7 +34,6 @@ export function commonAlgorithms({ } describe(`${name}: ${keyType}`, function() { let securedCredential = null; - let proofs = []; before(async function() { securedCredential = await createInitialVc({ issuer, @@ -34,27 +41,41 @@ export function commonAlgorithms({ vc: credential, mandatoryPointers }); - if(securedCredential) { - proofs = Array.isArray(securedCredential.proof) ? - securedCredential?.proof : [securedCredential?.proof]; - // only test proofs that match the relevant cryptosuite - proofs = proofs.filter(p => p?.cryptosuite === suiteName); - } }); it('When generating ECDSA signatures, the signature value MUST be ' + - 'expressed according to section 7 of [RFC4754] (sometimes referred to ' + - 'as the IEEE P1363 format) and encoded according to the specific ' + + 'expressed according to section 7 of [RFC4754] (sometimes referred ' + + 'to as the IEEE P1363 format) and encoded according to the specific ' + 'cryptosuite proof generation algorithm.', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=When%20generating%20ECDSA%20signatures%2C%20the%20signature%20value%20MUST%20be%20expressed%20according%20to%20section%207%20of%20%5BRFC4754%5D%20(sometimes%20referred%20to%20as%20the%20IEEE%20P1363%20format)%20and%20encoded%20according%20to%20the%20specific%20cryptosuite%20proof%20generation%20algorithm'; + await assertions.verificationSuccess({ + credential: securedCredential, + verifier, + reason: `Should verify VC signed with ${suiteName} ${keyType}` + }); }); - it('For P-256 keys, the default hashing function, SHA-2 with 256 bits of ' + - 'output, MUST be used.', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D256%20keys%2C%20the%20default%20hashing%20function%2C%20SHA%2D2%20with%20256%20bits%20of%20output%2C%20MUST%20be%20used.'; - }); - it('For P-384 keys, SHA-2 with 384-bits of output MUST be used, specified ' + - 'via the RDFC-1.0 implementation-specific parameter.', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D384%20keys%2C%20SHA%2D2%20with%20384%2Dbits%20of%20output%20MUST%20be%20used%2C%20specified%20via%20the%20RDFC%2D1.0%20implementation%2Dspecific%20parameter.'; - }); + if(keyType === 'P-256') { + it('For P-256 keys, the default hashing function, SHA-2 with 256 bits' + + 'of output, MUST be used.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D256%20keys%2C%20the%20default%20hashing%20function%2C%20SHA%2D2%20with%20256%20bits%20of%20output%2C%20MUST%20be%20used.'; + await assertions.verificationSuccess({ + credential: securedCredential, + verifier, + reason: `Should verify VC signed with ${suiteName} ${keyType}` + }); + }); + } + if(keyType === 'P-384') { + it('For P-384 keys, SHA-2 with 384-bits of output MUST be used, ' + + 'specified via the RDFC-1.0 implementation-specific parameter.', + async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D384%20keys%2C%20SHA%2D2%20with%20384%2Dbits%20of%20output%20MUST%20be%20used%2C%20specified%20via%20the%20RDFC%2D1.0%20implementation%2Dspecific%20parameter.'; + await assertions.verificationSuccess({ + credential: securedCredential, + verifier, + reason: `Should verify VC signed with ${suiteName} ${keyType}` + }); + }); + } }); } } From eb32e935c279a823b8affcc1d45649480dc9bd13 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 8 Nov 2024 15:43:33 -0500 Subject: [PATCH 07/35] Fill in dummy data for rdfc-2019 algorithms. --- tests/suites/algorithms.js | 80 +++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 65ea44f2..632665d3 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -11,11 +11,6 @@ import {createInitialVc, endpointCheck} from '../helpers.js'; import {expect} from 'chai'; import {localVerifier} from '../vc-verifier/index.js'; -export function algorithmSuite({ - suiteName -}) { -} - export function commonAlgorithms({ credential, issuers, @@ -84,9 +79,11 @@ export function ecdsaRdfc2019Algorithms({ credential, verifiers, mandatoryPointers, + selectivePointers, keyType, suiteName, - vcVersion + vcVersion, + suite = _suite }) { return describe(`${suiteName} - Algorithms - VC ${vcVersion}`, function() { this.matrix = true; @@ -94,29 +91,19 @@ export function ecdsaRdfc2019Algorithms({ this.implemented = [...verifiers]; this.rowLabel = 'Test Name'; this.columnLabel = 'Implementation'; + let credentials = new Map(); + before(async function() { + credentials = await setup({ + suiteName, + keyType, + credential, + mandatoryPointers, + selectivePointers + }); + }); for(const [name, {endpoints}] of verifiers) { const [verifier] = endpoints; - // does the endpoint support this test? - if(!endpointCheck({endpoint: verifier, keyType, vcVersion})) { - continue; - } describe(`${name}: ${keyType}`, function() { - let securedCredential = null; - let proofs = []; - before(async function() { - securedCredential = await createInitialVc({ - issuer, - vcVersion, - vc: credential, - mandatoryPointers - }); - if(securedCredential) { - proofs = Array.isArray(securedCredential.proof) ? - securedCredential?.proof : [securedCredential?.proof]; - // only test proofs that match the relevant cryptosuite - proofs = proofs.filter(p => p?.cryptosuite === suiteName); - } - }); beforeEach(function() { this.currentTest.cell = { rowId: this.currentTest.title, @@ -127,36 +114,77 @@ export function ecdsaRdfc2019Algorithms({ 'the cryptographic suite (type) and a cryptosuite identifier ' + '(cryptosuite).', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('noTypeOrCryptosuite'), + reason: 'Should not verify VC w/ no type or cryptosuite identifier' + }); }); it('Whenever this algorithm encodes strings, it MUST use UTF-8 ' + 'encoding. (proof.type)', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('notUTF8'), + reason: 'Should not verify VC w/ non UTF-8 encoding' + }); }); it('If options.type is not set to the string DataIntegrityProof ' + 'and options.cryptosuite is not set to the string ecdsa-rdfc-2019, ' + 'an error MUST be raised ', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019:~:text=If%20options.type%20is%20not%20set%20to%20the%20string%20DataIntegrityProof%20and%20options.cryptosuite%20is%20not%20set%20to%20the%20string%20ecdsa%2Drdfc%2D2019%2C%20an%20error%20MUST%20be%20raised'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('noTypeOrCryptosuite'), + reason: 'Should not verify VC w/ no type or cryptosuite identifier' + }); }); 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://w3c.github.io/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('noTypeOrCryptosuite'), + reason: 'Should not verify VC w/ no type or cryptosuite identifier' + }); }); 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', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019:~:text=If%20proofConfig.type%20is%20not%20set%20to%20DataIntegrityProof%20and/or%20proofConfig.cryptosuite%20is%20not%20set%20to%20ecdsa%2Drdfc%2D2019%2C%20an%20error%20MUST%20be%20raised'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('noTypeOrCryptosuite'), + reason: 'Should not verify VC w/ no type or cryptosuite identifier' + }); }); it('If proofConfig.created is set and if the value is not a valid ' + '[XMLSCHEMA11-2] datetime, an error MUST be raised', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('invalidCreated'), + reason: 'Should not verify VC w/ invalid "proof.created"' + }); }); 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://w3c.github.io/vc-di-ecdsa/#proof-serialization-ecdsa-rdfc-2019'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('noTypeOrCryptosuite'), + reason: 'Should not verify VC w/ no type or cryptosuite identifier' + }); }); }); } }); } + +async function _suite({ + +}) { + +} From 27f53d802511d8691b9600561ceab67345e0bf08 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Sat, 9 Nov 2024 11:14:24 -0500 Subject: [PATCH 08/35] Start work on generators for rdfc 2019 setup. --- tests/suites/algorithms.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 632665d3..2cf07b86 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -8,7 +8,6 @@ import { issueCloned } from 'data-integrity-test-suite-assertion'; import {createInitialVc, endpointCheck} from '../helpers.js'; -import {expect} from 'chai'; import {localVerifier} from '../vc-verifier/index.js'; export function commonAlgorithms({ @@ -83,7 +82,7 @@ export function ecdsaRdfc2019Algorithms({ keyType, suiteName, vcVersion, - suite = _suite + setup = _setup }) { return describe(`${suiteName} - Algorithms - VC ${vcVersion}`, function() { this.matrix = true; @@ -183,8 +182,18 @@ export function ecdsaRdfc2019Algorithms({ }); } -async function _suite({ - +async function _setup({ + credential, + mandatoryPointers, + selectivePointers, + suiteName, + keyType }) { + const { + invalidProofType, + invalidCryptosuite + } = generators?.mandatory; + const credentials = new Map(); + const {invalidCreated} = generators?.dates; } From 299a12fc31f39ac1c509eba8848194b21c3bbf7b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Sun, 10 Nov 2024 17:59:28 +0000 Subject: [PATCH 09/35] Move getSuites to common helpers file. --- tests/suites/conformance.js | 36 ++++-------------------------------- tests/suites/helpers.js | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 32 deletions(-) create mode 100644 tests/suites/helpers.js diff --git a/tests/suites/conformance.js b/tests/suites/conformance.js index 8df7bce0..2952915b 100644 --- a/tests/suites/conformance.js +++ b/tests/suites/conformance.js @@ -7,9 +7,8 @@ import { generators, issueCloned } from 'data-integrity-test-suite-assertion'; -import {DataIntegrityProof} from '@digitalbazaar/data-integrity'; import {getMultiKey} from '../vc-generator/key-gen.js'; -import {getSuite} from '../vc-generator/cryptosuites.js'; +import {getSuites} from './helpers.js'; export function conformanceSuite({ verifiers, @@ -101,7 +100,7 @@ async function _setup({ // invalid cryptosuite name invalidCryptosuite credentials.set('invalid cryptosuite', await issueCloned(invalidCryptosuite({ credential: structuredClone(_credential), - ..._getSuites({ + ...getSuites({ signer, suiteName, selectivePointers, @@ -110,7 +109,7 @@ async function _setup({ }))); credentials.set('invalid VerificationMethod', await issueCloned(invalidVm({ credential: structuredClone(_credential), - ..._getSuites({ + ...getSuites({ signer, suiteName, selectivePointers, @@ -119,7 +118,7 @@ async function _setup({ }))); credentials.set('invalid Proof Type', await issueCloned(invalidProofType({ credential: structuredClone(_credential), - ..._getSuites({ + ...getSuites({ signer, suiteName, selectivePointers, @@ -128,30 +127,3 @@ async function _setup({ }))); return credentials; } - -function _getSuites({ - signer, - suiteName, - mandatoryPointers, - selectivePointers -}) { - const suites = { - suite: new DataIntegrityProof({ - signer, - cryptosuite: getSuite({ - suite: suiteName, - mandatoryPointers - }) - }) - }; - if(selectivePointers) { - suites.selectiveSuite = new DataIntegrityProof({ - signer, - cryptosuite: getSuite({ - suite: suiteName, - selectivePointers - }) - }); - } - return suites; -} diff --git a/tests/suites/helpers.js b/tests/suites/helpers.js new file mode 100644 index 00000000..6d06791c --- /dev/null +++ b/tests/suites/helpers.js @@ -0,0 +1,36 @@ +/*! + * Copyright 2024 Digital Bazaar, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + +import {DataIntegrityProof} from '@digitalbazaar/data-integrity'; +import {getSuite} from '../vc-generator/cryptosuites.js'; + +// FIXME:an existing function in data integrity test suite assertion +// does something similar to this function, but is not currently exported +export function getSuites({ + signer, + suiteName, + mandatoryPointers, + selectivePointers +}) { + const suites = { + suite: new DataIntegrityProof({ + signer, + cryptosuite: getSuite({ + suite: suiteName, + mandatoryPointers + }) + }) + }; + if(selectivePointers) { + suites.selectiveSuite = new DataIntegrityProof({ + signer, + cryptosuite: getSuite({ + suite: suiteName, + selectivePointers + }) + }); + } + return suites; +} From c7a5bb742142323479591966be05fe105e1d72bd Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Sun, 10 Nov 2024 20:10:41 +0000 Subject: [PATCH 10/35] Further work on algorithms setup. --- tests/suites/algorithms.js | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 2cf07b86..dcdcd35b 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -8,6 +8,8 @@ import { issueCloned } from 'data-integrity-test-suite-assertion'; import {createInitialVc, endpointCheck} from '../helpers.js'; +import {getMultiKey} from '../vc-generator/key-gen.js'; +import {getSuites} from './helpers.js'; import {localVerifier} from '../vc-verifier/index.js'; export function commonAlgorithms({ @@ -188,12 +190,37 @@ async function _setup({ selectivePointers, suiteName, keyType +}) { + // stub suite canonize via Proxy cryptosuite.canonize and set safe to false + const credentials = new Map(); + const keyPair = await getMultiKey({keyType}); + const signer = keyPair.signer(); + const _credential = structuredClone(credential); + _credential.issuer = keyPair.controller; + const {invalidCreated} = generators?.dates; + credentials.set('invalidCreated', await issueCloned(invalidCreated({ + credential: structuredClone(_credential), + ...getSuites({ + signer, + suiteName, + selectivePointers, + mandatoryPointers + }) + }))); + return credentials; +} + +async function _generateNoTypeCryptosuite({ + signer, + credential, + mandatoryPointers, + selectivePointers }) { const { invalidProofType, invalidCryptosuite } = generators?.mandatory; - const credentials = new Map(); - const {invalidCreated} = generators?.dates; + const noType = invalidProofType({ + }); } From 0b3d4701a25c7613ffe3318cf9318ab873575e8f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Sun, 10 Nov 2024 22:06:48 +0000 Subject: [PATCH 11/35] Stub unsafe for canonize. --- tests/suites/algorithms.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index dcdcd35b..47bddb4e 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -207,20 +207,55 @@ async function _setup({ mandatoryPointers }) }))); + credentials.set('noTypeOrCryptosuite', + await issueCloned(_generateNoTypeCryptosuite({ + signer, + suiteName, + credential, + mandatoryPointers, + selectivePointers + }))); return credentials; } async function _generateNoTypeCryptosuite({ signer, + suiteName, credential, mandatoryPointers, selectivePointers }) { + const {suite, selectiveSuite} = getSuites({ + signer, + suiteName, + selectivePointers, + mandatoryPointers + }); const { invalidProofType, invalidCryptosuite } = generators?.mandatory; const noType = invalidProofType({ + credential: structuredClone(credential), + suite: stubUnsafe(suite), + selectiveSuite: stubUnsafe(selectiveSuite), + proofType: '' + }); + return invalidCryptosuite({...noType, cryptosuiteName: ''}); +} +function stubUnsafe(suite) { + if(typeof suite !== 'object') { + return suite; + } + return new Proxy(suite, { + get(target, prop) { + if(prop === 'canonize') { + return function(doc, options) { + return suite.canonize(doc, {...options, safe: false}); + }; + } + return Reflect.get(...arguments); + } }); } From 7f49ed1f108bc81a73264bf0332f5d6d2269743d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Sun, 10 Nov 2024 22:21:26 +0000 Subject: [PATCH 12/35] Add basic algorithms test. --- tests/90-algorithms.js | 37 +++++++++++++++++++++++++++++++++++++ tests/suites/algorithms.js | 4 ++-- 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/90-algorithms.js diff --git a/tests/90-algorithms.js b/tests/90-algorithms.js new file mode 100644 index 00000000..da1150c4 --- /dev/null +++ b/tests/90-algorithms.js @@ -0,0 +1,37 @@ +/*! + * Copyright 2024 Digital Bazaar, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +import {ecdsaRdfc2019Algorithms} from './suites/algorithms.js'; +import {endpoints} from 'vc-test-suite-implementations'; +import {getSuiteConfig} from './test-config.js'; + +const cryptosuites = [ + 'ecdsa-rdfc-2019', +]; + +for(const suiteName of cryptosuites) { + const {tags, credentials, vectors} = getSuiteConfig(suiteName); + const {match: verifiers} = endpoints.filterByTag({ + tags: [...tags], + property: 'verifiers' + }); + for(const vcVersion of vectors.vcTypes) { + const { + document, + mandatoryPointers, + selectivePointers + } = credentials.create[vcVersion]; + for(const keyType of vectors.keyTypes) { + ecdsaRdfc2019Algorithms({ + verifiers, + suiteName, + keyType, + vcVersion, + credential: document, + mandatoryPointers, + selectivePointers + }); + } + } +} diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 47bddb4e..d0e06c73 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -211,14 +211,14 @@ async function _setup({ await issueCloned(_generateNoTypeCryptosuite({ signer, suiteName, - credential, + credential: _credential, mandatoryPointers, selectivePointers }))); return credentials; } -async function _generateNoTypeCryptosuite({ +function _generateNoTypeCryptosuite({ signer, suiteName, credential, From 66d96b832008291b57ec7caf02e41702dfb61da5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Sun, 10 Nov 2024 22:33:21 +0000 Subject: [PATCH 13/35] Proxy canonize on cryptosuite itself. --- tests/suites/algorithms.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index d0e06c73..c75c0e21 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -248,6 +248,18 @@ function stubUnsafe(suite) { if(typeof suite !== 'object') { return suite; } + // if the suite has a cryptosuite object proxy it + if(suite._cryptosuite) { + suite._cryptosuite = new Proxy(suite._cryptosuite, { + get(target, prop) { + if(prop === 'canonize') { + return function(doc, options) { + return suite._cryptosuite.canonize(doc, {...options, safe: false}); + }; + } + } + }); + } return new Proxy(suite, { get(target, prop) { if(prop === 'canonize') { From 6b5446534ed24af5b4bdbe36c1024bd4101778c8 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 11 Nov 2024 14:52:41 +0000 Subject: [PATCH 14/35] Use unsafeProxy for no proof type or cryptosuite. --- tests/suites/algorithms.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index c75c0e21..8791e26c 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -237,14 +237,14 @@ function _generateNoTypeCryptosuite({ } = generators?.mandatory; const noType = invalidProofType({ credential: structuredClone(credential), - suite: stubUnsafe(suite), - selectiveSuite: stubUnsafe(selectiveSuite), + suite: unsafeProxy(suite), + selectiveSuite: unsafeProxy(selectiveSuite), proofType: '' }); return invalidCryptosuite({...noType, cryptosuiteName: ''}); } -function stubUnsafe(suite) { +function unsafeProxy(suite) { if(typeof suite !== 'object') { return suite; } @@ -257,6 +257,7 @@ function stubUnsafe(suite) { return suite._cryptosuite.canonize(doc, {...options, safe: false}); }; } + return Reflect.get(...arguments); } }); } From 9a0f1d9b4d2d2db6a612b85f62f618f55794568a Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 11 Nov 2024 16:39:00 +0000 Subject: [PATCH 15/35] Add beforeEach & fix unsafeProxy. --- tests/suites/algorithms.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 8791e26c..1984ada2 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -38,6 +38,12 @@ export function commonAlgorithms({ mandatoryPointers }); }); + beforeEach(function() { + this.currentTest.cell = { + rowId: this.currentTest.title, + columnId: this.currentTest.parent.title + }; + }); it('When generating ECDSA signatures, the signature value MUST be ' + 'expressed according to section 7 of [RFC4754] (sometimes referred ' + 'to as the IEEE P1363 format) and encoded according to the specific ' + @@ -254,7 +260,7 @@ function unsafeProxy(suite) { get(target, prop) { if(prop === 'canonize') { return function(doc, options) { - return suite._cryptosuite.canonize(doc, {...options, safe: false}); + return target.canonize(doc, {...options, safe: false}); }; } return Reflect.get(...arguments); @@ -265,7 +271,7 @@ function unsafeProxy(suite) { get(target, prop) { if(prop === 'canonize') { return function(doc, options) { - return suite.canonize(doc, {...options, safe: false}); + return target.canonize(doc, {...options, safe: false}); }; } return Reflect.get(...arguments); From a668cfa44da94d0e69506f725cf1bd14ca61585c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 11 Nov 2024 17:46:11 +0000 Subject: [PATCH 16/35] Change to implemented array. --- tests/suites/algorithms.js | 3 ++- tests/suites/conformance.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 1984ada2..cb708d2c 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -95,7 +95,7 @@ export function ecdsaRdfc2019Algorithms({ return describe(`${suiteName} - Algorithms - VC ${vcVersion}`, function() { this.matrix = true; this.report = true; - this.implemented = [...verifiers]; + this.implemented = []; this.rowLabel = 'Test Name'; this.columnLabel = 'Implementation'; let credentials = new Map(); @@ -110,6 +110,7 @@ export function ecdsaRdfc2019Algorithms({ }); for(const [name, {endpoints}] of verifiers) { const [verifier] = endpoints; + this.implemented.push(`${name}: ${keyType}`); describe(`${name}: ${keyType}`, function() { beforeEach(function() { this.currentTest.cell = { diff --git a/tests/suites/conformance.js b/tests/suites/conformance.js index 2952915b..1e0e371f 100644 --- a/tests/suites/conformance.js +++ b/tests/suites/conformance.js @@ -41,7 +41,7 @@ export function conformanceSuite({ for(const [name, {endpoints}] of verifiers) { const [verifier] = endpoints; for(const keyType of keyTypes) { - // add implementer name and keyType to test report + // add implementer name and keyType to test report this.implemented.push(`${name}: ${keyType}`); describe(`${name}: ${keyType}`, function() { beforeEach(function() { From 87bc3d2670c1f58cc34930700e70e3f6a8b68092 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 11 Nov 2024 14:10:23 -0500 Subject: [PATCH 17/35] Move keyTypes into algorithms. --- tests/90-algorithms.js | 20 ++--- tests/suites/algorithms.js | 167 ++++++++++++++++++++----------------- 2 files changed, 98 insertions(+), 89 deletions(-) diff --git a/tests/90-algorithms.js b/tests/90-algorithms.js index da1150c4..3deb87e1 100644 --- a/tests/90-algorithms.js +++ b/tests/90-algorithms.js @@ -22,16 +22,14 @@ for(const suiteName of cryptosuites) { mandatoryPointers, selectivePointers } = credentials.create[vcVersion]; - for(const keyType of vectors.keyTypes) { - ecdsaRdfc2019Algorithms({ - verifiers, - suiteName, - keyType, - vcVersion, - credential: document, - mandatoryPointers, - selectivePointers - }); - } + ecdsaRdfc2019Algorithms({ + verifiers, + suiteName, + keyTypes: vectors.keyTypes, + vcVersion, + credential: document, + mandatoryPointers, + selectivePointers + }); } } diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index cb708d2c..8445e193 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -87,7 +87,7 @@ export function ecdsaRdfc2019Algorithms({ verifiers, mandatoryPointers, selectivePointers, - keyType, + keyTypes, suiteName, vcVersion, setup = _setup @@ -98,95 +98,106 @@ export function ecdsaRdfc2019Algorithms({ this.implemented = []; this.rowLabel = 'Test Name'; this.columnLabel = 'Implementation'; - let credentials = new Map(); + const credentials = new Map(keyTypes.map(kt => [kt, null])); before(async function() { - credentials = await setup({ - suiteName, - keyType, - credential, - mandatoryPointers, - selectivePointers - }); + for(const keyType of keyTypes) { + credentials.set(keyType, await setup({ + suiteName, + keyType, + credential, + mandatoryPointers, + selectivePointers + })); + } }); for(const [name, {endpoints}] of verifiers) { const [verifier] = endpoints; - this.implemented.push(`${name}: ${keyType}`); - describe(`${name}: ${keyType}`, function() { - beforeEach(function() { - this.currentTest.cell = { - rowId: this.currentTest.title, - columnId: this.currentTest.parent.title - }; - }); - 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://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; - await assertions.verificationFail({ - verifier, - credentials: credentials.get('noTypeOrCryptosuite'), - reason: 'Should not verify VC w/ no type or cryptosuite identifier' + for(const keyType of keyTypes) { + this.implemented.push(`${name}: ${keyType}`); + describe(`${name}: ${keyType}`, function() { + beforeEach(function() { + this.currentTest.cell = { + rowId: this.currentTest.title, + columnId: this.currentTest.parent.title + }; }); - }); - it('Whenever this algorithm encodes strings, it MUST use UTF-8 ' + - 'encoding. (proof.type)', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; - await assertions.verificationFail({ - verifier, - credentials: credentials.get('notUTF8'), - reason: 'Should not verify VC w/ non UTF-8 encoding' + 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://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('noTypeOrCryptosuite'), + reason: 'Should not verify VC w/ no type or cryptosuite ' + + 'identifier' + }); }); - }); - it('If options.type is not set to the string DataIntegrityProof ' + - 'and options.cryptosuite is not set to the string ecdsa-rdfc-2019, ' + - 'an error MUST be raised ', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019:~:text=If%20options.type%20is%20not%20set%20to%20the%20string%20DataIntegrityProof%20and%20options.cryptosuite%20is%20not%20set%20to%20the%20string%20ecdsa%2Drdfc%2D2019%2C%20an%20error%20MUST%20be%20raised'; - await assertions.verificationFail({ - verifier, - credentials: credentials.get('noTypeOrCryptosuite'), - reason: 'Should not verify VC w/ no type or cryptosuite identifier' + it('Whenever this algorithm encodes strings, it MUST use UTF-8 ' + + 'encoding. (proof.type)', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('notUTF8'), + reason: 'Should not verify VC w/ non UTF-8 encoding' + }); }); - }); - 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://w3c.github.io/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; - await assertions.verificationFail({ - verifier, - credentials: credentials.get('noTypeOrCryptosuite'), - reason: 'Should not verify VC w/ no type or cryptosuite identifier' + it('If options.type is not set to the string DataIntegrityProof ' + + 'and options.cryptosuite is not set to the string ecdsa-rdfc-2019, ' + + 'an error MUST be raised ', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#transformation-ecdsa-rdfc-2019:~:text=If%20options.type%20is%20not%20set%20to%20the%20string%20DataIntegrityProof%20and%20options.cryptosuite%20is%20not%20set%20to%20the%20string%20ecdsa%2Drdfc%2D2019%2C%20an%20error%20MUST%20be%20raised'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('noTypeOrCryptosuite'), + reason: 'Should not verify VC w/ no type or cryptosuite ' + + 'identifier' + }); }); - }); - 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', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019:~:text=If%20proofConfig.type%20is%20not%20set%20to%20DataIntegrityProof%20and/or%20proofConfig.cryptosuite%20is%20not%20set%20to%20ecdsa%2Drdfc%2D2019%2C%20an%20error%20MUST%20be%20raised'; - await assertions.verificationFail({ - verifier, - credentials: credentials.get('noTypeOrCryptosuite'), - reason: 'Should not verify VC w/ no type or cryptosuite identifier' + 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://w3c.github.io/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('noTypeOrCryptosuite'), + reason: 'Should not verify VC w/ no type or cryptosuite ' + + 'identifier' + }); }); - }); - it('If proofConfig.created is set and if the value is not a valid ' + - '[XMLSCHEMA11-2] datetime, an error MUST be raised', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; - await assertions.verificationFail({ - verifier, - credentials: credentials.get('invalidCreated'), - reason: 'Should not verify VC w/ invalid "proof.created"' + 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', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019:~:text=If%20proofConfig.type%20is%20not%20set%20to%20DataIntegrityProof%20and/or%20proofConfig.cryptosuite%20is%20not%20set%20to%20ecdsa%2Drdfc%2D2019%2C%20an%20error%20MUST%20be%20raised'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('noTypeOrCryptosuite'), + reason: 'Should not verify VC w/ no type or cryptosuite ' + + 'identifier' + }); }); - }); - 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://w3c.github.io/vc-di-ecdsa/#proof-serialization-ecdsa-rdfc-2019'; - await assertions.verificationFail({ - verifier, - credentials: credentials.get('noTypeOrCryptosuite'), - reason: 'Should not verify VC w/ no type or cryptosuite identifier' + it('If proofConfig.created is set and if the value is not a valid ' + + '[XMLSCHEMA11-2] datetime, an error MUST be raised', + async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#proof-configuration-ecdsa-rdfc-2019'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('invalidCreated'), + reason: 'Should not verify VC w/ invalid "proof.created"' + }); + }); + 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://w3c.github.io/vc-di-ecdsa/#proof-serialization-ecdsa-rdfc-2019'; + await assertions.verificationFail({ + verifier, + credentials: credentials.get('noTypeOrCryptosuite'), + reason: 'Should not verify VC w/ no type or cryptosuite ' + + 'identifier' + }); }); }); - }); + + } } }); } From acd5776f01226271a6b24e87ddd127b750f647b4 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 12 Nov 2024 11:47:25 -0500 Subject: [PATCH 18/35] Change common tests to verifier tests. --- tests/suites/algorithms.js | 102 +++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 49 deletions(-) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 8445e193..237ead1b 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -7,79 +7,79 @@ import { generators, issueCloned } from 'data-integrity-test-suite-assertion'; -import {createInitialVc, endpointCheck} from '../helpers.js'; import {getMultiKey} from '../vc-generator/key-gen.js'; import {getSuites} from './helpers.js'; -import {localVerifier} from '../vc-verifier/index.js'; export function commonAlgorithms({ credential, - issuers, + verifiers, mandatoryPointers, - keyType, - cryptosuite, + selectivePointers, + keyTypes, suiteName, - vcVersion + vcVersion, + setup = _commonSetup }) { - const verifier = localVerifier({cryptosuite}); - for(const [name, {endpoints}] of issuers) { - const [issuer] = endpoints; - // does the endpoint support this test? - if(!endpointCheck({endpoint: issuer, keyType, vcVersion})) { - continue; - } - describe(`${name}: ${keyType}`, function() { - let securedCredential = null; - before(async function() { - securedCredential = await createInitialVc({ - issuer, - vcVersion, - vc: credential, - mandatoryPointers + const title = `${suiteName} - Algorithms Common - VC ${vcVersion}`; + return describe(title, function() { + const credentials = new Map(keyTypes.map(keyType => [keyType, null])); + before(async function() { + for(const keyType of keyTypes) { + credentials.set(keyType, await setup({ + credential, + verifiers, + mandatoryPointers, + selectivePointers, + keyType, + suiteName, + vcVersion + })); + } + }); + for(const [name, {endpoints}] of verifiers) { + const [verifier] = endpoints; + describe(`${name}`, function() { + beforeEach(function() { + this.currentTest.cell = { + rowId: this.currentTest.title, + columnId: this.currentTest.parent.title + }; }); - }); - beforeEach(function() { - this.currentTest.cell = { - rowId: this.currentTest.title, - columnId: this.currentTest.parent.title - }; - }); - it('When generating ECDSA signatures, the signature value MUST be ' + - 'expressed according to section 7 of [RFC4754] (sometimes referred ' + - 'to as the IEEE P1363 format) and encoded according to the specific ' + - 'cryptosuite proof generation algorithm.', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=When%20generating%20ECDSA%20signatures%2C%20the%20signature%20value%20MUST%20be%20expressed%20according%20to%20section%207%20of%20%5BRFC4754%5D%20(sometimes%20referred%20to%20as%20the%20IEEE%20P1363%20format)%20and%20encoded%20according%20to%20the%20specific%20cryptosuite%20proof%20generation%20algorithm'; - await assertions.verificationSuccess({ - credential: securedCredential, - verifier, - reason: `Should verify VC signed with ${suiteName} ${keyType}` + it('When generating ECDSA signatures, the signature value MUST be ' + + 'expressed according to section 7 of [RFC4754] (sometimes referred ' + + 'to as the IEEE P1363 format) and encoded according to the ' + + 'specific cryptosuite proof generation algorithm.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=When%20generating%20ECDSA%20signatures%2C%20the%20signature%20value%20MUST%20be%20expressed%20according%20to%20section%207%20of%20%5BRFC4754%5D%20(sometimes%20referred%20to%20as%20the%20IEEE%20P1363%20format)%20and%20encoded%20according%20to%20the%20specific%20cryptosuite%20proof%20generation%20algorithm'; + for(const [keyType, fixtures] of credentials) { + await assertions.verificationSuccess({ + credential: fixtures.get('invalidHash'), + verifier, + reason: `Should not verify VC signed w/ ${keyType} & invalidHash.` + }); + } }); - }); - if(keyType === 'P-256') { it('For P-256 keys, the default hashing function, SHA-2 with 256 bits' + 'of output, MUST be used.', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D256%20keys%2C%20the%20default%20hashing%20function%2C%20SHA%2D2%20with%20256%20bits%20of%20output%2C%20MUST%20be%20used.'; await assertions.verificationSuccess({ - credential: securedCredential, + credential: credentials.get('P-256').get('invalidHash'), verifier, - reason: `Should verify VC signed with ${suiteName} ${keyType}` + reason: `Should not verify VC with invalid hash.` }); }); - } - if(keyType === 'P-384') { it('For P-384 keys, SHA-2 with 384-bits of output MUST be used, ' + 'specified via the RDFC-1.0 implementation-specific parameter.', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D384%20keys%2C%20SHA%2D2%20with%20384%2Dbits%20of%20output%20MUST%20be%20used%2C%20specified%20via%20the%20RDFC%2D1.0%20implementation%2Dspecific%20parameter.'; - await assertions.verificationSuccess({ - credential: securedCredential, + await assertions.verificationFail({ + credential: credentials.get('P-384').get('invalidHash'), verifier, - reason: `Should verify VC signed with ${suiteName} ${keyType}` + reason: `Should not verify VC with invalid hash.` }); }); - } - }); - } + }); + } + }); } export function ecdsaRdfc2019Algorithms({ @@ -290,3 +290,7 @@ function unsafeProxy(suite) { } }); } + +function _commonSetup({}) { + +} From a8f9f636ed58318ecd7e69277156bad9c74442ac Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 12 Nov 2024 11:50:11 -0500 Subject: [PATCH 19/35] Only run keyType statements if suite supports keyTypes. --- tests/suites/algorithms.js | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 237ead1b..bc93444a 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -58,25 +58,29 @@ export function commonAlgorithms({ }); } }); - it('For P-256 keys, the default hashing function, SHA-2 with 256 bits' + - 'of output, MUST be used.', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D256%20keys%2C%20the%20default%20hashing%20function%2C%20SHA%2D2%20with%20256%20bits%20of%20output%2C%20MUST%20be%20used.'; - await assertions.verificationSuccess({ - credential: credentials.get('P-256').get('invalidHash'), - verifier, - reason: `Should not verify VC with invalid hash.` + if(keyTypes.includes('P-256')) { + it('For P-256 keys, the default hashing function, SHA-2 with 256 ' + + 'bits of output, MUST be used.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D256%20keys%2C%20the%20default%20hashing%20function%2C%20SHA%2D2%20with%20256%20bits%20of%20output%2C%20MUST%20be%20used.'; + await assertions.verificationSuccess({ + credential: credentials.get('P-256').get('invalidHash'), + verifier, + reason: `Should not verify VC with invalid hash.` + }); }); - }); - it('For P-384 keys, SHA-2 with 384-bits of output MUST be used, ' + - 'specified via the RDFC-1.0 implementation-specific parameter.', - async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D384%20keys%2C%20SHA%2D2%20with%20384%2Dbits%20of%20output%20MUST%20be%20used%2C%20specified%20via%20the%20RDFC%2D1.0%20implementation%2Dspecific%20parameter.'; - await assertions.verificationFail({ - credential: credentials.get('P-384').get('invalidHash'), - verifier, - reason: `Should not verify VC with invalid hash.` + } + if(keyTypes.includes('P-384')) { + it('For P-384 keys, SHA-2 with 384-bits of output MUST be used, ' + + 'specified via the RDFC-1.0 implementation-specific parameter.', + async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D384%20keys%2C%20SHA%2D2%20with%20384%2Dbits%20of%20output%20MUST%20be%20used%2C%20specified%20via%20the%20RDFC%2D1.0%20implementation%2Dspecific%20parameter.'; + await assertions.verificationFail({ + credential: credentials.get('P-384').get('invalidHash'), + verifier, + reason: `Should not verify VC with invalid hash.` + }); }); - }); + } }); } }); From 494e3506cd48ed53f1639746f9c3891f42d24cc5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 13:24:05 +0000 Subject: [PATCH 20/35] Start work on common setup and proxy. --- tests/suites/algorithms.js | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index bc93444a..46529163 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -213,7 +213,6 @@ async function _setup({ suiteName, keyType }) { - // stub suite canonize via Proxy cryptosuite.canonize and set safe to false const credentials = new Map(); const keyPair = await getMultiKey({keyType}); const signer = keyPair.signer(); @@ -229,6 +228,7 @@ async function _setup({ mandatoryPointers }) }))); + // stub suite canonize via Proxy cryptosuite.canonize and set safe to false credentials.set('noTypeOrCryptosuite', await issueCloned(_generateNoTypeCryptosuite({ signer, @@ -295,6 +295,38 @@ function unsafeProxy(suite) { }); } -function _commonSetup({}) { +async function _commonSetup({ + credential, + mandatoryPointers, + selectivePointers, + suiteName, + keyType +}) { + const credentials = new Map(); + const keyPair = await getMultiKey({keyType}); + const signer = keyPair.signer(); + const _credential = structuredClone(credential); + _credential.issuer = keyPair.controller; + const {suite, selectiveSuite} = getSuites({ + signer, + suiteName, + selectivePointers, + mandatoryPointers + }); + credentials.set('invalidHash', await issueCloned({ + credential: _credential, + suite: invalidHashProxy({suite, suiteName}), + selectiveSuite: invalidHashProxy({suite: selectiveSuite, suiteName}) + })); + return credentials; +} + +function invalidHashProxy({ + suiteName, + suite, +}) { + if(typeof suite !== 'object') { + return suite; + } } From b0b8e2fc32c90d269ff87b9a6b976e7b505f5fad Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 15:21:49 +0000 Subject: [PATCH 21/35] Add proxy for createVerifyData that uses sha512. --- tests/suites/algorithms.js | 70 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 46529163..2653f4c7 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -7,6 +7,7 @@ import { generators, issueCloned } from 'data-integrity-test-suite-assertion'; +import crypto from 'node:crypto'; import {getMultiKey} from '../vc-generator/key-gen.js'; import {getSuites} from './helpers.js'; @@ -328,5 +329,74 @@ function invalidHashProxy({ if(typeof suite !== 'object') { return suite; } + if(suite._cryptosuite) { + if(suiteName !== 'ecdsa-rdfc-2019') { + throw new Error(`Unsupported suite ${suiteName}`); + } + suite._cryptosuite = new Proxy(suite._cryptosuite, { + get(target, prop) { + if(prop === 'createVerifyData') { + return async function({ + cryptosuite, document, proof, + documentLoader, dataIntegrityProof + } = {}) { + const algorithm = 'SHA-512'; + + const c14nOptions = { + documentLoader, + safe: true, + base: null, + skipExpansion: false, + messageDigestAlgorithm: algorithm + }; + // await both c14n proof hash and c14n document hash + const [proofHash, docHash] = await Promise.all([ + // canonize and hash proof + _canonizeProof(proof, { + document, cryptosuite, dataIntegrityProof, c14nOptions + }).then(c14nProofOptions => sha512({ + algorithm, + string: c14nProofOptions + })), + // canonize and hash document + cryptosuite.canonize(document, c14nOptions).then( + c14nDocument => sha512({algorithm, string: c14nDocument})) + ]); + // concatenate hash of c14n proof options and hash of c14n document + return _concat(proofHash, docHash); + }; + } + return Reflect.get(...arguments); + } + }); + } + return suite; +} + +function _concat(b1, b2) { + const rval = new Uint8Array(b1.length + b2.length); + rval.set(b1, 0); + rval.set(b2, b1.length); + return rval; +} + +export async function sha512({string}) { + return new Uint8Array(crypto.createHash('sha512').update(string).digest()); } + +async function _canonizeProof(proof, { + document, cryptosuite, dataIntegrityProof, c14nOptions +}) { + // `proofValue` must not be included in the proof options + proof = { + '@context': document['@context'], + ...proof + }; + dataIntegrityProof.ensureSuiteContext({ + document: proof, addSuiteContext: true + }); + delete proof.proofValue; + return cryptosuite.canonize(proof, c14nOptions); +} + From 4f6d2752a0fb00fc147f754d39696acd73dc828c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 15:53:24 +0000 Subject: [PATCH 22/35] Switch the sha hashes for keyTypes. --- tests/90-algorithms.js | 14 +++++++++++++- tests/suites/algorithms.js | 24 ++++++++++++++---------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/tests/90-algorithms.js b/tests/90-algorithms.js index 3deb87e1..e14901ba 100644 --- a/tests/90-algorithms.js +++ b/tests/90-algorithms.js @@ -2,7 +2,10 @@ * Copyright 2024 Digital Bazaar, Inc. * SPDX-License-Identifier: BSD-3-Clause */ -import {ecdsaRdfc2019Algorithms} from './suites/algorithms.js'; +import { + commonAlgorithms, + ecdsaRdfc2019Algorithms +} from './suites/algorithms.js'; import {endpoints} from 'vc-test-suite-implementations'; import {getSuiteConfig} from './test-config.js'; @@ -31,5 +34,14 @@ for(const suiteName of cryptosuites) { mandatoryPointers, selectivePointers }); + commonAlgorithms({ + verifiers, + suiteName, + keyTypes: vectors.keyTypes, + vcVersion, + credential: document, + mandatoryPointers, + selectivePointers + }); } } diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index 2653f4c7..da6bd70b 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -52,7 +52,7 @@ export function commonAlgorithms({ 'specific cryptosuite proof generation algorithm.', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=When%20generating%20ECDSA%20signatures%2C%20the%20signature%20value%20MUST%20be%20expressed%20according%20to%20section%207%20of%20%5BRFC4754%5D%20(sometimes%20referred%20to%20as%20the%20IEEE%20P1363%20format)%20and%20encoded%20according%20to%20the%20specific%20cryptosuite%20proof%20generation%20algorithm'; for(const [keyType, fixtures] of credentials) { - await assertions.verificationSuccess({ + await assertions.verificationFail({ credential: fixtures.get('invalidHash'), verifier, reason: `Should not verify VC signed w/ ${keyType} & invalidHash.` @@ -63,7 +63,7 @@ export function commonAlgorithms({ it('For P-256 keys, the default hashing function, SHA-2 with 256 ' + 'bits of output, MUST be used.', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#algorithms:~:text=For%20P%2D256%20keys%2C%20the%20default%20hashing%20function%2C%20SHA%2D2%20with%20256%20bits%20of%20output%2C%20MUST%20be%20used.'; - await assertions.verificationSuccess({ + await assertions.verificationFail({ credential: credentials.get('P-256').get('invalidHash'), verifier, reason: `Should not verify VC with invalid hash.` @@ -316,14 +316,19 @@ async function _commonSetup({ }); credentials.set('invalidHash', await issueCloned({ credential: _credential, - suite: invalidHashProxy({suite, suiteName}), - selectiveSuite: invalidHashProxy({suite: selectiveSuite, suiteName}) + suite: invalidHashProxy({suite, suiteName, keyType}), + selectiveSuite: invalidHashProxy({ + suite: selectiveSuite, + suiteName, + keyType + }) })); return credentials; } function invalidHashProxy({ suiteName, + keyType, suite, }) { if(typeof suite !== 'object') { @@ -340,8 +345,7 @@ function invalidHashProxy({ cryptosuite, document, proof, documentLoader, dataIntegrityProof } = {}) { - const algorithm = 'SHA-512'; - + const algorithm = (keyType === 'P-256') ? 'sha384' : 'sha256'; const c14nOptions = { documentLoader, safe: true, @@ -355,13 +359,13 @@ function invalidHashProxy({ // canonize and hash proof _canonizeProof(proof, { document, cryptosuite, dataIntegrityProof, c14nOptions - }).then(c14nProofOptions => sha512({ + }).then(c14nProofOptions => sha({ algorithm, string: c14nProofOptions })), // canonize and hash document cryptosuite.canonize(document, c14nOptions).then( - c14nDocument => sha512({algorithm, string: c14nDocument})) + c14nDocument => sha({algorithm, string: c14nDocument})) ]); // concatenate hash of c14n proof options and hash of c14n document return _concat(proofHash, docHash); @@ -381,8 +385,8 @@ function _concat(b1, b2) { return rval; } -export async function sha512({string}) { - return new Uint8Array(crypto.createHash('sha512').update(string).digest()); +export async function sha({algorithm, string}) { + return new Uint8Array(crypto.createHash(algorithm).update(string).digest()); } async function _canonizeProof(proof, { From d13dd26af0dabf4da64ec1f51e28f559a870f0d0 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 16:14:08 +0000 Subject: [PATCH 23/35] Add matrix code to common & push name to implemented. --- tests/suites/algorithms.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/suites/algorithms.js b/tests/suites/algorithms.js index da6bd70b..f26df9a5 100644 --- a/tests/suites/algorithms.js +++ b/tests/suites/algorithms.js @@ -23,6 +23,11 @@ export function commonAlgorithms({ }) { const title = `${suiteName} - Algorithms Common - VC ${vcVersion}`; return describe(title, function() { + this.matrix = true; + this.report = true; + this.implemented = []; + this.rowLabel = 'Test Name'; + this.columnLabel = 'Implementation'; const credentials = new Map(keyTypes.map(keyType => [keyType, null])); before(async function() { for(const keyType of keyTypes) { @@ -39,6 +44,7 @@ export function commonAlgorithms({ }); for(const [name, {endpoints}] of verifiers) { const [verifier] = endpoints; + this.implemented.push(`${name}`); describe(`${name}`, function() { beforeEach(function() { this.currentTest.cell = { @@ -345,6 +351,7 @@ function invalidHashProxy({ cryptosuite, document, proof, documentLoader, dataIntegrityProof } = {}) { + // this switch the hash to the wrong hash for that keyType const algorithm = (keyType === 'P-256') ? 'sha384' : 'sha256'; const c14nOptions = { documentLoader, From f79c096b7486977cc4faeae3480c077e7912dcfa Mon Sep 17 00:00:00 2001 From: PatStLouis Date: Mon, 11 Nov 2024 21:01:34 +0000 Subject: [PATCH 24/35] ecdsa-jcs algorithms and helpers Signed-off-by: PatStLouis --- tests/90-algorithms-jcs.js | 7 + tests/helpers.js | 75 +++++++++++ tests/suites/algorithms-jcs.js | 228 +++++++++++++++++++++++++++++++++ 3 files changed, 310 insertions(+) create mode 100644 tests/90-algorithms-jcs.js create mode 100644 tests/suites/algorithms-jcs.js diff --git a/tests/90-algorithms-jcs.js b/tests/90-algorithms-jcs.js new file mode 100644 index 00000000..6fe2c455 --- /dev/null +++ b/tests/90-algorithms-jcs.js @@ -0,0 +1,7 @@ +/*! + * Copyright 2024 Digital Bazaar, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +import {ecdsaJcs2019Algorithms} from './suites/algorithms-jcs.js'; + +ecdsaJcs2019Algorithms(); diff --git a/tests/helpers.js b/tests/helpers.js index 5dc06626..39c2aefc 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -5,7 +5,9 @@ import * as bs58 from 'base58-universal'; import * as bs64 from 'base64url-universal'; import {createRequire} from 'node:module'; +import {isUtf8} from 'node:buffer'; import {klona} from 'klona'; +import {readFileSync} from 'fs'; import {v4 as uuidv4} from 'uuid'; export const require = createRequire(import.meta.url); @@ -216,3 +218,76 @@ export function setupReportableTestSuite(runnerContext, name) { runnerContext.implemented = []; } + +export function isValidUtf8(string) { + const textEncoder = new TextEncoder(); + const uint8Array = textEncoder.encode(string); + if(!isUtf8(uint8Array)) { + return false; + } else { + return true; + } +} + +export function isValidDatetime(dateString) { + return !isNaN(Date.parse(dateString)); +} + +export function setupMatrix(match) { + // this will tell the report + // to make an interop matrix with this suite + this.matrix = true; + this.report = true; + this.implemented = [...match.keys()]; + this.rowLabel = 'Test Name'; + this.columnLabel = 'Implementer'; +} + +export const config = JSON.parse(readFileSync('./config/runner.json')); + +export function createValidCredential(version = 2) { + let credential = { + type: ['VerifiableCredential'], + id: `urn:uuid:${uuidv4()}`, + credentialSubject: {id: 'did:example:alice'} + }; + if(version === 1) { + // add v1.1 context and issuanceDate + credential = Object.assign({}, { + '@context': [ + 'https://www.w3.org/2018/credentials/v1', + 'https://w3id.org/security/data-integrity/v2' + ], + issuanceDate: ISOTimeStamp() + }, credential); + } else if(version === 2) { + // add v2 context + credential = Object.assign({}, { + '@context': [ + 'https://www.w3.org/ns/credentials/v2' + ] + }, credential); + } else { + return null; + } + return credential; +} + +export function setupRow() { + // append test meta data to the it/test this. + this.currentTest.cell = { + columnId: this.currentTest.parent.title, + rowId: this.currentTest.title + }; +} + +export function getProofs(issuedVc) { + // if the implementation failed to issue a VC or to sign the VC, return + // an empty array + if(!issuedVc?.proof) { + return []; + } + const proofs = Array.isArray(issuedVc?.proof) ? + issuedVc.proof : [issuedVc?.proof]; + return proofs; +} diff --git a/tests/suites/algorithms-jcs.js b/tests/suites/algorithms-jcs.js new file mode 100644 index 00000000..4fa29ebc --- /dev/null +++ b/tests/suites/algorithms-jcs.js @@ -0,0 +1,228 @@ +/*! + * Copyright 2024 Digital Bazaar, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +import { + config, + createInitialVc, + createValidCredential, + getProofs, + setupMatrix, + setupRow +} from '../helpers.js'; +import {isValidDatetime, isValidUtf8} from './helpers.js'; +import chai from 'chai'; +import {endpoints} from 'vc-test-suite-implementations'; + +export function ecdsaJcs2019Algorithms() { + const cryptosuite = 'ecdsa-jcs-2022'; + const {tags} = config.suites[ + cryptosuite + ]; + const {issuerMatch} = endpoints.filterByTag({ + tags: [...tags], + property: 'issuers' + }); + // const {verifierMatch} = endpoints.filterByTag({ + // tags: [...tags], + // property: 'verifiers' + // }); + const should = chai.should(); + + describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { + setupMatrix.call(this, issuerMatch); + let validCredential; + before(async function() { + validCredential = await createValidCredential(); + }); + for(const [columnId, {endpoints}] of issuerMatch) { + describe(columnId, function() { + const [issuer] = endpoints; + let issuedVc; + let proofs; + let ecdsa2022Proofs = []; + before(async function() { + issuedVc = await createInitialVc({issuer, vc: validCredential}); + proofs = getProofs(issuedVc); + if(proofs?.length) { + ecdsa2022Proofs = 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.'); + ecdsa2022Proofs.length.should.be.gte(1, 'Expected at least one ' + + 'ecdsa-jcs-2019 cryptosuite.'); + }; + 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 ecdsa2022Proofs) { + 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 ecdsa2022Proofs) { + 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 ecdsa2022Proofs) { + 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-2022', + 'Expected ecdsa-jcs-2022 cryptosuite.'); + } + }); + }); + } + }); + + describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { + setupMatrix.call(this, issuerMatch); + let validCredential; + before(async function() { + validCredential = await createValidCredential(); + }); + for(const [columnId, {endpoints}] of issuerMatch) { + describe(columnId, function() { + const [issuer] = endpoints; + let issuedVc; + let proofs; + let ecdsa2022Proofs = []; + before(async function() { + issuedVc = await createInitialVc({issuer, vc: validCredential}); + proofs = getProofs(issuedVc); + if(proofs?.length) { + ecdsa2022Proofs = 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.'); + ecdsa2022Proofs.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 ecdsa2022Proofs) { + 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 ecdsa2022Proofs) { + 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-2022', + 'Expected ecdsa-jcs-2022 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 ecdsa2022Proofs) { + if(proof?.created) { + isValidDatetime(proof.created).should.equal( + true, + 'Expected created value to be a valid datetime string.' + ); + } + } + }); + }); + } + }); + + describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { + setupMatrix.call(this, issuerMatch); + let validCredential; + before(async function() { + validCredential = await createValidCredential(); + }); + for(const [columnId, {endpoints}] of issuerMatch) { + describe(columnId, function() { + const [issuer] = endpoints; + let issuedVc; + let proofs; + let ecdsa2022Proofs = []; + before(async function() { + issuedVc = await createInitialVc({issuer, vc: validCredential}); + proofs = getProofs(issuedVc); + if(proofs?.length) { + ecdsa2022Proofs = 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.'); + ecdsa2022Proofs.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 ecdsa2022Proofs) { + should.exist(proof.type, + 'Expected a type identifier on the proof.'); + } + }); + }); + } + }); +} From 7244c288e2a617aed3168692215079f4458c6b04 Mon Sep 17 00:00:00 2001 From: Patrick St-Louis <43082425+PatStLouis@users.noreply.github.com> Date: Tue, 12 Nov 2024 13:00:17 -0500 Subject: [PATCH 25/35] Apply text suggestion Co-authored-by: Ted Thibodeau Jr --- tests/helpers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/helpers.js b/tests/helpers.js index 39c2aefc..ede9c5aa 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -282,8 +282,8 @@ export function setupRow() { } export function getProofs(issuedVc) { - // if the implementation failed to issue a VC or to sign the VC, return - // an empty array + // if the implementation failed to issue a VC or to sign the VC, + // return an empty array if(!issuedVc?.proof) { return []; } From 17d6e68ca30cba9ae81ea97007e1927d9e7361ac Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 17:02:27 +0000 Subject: [PATCH 26/35] Use test helpers not suite helpers. --- tests/suites/algorithms-jcs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/algorithms-jcs.js b/tests/suites/algorithms-jcs.js index 4fa29ebc..b9f5fd8e 100644 --- a/tests/suites/algorithms-jcs.js +++ b/tests/suites/algorithms-jcs.js @@ -10,7 +10,7 @@ import { setupMatrix, setupRow } from '../helpers.js'; -import {isValidDatetime, isValidUtf8} from './helpers.js'; +import {isValidDatetime, isValidUtf8} from '../helpers.js'; import chai from 'chai'; import {endpoints} from 'vc-test-suite-implementations'; From db117a6be3eec4524d372b842f394aacaa3148a0 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 17:05:05 +0000 Subject: [PATCH 27/35] Switch default interop vc version to 2.0 for rdfc-2019. --- config/runner.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/runner.json b/config/runner.json index d3dc716e..4cbf752a 100644 --- a/config/runner.json +++ b/config/runner.json @@ -8,7 +8,7 @@ "P-384": 96 }, "interop": { - "vcVersion": "1.1" + "vcVersion": "2.0" } }, "ecdsa-sd-2023": { From c4db008799d8241edf975dd07fc055a0a9670468 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 17:05:24 +0000 Subject: [PATCH 28/35] Merge isValid utils into common helpers import. --- tests/suites/algorithms-jcs.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/suites/algorithms-jcs.js b/tests/suites/algorithms-jcs.js index b9f5fd8e..200a26a3 100644 --- a/tests/suites/algorithms-jcs.js +++ b/tests/suites/algorithms-jcs.js @@ -7,10 +7,11 @@ import { createInitialVc, createValidCredential, getProofs, + isValidDatetime, + isValidUtf8, setupMatrix, setupRow } from '../helpers.js'; -import {isValidDatetime, isValidUtf8} from '../helpers.js'; import chai from 'chai'; import {endpoints} from 'vc-test-suite-implementations'; From befb9e9e57aecef9c76cbe24b8022e3a8bf4cfb8 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 17:08:13 +0000 Subject: [PATCH 29/35] Add initial jcs 2019 config and update cryptosuite name. --- config/runner.json | 10 ++++++++++ tests/suites/algorithms-jcs.js | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/config/runner.json b/config/runner.json index 4cbf752a..52f24956 100644 --- a/config/runner.json +++ b/config/runner.json @@ -11,6 +11,16 @@ "vcVersion": "2.0" } }, + "ecdsa-jcs-2019": { + "tags": ["ecdsa-jcs-2019"], + "proofLengths": { + "P-256": 64, + "P-384": 96 + }, + "interop": { + "vcVersion": "2.0" + } + }, "ecdsa-sd-2023": { "tags": ["ecdsa-sd-2023"], "interop": { diff --git a/tests/suites/algorithms-jcs.js b/tests/suites/algorithms-jcs.js index 200a26a3..a3bd7c21 100644 --- a/tests/suites/algorithms-jcs.js +++ b/tests/suites/algorithms-jcs.js @@ -16,7 +16,7 @@ import chai from 'chai'; import {endpoints} from 'vc-test-suite-implementations'; export function ecdsaJcs2019Algorithms() { - const cryptosuite = 'ecdsa-jcs-2022'; + const cryptosuite = 'ecdsa-jcs-2019'; const {tags} = config.suites[ cryptosuite ]; From 0a889e56efb32bee6f66aca6886f4adb50e5a8bd Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 18:35:45 +0000 Subject: [PATCH 30/35] Change default supported vc type to 2.0. --- tests/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/helpers.js b/tests/helpers.js index ede9c5aa..7440e596 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -92,7 +92,7 @@ export const endpointCheck = ({endpoint, vcVersion, keyType}) => { const { supportedEcdsaKeyTypes, // assume support for vc 1.1 - supports = {vc: ['1.1']} + supports = {vc: ['2.0']} } = endpoint.settings; // if an issuer does not support the current keyType skip it const keyTypes = supportedEcdsaKeyTypes || supports?.keyTypes; From 5832b1b5fdf66959dfacdca2c934079bed7dfb18 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 18:41:54 +0000 Subject: [PATCH 31/35] Minor corrections to jcs suite. --- tests/helpers.js | 16 ++++------------ tests/suites/algorithms-jcs.js | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/tests/helpers.js b/tests/helpers.js index 7440e596..f896e331 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -210,12 +210,14 @@ export function getColumnNameForTestCategory(testCategory) { } } -export function setupReportableTestSuite(runnerContext, name) { +export function setupReportableTestSuite( + runnerContext, + name = 'Implementation' +) { runnerContext.matrix = true; runnerContext.report = true; runnerContext.rowLabel = 'Test Name'; runnerContext.columnLabel = name; - runnerContext.implemented = []; } @@ -233,16 +235,6 @@ export function isValidDatetime(dateString) { return !isNaN(Date.parse(dateString)); } -export function setupMatrix(match) { - // this will tell the report - // to make an interop matrix with this suite - this.matrix = true; - this.report = true; - this.implemented = [...match.keys()]; - this.rowLabel = 'Test Name'; - this.columnLabel = 'Implementer'; -} - export const config = JSON.parse(readFileSync('./config/runner.json')); export function createValidCredential(version = 2) { diff --git a/tests/suites/algorithms-jcs.js b/tests/suites/algorithms-jcs.js index a3bd7c21..283cb17f 100644 --- a/tests/suites/algorithms-jcs.js +++ b/tests/suites/algorithms-jcs.js @@ -9,7 +9,7 @@ import { getProofs, isValidDatetime, isValidUtf8, - setupMatrix, + setupReportableTestSuite, setupRow } from '../helpers.js'; import chai from 'chai'; @@ -20,7 +20,7 @@ export function ecdsaJcs2019Algorithms() { const {tags} = config.suites[ cryptosuite ]; - const {issuerMatch} = endpoints.filterByTag({ + const {match: issuers} = endpoints.filterByTag({ tags: [...tags], property: 'issuers' }); @@ -31,12 +31,12 @@ export function ecdsaJcs2019Algorithms() { const should = chai.should(); describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { - setupMatrix.call(this, issuerMatch); + setupReportableTestSuite(this); let validCredential; before(async function() { validCredential = await createValidCredential(); }); - for(const [columnId, {endpoints}] of issuerMatch) { + for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; let issuedVc; @@ -99,8 +99,8 @@ export function ecdsaJcs2019Algorithms() { 'Expected a cryptosuite identifier on the proof.'); proof.type.should.equal('DataIntegrityProof', 'Expected DataIntegrityProof type.'); - proof.cryptosuite.should.equal('ecdsa-jcs-2022', - 'Expected ecdsa-jcs-2022 cryptosuite.'); + proof.cryptosuite.should.equal('ecdsa-jcs-2019', + 'Expected ecdsa-jcs-2019 cryptosuite.'); } }); }); @@ -108,12 +108,12 @@ export function ecdsaJcs2019Algorithms() { }); describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { - setupMatrix.call(this, issuerMatch); + setupReportableTestSuite(this); let validCredential; before(async function() { validCredential = await createValidCredential(); }); - for(const [columnId, {endpoints}] of issuerMatch) { + for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; let issuedVc; @@ -162,8 +162,8 @@ export function ecdsaJcs2019Algorithms() { 'Expected a cryptosuite identifier on the proof.'); proof.type.should.equal('DataIntegrityProof', 'Expected DataIntegrityProof type.'); - proof.cryptosuite.should.equal('ecdsa-jcs-2022', - 'Expected ecdsa-jcs-2022 cryptosuite.'); + 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 ' + @@ -185,12 +185,12 @@ export function ecdsaJcs2019Algorithms() { }); describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { - setupMatrix.call(this, issuerMatch); + setupReportableTestSuite(this); let validCredential; before(async function() { validCredential = await createValidCredential(); }); - for(const [columnId, {endpoints}] of issuerMatch) { + for(const [columnId, {endpoints}] of issuers) { describe(columnId, function() { const [issuer] = endpoints; let issuedVc; From 405cce223396ddb836897727e73c02c03c184b08 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 18:53:03 +0000 Subject: [PATCH 32/35] Add implemented to suites. --- tests/suites/algorithms-jcs.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/suites/algorithms-jcs.js b/tests/suites/algorithms-jcs.js index 283cb17f..f660c573 100644 --- a/tests/suites/algorithms-jcs.js +++ b/tests/suites/algorithms-jcs.js @@ -24,14 +24,11 @@ export function ecdsaJcs2019Algorithms() { tags: [...tags], property: 'issuers' }); - // const {verifierMatch} = endpoints.filterByTag({ - // tags: [...tags], - // property: 'verifiers' - // }); const should = chai.should(); describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { setupReportableTestSuite(this); + this.implemented = [...issuers.keys()]; let validCredential; before(async function() { validCredential = await createValidCredential(); @@ -109,6 +106,7 @@ export function ecdsaJcs2019Algorithms() { describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() { setupReportableTestSuite(this); + this.implemented = [...issuers.keys()]; let validCredential; before(async function() { validCredential = await createValidCredential(); @@ -186,6 +184,7 @@ export function ecdsaJcs2019Algorithms() { describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { setupReportableTestSuite(this); + this.implemented = [...issuers.keys()]; let validCredential; before(async function() { validCredential = await createValidCredential(); From da85c81eaa094732cad3e286ce78361c82e2be7f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 19:00:10 +0000 Subject: [PATCH 33/35] Replace ecdsa2022 w/ jcs2019Proofs. --- tests/suites/algorithms-jcs.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/suites/algorithms-jcs.js b/tests/suites/algorithms-jcs.js index f660c573..3543f9bc 100644 --- a/tests/suites/algorithms-jcs.js +++ b/tests/suites/algorithms-jcs.js @@ -38,12 +38,12 @@ export function ecdsaJcs2019Algorithms() { const [issuer] = endpoints; let issuedVc; let proofs; - let ecdsa2022Proofs = []; + let jcs2019Proofs = []; before(async function() { issuedVc = await createInitialVc({issuer, vc: validCredential}); proofs = getProofs(issuedVc); if(proofs?.length) { - ecdsa2022Proofs = proofs.filter( + jcs2019Proofs = proofs.filter( proof => proof?.cryptosuite === cryptosuite); } }); @@ -52,7 +52,7 @@ export function ecdsaJcs2019Algorithms() { should.exist(issuedVc, 'Expected issuer to have issued a ' + 'credential.'); should.exist(proofs, 'Expected credential to have a proof.'); - ecdsa2022Proofs.length.should.be.gte(1, 'Expected at least one ' + + jcs2019Proofs.length.should.be.gte(1, 'Expected at least one ' + 'ecdsa-jcs-2019 cryptosuite.'); }; it('The transformation options MUST contain a type identifier ' + @@ -61,7 +61,7 @@ export function ecdsaJcs2019Algorithms() { async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; assertBefore(); - for(const proof of ecdsa2022Proofs) { + for(const proof of jcs2019Proofs) { should.exist(proof.type, 'Expected a type identifier on ' + 'the proof.'); should.exist(proof.cryptosuite, @@ -73,7 +73,7 @@ export function ecdsaJcs2019Algorithms() { async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; assertBefore(); - for(const proof of ecdsa2022Proofs) { + for(const proof of jcs2019Proofs) { should.exist(proof?.proofValue, 'Expected proofValue to exist.'); isValidUtf8(proof.proofValue).should.equal( @@ -89,7 +89,7 @@ export function ecdsaJcs2019Algorithms() { async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019'; assertBefore(); - for(const proof of ecdsa2022Proofs) { + for(const proof of jcs2019Proofs) { should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -116,12 +116,12 @@ export function ecdsaJcs2019Algorithms() { const [issuer] = endpoints; let issuedVc; let proofs; - let ecdsa2022Proofs = []; + let jcs2019Proofs = []; before(async function() { issuedVc = await createInitialVc({issuer, vc: validCredential}); proofs = getProofs(issuedVc); if(proofs?.length) { - ecdsa2022Proofs = proofs.filter( + jcs2019Proofs = proofs.filter( proof => proof?.cryptosuite === cryptosuite); } }); @@ -130,7 +130,7 @@ export function ecdsaJcs2019Algorithms() { should.exist(issuedVc, 'Expected issuer to have issued a ' + 'credential.'); should.exist(proofs, 'Expected credential to have a proof.'); - ecdsa2022Proofs.length.should.be.gte(1, 'Expected at least one ' + + 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 ' + @@ -139,7 +139,7 @@ export function ecdsaJcs2019Algorithms() { async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; assertBefore(); - for(const proof of ecdsa2022Proofs) { + for(const proof of jcs2019Proofs) { should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -153,7 +153,7 @@ export function ecdsaJcs2019Algorithms() { async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019'; assertBefore(); - for(const proof of ecdsa2022Proofs) { + for(const proof of jcs2019Proofs) { should.exist(proof.type, 'Expected a type identifier on the proof.'); should.exist(proof.cryptosuite, @@ -169,7 +169,7 @@ export function ecdsaJcs2019Algorithms() { '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 ecdsa2022Proofs) { + for(const proof of jcs2019Proofs) { if(proof?.created) { isValidDatetime(proof.created).should.equal( true, @@ -194,12 +194,12 @@ export function ecdsaJcs2019Algorithms() { const [issuer] = endpoints; let issuedVc; let proofs; - let ecdsa2022Proofs = []; + let jcs2019Proofs = []; before(async function() { issuedVc = await createInitialVc({issuer, vc: validCredential}); proofs = getProofs(issuedVc); if(proofs?.length) { - ecdsa2022Proofs = proofs.filter( + jcs2019Proofs = proofs.filter( proof => proof?.cryptosuite === cryptosuite); } }); @@ -208,7 +208,7 @@ export function ecdsaJcs2019Algorithms() { should.exist(issuedVc, 'Expected issuer to have issued a ' + 'credential.'); should.exist(proofs, 'Expected credential to have a proof.'); - ecdsa2022Proofs.length.should.be.gte(1, 'Expected at least one ' + + 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 ' + @@ -217,7 +217,7 @@ export function ecdsaJcs2019Algorithms() { async function() { this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019'; assertBefore(); - for(const proof of ecdsa2022Proofs) { + for(const proof of jcs2019Proofs) { should.exist(proof.type, 'Expected a type identifier on the proof.'); } From bf0e8ca06d95749c25b8281139c7e72470621d1a Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 19:12:25 +0000 Subject: [PATCH 34/35] Move lone transformation test to main area. --- tests/suites/algorithms-jcs.js | 58 ++++++++-------------------------- 1 file changed, 13 insertions(+), 45 deletions(-) diff --git a/tests/suites/algorithms-jcs.js b/tests/suites/algorithms-jcs.js index 3543f9bc..5c55a95a 100644 --- a/tests/suites/algorithms-jcs.js +++ b/tests/suites/algorithms-jcs.js @@ -15,6 +15,8 @@ import { import chai from 'chai'; import {endpoints} from 'vc-test-suite-implementations'; +const should = chai.should(); + export function ecdsaJcs2019Algorithms() { const cryptosuite = 'ecdsa-jcs-2019'; const {tags} = config.suites[ @@ -24,7 +26,6 @@ export function ecdsaJcs2019Algorithms() { tags: [...tags], property: 'issuers' }); - const should = chai.should(); describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() { setupReportableTestSuite(this); @@ -55,6 +56,17 @@ export function ecdsaJcs2019Algorithms() { 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).', @@ -181,48 +193,4 @@ export function ecdsaJcs2019Algorithms() { }); } }); - - 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.'); - } - }); - }); - } - }); } From e644d7423676d8d286c3d4e719eb8740b04448a1 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 13 Nov 2024 20:18:35 +0000 Subject: [PATCH 35/35] Update tests/helpers.js comment about test version support. Co-authored-by: BigBlueHat --- tests/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/helpers.js b/tests/helpers.js index f896e331..04d907dd 100644 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -91,7 +91,7 @@ export const createDisclosedVc = async ({ export const endpointCheck = ({endpoint, vcVersion, keyType}) => { const { supportedEcdsaKeyTypes, - // assume support for vc 1.1 + // assume support for vc 2.0 supports = {vc: ['2.0']} } = endpoint.settings; // if an issuer does not support the current keyType skip it