Skip to content

Commit

Permalink
fix: expose JOSENotSupported key import errors on unsupported runtimes
Browse files Browse the repository at this point in the history
  • Loading branch information
panva committed Jan 8, 2020
1 parent bb58c9c commit bc81e5d
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 12 deletions.
30 changes: 26 additions & 4 deletions lib/help/key_object.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 } = {}) {
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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'
Expand All @@ -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
Expand Down
12 changes: 10 additions & 2 deletions lib/jwk/import.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ const asKey = (key, parameters, { calculateMissingRSAPrimes = false } = {}) => {
} else if (key && (typeof key === 'object' || typeof key === 'string')) { // <Object> | <string> | <Buffer> passed to crypto.createPrivateKey or crypto.createPublicKey or <Buffer> passed to crypto.createSecretKey
try {
privateKey = createPrivateKey(key)
} catch (err) {}
} catch (err) {
if (err instanceof errors.JOSEError) {
throw err
}
}

try {
publicKey = createPublicKey(key)
Expand All @@ -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
Expand Down
16 changes: 12 additions & 4 deletions test/jwk/import.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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' })
})
}
33 changes: 31 additions & 2 deletions test/jwk/okp_sig.test.js
Original file line number Diff line number Diff line change
@@ -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')

Expand Down

0 comments on commit bc81e5d

Please sign in to comment.