diff --git a/README.md b/README.md index ae39934ae0..7058158a67 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Legend: | -- | -- | -- | | RSASSA-PKCS1-v1_5 | ✓ | RS256, RS384, RS512 | | RSASSA-PSS | ✓ | PS256, PS384, PS512 | -| ECDSA | ✓ | ES256, ES384, ES512 | +| ECDSA | ✓ | ES256, ES256K, ES384, ES512 | | HMAC with SHA-2 | ✓ | HS256, HS384, HS512 | | JWE Key Management Algorithms | Supported || diff --git a/lib/help/asn1/index.js b/lib/help/asn1/index.js index 7c1054de44..9e437f7376 100644 --- a/lib/help/asn1/index.js +++ b/lib/help/asn1/index.js @@ -21,4 +21,3 @@ const RSAPublicKey = asn1.define('RSAPublicKey', require('./rsa_public_key')) types.set('RSAPublicKey', RSAPublicKey) module.exports = types -module.exports.BN = asn1.bignum diff --git a/lib/help/ecdsa_signatures.js b/lib/help/ecdsa_signatures.js index 0d08138cdd..ee2e742458 100644 --- a/lib/help/ecdsa_signatures.js +++ b/lib/help/ecdsa_signatures.js @@ -10,6 +10,7 @@ const getParamSize = keySize => ((keySize / 8) | 0) + (keySize % 8 === 0 ? 0 : 1 const paramBytesForAlg = { ES256: getParamSize(256), + ES256K: getParamSize(256), ES384: getParamSize(384), ES512: getParamSize(521) } diff --git a/lib/help/key_utils.js b/lib/help/key_utils.js index dc3556b976..e1bf54990a 100644 --- a/lib/help/key_utils.js +++ b/lib/help/key_utils.js @@ -2,21 +2,29 @@ const base64url = require('./base64url') const errors = require('../errors') const asn1 = require('./asn1') -const EC_CURVES = new Set(['P-256', 'P-384', 'P-521']) +const EC_CURVES = new Set([ + 'P-256', + 'P-256K', + 'P-384', + 'P-521' +]) const oidHexToCurve = new Map([ ['06082a8648ce3d030107', 'P-256'], + ['06052b8104000a', 'P-256K'], ['06052b81040022', 'P-384'], ['06052b81040023', 'P-521'] ]) const EC_KEY_OID = '1.2.840.10045.2.1'.split('.') const crvToOid = new Map([ ['P-256', '1.2.840.10045.3.1.7'.split('.')], + ['P-256K', '1.3.132.0.10'.split('.')], ['P-384', '1.3.132.0.34'.split('.')], ['P-521', '1.3.132.0.35'.split('.')] ]) const crvToOidBuf = new Map([ ['P-256', Buffer.from('06082a8648ce3d030107', 'hex')], + ['P-256K', Buffer.from('06052b8104000a', 'hex')], ['P-384', Buffer.from('06052b81040022', 'hex')], ['P-521', Buffer.from('06052b81040023', 'hex')] ]) diff --git a/lib/help/node_alg.js b/lib/help/node_alg.js index f5b95ee267..0e1ae43c49 100644 --- a/lib/help/node_alg.js +++ b/lib/help/node_alg.js @@ -4,6 +4,7 @@ module.exports = (alg) => { case 'PS256': case 'HS256': case 'ES256': + case 'ES256K': return 'sha256' case 'RS384': case 'PS384': diff --git a/lib/index.d.ts b/lib/index.d.ts index a1377576f3..d74fe1dcc2 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -8,7 +8,7 @@ interface KeyParameters { use?: use kid?: string } -type curve = 'P-256' | 'P-384' | 'P-521' +type curve = 'P-256' | 'P-256K' | 'P-384' | 'P-521' type keyType = 'RSA' | 'EC' | 'oct' type keyOperation = 'encrypt' | 'decrypt' | 'sign' | 'verify' | 'wrapKey' | 'unwrapKey' diff --git a/lib/jwa/ecdh/derive.js b/lib/jwa/ecdh/derive.js index 91ff7a17b6..22b62e0704 100644 --- a/lib/jwa/ecdh/derive.js +++ b/lib/jwa/ecdh/derive.js @@ -6,6 +6,8 @@ const crvToCurve = (crv) => { switch (crv) { case 'P-256': return 'prime256v1' + case 'P-256K': + return 'secp256k1' case 'P-384': return 'secp384r1' case 'P-521': diff --git a/lib/jwa/ecdsa.js b/lib/jwa/ecdsa.js index 80df4b2cd5..d69ecefe4a 100644 --- a/lib/jwa/ecdsa.js +++ b/lib/jwa/ecdsa.js @@ -23,7 +23,7 @@ const verify = (jwaAlg, nodeAlg, { [KEYOBJECT]: keyObject }, payload, signature) } module.exports = (JWA) => { - ['ES256', 'ES384', 'ES512'].forEach((jwaAlg) => { + ['ES256', 'ES384', 'ES512', 'ES256K'].forEach((jwaAlg) => { const nodeAlg = resolveNodeAlg(jwaAlg) assert(!JWA.sign.has(jwaAlg), `sign alg ${jwaAlg} already registered`) diff --git a/lib/jwk/key/ec.js b/lib/jwk/key/ec.js index 5e59cc888d..917b0733b0 100644 --- a/lib/jwk/key/ec.js +++ b/lib/jwk/key/ec.js @@ -18,6 +18,8 @@ const crvToDSA = (crv) => { switch (crv) { case 'P-256': return 'ES256' + case 'P-256K': + return 'ES256K' case 'P-384': return 'ES384' case 'P-521': @@ -93,12 +95,18 @@ class ECKey extends Key { } static async generate (crv = 'P-256', privat = true) { + if (crv === 'P-256K') { + crv = 'secp256k1' + } const { privateKey, publicKey } = await generateKeyPair('ec', { namedCurve: crv }) return privat ? privateKey : publicKey } static generateSync (crv = 'P-256', privat = true) { + if (crv === 'P-256K') { + crv = 'secp256k1' + } const { privateKey, publicKey } = generateKeyPairSync('ec', { namedCurve: crv }) return privat ? privateKey : publicKey diff --git a/test/fixtures/P-256K.key b/test/fixtures/P-256K.key new file mode 100644 index 0000000000..149e95c8a3 --- /dev/null +++ b/test/fixtures/P-256K.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgxTAmXNRL8ksBlr+F3yXD +rUdRDn1gyIvY/PC2e/iUK7ehRANCAARVFouq0yOD8lFoPORt+K3vOieQ4YNnjapt +nKWOGqyDdeaoE8aEQH9IScXKYVYNTRPa9F7/hx2clSCcRG6OkgLE +-----END PRIVATE KEY----- diff --git a/test/fixtures/P-256K.pem b/test/fixtures/P-256K.pem new file mode 100644 index 0000000000..7affcba985 --- /dev/null +++ b/test/fixtures/P-256K.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEVRaLqtMjg/JRaDzkbfit7zonkOGDZ42q +bZyljhqsg3XmqBPGhEB/SEnFymFWDU0T2vRe/4cdnJUgnERujpICxA== +-----END PUBLIC KEY----- diff --git a/test/fixtures/index.js b/test/fixtures/index.js index 51cfeba94b..f1e6a0773b 100644 --- a/test/fixtures/index.js +++ b/test/fixtures/index.js @@ -28,6 +28,14 @@ module.exports.JWK = { d: '_i_1Ac5oVmbBxGvEvOEFHMpzMXKZi8voUx8I3Gl6IxY' }, + 'P-256K': { + kty: 'EC', + crv: 'P-256', + x: 'VRaLqtMjg_JRaDzkbfit7zonkOGDZ42qbZyljhqsg3U', + y: '5qgTxoRAf0hJxcphVg1NE9r0Xv-HHZyVIJxEbo6SAsQ', + d: 'xTAmXNRL8ksBlr-F3yXDrUdRDn1gyIvY_PC2e_iUK7c' + }, + 'P-384': { kty: 'EC', crv: 'P-384', @@ -56,6 +64,10 @@ module.exports.PEM = { private: readFileSync(join(__dirname, 'P-256.key')), public: readFileSync(join(__dirname, 'P-256.pem')) }, + 'P-256K': { + private: readFileSync(join(__dirname, 'P-256K.key')), + public: readFileSync(join(__dirname, 'P-256K.pem')) + }, 'P-384': { private: readFileSync(join(__dirname, 'P-384.key')), public: readFileSync(join(__dirname, 'P-384.pem')) diff --git a/test/help/key_utils.test.js b/test/help/key_utils.test.js index 10e1487090..023947ef96 100644 --- a/test/help/key_utils.test.js +++ b/test/help/key_utils.test.js @@ -12,10 +12,10 @@ test('jwkToPem only works for EC and RSA', t => { }, { instanceOf: errors.JOSENotSupported, message: 'unsupported key type: OKP' }) }) -test('jwkToPem only does rfc7518 EC', t => { +test('jwkToPem only handles known curves', t => { t.throws(() => { - jwkToPem({ kty: 'EC', crv: 'P-256K' }) - }, { instanceOf: errors.JOSENotSupported, message: 'unsupported EC key curve: P-256K' }) + jwkToPem({ kty: 'EC', crv: 'foo' }) + }, { instanceOf: errors.JOSENotSupported, message: 'unsupported EC key curve: foo' }) }) test('RSA Public key', t => { diff --git a/test/jwk/ec.test.js b/test/jwk/ec.test.js index 59fe9c433d..82badddff9 100644 --- a/test/jwk/ec.test.js +++ b/test/jwk/ec.test.js @@ -12,10 +12,16 @@ test(`EC key .algorithms invalid operation`, t => { Object.entries({ 'P-256': [256, 'rDd6H6t9-nJUoz72nTpz8tInvypVWhE2iQoPznj8ZY8'], + 'P-256K': [256, 'zZYrH69YCAAihM7ZCoRj90VI55H5MmQscSpf-JuUS50'], 'P-384': [384, '5gebayAhpztJCs4Pxo-z1hhsN0upoyG2NAoKpiiH2b0'], 'P-521': [512, 'BQtkbSY3xgN4M2ZP3IHMLG7-Rp1L29teCMfNqgJHtTY'] }).forEach(([crv, [len, kid]]) => { - const alg = `ES${len}` + let alg + if (crv === 'P-256K') { + alg = 'ES256K' + } else { + alg = `ES${len}` + } // private ;(() => { diff --git a/test/jwk/generate.test.js b/test/jwk/generate.test.js index 53704fa9e1..cbec133121 100644 --- a/test/jwk/generate.test.js +++ b/test/jwk/generate.test.js @@ -23,6 +23,13 @@ const { JWK: { generate, generateSync }, errors } = require('../..') ['EC', 'P-256', { use: 'enc', alg: 'ECDH-ES' }], ['EC', 'P-256', { alg: 'ES256' }], ['EC', 'P-256', { alg: 'ECDH-ES' }], + ['EC', 'P-256K'], + ['EC', 'P-256K', { use: 'sig' }], + ['EC', 'P-256K', { use: 'enc' }], + ['EC', 'P-256K', { use: 'sig', alg: 'ES256K' }], + ['EC', 'P-256K', { use: 'enc', alg: 'ECDH-ES' }], + ['EC', 'P-256K', { alg: 'ES256K' }], + ['EC', 'P-256K', { alg: 'ECDH-ES' }], ['EC', 'P-384'], ['EC', 'P-384', { use: 'sig' }], ['EC', 'P-384', { use: 'enc' }],