Skip to content

Commit

Permalink
fix: swallow invalid signature encoding errors
Browse files Browse the repository at this point in the history
  • Loading branch information
panva committed Mar 11, 2021
1 parent 348b837 commit e0adf49
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 8 deletions.
7 changes: 6 additions & 1 deletion src/runtime/browser/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ const verify: VerifyFunction = async (alg, key: CryptoKey | Uint8Array, signatur

checkKeyLength(alg, cryptoKey)

return crypto.subtle.verify(subtleAlgorithm(alg), cryptoKey, signature, data)
const algorithm = subtleAlgorithm(alg)
try {
return await crypto.subtle.verify(algorithm, cryptoKey, signature, data)
} catch {
return false
}
}

export default verify
7 changes: 6 additions & 1 deletion src/runtime/node/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ const verify: VerifyFunction = async (alg, key: KeyLike, signature, data) => {
throw new TypeError('invalid key object type provided')
}

return oneShotVerify(algorithm, data, nodeKey(alg, key), signature)
const keyInput = nodeKey(alg, key)
try {
return oneShotVerify(algorithm, data, keyInput, signature)
} catch {
return false
}
}

export default verify
47 changes: 41 additions & 6 deletions test/jws/restrictions.test.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable no-param-reassign */
import test from 'ava';
import * as crypto from 'crypto';

let root;
let keyRoot;
Expand All @@ -19,6 +20,8 @@ Promise.all([
import(`${root}/jwe/flattened/encrypt`),
import(`${root}/jwe/flattened/decrypt`),
import(`${root}/util/random`),
import(`${root}/util/base64url`),
import(`${keyRoot}/util/generate_key_pair`),
import(`${keyRoot}/jwk/parse`),
]).then(
([
Expand All @@ -27,6 +30,8 @@ Promise.all([
{ default: FlattenedEncrypt },
{ default: flattenedDecrypt },
{ default: random },
base64url,
{ default: generateKeyPair },
{ default: parseJwk },
]) => {
function pubjwk(jwk) {
Expand Down Expand Up @@ -143,6 +148,25 @@ Promise.all([
testRSAenc.title = (title, alg) =>
`${alg} requires key modulusLength to be 2048 bits or larger`;

async function testECDSASigEncoding(t, alg) {
const { privateKey, publicKey } = await generateKeyPair(alg);

const jws = await new FlattenedSign(t.context.payload)
.setProtectedHeader({ alg })
.sign(privateKey);

const derEncodedSignature = base64url.encode(
crypto.sign(`sha${alg.substr(2, 3)}`, Buffer.from('foo'), privateKey),
);

await t.throwsAsync(flattenedVerify({ ...jws, signature: derEncodedSignature }, publicKey), {
message: 'signature verification failed',
code: 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED',
});
}
testECDSASigEncoding.title = (title, alg) =>
`${alg} swallows invalid signature encoding errors`;

test(testRSAsig, 'RS256');
test(testRSAsig, 'PS256');
test(testRSAsig, 'RS384');
Expand All @@ -155,13 +179,24 @@ Promise.all([
test(testRSAenc, 'RSA-OAEP-384');
test(testRSAenc, 'RSA-OAEP-512');

let conditional;
if ('WEBCRYPTO' in process.env || 'CRYPTOKEY' in process.env) {
conditional = test.failing;
} else {
conditional = test;
test(testECDSASigEncoding, 'ES256');
test(testECDSASigEncoding, 'ES384');
test(testECDSASigEncoding, 'ES512');

function conditional({ webcrypto = 1, electron = 1 } = {}, ...args) {
let run = test;
if ((!webcrypto && 'WEBCRYPTO' in process.env) || 'CRYPTOKEY' in process.env) {
run = run.failing;
}

if (!electron && 'electron' in process.versions) {
run = run.failing;
}
return run;
}
conditional(testRSAenc, 'RSA1_5');

conditional({ webcrypto: 0 })(testRSAenc, 'RSA1_5');
conditional({ webcrypto: 0, electron: 0 })(testECDSASigEncoding, 'ES256K');
},
(err) => {
test('failed to import', (t) => {
Expand Down

0 comments on commit e0adf49

Please sign in to comment.