diff --git a/lib/help/key_object.js b/lib/help/key_object.js index b1d3bcde..c335a697 100644 --- a/lib/help/key_object.js +++ b/lib/help/key_object.js @@ -32,6 +32,26 @@ if (!keyObjectSupported) { const pemToDer = pem => Buffer.from(pem.replace(/(?:-----(?:BEGIN|END)(?: (?:RSA|EC))? (?:PRIVATE|PUBLIC) KEY-----|\s)/g, ''), 'base64') const derToPem = (der, label) => `-----BEGIN ${label}-----${EOL}${der.toString('base64').match(/.{1,64}/g).join(EOL)}${EOL}-----END ${label}-----` + const unsupported = (label) => { + switch (label) { + case '1.3.101.110': + label = 'X25519' + break + case '1.3.101.111': + label = 'X448' + break + case '1.3.101.112': + label = 'Ed25519' + break + case '1.3.101.113': + label = 'Ed448' + break + default: + label = `OID ${label}` + } + + throw new errors.JOSENotSupported(`${label} is not supported in your Node.js runtime version`) + } KeyObject = class KeyObject { export ({ cipher, passphrase, type, format } = {}) { @@ -286,7 +306,8 @@ if (!keyObjectSupported) { const parsed = PublicKeyInfo.decode(key, format, { label }) let type, keyObject - switch (parsed.algorithm.algorithm.join('.')) { + const oid = parsed.algorithm.algorithm.join('.') + switch (oid) { case '1.2.840.10045.2.1': { keyObject = new KeyObject() i(keyObject).asn1 = parsed @@ -302,7 +323,7 @@ if (!keyObjectSupported) { break } default: - throw new errors.JOSENotSupported(`OID ${parsed.algorithm.algorithm.join('.')} is not supported in your Node.js runtime version`) + unsupported(oid) } return keyObject @@ -375,7 +396,8 @@ if (!keyObjectSupported) { const parsed = PrivateKeyInfo.decode(key, format, { label }) let type, keyObject - switch (parsed.algorithm.algorithm.join('.')) { + const oid = parsed.algorithm.algorithm.join('.') + switch (oid) { case '1.2.840.10045.2.1': { const OID = asn1.get('OID') type = 'sec1' @@ -388,7 +410,7 @@ if (!keyObjectSupported) { break } default: - throw new errors.JOSENotSupported(`OID ${parsed.algorithm.algorithm.join('.')} is not supported in your Node.js runtime version`) + unsupported(oid) } i(keyObject).pkcs8 = key diff --git a/lib/jwk/import.js b/lib/jwk/import.js index dd195389..78320f61 100644 --- a/lib/jwk/import.js +++ b/lib/jwk/import.js @@ -86,7 +86,11 @@ const asKey = (key, parameters, { calculateMissingRSAPrimes = false } = {}) => { } else if (key && (typeof key === 'object' || typeof key === 'string')) { // | | passed to crypto.createPrivateKey or crypto.createPublicKey or passed to crypto.createSecretKey try { privateKey = createPrivateKey(key) - } catch (err) {} + } catch (err) { + if (err instanceof errors.JOSEError) { + throw err + } + } try { publicKey = createPublicKey(key) @@ -95,7 +99,11 @@ const asKey = (key, parameters, { calculateMissingRSAPrimes = false } = {}) => { x5c: [key.replace(/(?:-----(?:BEGIN|END) CERTIFICATE-----|\s)/g, '')] }) } - } catch (err) {} + } catch (err) { + if (err instanceof errors.JOSEError) { + throw err + } + } try { // this is to filter out invalid PEM keys and certs, i'll rather have them fail import then diff --git a/test/jwk/import.test.js b/test/jwk/import.test.js index b08eeaf7..634b3e4b 100644 --- a/test/jwk/import.test.js +++ b/test/jwk/import.test.js @@ -165,9 +165,7 @@ test('invalid encoded oct jwk import', async t => { }, { instanceOf: errors.JOSEInvalidEncoding, code: 'ERR_JOSE_INVALID_ENCODING', message: 'input is not a valid base64url encoded string' }) }) -if (keyObjectSupported) { - test('importing a certificate file populates the certificate properties', t => { - const key = asKey(`-----BEGIN CERTIFICATE----- +const cert = `-----BEGIN CERTIFICATE----- MIIC4DCCAcgCCQDO8JBSH914NDANBgkqhkiG9w0BAQsFADAyMQswCQYDVQQGEwJD WjEPMA0GA1UEBwwGUHJhZ3VlMRIwEAYDVQQDDAlwa210bHN0d28wHhcNMTkwNjE4 MTIzMjAxWhcNMjAwNjE3MTIzMjAxWjAyMQswCQYDVQQGEwJDWjEPMA0GA1UEBwwG @@ -184,9 +182,19 @@ KwwOdRu7VJpAxvweA/3woKl6Cjfy20ZupPH9mxr1R78BMKgEtdFsiLwbB7MOdDbT LsrUcEcupXv+gZek22upQKrAk/XFP067KIqKmCEhDidxhP251SloUaruv9cHEx0a DKol9eR465FAiBLvg2N7qJHCKlWdn99SgN4Y3kINsuFR7Tj4QIJZNubOjV0YeOgn AWzRJlZD89KZAQgjj4Z215QeLxA= ------END CERTIFICATE-----`) +-----END CERTIFICATE-----` + +if (keyObjectSupported) { + test('importing a certificate file populates the certificate properties', t => { + const key = asKey(cert) t.truthy(key.x5c) t.truthy(key.x5t) t.truthy(key['x5t#S256']) }) +} else { + test('cannot import a certificate', t => { + t.throws(() => { + asKey(cert) + }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'X.509 certificates are not supported in your Node.js runtime version' }) + }) } diff --git a/test/jwk/okp_sig.test.js b/test/jwk/okp_sig.test.js index 5572610b..889ca0ec 100644 --- a/test/jwk/okp_sig.test.js +++ b/test/jwk/okp_sig.test.js @@ -1,12 +1,41 @@ const test = require('ava') const { keyObjectSupported } = require('../../lib/help/runtime_support') +const errors = require('../../lib/errors') -if (!keyObjectSupported) return +const fixtures = require('../fixtures') + +if (!keyObjectSupported) { + const JWK = require('../../lib/jwk') + ;[ + [fixtures.PEM.Ed25519.public, 'Ed25519'], + [fixtures.PEM.Ed25519.private, 'Ed25519'], + [fixtures.PEM.Ed448.public, 'Ed448'], + [fixtures.PEM.Ed448.private, 'Ed448'], + [fixtures.PEM.X25519.public, 'X25519'], + [fixtures.PEM.X25519.private, 'X25519'], + [fixtures.PEM.X448.public, 'X448'], + [fixtures.PEM.X448.private, 'X448'], + [fixtures.JWK.Ed25519, 'Ed25519'], + [fixtures.JWK.Ed448, 'Ed448'], + [fixtures.JWK.X25519, 'X25519'], + [fixtures.JWK.X448, 'X448'], + [{ ...fixtures.JWK.Ed25519, d: undefined }, 'Ed25519'], + [{ ...fixtures.JWK.Ed448, d: undefined }, 'Ed448'], + [{ ...fixtures.JWK.X25519, d: undefined }, 'X25519'], + [{ ...fixtures.JWK.X448, d: undefined }, 'X448'] + ].forEach(([input, label], i, { length }) => { + test(`OKP ${i + 1} / ${length}`, t => { + t.throws(() => { + JWK.asKey(input) + }, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: `${label} is not supported in your Node.js runtime version` }) + }) + }) + return +} const { createPrivateKey, createPublicKey } = require('crypto') const { hasProperty, hasNoProperties, hasProperties } = require('../macros') -const fixtures = require('../fixtures') const OKPKey = require('../../lib/jwk/key/okp')