Skip to content

Commit

Permalink
feat: expose crypto.KeyObject instances in supported runtimes
Browse files Browse the repository at this point in the history
  • Loading branch information
panva committed Nov 3, 2019
1 parent 89db91c commit 8ea9683
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 12 deletions.
10 changes: 10 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ If you or your business use `jose`, please consider becoming a [sponsor][support
- [key.public](#keypublic)
- [key.private](#keyprivate)
- [key.secret](#keysecret)
- [key.keyObject](#keykeyobject)
- [key.algorithms([operation])](#keyalgorithmsoperation)
- [key.toJWK([private])](#keytojwkprivate)
- [key.toPEM([private[, encoding]])](#keytopemprivate-encoding)
Expand Down Expand Up @@ -198,6 +199,15 @@ Returns true/false if the key is symmetric. Returns false for asymmetric keys.

---

#### `key.keyObject`

Returns the underlying [`KeyObject`](https://nodejs.org/api/crypto.html#crypto_class_keyobject)
instance. Throws `JOSENotSupported` when KeyObject API is not supported in the Node.js runtime.

- `<KeyObject>`

---

#### `key.algorithms([operation])`

Returns a [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)
Expand Down
9 changes: 9 additions & 0 deletions lib/jwk/key/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ class Key {

Object.defineProperties(this, {
[KEYOBJECT]: { value: isObject(keyObject) ? undefined : keyObject },
keyObject: {
get () {
if (!keyObjectSupported) {
throw new errors.JOSENotSupported('KeyObject class is not supported in your Node.js runtime version')
}

return this[KEYOBJECT]
}
},
type: { value: keyObject.type },
private: { value: keyObject.type === 'private' },
public: { value: keyObject.type === 'public' },
Expand Down
6 changes: 3 additions & 3 deletions test/help/key_utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ const clone = obj => JSON.parse(JSON.stringify(obj))
test('jwkToPem only works for EC, RSA and OKP', t => {
t.throws(() => {
jwkToPem({ kty: 'foo' })
}, { instanceOf: errors.JOSENotSupported, message: 'unsupported key type: foo' })
}, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported key type: foo' })
})

test('jwkToPem only handles known EC curves', t => {
t.throws(() => {
jwkToPem({ kty: 'EC', crv: 'foo' })
}, { instanceOf: errors.JOSENotSupported, message: 'unsupported EC key curve: foo' })
}, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported EC key curve: foo' })
})

test('jwkToPem only handles known OKP curves', t => {
t.throws(() => {
jwkToPem({ kty: 'OKP', crv: 'foo' })
}, { instanceOf: errors.JOSENotSupported, message: 'unsupported OKP key curve: foo' })
}, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported OKP key curve: foo' })
})

test('RSA Public key', t => {
Expand Down
36 changes: 27 additions & 9 deletions test/jwk/generate.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const test = require('ava')

const { edDSASupported } = require('../../lib/help/runtime_support')
const crypto = require('crypto')

const { edDSASupported, keyObjectSupported } = require('../../lib/help/runtime_support')

const { JWK: { generate, generateSync }, errors } = require('../..')

Expand Down Expand Up @@ -80,6 +82,14 @@ const { JWK: { generate, generateSync }, errors } = require('../..')
const key = generateSync(args[0], args[1], args[2], args[3])
t.truthy(key)

if (keyObjectSupported) {
t.true(key.keyObject instanceof crypto.KeyObject)
} else {
t.throws(() => {
return key.keyObject
}, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'KeyObject class is not supported in your Node.js runtime version' })
}

if (key.kty !== 'oct') {
if (args.length === 4) {
if (args[3] === true) {
Expand Down Expand Up @@ -110,6 +120,14 @@ const { JWK: { generate, generateSync }, errors } = require('../..')
const key = await generate(args[0], args[1], args[2], args[3])
t.truthy(key)

if (keyObjectSupported) {
t.true(key.keyObject instanceof crypto.KeyObject)
} else {
t.throws(() => {
return key.keyObject
}, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'KeyObject class is not supported in your Node.js runtime version' })
}

if (key.kty !== 'oct') {
if (args.length === 4) {
if (args[3] === true) {
Expand Down Expand Up @@ -140,51 +158,51 @@ const { JWK: { generate, generateSync }, errors } = require('../..')
test('fails to generateSync unsupported kty', t => {
t.throws(() => {
generateSync('foo')
}, { instanceOf: errors.JOSENotSupported, message: 'unsupported key type: foo' })
}, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported key type: foo' })
})

test('fails to generate unsupported kty', async t => {
await t.throwsAsync(() => {
return generate('foo')
}, { instanceOf: errors.JOSENotSupported, message: 'unsupported key type: foo' })
}, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported key type: foo' })
})

if (edDSASupported) {
test('fails to generate unsupported OKP crv', async t => {
await t.throwsAsync(() => {
return generate('OKP', 'foo')
}, { instanceOf: errors.JOSENotSupported, message: 'unsupported OKP key curve: foo' })
}, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported OKP key curve: foo' })
})

test('fails to generateSync unsupported OKP crv', async t => {
await t.throws(() => {
return generateSync('OKP', 'foo')
}, { instanceOf: errors.JOSENotSupported, message: 'unsupported OKP key curve: foo' })
}, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported OKP key curve: foo' })
})
} else {
test('fails to generate OKP when not supported', async t => {
await t.throwsAsync(() => {
return generate('OKP')
}, { instanceOf: errors.JOSENotSupported, message: 'OKP keys are not supported in your Node.js runtime version' })
}, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'OKP keys are not supported in your Node.js runtime version' })
})

test('fails to generateSync OKP when not supported', async t => {
await t.throws(() => {
return generateSync('OKP')
}, { instanceOf: errors.JOSENotSupported, message: 'OKP keys are not supported in your Node.js runtime version' })
}, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'OKP keys are not supported in your Node.js runtime version' })
})
}

test('fails to generateSync unsupported EC crv', t => {
t.throws(() => {
generateSync('EC', 'foo')
}, { instanceOf: errors.JOSENotSupported, message: 'unsupported EC key curve: foo' })
}, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported EC key curve: foo' })
})

test('fails to generate unsupported EC crv', async t => {
await t.throwsAsync(() => {
return generate('EC', 'foo')
}, { instanceOf: errors.JOSENotSupported, message: 'unsupported EC key curve: foo' })
}, { instanceOf: errors.JOSENotSupported, code: 'ERR_JOSE_NOT_SUPPORTED', message: 'unsupported EC key curve: foo' })
})

test('fails to generateSync RSA with invalid bit lengths', t => {
Expand Down
4 changes: 4 additions & 0 deletions test/jwk/oct.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const test = require('ava')

const { createSecretKey } = require('../../lib/help/key_object')
const { hasProperty, hasNoProperties } = require('../macros')
const { keyObjectSupported } = require('../../lib/help/runtime_support')

const errors = require('../../lib/errors')
const OctKey = require('../../lib/jwk/key/oct')
Expand Down Expand Up @@ -151,6 +152,9 @@ test('they may be imported from (no kid)', t => {
})

t.is(key.k, undefined)
if (keyObjectSupported) {
t.is(key.keyObject, undefined)
}
t.false(key.private)
t.false(key.public)
t.deepEqual([...key.algorithms()], [])
Expand Down
1 change: 1 addition & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export namespace JWK {
x5c?: string[];
x5t?: string;
'x5t#S256'?: string;
keyObject: KeyObject;

toPEM(private?: boolean, encoding?: pemEncodingOptions): string;

Expand Down

0 comments on commit 8ea9683

Please sign in to comment.