From 6b06803aa74cfbb934cdeacd2aabc2e76e04de44 Mon Sep 17 00:00:00 2001 From: Dmitri Zagidulin Date: Sun, 9 Aug 2020 16:22:51 -0400 Subject: [PATCH 01/18] Initial commit (extract from jsonld-signatures). --- README.md | 2 +- lib/Example.js | 6 - lib/JwsLinkedDataSignature.js | 181 ++++++++++++++++++ lib/create-jws.js | 24 +++ lib/main.js | 2 +- package.json | 7 +- ...spec.js => JwsLinkedDataSignature.spec.js} | 6 +- 7 files changed, 215 insertions(+), 13 deletions(-) delete mode 100644 lib/Example.js create mode 100644 lib/JwsLinkedDataSignature.js create mode 100644 lib/create-jws.js rename tests/unit/{Example.spec.js => JwsLinkedDataSignature.spec.js} (66%) diff --git a/README.md b/README.md index feed2cd..1d0c4cf 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ## Background -TBD +For use with https://github.com/digitalbazaar/jsonld-signatures v6.0 and above. ## Security diff --git a/lib/Example.js b/lib/Example.js deleted file mode 100644 index 0b48a89..0000000 --- a/lib/Example.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! - * Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved. - */ -// import * as env from './env.js'; - -export class Example {} diff --git a/lib/JwsLinkedDataSignature.js b/lib/JwsLinkedDataSignature.js new file mode 100644 index 0000000..45daf31 --- /dev/null +++ b/lib/JwsLinkedDataSignature.js @@ -0,0 +1,181 @@ +/*! + * Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved. + */ +import jsonld from 'jsonld'; +import jsigs from 'jsonld-signatures'; +const {LinkedDataSignature} = jsigs.suites; +import {encode, decode} from 'base64url-universal'; +import {createJwsFactory} from './create-jws.js'; + +const createJws = createJwsFactory(); + +export class JwsLinkedDataSignature extends LinkedDataSignature { + /** + * @param type {string} Provided by subclass. + * @param alg {string} JWS alg provided by subclass. + * @param [LDKeyClass] {LDKeyClass} provided by subclass or subclass + * overrides `getVerificationMethod`. + * + * @param [verificationMethod] {string} A key id URL to the paired public key. + * + * This parameter is required for signing: + * + * @param [signer] {function} an optional signer. + * + * Advanced optional parameters and overrides: + * + * @param [proof] {object} a JSON-LD document with options to use for + * the `proof` node (e.g. any other custom fields can be provided here + * using a context different from security-v2). + * @param [date] {string|Date} signing date to use if not passed. + * @param [key] {LDKeyPair} an optional crypto-ld KeyPair. + * @param [useNativeCanonize] {boolean} true to use a native canonize + * algorithm. + */ + constructor({ + type, alg, LDKeyClass, verificationMethod, signer, key, proof, + date, useNativeCanonize} = {}) { + super({type, verificationMethod, proof, date, useNativeCanonize}); + this.alg = alg; + this.LDKeyClass = LDKeyClass; + this.signer = signer; + if(key) { + if(verificationMethod === undefined) { + const publicKey = key.export({publicKey: true}); + this.verificationMethod = publicKey.id; + } + this.key = key; + if(typeof key.signer === 'function') { + this.signer = key.signer(); + } + if(typeof key.verifier === 'function') { + this.verifier = key.verifier(); + } + } + } + + /** + * @param verifyData {Uint8Array}. + * @param proof {object} + * + * @returns {Promise<{object}>} the proof containing the signature value. + */ + async sign({verifyData, proof}) { + if(!(this.signer && typeof this.signer.sign === 'function')) { + throw new Error('A signer API has not been specified.'); + } + // JWS header + const header = { + alg: this.alg, + b64: false, + crit: ['b64'] + }; + + /* + +-------+-----------------------------------------------------------+ + | "b64" | JWS Signing Input Formula | + +-------+-----------------------------------------------------------+ + | true | ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.' || | + | | BASE64URL(JWS Payload)) | + | | | + | false | ASCII(BASE64URL(UTF8(JWS Protected Header)) || '.') || | + | | JWS Payload | + +-------+-----------------------------------------------------------+ + */ + + // create JWS data and sign + const encodedHeader = encode(JSON.stringify(header)); + const data = createJws({encodedHeader, verifyData}); + const signature = await this.signer.sign({data}); + + // create detached content signature + const encodedSignature = encode(signature); + proof.jws = encodedHeader + '..' + encodedSignature; + return proof; + } + + /** + * @param verifyData {Uint8Array}. + * @param verificationMethod {object}. + * @param document {object} the document the proof applies to. + * @param proof {object} the proof to be verified. + * @param purpose {ProofPurpose} + * @param documentLoader {function} + * @param expansionMap {function} + * + * @returns {Promise<{boolean}>} Resolves with the verification result. + */ + async verifySignature({verifyData, verificationMethod, proof}) { + if(!(proof.jws && typeof proof.jws === 'string' && + proof.jws.includes('.'))) { + throw new TypeError('The proof does not include a valid "jws" property.'); + } + // add payload into detached content signature + const [encodedHeader, /*payload*/, encodedSignature] = proof.jws.split('.'); + + let header; + try { + header = JSON.parse(decode(encodedHeader)); + } catch(e) { + throw new Error('Could not parse JWS header; ' + e); + } + if(!(header && typeof header === 'object')) { + throw new Error('Invalid JWS header.'); + } + + // confirm header matches all expectations + if(!(header.alg === this.alg && header.b64 === false && + Array.isArray(header.crit) && header.crit.length === 1 && + header.crit[0] === 'b64') && Object.keys(header).length === 3) { + throw new Error( + `Invalid JWS header parameters for ${this.type}.`); + } + + // do signature verification + const signature = decode(encodedSignature); + const data = createJws({encodedHeader, verifyData}); + let {verifier} = this; + if(!verifier) { + const key = await this.LDKeyClass.from(verificationMethod); + verifier = key.verifier(); + } + return verifier.verify({data, signature}); + } + + async assertVerificationMethod({verificationMethod}) { + if(!jsonld.hasValue(verificationMethod, 'type', this.requiredKeyType)) { + throw new Error( + `Invalid key type. Key type must be "${this.requiredKeyType}".`); + } + } + + async getVerificationMethod({proof, documentLoader}) { + if(this.key) { + return this.key.export({publicKey: true}); + } + + const verificationMethod = await super.getVerificationMethod( + {proof, documentLoader}); + await this.assertVerificationMethod({verificationMethod}); + return verificationMethod; + } + + async matchProof({proof, document, purpose, documentLoader, expansionMap}) { + if(!await super.matchProof( + {proof, document, purpose, documentLoader, expansionMap})) { + return false; + } + if(!this.key) { + // no key specified, so assume this suite matches and it can be retrieved + return true; + } + + const {verificationMethod} = proof; + + // only match if the key specified matches the one in the proof + if(typeof verificationMethod === 'object') { + return verificationMethod.id === this.key.id; + } + return verificationMethod === this.key.id; + } +} diff --git a/lib/create-jws.js b/lib/create-jws.js new file mode 100644 index 0000000..e132436 --- /dev/null +++ b/lib/create-jws.js @@ -0,0 +1,24 @@ +/*! + * Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved. + */ +import * as env from './env.js'; +import * as forge from 'node-forge'; + +export function createJwsFactory() { + if(env.nodejs) { + return ({encodedHeader, verifyData}) => { + const buffer = Buffer.concat([ + Buffer.from(encodedHeader + '.', 'utf8'), + Buffer.from(verifyData.buffer, verifyData.byteOffset, verifyData.length) + ]); + return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.length); + }; + } + + return ({encodedHeader, verifyData}) => { + const buffer = new forge.util.ByteBuffer(encodedHeader + '.', 'utf8'); + const binaryString = forge.util.binary.raw.encode(verifyData); + buffer.putBytes(binaryString); + return forge.util.binary.raw.decode(buffer.getBytes()); + }; +} diff --git a/lib/main.js b/lib/main.js index a01c5cd..602b672 100644 --- a/lib/main.js +++ b/lib/main.js @@ -1,4 +1,4 @@ /*! * Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved. */ -export {Example} from './Example.js'; +export {JwsLinkedDataSignature} from './JwsLinkedDataSignature.js'; diff --git a/package.json b/package.json index 43d8ff8..93083e3 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,10 @@ ], "module": "lib/main.js", "dependencies": { - "esm": "^3.2.25" + "base64url-universal": "^1.1.0", + "esm": "^3.2.25", + "jsonld-signatures": "digitalbazaar/jsonld-signatures#v6.x", + "node-forge": "^0.9.1" }, "devDependencies": { "@babel/core": "^7.11.0", @@ -46,7 +49,7 @@ "karma-mocha-reporter": "^2.2.5", "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^4.0.2", - "mocha": "^8.1.0", + "mocha": "^8.1.1", "mocha-lcov-reporter": "^1.3.0", "nyc": "^15.1.0", "webpack": "^4.44.1" diff --git a/tests/unit/Example.spec.js b/tests/unit/JwsLinkedDataSignature.spec.js similarity index 66% rename from tests/unit/Example.spec.js rename to tests/unit/JwsLinkedDataSignature.spec.js index 234e55c..bd6d8c6 100644 --- a/tests/unit/Example.spec.js +++ b/tests/unit/JwsLinkedDataSignature.spec.js @@ -7,12 +7,12 @@ chai.use(dirtyChai); chai.should(); const {expect} = chai; -import {Example} from '../../'; +import {JwsLinkedDataSignature} from '../../'; -describe('Example', () => { +describe('JwsLinkedDataSignature', () => { describe('constructor', () => { it('should exist', async () => { - const ex = new Example(); + const ex = new JwsLinkedDataSignature({type: 'ExampleType'}); expect(ex).to.exist(); }); From f0c9cba7c363f0ff8fc8cf04ee74384a63c7fff5 Mon Sep 17 00:00:00 2001 From: Dmitri Zagidulin Date: Sun, 9 Aug 2020 16:24:28 -0400 Subject: [PATCH 02/18] Add jsonld dep. --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 93083e3..a634d40 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "dependencies": { "base64url-universal": "^1.1.0", "esm": "^3.2.25", + "jsonld": "^2.0.2", "jsonld-signatures": "digitalbazaar/jsonld-signatures#v6.x", "node-forge": "^0.9.1" }, From db535a188ee1b2dd3f6dd3f8910ef41ca9b1bb01 Mon Sep 17 00:00:00 2001 From: Dmitri Zagidulin Date: Sun, 7 Mar 2021 00:00:16 -0500 Subject: [PATCH 03/18] Update copyright dates. --- lib/JwsLinkedDataSignature.js | 2 +- lib/create-jws.js | 2 +- lib/env.js | 2 +- lib/index.js | 2 +- lib/main.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/JwsLinkedDataSignature.js b/lib/JwsLinkedDataSignature.js index 45daf31..3001ea3 100644 --- a/lib/JwsLinkedDataSignature.js +++ b/lib/JwsLinkedDataSignature.js @@ -1,5 +1,5 @@ /*! - * Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved. + * Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved. */ import jsonld from 'jsonld'; import jsigs from 'jsonld-signatures'; diff --git a/lib/create-jws.js b/lib/create-jws.js index e132436..26d2158 100644 --- a/lib/create-jws.js +++ b/lib/create-jws.js @@ -1,5 +1,5 @@ /*! - * Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved. + * Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved. */ import * as env from './env.js'; import * as forge from 'node-forge'; diff --git a/lib/env.js b/lib/env.js index ed43c8a..e0c4e0c 100644 --- a/lib/env.js +++ b/lib/env.js @@ -1,5 +1,5 @@ /*! - * Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved. + * Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved. */ export const nodejs = ( typeof process !== 'undefined' && process.versions && process.versions.node); diff --git a/lib/index.js b/lib/index.js index c1ff223..e636804 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,5 @@ /*! - * Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved. + * Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved. */ 'use strict'; diff --git a/lib/main.js b/lib/main.js index 602b672..72cc01c 100644 --- a/lib/main.js +++ b/lib/main.js @@ -1,4 +1,4 @@ /*! - * Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved. + * Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved. */ export {JwsLinkedDataSignature} from './JwsLinkedDataSignature.js'; From a07db2024582818bea392c7f2061705ede904da7 Mon Sep 17 00:00:00 2001 From: Dmitri Zagidulin Date: Sun, 7 Mar 2021 00:03:17 -0500 Subject: [PATCH 04/18] Rename test directory. --- package.json | 4 ++-- {tests => test}/.eslintrc | 0 {tests => test}/karma.conf.js | 2 +- {tests => test}/unit/JwsLinkedDataSignature.spec.js | 6 ++---- 4 files changed, 5 insertions(+), 7 deletions(-) rename {tests => test}/.eslintrc (100%) rename {tests => test}/karma.conf.js (95%) rename {tests => test}/unit/JwsLinkedDataSignature.spec.js (68%) diff --git a/package.json b/package.json index a634d40..8d63426 100644 --- a/package.json +++ b/package.json @@ -78,8 +78,8 @@ ], "scripts": { "test": "npm run lint && npm run test-node && npm run test-karma", - "test-node": "cross-env NODE_ENV=test mocha -r esm --preserve-symlinks -t 10000 tests/**/*.spec.js", - "test-karma": "karma start tests/karma.conf.js", + "test-node": "cross-env NODE_ENV=test mocha -r esm --preserve-symlinks -t 10000 test/**/*.spec.js", + "test-karma": "karma start test/karma.conf.js", "coverage": "cross-env NODE_ENV=test nyc --reporter=lcov --reporter=text-summary npm run test-node", "coverage-ci": "cross-env NODE_ENV=test nyc --reporter=text-lcov npm run test-node > coverage.lcov", "coverage-report": "nyc report", diff --git a/tests/.eslintrc b/test/.eslintrc similarity index 100% rename from tests/.eslintrc rename to test/.eslintrc diff --git a/tests/karma.conf.js b/test/karma.conf.js similarity index 95% rename from tests/karma.conf.js rename to test/karma.conf.js index b763403..2681cd3 100644 --- a/tests/karma.conf.js +++ b/test/karma.conf.js @@ -39,7 +39,7 @@ module.exports = function(config) { singleRun: true, - // enable / disable watching file and executing tests whenever any + // enable / disable watching file and executing test whenever any // file changes autoWatch: false, diff --git a/tests/unit/JwsLinkedDataSignature.spec.js b/test/unit/JwsLinkedDataSignature.spec.js similarity index 68% rename from tests/unit/JwsLinkedDataSignature.spec.js rename to test/unit/JwsLinkedDataSignature.spec.js index bd6d8c6..39ebdda 100644 --- a/tests/unit/JwsLinkedDataSignature.spec.js +++ b/test/unit/JwsLinkedDataSignature.spec.js @@ -1,9 +1,7 @@ /*! - * Copyright (c) 2020 Digital Bazaar, Inc. All rights reserved. + * Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved. */ import chai from 'chai'; -import dirtyChai from 'dirty-chai'; -chai.use(dirtyChai); chai.should(); const {expect} = chai; @@ -14,7 +12,7 @@ describe('JwsLinkedDataSignature', () => { it('should exist', async () => { const ex = new JwsLinkedDataSignature({type: 'ExampleType'}); - expect(ex).to.exist(); + expect(ex).to.exist; }); }); }); From ce998086e12149e8ca28cd882a4ed23a69e1e76b Mon Sep 17 00:00:00 2001 From: Dmitri Zagidulin Date: Sun, 7 Mar 2021 00:05:40 -0500 Subject: [PATCH 05/18] Text-decode the Uint8Array returned from base64url decoding. --- lib/JwsLinkedDataSignature.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/JwsLinkedDataSignature.js b/lib/JwsLinkedDataSignature.js index 3001ea3..def4132 100644 --- a/lib/JwsLinkedDataSignature.js +++ b/lib/JwsLinkedDataSignature.js @@ -115,7 +115,8 @@ export class JwsLinkedDataSignature extends LinkedDataSignature { let header; try { - header = JSON.parse(decode(encodedHeader)); + const utf8decoder = new TextDecoder(); + header = JSON.parse(utf8decoder.decode(decode(encodedHeader))); } catch(e) { throw new Error('Could not parse JWS header; ' + e); } From 40afb2c0e238b89bd0cd20b1783fc2f52951290e Mon Sep 17 00:00:00 2001 From: Dmitri Zagidulin Date: Thu, 18 Mar 2021 17:17:51 -0400 Subject: [PATCH 06/18] Update to latest jsonld / jsigs deps. --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8d63426..314aa75 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ "dependencies": { "base64url-universal": "^1.1.0", "esm": "^3.2.25", - "jsonld": "^2.0.2", - "jsonld-signatures": "digitalbazaar/jsonld-signatures#v6.x", + "jsonld": "^5.0.0", + "jsonld-signatures": "digitalbazaar/jsonld-signatures#v8.x", "node-forge": "^0.9.1" }, "devDependencies": { From 680335f9626246667e85505d063befac799072b2 Mon Sep 17 00:00:00 2001 From: Dmitri Zagidulin Date: Thu, 18 Mar 2021 18:44:05 -0400 Subject: [PATCH 07/18] Remove node-forge and env.js script. --- lib/JwsLinkedDataSignature.js | 16 +++++++++++----- lib/create-jws.js | 24 ------------------------ lib/env.js | 8 -------- package.json | 2 +- 4 files changed, 12 insertions(+), 38 deletions(-) delete mode 100644 lib/create-jws.js delete mode 100644 lib/env.js diff --git a/lib/JwsLinkedDataSignature.js b/lib/JwsLinkedDataSignature.js index def4132..5204e07 100644 --- a/lib/JwsLinkedDataSignature.js +++ b/lib/JwsLinkedDataSignature.js @@ -5,9 +5,6 @@ import jsonld from 'jsonld'; import jsigs from 'jsonld-signatures'; const {LinkedDataSignature} = jsigs.suites; import {encode, decode} from 'base64url-universal'; -import {createJwsFactory} from './create-jws.js'; - -const createJws = createJwsFactory(); export class JwsLinkedDataSignature extends LinkedDataSignature { /** @@ -85,7 +82,11 @@ export class JwsLinkedDataSignature extends LinkedDataSignature { // create JWS data and sign const encodedHeader = encode(JSON.stringify(header)); - const data = createJws({encodedHeader, verifyData}); + // concatenate the two uint8arrays + const data = new Uint8Array(encodedHeader.length + verifyData.length); + data.set(encodedHeader, 0); + data.set(verifyData, encodedHeader.length); + const signature = await this.signer.sign({data}); // create detached content signature @@ -134,7 +135,12 @@ export class JwsLinkedDataSignature extends LinkedDataSignature { // do signature verification const signature = decode(encodedSignature); - const data = createJws({encodedHeader, verifyData}); + + // concatenate the two uint8arrays + const data = new Uint8Array(encodedHeader.length + verifyData.length); + data.set(encodedHeader, 0); + data.set(verifyData, encodedHeader.length); + let {verifier} = this; if(!verifier) { const key = await this.LDKeyClass.from(verificationMethod); diff --git a/lib/create-jws.js b/lib/create-jws.js deleted file mode 100644 index 26d2158..0000000 --- a/lib/create-jws.js +++ /dev/null @@ -1,24 +0,0 @@ -/*! - * Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved. - */ -import * as env from './env.js'; -import * as forge from 'node-forge'; - -export function createJwsFactory() { - if(env.nodejs) { - return ({encodedHeader, verifyData}) => { - const buffer = Buffer.concat([ - Buffer.from(encodedHeader + '.', 'utf8'), - Buffer.from(verifyData.buffer, verifyData.byteOffset, verifyData.length) - ]); - return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.length); - }; - } - - return ({encodedHeader, verifyData}) => { - const buffer = new forge.util.ByteBuffer(encodedHeader + '.', 'utf8'); - const binaryString = forge.util.binary.raw.encode(verifyData); - buffer.putBytes(binaryString); - return forge.util.binary.raw.decode(buffer.getBytes()); - }; -} diff --git a/lib/env.js b/lib/env.js deleted file mode 100644 index e0c4e0c..0000000 --- a/lib/env.js +++ /dev/null @@ -1,8 +0,0 @@ -/*! - * Copyright (c) 2020-2021 Digital Bazaar, Inc. All rights reserved. - */ -export const nodejs = ( - typeof process !== 'undefined' && process.versions && process.versions.node); - -export const browser = !nodejs && - (typeof window !== 'undefined' || typeof self !== 'undefined'); diff --git a/package.json b/package.json index 314aa75..7df4cb1 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "dirty-chai": "^2.0.1", "eslint": "^7.6.0", "eslint-config-digitalbazaar": "^2.5.0", - "eslint-plugin-jsdoc": "^30.2.0", + "eslint-plugin-jsdoc": "^32.3.0", "karma": "^5.1.1", "karma-babel-preprocessor": "^8.0.1", "karma-chai": "^0.1.0", From 8864b5a1c90752de4835563bb4c7fa951c469a4b Mon Sep 17 00:00:00 2001 From: Dmitri Zagidulin Date: Thu, 18 Mar 2021 19:03:26 -0400 Subject: [PATCH 08/18] Update to latest jsigs release, remove node-forge. --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 7df4cb1..c71f3aa 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,7 @@ "base64url-universal": "^1.1.0", "esm": "^3.2.25", "jsonld": "^5.0.0", - "jsonld-signatures": "digitalbazaar/jsonld-signatures#v8.x", - "node-forge": "^0.9.1" + "jsonld-signatures": "^8.0.0" }, "devDependencies": { "@babel/core": "^7.11.0", From e443e8799bd539143d0189d3c990627a81cb0076 Mon Sep 17 00:00:00 2001 From: Dmitri Zagidulin Date: Thu, 18 Mar 2021 19:04:43 -0400 Subject: [PATCH 09/18] Update lib/JwsLinkedDataSignature.js (fix format) Co-authored-by: Dave Longley --- lib/JwsLinkedDataSignature.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/JwsLinkedDataSignature.js b/lib/JwsLinkedDataSignature.js index 5204e07..0982f6f 100644 --- a/lib/JwsLinkedDataSignature.js +++ b/lib/JwsLinkedDataSignature.js @@ -31,7 +31,8 @@ export class JwsLinkedDataSignature extends LinkedDataSignature { */ constructor({ type, alg, LDKeyClass, verificationMethod, signer, key, proof, - date, useNativeCanonize} = {}) { + date, useNativeCanonize + } = {}) { super({type, verificationMethod, proof, date, useNativeCanonize}); this.alg = alg; this.LDKeyClass = LDKeyClass; From 3654abd443c24677341ce1de82edc83c675f502a Mon Sep 17 00:00:00 2001 From: Dmitri Zagidulin Date: Thu, 18 Mar 2021 19:07:16 -0400 Subject: [PATCH 10/18] Add note about contexts. --- lib/JwsLinkedDataSignature.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/JwsLinkedDataSignature.js b/lib/JwsLinkedDataSignature.js index 0982f6f..2383406 100644 --- a/lib/JwsLinkedDataSignature.js +++ b/lib/JwsLinkedDataSignature.js @@ -173,6 +173,9 @@ export class JwsLinkedDataSignature extends LinkedDataSignature { {proof, document, purpose, documentLoader, expansionMap})) { return false; } + // NOTE: When subclassing this suite: Extending suites will need to check + // for the presence their contexts here and in sign() + if(!this.key) { // no key specified, so assume this suite matches and it can be retrieved return true; From 7b79d80efc7c394cca2ad74913289b3c28b69dc3 Mon Sep 17 00:00:00 2001 From: Dmitri Zagidulin Date: Thu, 18 Mar 2021 20:06:07 -0400 Subject: [PATCH 11/18] Fix jws creation. --- lib/JwsLinkedDataSignature.js | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/JwsLinkedDataSignature.js b/lib/JwsLinkedDataSignature.js index 2383406..f1a9e5f 100644 --- a/lib/JwsLinkedDataSignature.js +++ b/lib/JwsLinkedDataSignature.js @@ -83,10 +83,8 @@ export class JwsLinkedDataSignature extends LinkedDataSignature { // create JWS data and sign const encodedHeader = encode(JSON.stringify(header)); - // concatenate the two uint8arrays - const data = new Uint8Array(encodedHeader.length + verifyData.length); - data.set(encodedHeader, 0); - data.set(verifyData, encodedHeader.length); + + const data = _createJws({encodedHeader, verifyData}); const signature = await this.signer.sign({data}); @@ -137,10 +135,7 @@ export class JwsLinkedDataSignature extends LinkedDataSignature { // do signature verification const signature = decode(encodedSignature); - // concatenate the two uint8arrays - const data = new Uint8Array(encodedHeader.length + verifyData.length); - data.set(encodedHeader, 0); - data.set(verifyData, encodedHeader.length); + const data = _createJws({encodedHeader, verifyData}); let {verifier} = this; if(!verifier) { @@ -190,3 +185,20 @@ export class JwsLinkedDataSignature extends LinkedDataSignature { return verificationMethod === this.key.id; } } + +/** + * Creates the bytes ready for signing. + * + * @param {string} encodedHeader - base64url encoded JWT header. + * @param {Uint8Array} verifyData - Payload to sign/verify. + * @returns {Uint8Array} A combined byte array for signing. + */ +function _createJws({encodedHeader, verifyData}) { + const encodedHeaderBytes = new TextEncoder().encode(encodedHeader + '.'); + + // concatenate the two uint8arrays + const data = new Uint8Array(encodedHeaderBytes.length + verifyData.length); + data.set(encodedHeaderBytes, 0); + data.set(verifyData, encodedHeaderBytes.length); + return data; +} From 258ed66fe78495b1c81a4f3200534bb68cd1637f Mon Sep 17 00:00:00 2001 From: Dmitri Zagidulin Date: Thu, 18 Mar 2021 20:23:33 -0400 Subject: [PATCH 12/18] Update version in readme. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d0c4cf..ba59845 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ## Background -For use with https://github.com/digitalbazaar/jsonld-signatures v6.0 and above. +For use with https://github.com/digitalbazaar/jsonld-signatures v8.0 and above. ## Security From 9f05fa22da72c9a34a879420519eac1d0671ff49 Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Thu, 18 Mar 2021 20:48:10 -0400 Subject: [PATCH 13/18] Add test note. --- test/unit/JwsLinkedDataSignature.spec.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/unit/JwsLinkedDataSignature.spec.js b/test/unit/JwsLinkedDataSignature.spec.js index 39ebdda..2a284ec 100644 --- a/test/unit/JwsLinkedDataSignature.spec.js +++ b/test/unit/JwsLinkedDataSignature.spec.js @@ -7,6 +7,10 @@ const {expect} = chai; import {JwsLinkedDataSignature} from '../../'; +/** + * NOTE: Test coverage of this package currently depends on indirect testing + * through other signature package test suites. + */ describe('JwsLinkedDataSignature', () => { describe('constructor', () => { it('should exist', async () => { From 3936c47ee6e88ebc8812311a6af19163f2cbce92 Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Thu, 18 Mar 2021 20:51:24 -0400 Subject: [PATCH 14/18] Remove unused karma babel support. --- package.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/package.json b/package.json index c71f3aa..daa57e6 100644 --- a/package.json +++ b/package.json @@ -29,12 +29,6 @@ "jsonld-signatures": "^8.0.0" }, "devDependencies": { - "@babel/core": "^7.11.0", - "@babel/plugin-transform-modules-commonjs": "^7.10.4", - "@babel/plugin-transform-runtime": "^7.11.0", - "@babel/preset-env": "^7.11.0", - "@babel/runtime": "^7.11.0", - "babel-loader": "^8.1.0", "chai": "^4.2.0", "cross-env": "^7.0.2", "dirty-chai": "^2.0.1", @@ -42,7 +36,6 @@ "eslint-config-digitalbazaar": "^2.5.0", "eslint-plugin-jsdoc": "^32.3.0", "karma": "^5.1.1", - "karma-babel-preprocessor": "^8.0.1", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^3.1.0", "karma-mocha": "^2.0.1", From bf04d640edc7d6d55a087c33346c241cd930d4d8 Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Thu, 18 Mar 2021 20:53:35 -0400 Subject: [PATCH 15/18] Add editor files. --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 6704566..74c12ad 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,7 @@ dist # TernJS port file .tern-port + +# Editor files +*~ +*.sw[nop] From 6353c4ec025ba9cd83f693b00e3094e7d6c203c9 Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Thu, 18 Mar 2021 20:53:44 -0400 Subject: [PATCH 16/18] Fix test dir name. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index daa57e6..a5a3abc 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ }, "nyc": { "exclude": [ - "tests" + "test" ], "reporter": [ "html", From ebe261756ddf532e6124d1834a6e0d52d4807954 Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Thu, 18 Mar 2021 21:15:43 -0400 Subject: [PATCH 17/18] Update changelog. --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e42b410..18f4820 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ -# isomorphic-js-lib-template Changelog +# @digitalbazaar/jws-linked-data-signature Changelog ## 1.0.0 - TBD ### Added -- Initial commit. +- Initial files extracted from https://github.com/digitalbazaar/jsonld-signatures. From 2bf931e63d69d10e003f5c440cc7efde4e56d519 Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Thu, 18 Mar 2021 21:34:33 -0400 Subject: [PATCH 18/18] Update badges. --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ba59845..33eb3d7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # JwsLinkedDataSignature suite _(@digitalbazaar/jws-linked-data-signature)_ -[![Node.js CI](https://github.com/digitalbazaar/jws-linked-data-signature/workflows/Node.js%20CI/badge.svg)](https://github.com/digitalbazaar/jws-linked-data-signature/actions?query=workflow%3A%22Node.js+CI%22) +[![Build status](https://img.shields.io/github/workflow/status/digitalbazaar/jws-linked-data-signature/Node.js%20CI)](https://github.com/digitalbazaar/jws-linked-data-signature/actions?query=workflow%3A%22Node.js+CI%22) +[![Coverage status](https://img.shields.io/codecov/c/github/digitalbazaar/jws-linked-data-signature)](https://codecov.io/gh/digitalbazaar/jws-linked-data-signature) +[![Dependency Status](https://img.shields.io/david/digitalbazaar/jws-linked-data-signature.svg)](https://david-dm.org/digitalbazaar/jws-linked-data-signature) +[![NPM Version](https://img.shields.io/npm/v/digitalbazaar/jws-linked-data-signature.svg)](https://npm.im/digitalbazaar/jws-linked-data-signature) > Abstract Linked Data Proof suite for use with jsonld-signatures with Ed25519Signature2018 and RsaSignature2018 suites.