From bcd920600dab07e87b1406d9ebfbd54925577a7f Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Sat, 16 Feb 2019 14:12:47 +0100 Subject: [PATCH] test: keystore verify --- lib/jwk/import.js | 2 +- lib/jws/verify.js | 23 +++++++++------- test/cookbook/4_1.rsa_v15_signature.test.js | 27 +++++++++++++++---- test/cookbook/4_2.rsa-pss_signature.test.js | 21 +++++++++++++-- test/cookbook/4_3.ecdsa_signature.test.js | 21 +++++++++++++-- ...4_4.hmac-sha2_integrity_protection.test.js | 21 +++++++++++++-- ....protecting_specific_header_fields.test.js | 17 ++++++++++-- .../4_7.protecting_content_only.test.js | 17 ++++++++++-- test/cookbook/4_8.multiple_signatures.test.js | 7 ++++- 9 files changed, 129 insertions(+), 27 deletions(-) diff --git a/lib/jwk/import.js b/lib/jwk/import.js index f1d00631..3f3681d3 100644 --- a/lib/jwk/import.js +++ b/lib/jwk/import.js @@ -13,7 +13,7 @@ const importable = new Set(['string', 'buffer', 'object']) const parametersTypes = new Set(['object', 'undefined']) const mergedParameters = (target = {}, source = {}) => { - return Object.assign({}, { alg: source.alg, use: source.use }, target) + return Object.assign({}, { alg: source.alg, use: source.use, kid: source.kid }, target) } const importKey = (key, parameters) => { diff --git a/lib/jws/verify.js b/lib/jws/verify.js index 8588f2ed..4881c23d 100644 --- a/lib/jws/verify.js +++ b/lib/jws/verify.js @@ -40,19 +40,22 @@ const jwsVerify = (skipValidateHeaders = false, serialization, jws, key) => { const keystore = key const combinedHeader = { ...parsedProt, ...header } const keys = keystore.all(combinedHeader) - - for (const key of keys) { - try { - return jwsVerify(true, serialization, jws, key) - } catch (err) { - if (err instanceof JWSVerificationFailed) { - continue + if (keys.length === 1) { + key = keys[0] + } else { + for (const key of keys) { + try { + return jwsVerify(true, serialization, jws, key) + } catch (err) { + if (err instanceof JWSVerificationFailed) { + continue + } + throw err } - throw err } - } - throw new JWSVerificationFailed() + throw new JWSVerificationFailed() + } } alg = parsedProt.alg || header.alg diff --git a/test/cookbook/4_1.rsa_v15_signature.test.js b/test/cookbook/4_1.rsa_v15_signature.test.js index 4e401327..332ed949 100644 --- a/test/cookbook/4_1.rsa_v15_signature.test.js +++ b/test/cookbook/4_1.rsa_v15_signature.test.js @@ -2,11 +2,14 @@ const test = require('ava') const recipe = require('./recipes').get('4.1') -const { JWS, JWK } = require('../..') +const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore } } = require('../..') const { input: { payload, key: jwk }, signing: { protected: header } } = recipe -const key = JWK.importKey(jwk) +const key = importKey(jwk) + +const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) test(`${recipe.title} - compact sign`, t => { t.is(JWS.sign(payload, key, header), recipe.output.compact) @@ -20,14 +23,28 @@ test(`${recipe.title} - general sign`, t => { t.deepEqual(JWS.sign.general(payload, key, header), recipe.output.json) }) -test(`${recipe.title} - compact verify`, t => { +test(`${recipe.title} - compact verify (using key)`, t => { t.is(JWS.verify(recipe.output.compact, key), payload) }) -test(`${recipe.title} - flattened verify`, t => { +test(`${recipe.title} - flattened verify (using key)`, t => { t.is(JWS.verify(recipe.output.json_flat, key), payload) }) -test(`${recipe.title} - general verify`, t => { +test(`${recipe.title} - general verify (using key)`, t => { t.is(JWS.verify(recipe.output.json, key), payload) }) + +;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { + test(`${recipe.title} - compact verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.compact, keystore), payload) + }) + + test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.json_flat, keystore), payload) + }) + + test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.json, keystore), payload) + }) +}) diff --git a/test/cookbook/4_2.rsa-pss_signature.test.js b/test/cookbook/4_2.rsa-pss_signature.test.js index 58c3b0f5..bbce4692 100644 --- a/test/cookbook/4_2.rsa-pss_signature.test.js +++ b/test/cookbook/4_2.rsa-pss_signature.test.js @@ -2,11 +2,14 @@ const test = require('ava') const recipe = require('./recipes').get('4.2') -const { JWS, JWK } = require('../..') +const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore } } = require('../..') const { input: { payload, key: jwk }, signing: { protected: header } } = recipe -const key = JWK.importKey(jwk) +const key = importKey(jwk) + +const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) test(`${recipe.title} - compact sign (random)`, t => { const res = JWS.sign(payload, key, header) @@ -37,3 +40,17 @@ test(`${recipe.title} - flattened verify`, t => { test(`${recipe.title} - general verify`, t => { t.is(JWS.verify(recipe.output.json, key), payload) }) + +;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { + test(`${recipe.title} - compact verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.compact, keystore), payload) + }) + + test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.json_flat, keystore), payload) + }) + + test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.json, keystore), payload) + }) +}) diff --git a/test/cookbook/4_3.ecdsa_signature.test.js b/test/cookbook/4_3.ecdsa_signature.test.js index f40a58f9..e06d18ae 100644 --- a/test/cookbook/4_3.ecdsa_signature.test.js +++ b/test/cookbook/4_3.ecdsa_signature.test.js @@ -2,11 +2,14 @@ const test = require('ava') const recipe = require('./recipes').get('4.3') -const { JWS, JWK } = require('../..') +const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore } } = require('../..') const { input: { payload, key: jwk }, signing: { protected: header } } = recipe -const key = JWK.importKey(jwk) +const key = importKey(jwk) + +const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use }), key) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.crv, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) test(`${recipe.title} - compact sign (random)`, t => { const res = JWS.sign(payload, key, header) @@ -37,3 +40,17 @@ test(`${recipe.title} - flattened verify`, t => { test(`${recipe.title} - general verify`, t => { t.is(JWS.verify(recipe.output.json, key), payload) }) + +;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { + test(`${recipe.title} - compact verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.compact, keystore), payload) + }) + + test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.json_flat, keystore), payload) + }) + + test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.json, keystore), payload) + }) +}) diff --git a/test/cookbook/4_4.hmac-sha2_integrity_protection.test.js b/test/cookbook/4_4.hmac-sha2_integrity_protection.test.js index 35a4b55d..5380047c 100644 --- a/test/cookbook/4_4.hmac-sha2_integrity_protection.test.js +++ b/test/cookbook/4_4.hmac-sha2_integrity_protection.test.js @@ -2,11 +2,14 @@ const test = require('ava') const recipe = require('./recipes').get('4.4') -const { JWS, JWK } = require('../..') +const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore } } = require('../..') const { input: { payload, key: jwk }, signing: { protected: header } } = recipe -const key = JWK.importKey(jwk) +const key = importKey(jwk) + +const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) test(`${recipe.title} - compact sign`, t => { t.is(JWS.sign(payload, key, header), recipe.output.compact) @@ -31,3 +34,17 @@ test(`${recipe.title} - flattened verify`, t => { test(`${recipe.title} - general verify`, t => { t.is(JWS.verify(recipe.output.json, key), payload) }) + +;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { + test(`${recipe.title} - compact verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.compact, keystore), payload) + }) + + test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.json_flat, keystore), payload) + }) + + test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.json, keystore), payload) + }) +}) diff --git a/test/cookbook/4_6.protecting_specific_header_fields.test.js b/test/cookbook/4_6.protecting_specific_header_fields.test.js index d7ed7dd1..479a256f 100644 --- a/test/cookbook/4_6.protecting_specific_header_fields.test.js +++ b/test/cookbook/4_6.protecting_specific_header_fields.test.js @@ -2,11 +2,14 @@ const test = require('ava') const recipe = require('./recipes').get('4.6') -const { JWS, JWK } = require('../..') +const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore } } = require('../..') const { input: { payload, key: jwk }, signing: { protected: protec, unprotected } } = recipe -const key = JWK.importKey(jwk) +const key = importKey(jwk) + +const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) test(`${recipe.title} - flattened sign`, t => { t.deepEqual(JWS.sign.flattened(payload, key, protec, unprotected), recipe.output.json_flat) @@ -23,3 +26,13 @@ test(`${recipe.title} - flattened verify`, t => { test(`${recipe.title} - general verify`, t => { t.is(JWS.verify(recipe.output.json, key), payload) }) + +;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { + test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.json_flat, keystore), payload) + }) + + test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.json, keystore), payload) + }) +}) diff --git a/test/cookbook/4_7.protecting_content_only.test.js b/test/cookbook/4_7.protecting_content_only.test.js index 8a8073c1..868e1072 100644 --- a/test/cookbook/4_7.protecting_content_only.test.js +++ b/test/cookbook/4_7.protecting_content_only.test.js @@ -2,11 +2,14 @@ const test = require('ava') const recipe = require('./recipes').get('4.7') -const { JWS, JWK } = require('../..') +const { JWS, JWK: { importKey, generateSync }, JWKS: { KeyStore } } = require('../..') const { input: { payload, key: jwk }, signing: { unprotected } } = recipe -const key = JWK.importKey(jwk) +const key = importKey(jwk) + +const keystoreMatchOne = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use }), key) +const keystoreMatchMore = new KeyStore(generateSync(key.kty, key.length, { alg: key.alg, use: key.use, kid: key.kid }), key, importKey(key)) test(`${recipe.title} - flattened sign`, t => { t.deepEqual(JWS.sign.flattened(payload, key, undefined, unprotected), recipe.output.json_flat) @@ -23,3 +26,13 @@ test(`${recipe.title} - flattened verify`, t => { test(`${recipe.title} - general verify`, t => { t.is(JWS.verify(recipe.output.json, key), payload) }) + +;[keystoreMatchOne, keystoreMatchMore].forEach((keystore, i) => { + test(`${recipe.title} - flattened verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.json_flat, keystore), payload) + }) + + test(`${recipe.title} - general verify (using keystore ${i + 1}/2)`, t => { + t.is(JWS.verify(recipe.output.json, keystore), payload) + }) +}) diff --git a/test/cookbook/4_8.multiple_signatures.test.js b/test/cookbook/4_8.multiple_signatures.test.js index 102b0cd7..9bf3ed1a 100644 --- a/test/cookbook/4_8.multiple_signatures.test.js +++ b/test/cookbook/4_8.multiple_signatures.test.js @@ -2,11 +2,12 @@ const test = require('ava') const recipe = require('./recipes').get('4.8') -const { JWS, JWK } = require('../..') +const { JWS, JWK, JWKS: { KeyStore } } = require('../..') const { input: { payload, key: jwks }, signing: recipients } = recipe const keys = jwks.map((jwk) => JWK.importKey(jwk)) +const keystore = new KeyStore(...keys) test(`${recipe.title} - general sign`, t => { const jws = new JWS.Sign(payload) @@ -34,3 +35,7 @@ keys.forEach((key, i) => { t.is(JWS.verify(recipe.output.json, key), payload) }) }) + +test(`${recipe.title} - general verify - keystore`, t => { + t.is(JWS.verify(recipe.output.json, keystore), payload) +})