Skip to content

Commit

Permalink
fix: restrict RS key algorithms by the key's bit size
Browse files Browse the repository at this point in the history
  • Loading branch information
panva committed Mar 17, 2019
1 parent 1dc58fc commit 9af295b
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 26 deletions.
49 changes: 31 additions & 18 deletions lib/jwk/key/rsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,6 @@ const { THUMBPRINT_MATERIAL, PUBLIC_MEMBERS, PRIVATE_MEMBERS, JWK_MEMBERS } = re
const Key = require('./base')

const generateKeyPair = promisify(async)
const SIG_ALGS = new Set([
'PS256',
'RS256',
'PS384',
'RS384',
'PS512',
'RS512'
])

const WRAP_ALGS = new Set([
'RSA-OAEP',
Expand All @@ -25,6 +17,31 @@ Object.freeze(RSA_PUBLIC)
const RSA_PRIVATE = new Set([...RSA_PUBLIC, 'd', 'p', 'q', 'dp', 'dq', 'qi'])
Object.freeze(RSA_PRIVATE)

const sigAlgsAvailableFor = (length) => {
switch (true) {
case length >= 1040:
return new Set(['PS256', 'RS256', 'PS384', 'RS384', 'PS512', 'RS512'])
case length >= 784:
return new Set(['PS256', 'RS256', 'PS384', 'RS384', 'RS512'])
case length >= 752:
return new Set(['PS256', 'RS256', 'RS384', 'RS512'])
case length >= 624:
return new Set(['PS256', 'RS256', 'RS384'])
case length >= 528:
return new Set(['PS256', 'RS256'])
default:
return new Set(['RS256'])
}
}

const wrapAlgsAvailableFor = (length) => {
if (length >= 592) {
return new Set(WRAP_ALGS)
}

return new Set(['RSA1_5'])
}

// RSA Key Type
class RSAKey extends Key {
constructor (...args) {
Expand Down Expand Up @@ -62,10 +79,6 @@ class RSAKey extends Key {
}

algorithms (operation, { use = this.use, alg = this.alg } = {}) {
if (this.length < 2048) {
return new Set()
}

if (alg) {
return new Set(this.algorithms(operation, { alg: null, use }).has(alg) ? [alg] : undefined)
}
Expand All @@ -79,25 +92,25 @@ class RSAKey extends Key {
return new Set()
}

return new Set(SIG_ALGS)
return sigAlgsAvailableFor(this.length)
case 'verify':
if (use === 'enc') {
return new Set()
}

return new Set(SIG_ALGS)
return sigAlgsAvailableFor(this.length)
case 'wrapKey':
if (use === 'sig') {
return new Set()
}

return new Set(WRAP_ALGS)
return wrapAlgsAvailableFor(this.length)
case 'unwrapKey':
if (this.public || use === 'sig') {
return new Set()
}

return new Set(WRAP_ALGS)
return wrapAlgsAvailableFor(this.length)
case undefined:
// just the ops needed to return all algs regardless of its use
return new Set([
Expand All @@ -110,7 +123,7 @@ class RSAKey extends Key {
}

static async generate (len = 2048, opts, privat = true) {
if (!Number.isSafeInteger(len) || len < 2048 || len % 8 !== 0) {
if (!Number.isSafeInteger(len) || len < 512 || len % 8 !== 0) {
throw new TypeError('invalid bit length')
}

Expand All @@ -120,7 +133,7 @@ class RSAKey extends Key {
}

static generateSync (len = 2048, opts, privat = true) {
if (!Number.isSafeInteger(len) || len < 2048 || len % 8 !== 0) {
if (!Number.isSafeInteger(len) || len < 512 || len % 8 !== 0) {
throw new TypeError('invalid bit length')
}

Expand Down
45 changes: 37 additions & 8 deletions test/jwk/rsa.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,6 @@ test(`RSA key .algorithms invalid operation`, t => {
t.deepEqual([...result], ['PS256', 'RS256', 'PS384', 'RS384', 'PS512', 'RS512', 'RSA-OAEP', 'RSA1_5'])
})

test('RSA < 2048 bits does not support any algorithms', t => {
const keyObject = createPublicKey(fixtures.RSA_512)
const key = new RSAKey(keyObject)
const result = key.algorithms()
t.is(result.constructor, Set)
t.deepEqual([...result], [])
})

test('RSA Private key algorithms (no operation, w/ alg)', t => {
const key = new RSAKey(keyObject, { alg: 'RS256' })
const result = key.algorithms()
Expand Down Expand Up @@ -257,4 +249,41 @@ test(`RSA key .algorithms invalid operation`, t => {
t.is(result.constructor, Set)
t.deepEqual([...result], [])
})

test('any RSA key can do RS256 and RSA1_5', t => {
const k = RSAKey.generateSync(512)
const result = k.algorithms()
t.is(result.constructor, Set)
t.deepEqual([...result], ['RS256', 'RSA1_5'])
})

test('RSA key >= 528 bits can do PS256', t => {
const k = RSAKey.generateSync(528)
t.true(k.algorithms().has('PS256'))
})

test('RSA key >= 592 bits can do RSA-OAEP', t => {
const k = RSAKey.generateSync(592)
t.true(k.algorithms().has('RSA-OAEP'))
})

test('RSA key >= 624 bits can do RS384', t => {
const k = RSAKey.generateSync(624)
t.true(k.algorithms().has('RS384'))
})

test('RSA key >= 752 bits can do RS512', t => {
const k = RSAKey.generateSync(752)
t.true(k.algorithms().has('RS512'))
})

test('RSA key >= 784 bits can do PS384', t => {
const k = RSAKey.generateSync(784)
t.true(k.algorithms().has('PS384'))
})

test('RSA key >= 1040 bits can do PS512', t => {
const k = RSAKey.generateSync(1040)
t.true(k.algorithms().has('PS512'))
})
})()

0 comments on commit 9af295b

Please sign in to comment.