Skip to content

Commit

Permalink
feat: allow JWKS.KeyStore .all and .get to filter for key curves
Browse files Browse the repository at this point in the history
  • Loading branch information
panva committed Nov 26, 2019
1 parent f1f3977 commit ea60338
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 19 deletions.
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ specified by the parameters are first.

- `parameters`: `<Object>`
- `kty`: `<string>` Key Type to filter for.
- `crv`: `<string>` Key Curve to filter for. (for EC and OKP keys)
- `alg`: `<string>` Key supported algorithm to filter for.
- `kid`: `<string>` Key ID to filter for.
- `use`: `<string>` Filter keys with the specified use defined. Keys missing "use" parameter will
Expand All @@ -643,6 +644,7 @@ parameters is returned.

- `parameters`: `<Object>`
- `kty`: `<string>` Key Type to filter for.
- `crv`: `<string>` Key Curve to filter for. (for EC and OKP keys)
- `alg`: `<string>` Key supported algorithm to filter for.
- `kid`: `<string>` Key ID to filter for.
- `use`: `<string>` Filter keys with the specified use defined. Keys missing "use" parameter will
Expand Down
30 changes: 11 additions & 19 deletions lib/jwks/keystore.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,13 @@ const Key = require('../jwk/key/base')
const importKey = require('../jwk/import')
const { USES_MAPPING } = require('../help/consts')

const keyscore = (key, { alg, kid, use, ops, x5t, x5t256 }) => {
const keyscore = (key, { alg, use, ops }) => {
let score = 0

if (alg && key.alg) {
score++
}

if (kid && key.kid) {
score++
}

if (x5t && key.x5t) {
score++
}

if (x5t256 && key['x5t#S256']) {
score++
}

if (use && key.use) {
score++
}
Expand Down Expand Up @@ -64,20 +52,16 @@ class KeyStore {
i(this).keys = new Set(keys)
}

all ({ alg, kid, use, kty, key_ops: ops, x5t, 'x5t#S256': x5t256 } = {}) {
all ({ alg, kid, use, kty, key_ops: ops, x5t, 'x5t#S256': x5t256, crv } = {}) {
if (ops !== undefined && (!Array.isArray(ops) || !ops.length || ops.some(x => typeof x !== 'string'))) {
throw new TypeError('`key_ops` must be a non-empty array of strings')
}

const search = { alg, kid, use, ops, x5t, x5t256 }
const search = { alg, use, ops }
return [...i(this).keys]
.filter((key) => {
let candidate = true

if (alg !== undefined && !key.algorithms().has(alg)) {
candidate = false
}

if (candidate && kid !== undefined && key.kid !== kid) {
candidate = false
}
Expand All @@ -94,6 +78,14 @@ class KeyStore {
candidate = false
}

if (candidate && crv !== undefined && (key.crv !== crv)) {
candidate = false
}

if (alg !== undefined && !key.algorithms().has(alg)) {
candidate = false
}

if (candidate && use !== undefined && (key.use !== undefined && key.use !== use)) {
candidate = false
}
Expand Down
12 changes: 12 additions & 0 deletions test/jwks/keystore.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,18 @@ test('.all() and .get() use sort', t => {
t.is(ks.get({ use: 'sig' }), k2)
})

test('.all() and .get() crv filter', t => {
const k = generateSync('EC', 'P-256')
const k2 = generateSync('EC', 'P-384')
const ks = new KeyStore(k, k2)
t.deepEqual(ks.all({ crv: 'P-256' }), [k])
t.deepEqual(ks.all({ crv: 'P-384' }), [k2])
t.deepEqual(ks.all({ crv: 'P-521' }), [])
t.is(ks.get({ crv: 'P-256' }), k)
t.is(ks.get({ crv: 'P-384' }), k2)
t.is(ks.get({ crv: 'P-521' }), undefined)
})

test('.all() and .get() kid filter', t => {
const k = generateSync('RSA', undefined, { kid: 'foobar' })
const ks = new KeyStore(k)
Expand Down
1 change: 1 addition & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ export namespace JWKS {
kty?: keyType;
x5t?: string;
'x5t#S256'?: string;
crv?: string;
}

class KeyStore {
Expand Down

0 comments on commit ea60338

Please sign in to comment.