From 4814207cfed7cdbd4484e539d18c9cd2d0461ffb Mon Sep 17 00:00:00 2001 From: Yarmo Mackenbach Date: Tue, 20 Sep 2022 21:37:09 +0200 Subject: [PATCH 1/6] Add hash dependency --- package.json | 1 + yarn.lock | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/package.json b/package.json index 2b97a88..58f607c 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dotenv": "^8.2.0", "express": "^4.17.1", "express-validator": "^6.10.0", + "hash-wasm": "^4.9.0", "irc-upd": "^0.11.0", "jsdom": "^20.0.0", "merge-options": "^3.0.3", diff --git a/yarn.lock b/yarn.lock index c558af9..b15782d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2801,6 +2801,11 @@ hash-base@^3.0.0: readable-stream "^3.6.0" safe-buffer "^5.2.0" +hash-wasm@^4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/hash-wasm/-/hash-wasm-4.9.0.tgz#7e9dcc9f7d6bd0cc802f2a58f24edce999744206" + integrity sha512-7SW7ejyfnRxuOc7ptQHSf4LDoZaWOivfzqw+5rpcQku0nHfmicPKE51ra9BiRLAmT8+gGLestr1XroUkqdjL6w== + hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" From 9dc2b9fae8527ed8e5e5f71eb242ca65763b85af Mon Sep 17 00:00:00 2001 From: Yarmo Mackenbach Date: Tue, 20 Sep 2022 21:37:39 +0200 Subject: [PATCH 2/6] Export verifications --- src/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.js b/src/index.js index e2e71ca..31ad312 100644 --- a/src/index.js +++ b/src/index.js @@ -21,6 +21,7 @@ const signatures = require('./signatures') const enums = require('./enums') const defaults = require('./defaults') const utils = require('./utils') +const verifications = require('./verifications') exports.Claim = Claim exports.claimDefinitions = claimDefinitions @@ -30,3 +31,4 @@ exports.signatures = signatures exports.enums = enums exports.defaults = defaults exports.utils = utils +exports.verifications = verifications From 4784c9b1898c396476caa5167ed92e5c138cdf66 Mon Sep 17 00:00:00 2001 From: Yarmo Mackenbach Date: Tue, 20 Sep 2022 21:38:11 +0200 Subject: [PATCH 3/6] Implement hashed proof logic --- src/verifications.js | 66 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/src/verifications.js b/src/verifications.js index 2caa419..40534de 100644 --- a/src/verifications.js +++ b/src/verifications.js @@ -15,21 +15,64 @@ limitations under the License. */ const utils = require('./utils') const E = require('./enums') +const { bcryptVerify, argon2Verify } = require('hash-wasm') /** * @module verifications * @ignore */ -const containsProof = async (data, target) => { +const containsProof = async (data, fingerprint, claimFormat) => { + const fingerprintFormatted = utils.generateClaim(fingerprint, claimFormat) + const fingerprintURI = utils.generateClaim(fingerprint, E.ClaimFormat.URI) let result = false // Check for plaintext proof result = data.replace(/\r?\n|\r/g, '') .toLowerCase() - .indexOf(target.toLowerCase()) !== -1 + .indexOf(fingerprintFormatted.toLowerCase()) !== -1 - // Check for HTTP proof if plaintext not found + // Check for hashed proof + if (!result) { + const hashRe = /\$(argon2(?:id|d|i)|2a|2b|2y)(?:\$[a-zA-Z0-9=+\-,.]+)+/g + let match + + while (!result && (match = hashRe.exec(data)) != null) { + switch (match[1]) { + case '2a': + case '2b': + case '2y': + try { + result = await bcryptVerify({ + password: fingerprintURI, + hash: match[0] + }) + } catch (err) { + result = false + } + break + + case 'argon2': + case 'argon2i': + case 'argon2d': + case 'argon2id': + try { + result = await argon2Verify({ + password: fingerprintURI, + hash: match[0] + }) + } catch (err) { + result = false + } + break + + default: + continue + } + } + } + + // Check for HTTP proof if (!result) { const uris = utils.getUriFromString(data) @@ -63,14 +106,14 @@ const containsProof = async (data, target) => { result = response.headers.get('ariadne-identity-proof') .toLowerCase() - .indexOf(target.toLowerCase()) !== -1 + .indexOf(fingerprintURI.toLowerCase()) !== -1 } } return result } -const runJSON = async (proofData, checkPath, checkClaim, checkRelation) => { +const runJSON = async (proofData, checkPath, checkClaim, checkClaimFormat, checkRelation) => { if (!proofData) { return false } @@ -85,7 +128,7 @@ const runJSON = async (proofData, checkPath, checkClaim, checkRelation) => { continue } - result = await runJSON(item, checkPath, checkClaim, checkRelation) + result = await runJSON(item, checkPath, checkClaim, checkClaimFormat, checkRelation) } return result @@ -94,12 +137,12 @@ const runJSON = async (proofData, checkPath, checkClaim, checkRelation) => { if (checkPath.length === 0) { switch (checkRelation) { case E.ClaimRelation.ONEOF: - return await containsProof(proofData.join('|'), checkClaim) + return await containsProof(proofData.join('|'), checkClaim, checkClaimFormat) case E.ClaimRelation.CONTAINS: case E.ClaimRelation.EQUALS: default: - return await containsProof(proofData, checkClaim) + return await containsProof(proofData, checkClaim, checkClaimFormat) } } @@ -111,6 +154,7 @@ const runJSON = async (proofData, checkPath, checkClaim, checkRelation) => { proofData[checkPath[0]], checkPath.slice(1), checkClaim, + checkClaimFormat, checkRelation ) } @@ -136,7 +180,8 @@ const run = async (proofData, claimData, fingerprint) => { res.result = await runJSON( proofData, claimData.claim.path, - utils.generateClaim(fingerprint, claimData.claim.format), + fingerprint, + claimData.claim.format, claimData.claim.relation ) res.completed = true @@ -147,7 +192,8 @@ const run = async (proofData, claimData, fingerprint) => { case E.ProofFormat.TEXT: try { res.result = await containsProof(proofData, - utils.generateClaim(fingerprint, claimData.claim.format)) + fingerprint, + claimData.claim.format) res.completed = true } catch (error) { res.errors.push('err_unknown_text_verification') From 5a15238ab595bfb46078eab7664fa194a6d31a1f Mon Sep 17 00:00:00 2001 From: Yarmo Mackenbach Date: Tue, 20 Sep 2022 21:44:29 +0200 Subject: [PATCH 4/6] Add tests for proof verifications --- test/verifications.test.js | 70 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 test/verifications.test.js diff --git a/test/verifications.test.js b/test/verifications.test.js new file mode 100644 index 0000000..6b788ad --- /dev/null +++ b/test/verifications.test.js @@ -0,0 +1,70 @@ +/* +Copyright 2022 Yarmo Mackenbach + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +const chai = require('chai') +const expect = chai.expect +chai.use(require('chai-as-promised')) + +const doipjs = require('../dist/doip') +// const verifications = require('../dist/verifications') +// const verifications = require('../src/verifications') + +const fingerprint = '3637202523e7c1309ab79e99ef2dc5827b445f4b' +const plaintextCorrectProofData = [ + 'openpgp4fpr:3637202523e7c1309ab79e99ef2dc5827b445f4b' +] +const plaintextIncorrectProofData = [ + 'openpgp4pr:b4f544b7285cd2fe99e97ba9031c7e3252027363' +] +const argon2CorrectProofData = [ + '$argon2id$v=19$m=16,t=2,p=1$UElOT0ZIU09mSHlReE1lcg$2nJmgFL0s3DHPksuSE2enw' +] +const argon2IncorrectProofData = [ + '$argon2id$v=19$m=16,t=2,p=1$UElOT0ZIU09mSHlReE1lcg$QH+tj5w78d2MZ8PrmOjXqQ' +] +const bcryptCorrectProofData = [ + '$2a$10$zNJGxR.xyKZ7djXpwWshpuhULOhRxerqRVZ.14fJAnkSPVxKSqGBC' +] +const bcryptIncorrectProofData = [ + '$2y$10$iHUhy320iUqJRVh7a/WlneAuJA/xRI/YEv7qxW8jfCDVmC7bmezX2' +] +const claimData = doipjs.claimDefinitions.data.irc.processURI('irc://domain.tld/test') + +describe('run', () => { + it('should verify a plaintext proof', async () => { + const result = await doipjs.verifications.run(plaintextCorrectProofData, claimData, fingerprint) + expect(result.result).to.be.true + }) + it('should not verify a wrong plaintext proof', async () => { + const result = await doipjs.verifications.run(plaintextIncorrectProofData, claimData, fingerprint) + expect(result.result).to.be.false + }) + it('should verify a argon2-hashed proof', async () => { + const result = await doipjs.verifications.run(argon2CorrectProofData, claimData, fingerprint) + expect(result.result).to.be.true + }) + it('should not verify a wrong argon2-hashed proof', async () => { + const result = await doipjs.verifications.run(argon2IncorrectProofData, claimData, fingerprint) + expect(result.result).to.be.false + }) + it('should verify a bcrypt-hashed proof', async () => { + const result = await doipjs.verifications.run(bcryptCorrectProofData, claimData, fingerprint) + expect(result.result).to.be.true + }) + it('should not verify a wrong bcrypt-hashed proof', async () => { + const result = await doipjs.verifications.run(bcryptIncorrectProofData, claimData, fingerprint) + expect(result.result).to.be.false + }) +}) From 45c08ffda7743a558c03ba6ce3858ca181534846 Mon Sep 17 00:00:00 2001 From: Yarmo Mackenbach Date: Tue, 20 Sep 2022 21:48:25 +0200 Subject: [PATCH 5/6] Remove commented code --- test/verifications.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/verifications.test.js b/test/verifications.test.js index 6b788ad..931bd6d 100644 --- a/test/verifications.test.js +++ b/test/verifications.test.js @@ -18,8 +18,6 @@ const expect = chai.expect chai.use(require('chai-as-promised')) const doipjs = require('../dist/doip') -// const verifications = require('../dist/verifications') -// const verifications = require('../src/verifications') const fingerprint = '3637202523e7c1309ab79e99ef2dc5827b445f4b' const plaintextCorrectProofData = [ From 4ae4decf91aabd30f4e6ab7773e458445947ef70 Mon Sep 17 00:00:00 2001 From: Yarmo Mackenbach Date: Tue, 20 Sep 2022 21:53:30 +0200 Subject: [PATCH 6/6] Fix require reference --- test/verifications.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/verifications.test.js b/test/verifications.test.js index 931bd6d..99ed401 100644 --- a/test/verifications.test.js +++ b/test/verifications.test.js @@ -17,7 +17,7 @@ const chai = require('chai') const expect = chai.expect chai.use(require('chai-as-promised')) -const doipjs = require('../dist/doip') +const doipjs = require('../src') const fingerprint = '3637202523e7c1309ab79e99ef2dc5827b445f4b' const plaintextCorrectProofData = [ @@ -40,7 +40,7 @@ const bcryptIncorrectProofData = [ ] const claimData = doipjs.claimDefinitions.data.irc.processURI('irc://domain.tld/test') -describe('run', () => { +describe('verifications.run', () => { it('should verify a plaintext proof', async () => { const result = await doipjs.verifications.run(plaintextCorrectProofData, claimData, fingerprint) expect(result.result).to.be.true