From fd3fa4295aab0364e48aa9d840e284c2aafdb8c3 Mon Sep 17 00:00:00 2001 From: JFrog-Frogbot Date: Fri, 22 Nov 2024 01:25:42 +0000 Subject: [PATCH] Upgrade jose to 2.0.7 --- node_modules/.package-lock.json | 45 +- node_modules/asn1.js/.eslintrc.js | 27 - node_modules/asn1.js/LICENSE | 21 - node_modules/asn1.js/README.md | 100 - node_modules/asn1.js/lib/asn1.js | 11 - node_modules/asn1.js/lib/asn1/api.js | 57 - node_modules/asn1.js/lib/asn1/base/buffer.js | 153 - node_modules/asn1.js/lib/asn1/base/index.js | 8 - node_modules/asn1.js/lib/asn1/base/node.js | 638 --- .../asn1.js/lib/asn1/base/reporter.js | 123 - .../asn1.js/lib/asn1/constants/der.js | 58 - .../asn1.js/lib/asn1/constants/index.js | 21 - node_modules/asn1.js/lib/asn1/decoders/der.js | 335 -- .../asn1.js/lib/asn1/decoders/index.js | 6 - node_modules/asn1.js/lib/asn1/decoders/pem.js | 51 - node_modules/asn1.js/lib/asn1/encoders/der.js | 295 -- .../asn1.js/lib/asn1/encoders/index.js | 6 - node_modules/asn1.js/lib/asn1/encoders/pem.js | 23 - node_modules/asn1.js/package.json | 36 - node_modules/bn.js/LICENSE | 19 - node_modules/bn.js/README.md | 200 - node_modules/bn.js/lib/bn.js | 3446 ----------------- node_modules/bn.js/package.json | 36 - node_modules/bn.js/util/genCombMulTo.js | 65 - node_modules/bn.js/util/genCombMulTo10.js | 65 - node_modules/jose/CHANGELOG.md | 400 -- node_modules/jose/README.md | 308 +- node_modules/jose/lib/errors.js | 11 +- .../lib/help/asn1/algorithm_identifier.js | 6 +- .../jose/lib/help/asn1/ec_private_key.js | 4 +- node_modules/jose/lib/help/asn1/index.js | 8 +- node_modules/jose/lib/help/base64url.js | 71 +- node_modules/jose/lib/help/consts.js | 23 - node_modules/jose/lib/help/generate_iv.js | 14 +- node_modules/jose/lib/help/key_object.js | 219 +- node_modules/jose/lib/help/key_utils.js | 118 +- node_modules/jose/lib/help/rsa_primes.js | 6 +- node_modules/jose/lib/help/runtime_support.js | 8 +- .../jose/lib/jwa/aes_cbc_hmac_sha2.js | 23 +- node_modules/jose/lib/jwa/aes_gcm.js | 25 +- node_modules/jose/lib/jwa/aes_gcm_kw.js | 29 +- node_modules/jose/lib/jwa/aes_kw.js | 97 +- node_modules/jose/lib/jwa/ecdh/derive.js | 49 +- node_modules/jose/lib/jwa/ecdh/dir.js | 26 +- node_modules/jose/lib/jwa/ecdh/kw.js | 33 +- node_modules/jose/lib/jwa/ecdsa.js | 65 +- node_modules/jose/lib/jwa/eddsa.js | 20 +- node_modules/jose/lib/jwa/hmac.js | 17 +- node_modules/jose/lib/jwa/index.js | 58 +- node_modules/jose/lib/jwa/pbes2.js | 21 +- node_modules/jose/lib/jwa/rsaes.js | 43 +- node_modules/jose/lib/jwa/rsassa.js | 42 +- node_modules/jose/lib/jwa/rsassa_pss.js | 66 +- node_modules/jose/lib/jwe/decrypt.js | 61 +- node_modules/jose/lib/jwe/encrypt.js | 103 +- node_modules/jose/lib/jwe/generate_cek.js | 14 +- node_modules/jose/lib/jwe/index.js | 8 +- node_modules/jose/lib/jwk/import.js | 39 +- node_modules/jose/lib/jwk/index.js | 23 +- node_modules/jose/lib/jwk/key/base.js | 134 +- node_modules/jose/lib/jwk/key/ec.js | 89 +- node_modules/jose/lib/jwk/key/oct.js | 80 +- node_modules/jose/lib/jwk/key/okp.js | 69 +- node_modules/jose/lib/jwk/key/rsa.js | 96 +- .../jose/lib/jwk/key/secp256k1_crv.js | 6 - node_modules/jose/lib/jwks/keystore.js | 93 +- node_modules/jose/lib/jws/index.js | 8 +- node_modules/jose/lib/jws/serializers.js | 13 +- node_modules/jose/lib/jws/sign.js | 70 +- node_modules/jose/lib/jws/verify.js | 80 +- node_modules/jose/lib/jwt/decode.js | 6 +- node_modules/jose/lib/jwt/index.js | 11 +- .../jose/lib/jwt/shared_validations.js | 43 +- node_modules/jose/lib/jwt/sign.js | 30 +- node_modules/jose/lib/jwt/verify.js | 231 +- node_modules/jose/package.json | 104 +- node_modules/jose/types/index.d.ts | 365 +- node_modules/minimalistic-assert/LICENSE | 13 - node_modules/minimalistic-assert/index.js | 11 - node_modules/minimalistic-assert/package.json | 19 - node_modules/minimalistic-assert/readme.md | 4 - package-lock.json | 47 +- package.json | 2 +- 83 files changed, 1634 insertions(+), 7893 deletions(-) delete mode 100644 node_modules/asn1.js/.eslintrc.js delete mode 100644 node_modules/asn1.js/LICENSE delete mode 100644 node_modules/asn1.js/README.md delete mode 100644 node_modules/asn1.js/lib/asn1.js delete mode 100644 node_modules/asn1.js/lib/asn1/api.js delete mode 100644 node_modules/asn1.js/lib/asn1/base/buffer.js delete mode 100644 node_modules/asn1.js/lib/asn1/base/index.js delete mode 100644 node_modules/asn1.js/lib/asn1/base/node.js delete mode 100644 node_modules/asn1.js/lib/asn1/base/reporter.js delete mode 100644 node_modules/asn1.js/lib/asn1/constants/der.js delete mode 100644 node_modules/asn1.js/lib/asn1/constants/index.js delete mode 100644 node_modules/asn1.js/lib/asn1/decoders/der.js delete mode 100644 node_modules/asn1.js/lib/asn1/decoders/index.js delete mode 100644 node_modules/asn1.js/lib/asn1/decoders/pem.js delete mode 100644 node_modules/asn1.js/lib/asn1/encoders/der.js delete mode 100644 node_modules/asn1.js/lib/asn1/encoders/index.js delete mode 100644 node_modules/asn1.js/lib/asn1/encoders/pem.js delete mode 100644 node_modules/asn1.js/package.json delete mode 100644 node_modules/bn.js/LICENSE delete mode 100644 node_modules/bn.js/README.md delete mode 100644 node_modules/bn.js/lib/bn.js delete mode 100644 node_modules/bn.js/package.json delete mode 100644 node_modules/bn.js/util/genCombMulTo.js delete mode 100644 node_modules/bn.js/util/genCombMulTo10.js delete mode 100644 node_modules/jose/CHANGELOG.md delete mode 100644 node_modules/jose/lib/jwk/key/secp256k1_crv.js delete mode 100644 node_modules/minimalistic-assert/LICENSE delete mode 100644 node_modules/minimalistic-assert/index.js delete mode 100644 node_modules/minimalistic-assert/package.json delete mode 100644 node_modules/minimalistic-assert/readme.md diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index 815be71..78a4400 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -22,6 +22,15 @@ "kuler": "^2.0.0" } }, + "node_modules/@panva/asn1.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", + "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", @@ -44,27 +53,11 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, - "node_modules/asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } - }, "node_modules/async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" }, - "node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" - }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -620,15 +613,18 @@ } }, "node_modules/jose": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/jose/-/jose-1.10.2.tgz", - "integrity": "sha512-xpH8tqepxOv1wlG5gwScZEJxbSPZKzIhPud7cvv1avNDexsF4zK3vCjKmMIs9Fs7Sgo46tcH3lXlwu2UiO/4Ew==", - "deprecated": "this version is no longer supported", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.7.tgz", + "integrity": "sha512-5hFWIigKqC+e/lRyQhfnirrAqUdIPMB7SJRqflJaO29dW7q5DFvH1XCSTmv6PQ6pb++0k6MJlLRoS0Wv4s38Wg==", + "license": "MIT", "dependencies": { - "asn1.js": "^5.2.0" + "@panva/asn1.js": "^1.0.0" }, "engines": { - "node": "^10.13.0 || >=12.0.0" + "node": ">=10.13.0 < 13 || >=13.7.0" + }, + "funding": { + "url": "https://github.com/sponsors/panva" } }, "node_modules/keygrip": { @@ -842,11 +838,6 @@ "node": ">= 0.6" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", diff --git a/node_modules/asn1.js/.eslintrc.js b/node_modules/asn1.js/.eslintrc.js deleted file mode 100644 index 6b5dc44..0000000 --- a/node_modules/asn1.js/.eslintrc.js +++ /dev/null @@ -1,27 +0,0 @@ -module.exports = { - 'env': { - 'browser': false, - 'commonjs': true, - 'es6': true, - 'node': true - }, - 'extends': 'eslint:recommended', - 'rules': { - 'indent': [ - 'error', - 2 - ], - 'linebreak-style': [ - 'error', - 'unix' - ], - 'quotes': [ - 'error', - 'single' - ], - 'semi': [ - 'error', - 'always' - ] - } -}; diff --git a/node_modules/asn1.js/LICENSE b/node_modules/asn1.js/LICENSE deleted file mode 100644 index caaf4f2..0000000 --- a/node_modules/asn1.js/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Fedor Indutny - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/node_modules/asn1.js/README.md b/node_modules/asn1.js/README.md deleted file mode 100644 index 9f04af7..0000000 --- a/node_modules/asn1.js/README.md +++ /dev/null @@ -1,100 +0,0 @@ -# ASN1.js - -ASN.1 DER Encoder/Decoder and DSL. - -## Example - -Define model: - -```javascript -var asn = require('asn1.js'); - -var Human = asn.define('Human', function() { - this.seq().obj( - this.key('firstName').octstr(), - this.key('lastName').octstr(), - this.key('age').int(), - this.key('gender').enum({ 0: 'male', 1: 'female' }), - this.key('bio').seqof(Bio) - ); -}); - -var Bio = asn.define('Bio', function() { - this.seq().obj( - this.key('time').gentime(), - this.key('description').octstr() - ); -}); -``` - -Encode data: - -```javascript -var output = Human.encode({ - firstName: 'Thomas', - lastName: 'Anderson', - age: 28, - gender: 'male', - bio: [ - { - time: +new Date('31 March 1999'), - description: 'freedom of mind' - } - ] -}, 'der'); -``` - -Decode data: - -```javascript -var human = Human.decode(output, 'der'); -console.log(human); -/* -{ firstName: , - lastName: , - age: 28, - gender: 'male', - bio: - [ { time: 922820400000, - description: } ] } -*/ -``` - -### Partial decode - -Its possible to parse data without stopping on first error. In order to do it, -you should call: - -```javascript -var human = Human.decode(output, 'der', { partial: true }); -console.log(human); -/* -{ result: { ... }, - errors: [ ... ] } -*/ -``` - -#### LICENSE - -This software is licensed under the MIT License. - -Copyright Fedor Indutny, 2017. - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to permit -persons to whom the Software is furnished to do so, subject to the -following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/asn1.js/lib/asn1.js b/node_modules/asn1.js/lib/asn1.js deleted file mode 100644 index c7d70b8..0000000 --- a/node_modules/asn1.js/lib/asn1.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -const asn1 = exports; - -asn1.bignum = require('bn.js'); - -asn1.define = require('./asn1/api').define; -asn1.base = require('./asn1/base'); -asn1.constants = require('./asn1/constants'); -asn1.decoders = require('./asn1/decoders'); -asn1.encoders = require('./asn1/encoders'); diff --git a/node_modules/asn1.js/lib/asn1/api.js b/node_modules/asn1.js/lib/asn1/api.js deleted file mode 100644 index 61e3eb2..0000000 --- a/node_modules/asn1.js/lib/asn1/api.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict'; - -const encoders = require('./encoders'); -const decoders = require('./decoders'); -const inherits = require('inherits'); - -const api = exports; - -api.define = function define(name, body) { - return new Entity(name, body); -}; - -function Entity(name, body) { - this.name = name; - this.body = body; - - this.decoders = {}; - this.encoders = {}; -} - -Entity.prototype._createNamed = function createNamed(Base) { - const name = this.name; - - function Generated(entity) { - this._initNamed(entity, name); - } - inherits(Generated, Base); - Generated.prototype._initNamed = function _initNamed(entity, name) { - Base.call(this, entity, name); - }; - - return new Generated(this); -}; - -Entity.prototype._getDecoder = function _getDecoder(enc) { - enc = enc || 'der'; - // Lazily create decoder - if (!this.decoders.hasOwnProperty(enc)) - this.decoders[enc] = this._createNamed(decoders[enc]); - return this.decoders[enc]; -}; - -Entity.prototype.decode = function decode(data, enc, options) { - return this._getDecoder(enc).decode(data, options); -}; - -Entity.prototype._getEncoder = function _getEncoder(enc) { - enc = enc || 'der'; - // Lazily create encoder - if (!this.encoders.hasOwnProperty(enc)) - this.encoders[enc] = this._createNamed(encoders[enc]); - return this.encoders[enc]; -}; - -Entity.prototype.encode = function encode(data, enc, /* internal */ reporter) { - return this._getEncoder(enc).encode(data, reporter); -}; diff --git a/node_modules/asn1.js/lib/asn1/base/buffer.js b/node_modules/asn1.js/lib/asn1/base/buffer.js deleted file mode 100644 index bb5bc06..0000000 --- a/node_modules/asn1.js/lib/asn1/base/buffer.js +++ /dev/null @@ -1,153 +0,0 @@ -'use strict'; - -const inherits = require('inherits'); -const Reporter = require('../base/reporter').Reporter; -const Buffer = require('safer-buffer').Buffer; - -function DecoderBuffer(base, options) { - Reporter.call(this, options); - if (!Buffer.isBuffer(base)) { - this.error('Input not Buffer'); - return; - } - - this.base = base; - this.offset = 0; - this.length = base.length; -} -inherits(DecoderBuffer, Reporter); -exports.DecoderBuffer = DecoderBuffer; - -DecoderBuffer.isDecoderBuffer = function isDecoderBuffer(data) { - if (data instanceof DecoderBuffer) { - return true; - } - - // Or accept compatible API - const isCompatible = typeof data === 'object' && - Buffer.isBuffer(data.base) && - data.constructor.name === 'DecoderBuffer' && - typeof data.offset === 'number' && - typeof data.length === 'number' && - typeof data.save === 'function' && - typeof data.restore === 'function' && - typeof data.isEmpty === 'function' && - typeof data.readUInt8 === 'function' && - typeof data.skip === 'function' && - typeof data.raw === 'function'; - - return isCompatible; -}; - -DecoderBuffer.prototype.save = function save() { - return { offset: this.offset, reporter: Reporter.prototype.save.call(this) }; -}; - -DecoderBuffer.prototype.restore = function restore(save) { - // Return skipped data - const res = new DecoderBuffer(this.base); - res.offset = save.offset; - res.length = this.offset; - - this.offset = save.offset; - Reporter.prototype.restore.call(this, save.reporter); - - return res; -}; - -DecoderBuffer.prototype.isEmpty = function isEmpty() { - return this.offset === this.length; -}; - -DecoderBuffer.prototype.readUInt8 = function readUInt8(fail) { - if (this.offset + 1 <= this.length) - return this.base.readUInt8(this.offset++, true); - else - return this.error(fail || 'DecoderBuffer overrun'); -}; - -DecoderBuffer.prototype.skip = function skip(bytes, fail) { - if (!(this.offset + bytes <= this.length)) - return this.error(fail || 'DecoderBuffer overrun'); - - const res = new DecoderBuffer(this.base); - - // Share reporter state - res._reporterState = this._reporterState; - - res.offset = this.offset; - res.length = this.offset + bytes; - this.offset += bytes; - return res; -}; - -DecoderBuffer.prototype.raw = function raw(save) { - return this.base.slice(save ? save.offset : this.offset, this.length); -}; - -function EncoderBuffer(value, reporter) { - if (Array.isArray(value)) { - this.length = 0; - this.value = value.map(function(item) { - if (!EncoderBuffer.isEncoderBuffer(item)) - item = new EncoderBuffer(item, reporter); - this.length += item.length; - return item; - }, this); - } else if (typeof value === 'number') { - if (!(0 <= value && value <= 0xff)) - return reporter.error('non-byte EncoderBuffer value'); - this.value = value; - this.length = 1; - } else if (typeof value === 'string') { - this.value = value; - this.length = Buffer.byteLength(value); - } else if (Buffer.isBuffer(value)) { - this.value = value; - this.length = value.length; - } else { - return reporter.error('Unsupported type: ' + typeof value); - } -} -exports.EncoderBuffer = EncoderBuffer; - -EncoderBuffer.isEncoderBuffer = function isEncoderBuffer(data) { - if (data instanceof EncoderBuffer) { - return true; - } - - // Or accept compatible API - const isCompatible = typeof data === 'object' && - data.constructor.name === 'EncoderBuffer' && - typeof data.length === 'number' && - typeof data.join === 'function'; - - return isCompatible; -}; - -EncoderBuffer.prototype.join = function join(out, offset) { - if (!out) - out = Buffer.alloc(this.length); - if (!offset) - offset = 0; - - if (this.length === 0) - return out; - - if (Array.isArray(this.value)) { - this.value.forEach(function(item) { - item.join(out, offset); - offset += item.length; - }); - } else { - if (typeof this.value === 'number') - out[offset] = this.value; - else if (typeof this.value === 'string') - out.write(this.value, offset); - else if (Buffer.isBuffer(this.value)) - this.value.copy(out, offset); - offset += this.length; - } - - return out; -}; diff --git a/node_modules/asn1.js/lib/asn1/base/index.js b/node_modules/asn1.js/lib/asn1/base/index.js deleted file mode 100644 index 8b92f20..0000000 --- a/node_modules/asn1.js/lib/asn1/base/index.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -const base = exports; - -base.Reporter = require('./reporter').Reporter; -base.DecoderBuffer = require('./buffer').DecoderBuffer; -base.EncoderBuffer = require('./buffer').EncoderBuffer; -base.Node = require('./node'); diff --git a/node_modules/asn1.js/lib/asn1/base/node.js b/node_modules/asn1.js/lib/asn1/base/node.js deleted file mode 100644 index d676d21..0000000 --- a/node_modules/asn1.js/lib/asn1/base/node.js +++ /dev/null @@ -1,638 +0,0 @@ -'use strict'; - -const Reporter = require('../base/reporter').Reporter; -const EncoderBuffer = require('../base/buffer').EncoderBuffer; -const DecoderBuffer = require('../base/buffer').DecoderBuffer; -const assert = require('minimalistic-assert'); - -// Supported tags -const tags = [ - 'seq', 'seqof', 'set', 'setof', 'objid', 'bool', - 'gentime', 'utctime', 'null_', 'enum', 'int', 'objDesc', - 'bitstr', 'bmpstr', 'charstr', 'genstr', 'graphstr', 'ia5str', 'iso646str', - 'numstr', 'octstr', 'printstr', 't61str', 'unistr', 'utf8str', 'videostr' -]; - -// Public methods list -const methods = [ - 'key', 'obj', 'use', 'optional', 'explicit', 'implicit', 'def', 'choice', - 'any', 'contains' -].concat(tags); - -// Overrided methods list -const overrided = [ - '_peekTag', '_decodeTag', '_use', - '_decodeStr', '_decodeObjid', '_decodeTime', - '_decodeNull', '_decodeInt', '_decodeBool', '_decodeList', - - '_encodeComposite', '_encodeStr', '_encodeObjid', '_encodeTime', - '_encodeNull', '_encodeInt', '_encodeBool' -]; - -function Node(enc, parent, name) { - const state = {}; - this._baseState = state; - - state.name = name; - state.enc = enc; - - state.parent = parent || null; - state.children = null; - - // State - state.tag = null; - state.args = null; - state.reverseArgs = null; - state.choice = null; - state.optional = false; - state.any = false; - state.obj = false; - state.use = null; - state.useDecoder = null; - state.key = null; - state['default'] = null; - state.explicit = null; - state.implicit = null; - state.contains = null; - - // Should create new instance on each method - if (!state.parent) { - state.children = []; - this._wrap(); - } -} -module.exports = Node; - -const stateProps = [ - 'enc', 'parent', 'children', 'tag', 'args', 'reverseArgs', 'choice', - 'optional', 'any', 'obj', 'use', 'alteredUse', 'key', 'default', 'explicit', - 'implicit', 'contains' -]; - -Node.prototype.clone = function clone() { - const state = this._baseState; - const cstate = {}; - stateProps.forEach(function(prop) { - cstate[prop] = state[prop]; - }); - const res = new this.constructor(cstate.parent); - res._baseState = cstate; - return res; -}; - -Node.prototype._wrap = function wrap() { - const state = this._baseState; - methods.forEach(function(method) { - this[method] = function _wrappedMethod() { - const clone = new this.constructor(this); - state.children.push(clone); - return clone[method].apply(clone, arguments); - }; - }, this); -}; - -Node.prototype._init = function init(body) { - const state = this._baseState; - - assert(state.parent === null); - body.call(this); - - // Filter children - state.children = state.children.filter(function(child) { - return child._baseState.parent === this; - }, this); - assert.equal(state.children.length, 1, 'Root node can have only one child'); -}; - -Node.prototype._useArgs = function useArgs(args) { - const state = this._baseState; - - // Filter children and args - const children = args.filter(function(arg) { - return arg instanceof this.constructor; - }, this); - args = args.filter(function(arg) { - return !(arg instanceof this.constructor); - }, this); - - if (children.length !== 0) { - assert(state.children === null); - state.children = children; - - // Replace parent to maintain backward link - children.forEach(function(child) { - child._baseState.parent = this; - }, this); - } - if (args.length !== 0) { - assert(state.args === null); - state.args = args; - state.reverseArgs = args.map(function(arg) { - if (typeof arg !== 'object' || arg.constructor !== Object) - return arg; - - const res = {}; - Object.keys(arg).forEach(function(key) { - if (key == (key | 0)) - key |= 0; - const value = arg[key]; - res[value] = key; - }); - return res; - }); - } -}; - -// -// Overrided methods -// - -overrided.forEach(function(method) { - Node.prototype[method] = function _overrided() { - const state = this._baseState; - throw new Error(method + ' not implemented for encoding: ' + state.enc); - }; -}); - -// -// Public methods -// - -tags.forEach(function(tag) { - Node.prototype[tag] = function _tagMethod() { - const state = this._baseState; - const args = Array.prototype.slice.call(arguments); - - assert(state.tag === null); - state.tag = tag; - - this._useArgs(args); - - return this; - }; -}); - -Node.prototype.use = function use(item) { - assert(item); - const state = this._baseState; - - assert(state.use === null); - state.use = item; - - return this; -}; - -Node.prototype.optional = function optional() { - const state = this._baseState; - - state.optional = true; - - return this; -}; - -Node.prototype.def = function def(val) { - const state = this._baseState; - - assert(state['default'] === null); - state['default'] = val; - state.optional = true; - - return this; -}; - -Node.prototype.explicit = function explicit(num) { - const state = this._baseState; - - assert(state.explicit === null && state.implicit === null); - state.explicit = num; - - return this; -}; - -Node.prototype.implicit = function implicit(num) { - const state = this._baseState; - - assert(state.explicit === null && state.implicit === null); - state.implicit = num; - - return this; -}; - -Node.prototype.obj = function obj() { - const state = this._baseState; - const args = Array.prototype.slice.call(arguments); - - state.obj = true; - - if (args.length !== 0) - this._useArgs(args); - - return this; -}; - -Node.prototype.key = function key(newKey) { - const state = this._baseState; - - assert(state.key === null); - state.key = newKey; - - return this; -}; - -Node.prototype.any = function any() { - const state = this._baseState; - - state.any = true; - - return this; -}; - -Node.prototype.choice = function choice(obj) { - const state = this._baseState; - - assert(state.choice === null); - state.choice = obj; - this._useArgs(Object.keys(obj).map(function(key) { - return obj[key]; - })); - - return this; -}; - -Node.prototype.contains = function contains(item) { - const state = this._baseState; - - assert(state.use === null); - state.contains = item; - - return this; -}; - -// -// Decoding -// - -Node.prototype._decode = function decode(input, options) { - const state = this._baseState; - - // Decode root node - if (state.parent === null) - return input.wrapResult(state.children[0]._decode(input, options)); - - let result = state['default']; - let present = true; - - let prevKey = null; - if (state.key !== null) - prevKey = input.enterKey(state.key); - - // Check if tag is there - if (state.optional) { - let tag = null; - if (state.explicit !== null) - tag = state.explicit; - else if (state.implicit !== null) - tag = state.implicit; - else if (state.tag !== null) - tag = state.tag; - - if (tag === null && !state.any) { - // Trial and Error - const save = input.save(); - try { - if (state.choice === null) - this._decodeGeneric(state.tag, input, options); - else - this._decodeChoice(input, options); - present = true; - } catch (e) { - present = false; - } - input.restore(save); - } else { - present = this._peekTag(input, tag, state.any); - - if (input.isError(present)) - return present; - } - } - - // Push object on stack - let prevObj; - if (state.obj && present) - prevObj = input.enterObject(); - - if (present) { - // Unwrap explicit values - if (state.explicit !== null) { - const explicit = this._decodeTag(input, state.explicit); - if (input.isError(explicit)) - return explicit; - input = explicit; - } - - const start = input.offset; - - // Unwrap implicit and normal values - if (state.use === null && state.choice === null) { - let save; - if (state.any) - save = input.save(); - const body = this._decodeTag( - input, - state.implicit !== null ? state.implicit : state.tag, - state.any - ); - if (input.isError(body)) - return body; - - if (state.any) - result = input.raw(save); - else - input = body; - } - - if (options && options.track && state.tag !== null) - options.track(input.path(), start, input.length, 'tagged'); - - if (options && options.track && state.tag !== null) - options.track(input.path(), input.offset, input.length, 'content'); - - // Select proper method for tag - if (state.any) { - // no-op - } else if (state.choice === null) { - result = this._decodeGeneric(state.tag, input, options); - } else { - result = this._decodeChoice(input, options); - } - - if (input.isError(result)) - return result; - - // Decode children - if (!state.any && state.choice === null && state.children !== null) { - state.children.forEach(function decodeChildren(child) { - // NOTE: We are ignoring errors here, to let parser continue with other - // parts of encoded data - child._decode(input, options); - }); - } - - // Decode contained/encoded by schema, only in bit or octet strings - if (state.contains && (state.tag === 'octstr' || state.tag === 'bitstr')) { - const data = new DecoderBuffer(result); - result = this._getUse(state.contains, input._reporterState.obj) - ._decode(data, options); - } - } - - // Pop object - if (state.obj && present) - result = input.leaveObject(prevObj); - - // Set key - if (state.key !== null && (result !== null || present === true)) - input.leaveKey(prevKey, state.key, result); - else if (prevKey !== null) - input.exitKey(prevKey); - - return result; -}; - -Node.prototype._decodeGeneric = function decodeGeneric(tag, input, options) { - const state = this._baseState; - - if (tag === 'seq' || tag === 'set') - return null; - if (tag === 'seqof' || tag === 'setof') - return this._decodeList(input, tag, state.args[0], options); - else if (/str$/.test(tag)) - return this._decodeStr(input, tag, options); - else if (tag === 'objid' && state.args) - return this._decodeObjid(input, state.args[0], state.args[1], options); - else if (tag === 'objid') - return this._decodeObjid(input, null, null, options); - else if (tag === 'gentime' || tag === 'utctime') - return this._decodeTime(input, tag, options); - else if (tag === 'null_') - return this._decodeNull(input, options); - else if (tag === 'bool') - return this._decodeBool(input, options); - else if (tag === 'objDesc') - return this._decodeStr(input, tag, options); - else if (tag === 'int' || tag === 'enum') - return this._decodeInt(input, state.args && state.args[0], options); - - if (state.use !== null) { - return this._getUse(state.use, input._reporterState.obj) - ._decode(input, options); - } else { - return input.error('unknown tag: ' + tag); - } -}; - -Node.prototype._getUse = function _getUse(entity, obj) { - - const state = this._baseState; - // Create altered use decoder if implicit is set - state.useDecoder = this._use(entity, obj); - assert(state.useDecoder._baseState.parent === null); - state.useDecoder = state.useDecoder._baseState.children[0]; - if (state.implicit !== state.useDecoder._baseState.implicit) { - state.useDecoder = state.useDecoder.clone(); - state.useDecoder._baseState.implicit = state.implicit; - } - return state.useDecoder; -}; - -Node.prototype._decodeChoice = function decodeChoice(input, options) { - const state = this._baseState; - let result = null; - let match = false; - - Object.keys(state.choice).some(function(key) { - const save = input.save(); - const node = state.choice[key]; - try { - const value = node._decode(input, options); - if (input.isError(value)) - return false; - - result = { type: key, value: value }; - match = true; - } catch (e) { - input.restore(save); - return false; - } - return true; - }, this); - - if (!match) - return input.error('Choice not matched'); - - return result; -}; - -// -// Encoding -// - -Node.prototype._createEncoderBuffer = function createEncoderBuffer(data) { - return new EncoderBuffer(data, this.reporter); -}; - -Node.prototype._encode = function encode(data, reporter, parent) { - const state = this._baseState; - if (state['default'] !== null && state['default'] === data) - return; - - const result = this._encodeValue(data, reporter, parent); - if (result === undefined) - return; - - if (this._skipDefault(result, reporter, parent)) - return; - - return result; -}; - -Node.prototype._encodeValue = function encode(data, reporter, parent) { - const state = this._baseState; - - // Decode root node - if (state.parent === null) - return state.children[0]._encode(data, reporter || new Reporter()); - - let result = null; - - // Set reporter to share it with a child class - this.reporter = reporter; - - // Check if data is there - if (state.optional && data === undefined) { - if (state['default'] !== null) - data = state['default']; - else - return; - } - - // Encode children first - let content = null; - let primitive = false; - if (state.any) { - // Anything that was given is translated to buffer - result = this._createEncoderBuffer(data); - } else if (state.choice) { - result = this._encodeChoice(data, reporter); - } else if (state.contains) { - content = this._getUse(state.contains, parent)._encode(data, reporter); - primitive = true; - } else if (state.children) { - content = state.children.map(function(child) { - if (child._baseState.tag === 'null_') - return child._encode(null, reporter, data); - - if (child._baseState.key === null) - return reporter.error('Child should have a key'); - const prevKey = reporter.enterKey(child._baseState.key); - - if (typeof data !== 'object') - return reporter.error('Child expected, but input is not object'); - - const res = child._encode(data[child._baseState.key], reporter, data); - reporter.leaveKey(prevKey); - - return res; - }, this).filter(function(child) { - return child; - }); - content = this._createEncoderBuffer(content); - } else { - if (state.tag === 'seqof' || state.tag === 'setof') { - // TODO(indutny): this should be thrown on DSL level - if (!(state.args && state.args.length === 1)) - return reporter.error('Too many args for : ' + state.tag); - - if (!Array.isArray(data)) - return reporter.error('seqof/setof, but data is not Array'); - - const child = this.clone(); - child._baseState.implicit = null; - content = this._createEncoderBuffer(data.map(function(item) { - const state = this._baseState; - - return this._getUse(state.args[0], data)._encode(item, reporter); - }, child)); - } else if (state.use !== null) { - result = this._getUse(state.use, parent)._encode(data, reporter); - } else { - content = this._encodePrimitive(state.tag, data); - primitive = true; - } - } - - // Encode data itself - if (!state.any && state.choice === null) { - const tag = state.implicit !== null ? state.implicit : state.tag; - const cls = state.implicit === null ? 'universal' : 'context'; - - if (tag === null) { - if (state.use === null) - reporter.error('Tag could be omitted only for .use()'); - } else { - if (state.use === null) - result = this._encodeComposite(tag, primitive, cls, content); - } - } - - // Wrap in explicit - if (state.explicit !== null) - result = this._encodeComposite(state.explicit, false, 'context', result); - - return result; -}; - -Node.prototype._encodeChoice = function encodeChoice(data, reporter) { - const state = this._baseState; - - const node = state.choice[data.type]; - if (!node) { - assert( - false, - data.type + ' not found in ' + - JSON.stringify(Object.keys(state.choice))); - } - return node._encode(data.value, reporter); -}; - -Node.prototype._encodePrimitive = function encodePrimitive(tag, data) { - const state = this._baseState; - - if (/str$/.test(tag)) - return this._encodeStr(data, tag); - else if (tag === 'objid' && state.args) - return this._encodeObjid(data, state.reverseArgs[0], state.args[1]); - else if (tag === 'objid') - return this._encodeObjid(data, null, null); - else if (tag === 'gentime' || tag === 'utctime') - return this._encodeTime(data, tag); - else if (tag === 'null_') - return this._encodeNull(); - else if (tag === 'int' || tag === 'enum') - return this._encodeInt(data, state.args && state.reverseArgs[0]); - else if (tag === 'bool') - return this._encodeBool(data); - else if (tag === 'objDesc') - return this._encodeStr(data, tag); - else - throw new Error('Unsupported tag: ' + tag); -}; - -Node.prototype._isNumstr = function isNumstr(str) { - return /^[0-9 ]*$/.test(str); -}; - -Node.prototype._isPrintstr = function isPrintstr(str) { - return /^[A-Za-z0-9 '()+,-./:=?]*$/.test(str); -}; diff --git a/node_modules/asn1.js/lib/asn1/base/reporter.js b/node_modules/asn1.js/lib/asn1/base/reporter.js deleted file mode 100644 index d05fe12..0000000 --- a/node_modules/asn1.js/lib/asn1/base/reporter.js +++ /dev/null @@ -1,123 +0,0 @@ -'use strict'; - -const inherits = require('inherits'); - -function Reporter(options) { - this._reporterState = { - obj: null, - path: [], - options: options || {}, - errors: [] - }; -} -exports.Reporter = Reporter; - -Reporter.prototype.isError = function isError(obj) { - return obj instanceof ReporterError; -}; - -Reporter.prototype.save = function save() { - const state = this._reporterState; - - return { obj: state.obj, pathLen: state.path.length }; -}; - -Reporter.prototype.restore = function restore(data) { - const state = this._reporterState; - - state.obj = data.obj; - state.path = state.path.slice(0, data.pathLen); -}; - -Reporter.prototype.enterKey = function enterKey(key) { - return this._reporterState.path.push(key); -}; - -Reporter.prototype.exitKey = function exitKey(index) { - const state = this._reporterState; - - state.path = state.path.slice(0, index - 1); -}; - -Reporter.prototype.leaveKey = function leaveKey(index, key, value) { - const state = this._reporterState; - - this.exitKey(index); - if (state.obj !== null) - state.obj[key] = value; -}; - -Reporter.prototype.path = function path() { - return this._reporterState.path.join('/'); -}; - -Reporter.prototype.enterObject = function enterObject() { - const state = this._reporterState; - - const prev = state.obj; - state.obj = {}; - return prev; -}; - -Reporter.prototype.leaveObject = function leaveObject(prev) { - const state = this._reporterState; - - const now = state.obj; - state.obj = prev; - return now; -}; - -Reporter.prototype.error = function error(msg) { - let err; - const state = this._reporterState; - - const inherited = msg instanceof ReporterError; - if (inherited) { - err = msg; - } else { - err = new ReporterError(state.path.map(function(elem) { - return '[' + JSON.stringify(elem) + ']'; - }).join(''), msg.message || msg, msg.stack); - } - - if (!state.options.partial) - throw err; - - if (!inherited) - state.errors.push(err); - - return err; -}; - -Reporter.prototype.wrapResult = function wrapResult(result) { - const state = this._reporterState; - if (!state.options.partial) - return result; - - return { - result: this.isError(result) ? null : result, - errors: state.errors - }; -}; - -function ReporterError(path, msg) { - this.path = path; - this.rethrow(msg); -} -inherits(ReporterError, Error); - -ReporterError.prototype.rethrow = function rethrow(msg) { - this.message = msg + ' at: ' + (this.path || '(shallow)'); - if (Error.captureStackTrace) - Error.captureStackTrace(this, ReporterError); - - if (!this.stack) { - try { - // IE only adds stack when thrown - throw new Error(this.message); - } catch (e) { - this.stack = e.stack; - } - } - return this; -}; diff --git a/node_modules/asn1.js/lib/asn1/constants/der.js b/node_modules/asn1.js/lib/asn1/constants/der.js deleted file mode 100644 index 2b678aa..0000000 --- a/node_modules/asn1.js/lib/asn1/constants/der.js +++ /dev/null @@ -1,58 +0,0 @@ -'use strict'; - -// Helper -function reverse(map) { - const res = {}; - - Object.keys(map).forEach(function(key) { - // Convert key to integer if it is stringified - if ((key | 0) == key) - key = key | 0; - - const value = map[key]; - res[value] = key; - }); - - return res; -} - -exports.tagClass = { - 0: 'universal', - 1: 'application', - 2: 'context', - 3: 'private' -}; -exports.tagClassByName = reverse(exports.tagClass); - -exports.tag = { - 0x00: 'end', - 0x01: 'bool', - 0x02: 'int', - 0x03: 'bitstr', - 0x04: 'octstr', - 0x05: 'null_', - 0x06: 'objid', - 0x07: 'objDesc', - 0x08: 'external', - 0x09: 'real', - 0x0a: 'enum', - 0x0b: 'embed', - 0x0c: 'utf8str', - 0x0d: 'relativeOid', - 0x10: 'seq', - 0x11: 'set', - 0x12: 'numstr', - 0x13: 'printstr', - 0x14: 't61str', - 0x15: 'videostr', - 0x16: 'ia5str', - 0x17: 'utctime', - 0x18: 'gentime', - 0x19: 'graphstr', - 0x1a: 'iso646str', - 0x1b: 'genstr', - 0x1c: 'unistr', - 0x1d: 'charstr', - 0x1e: 'bmpstr' -}; -exports.tagByName = reverse(exports.tag); diff --git a/node_modules/asn1.js/lib/asn1/constants/index.js b/node_modules/asn1.js/lib/asn1/constants/index.js deleted file mode 100644 index 632cf3d..0000000 --- a/node_modules/asn1.js/lib/asn1/constants/index.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -const constants = exports; - -// Helper -constants._reverse = function reverse(map) { - const res = {}; - - Object.keys(map).forEach(function(key) { - // Convert key to integer if it is stringified - if ((key | 0) == key) - key = key | 0; - - const value = map[key]; - res[value] = key; - }); - - return res; -}; - -constants.der = require('./der'); diff --git a/node_modules/asn1.js/lib/asn1/decoders/der.js b/node_modules/asn1.js/lib/asn1/decoders/der.js deleted file mode 100644 index c5b0515..0000000 --- a/node_modules/asn1.js/lib/asn1/decoders/der.js +++ /dev/null @@ -1,335 +0,0 @@ -'use strict'; - -const inherits = require('inherits'); - -const bignum = require('bn.js'); -const DecoderBuffer = require('../base/buffer').DecoderBuffer; -const Node = require('../base/node'); - -// Import DER constants -const der = require('../constants/der'); - -function DERDecoder(entity) { - this.enc = 'der'; - this.name = entity.name; - this.entity = entity; - - // Construct base tree - this.tree = new DERNode(); - this.tree._init(entity.body); -} -module.exports = DERDecoder; - -DERDecoder.prototype.decode = function decode(data, options) { - if (!DecoderBuffer.isDecoderBuffer(data)) { - data = new DecoderBuffer(data, options); - } - - return this.tree._decode(data, options); -}; - -// Tree methods - -function DERNode(parent) { - Node.call(this, 'der', parent); -} -inherits(DERNode, Node); - -DERNode.prototype._peekTag = function peekTag(buffer, tag, any) { - if (buffer.isEmpty()) - return false; - - const state = buffer.save(); - const decodedTag = derDecodeTag(buffer, 'Failed to peek tag: "' + tag + '"'); - if (buffer.isError(decodedTag)) - return decodedTag; - - buffer.restore(state); - - return decodedTag.tag === tag || decodedTag.tagStr === tag || - (decodedTag.tagStr + 'of') === tag || any; -}; - -DERNode.prototype._decodeTag = function decodeTag(buffer, tag, any) { - const decodedTag = derDecodeTag(buffer, - 'Failed to decode tag of "' + tag + '"'); - if (buffer.isError(decodedTag)) - return decodedTag; - - let len = derDecodeLen(buffer, - decodedTag.primitive, - 'Failed to get length of "' + tag + '"'); - - // Failure - if (buffer.isError(len)) - return len; - - if (!any && - decodedTag.tag !== tag && - decodedTag.tagStr !== tag && - decodedTag.tagStr + 'of' !== tag) { - return buffer.error('Failed to match tag: "' + tag + '"'); - } - - if (decodedTag.primitive || len !== null) - return buffer.skip(len, 'Failed to match body of: "' + tag + '"'); - - // Indefinite length... find END tag - const state = buffer.save(); - const res = this._skipUntilEnd( - buffer, - 'Failed to skip indefinite length body: "' + this.tag + '"'); - if (buffer.isError(res)) - return res; - - len = buffer.offset - state.offset; - buffer.restore(state); - return buffer.skip(len, 'Failed to match body of: "' + tag + '"'); -}; - -DERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer, fail) { - for (;;) { - const tag = derDecodeTag(buffer, fail); - if (buffer.isError(tag)) - return tag; - const len = derDecodeLen(buffer, tag.primitive, fail); - if (buffer.isError(len)) - return len; - - let res; - if (tag.primitive || len !== null) - res = buffer.skip(len); - else - res = this._skipUntilEnd(buffer, fail); - - // Failure - if (buffer.isError(res)) - return res; - - if (tag.tagStr === 'end') - break; - } -}; - -DERNode.prototype._decodeList = function decodeList(buffer, tag, decoder, - options) { - const result = []; - while (!buffer.isEmpty()) { - const possibleEnd = this._peekTag(buffer, 'end'); - if (buffer.isError(possibleEnd)) - return possibleEnd; - - const res = decoder.decode(buffer, 'der', options); - if (buffer.isError(res) && possibleEnd) - break; - result.push(res); - } - return result; -}; - -DERNode.prototype._decodeStr = function decodeStr(buffer, tag) { - if (tag === 'bitstr') { - const unused = buffer.readUInt8(); - if (buffer.isError(unused)) - return unused; - return { unused: unused, data: buffer.raw() }; - } else if (tag === 'bmpstr') { - const raw = buffer.raw(); - if (raw.length % 2 === 1) - return buffer.error('Decoding of string type: bmpstr length mismatch'); - - let str = ''; - for (let i = 0; i < raw.length / 2; i++) { - str += String.fromCharCode(raw.readUInt16BE(i * 2)); - } - return str; - } else if (tag === 'numstr') { - const numstr = buffer.raw().toString('ascii'); - if (!this._isNumstr(numstr)) { - return buffer.error('Decoding of string type: ' + - 'numstr unsupported characters'); - } - return numstr; - } else if (tag === 'octstr') { - return buffer.raw(); - } else if (tag === 'objDesc') { - return buffer.raw(); - } else if (tag === 'printstr') { - const printstr = buffer.raw().toString('ascii'); - if (!this._isPrintstr(printstr)) { - return buffer.error('Decoding of string type: ' + - 'printstr unsupported characters'); - } - return printstr; - } else if (/str$/.test(tag)) { - return buffer.raw().toString(); - } else { - return buffer.error('Decoding of string type: ' + tag + ' unsupported'); - } -}; - -DERNode.prototype._decodeObjid = function decodeObjid(buffer, values, relative) { - let result; - const identifiers = []; - let ident = 0; - let subident = 0; - while (!buffer.isEmpty()) { - subident = buffer.readUInt8(); - ident <<= 7; - ident |= subident & 0x7f; - if ((subident & 0x80) === 0) { - identifiers.push(ident); - ident = 0; - } - } - if (subident & 0x80) - identifiers.push(ident); - - const first = (identifiers[0] / 40) | 0; - const second = identifiers[0] % 40; - - if (relative) - result = identifiers; - else - result = [first, second].concat(identifiers.slice(1)); - - if (values) { - let tmp = values[result.join(' ')]; - if (tmp === undefined) - tmp = values[result.join('.')]; - if (tmp !== undefined) - result = tmp; - } - - return result; -}; - -DERNode.prototype._decodeTime = function decodeTime(buffer, tag) { - const str = buffer.raw().toString(); - - let year; - let mon; - let day; - let hour; - let min; - let sec; - if (tag === 'gentime') { - year = str.slice(0, 4) | 0; - mon = str.slice(4, 6) | 0; - day = str.slice(6, 8) | 0; - hour = str.slice(8, 10) | 0; - min = str.slice(10, 12) | 0; - sec = str.slice(12, 14) | 0; - } else if (tag === 'utctime') { - year = str.slice(0, 2) | 0; - mon = str.slice(2, 4) | 0; - day = str.slice(4, 6) | 0; - hour = str.slice(6, 8) | 0; - min = str.slice(8, 10) | 0; - sec = str.slice(10, 12) | 0; - if (year < 70) - year = 2000 + year; - else - year = 1900 + year; - } else { - return buffer.error('Decoding ' + tag + ' time is not supported yet'); - } - - return Date.UTC(year, mon - 1, day, hour, min, sec, 0); -}; - -DERNode.prototype._decodeNull = function decodeNull() { - return null; -}; - -DERNode.prototype._decodeBool = function decodeBool(buffer) { - const res = buffer.readUInt8(); - if (buffer.isError(res)) - return res; - else - return res !== 0; -}; - -DERNode.prototype._decodeInt = function decodeInt(buffer, values) { - // Bigint, return as it is (assume big endian) - const raw = buffer.raw(); - let res = new bignum(raw); - - if (values) - res = values[res.toString(10)] || res; - - return res; -}; - -DERNode.prototype._use = function use(entity, obj) { - if (typeof entity === 'function') - entity = entity(obj); - return entity._getDecoder('der').tree; -}; - -// Utility methods - -function derDecodeTag(buf, fail) { - let tag = buf.readUInt8(fail); - if (buf.isError(tag)) - return tag; - - const cls = der.tagClass[tag >> 6]; - const primitive = (tag & 0x20) === 0; - - // Multi-octet tag - load - if ((tag & 0x1f) === 0x1f) { - let oct = tag; - tag = 0; - while ((oct & 0x80) === 0x80) { - oct = buf.readUInt8(fail); - if (buf.isError(oct)) - return oct; - - tag <<= 7; - tag |= oct & 0x7f; - } - } else { - tag &= 0x1f; - } - const tagStr = der.tag[tag]; - - return { - cls: cls, - primitive: primitive, - tag: tag, - tagStr: tagStr - }; -} - -function derDecodeLen(buf, primitive, fail) { - let len = buf.readUInt8(fail); - if (buf.isError(len)) - return len; - - // Indefinite form - if (!primitive && len === 0x80) - return null; - - // Definite form - if ((len & 0x80) === 0) { - // Short form - return len; - } - - // Long form - const num = len & 0x7f; - if (num > 4) - return buf.error('length octect is too long'); - - len = 0; - for (let i = 0; i < num; i++) { - len <<= 8; - const j = buf.readUInt8(fail); - if (buf.isError(j)) - return j; - len |= j; - } - - return len; -} diff --git a/node_modules/asn1.js/lib/asn1/decoders/index.js b/node_modules/asn1.js/lib/asn1/decoders/index.js deleted file mode 100644 index 14fb05a..0000000 --- a/node_modules/asn1.js/lib/asn1/decoders/index.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -const decoders = exports; - -decoders.der = require('./der'); -decoders.pem = require('./pem'); diff --git a/node_modules/asn1.js/lib/asn1/decoders/pem.js b/node_modules/asn1.js/lib/asn1/decoders/pem.js deleted file mode 100644 index 2b050ef..0000000 --- a/node_modules/asn1.js/lib/asn1/decoders/pem.js +++ /dev/null @@ -1,51 +0,0 @@ -'use strict'; - -const inherits = require('inherits'); -const Buffer = require('safer-buffer').Buffer; - -const DERDecoder = require('./der'); - -function PEMDecoder(entity) { - DERDecoder.call(this, entity); - this.enc = 'pem'; -} -inherits(PEMDecoder, DERDecoder); -module.exports = PEMDecoder; - -PEMDecoder.prototype.decode = function decode(data, options) { - const lines = data.toString().split(/[\r\n]+/g); - - const label = options.label.toUpperCase(); - - const re = /^-----(BEGIN|END) ([^-]+)-----$/; - let start = -1; - let end = -1; - for (let i = 0; i < lines.length; i++) { - const match = lines[i].match(re); - if (match === null) - continue; - - if (match[2] !== label) - continue; - - if (start === -1) { - if (match[1] !== 'BEGIN') - break; - start = i; - } else { - if (match[1] !== 'END') - break; - end = i; - break; - } - } - if (start === -1 || end === -1) - throw new Error('PEM section not found for: ' + label); - - const base64 = lines.slice(start + 1, end).join(''); - // Remove excessive symbols - base64.replace(/[^a-z0-9+/=]+/gi, ''); - - const input = Buffer.from(base64, 'base64'); - return DERDecoder.prototype.decode.call(this, input, options); -}; diff --git a/node_modules/asn1.js/lib/asn1/encoders/der.js b/node_modules/asn1.js/lib/asn1/encoders/der.js deleted file mode 100644 index 55eb435..0000000 --- a/node_modules/asn1.js/lib/asn1/encoders/der.js +++ /dev/null @@ -1,295 +0,0 @@ -'use strict'; - -const inherits = require('inherits'); -const Buffer = require('safer-buffer').Buffer; -const Node = require('../base/node'); - -// Import DER constants -const der = require('../constants/der'); - -function DEREncoder(entity) { - this.enc = 'der'; - this.name = entity.name; - this.entity = entity; - - // Construct base tree - this.tree = new DERNode(); - this.tree._init(entity.body); -} -module.exports = DEREncoder; - -DEREncoder.prototype.encode = function encode(data, reporter) { - return this.tree._encode(data, reporter).join(); -}; - -// Tree methods - -function DERNode(parent) { - Node.call(this, 'der', parent); -} -inherits(DERNode, Node); - -DERNode.prototype._encodeComposite = function encodeComposite(tag, - primitive, - cls, - content) { - const encodedTag = encodeTag(tag, primitive, cls, this.reporter); - - // Short form - if (content.length < 0x80) { - const header = Buffer.alloc(2); - header[0] = encodedTag; - header[1] = content.length; - return this._createEncoderBuffer([ header, content ]); - } - - // Long form - // Count octets required to store length - let lenOctets = 1; - for (let i = content.length; i >= 0x100; i >>= 8) - lenOctets++; - - const header = Buffer.alloc(1 + 1 + lenOctets); - header[0] = encodedTag; - header[1] = 0x80 | lenOctets; - - for (let i = 1 + lenOctets, j = content.length; j > 0; i--, j >>= 8) - header[i] = j & 0xff; - - return this._createEncoderBuffer([ header, content ]); -}; - -DERNode.prototype._encodeStr = function encodeStr(str, tag) { - if (tag === 'bitstr') { - return this._createEncoderBuffer([ str.unused | 0, str.data ]); - } else if (tag === 'bmpstr') { - const buf = Buffer.alloc(str.length * 2); - for (let i = 0; i < str.length; i++) { - buf.writeUInt16BE(str.charCodeAt(i), i * 2); - } - return this._createEncoderBuffer(buf); - } else if (tag === 'numstr') { - if (!this._isNumstr(str)) { - return this.reporter.error('Encoding of string type: numstr supports ' + - 'only digits and space'); - } - return this._createEncoderBuffer(str); - } else if (tag === 'printstr') { - if (!this._isPrintstr(str)) { - return this.reporter.error('Encoding of string type: printstr supports ' + - 'only latin upper and lower case letters, ' + - 'digits, space, apostrophe, left and rigth ' + - 'parenthesis, plus sign, comma, hyphen, ' + - 'dot, slash, colon, equal sign, ' + - 'question mark'); - } - return this._createEncoderBuffer(str); - } else if (/str$/.test(tag)) { - return this._createEncoderBuffer(str); - } else if (tag === 'objDesc') { - return this._createEncoderBuffer(str); - } else { - return this.reporter.error('Encoding of string type: ' + tag + - ' unsupported'); - } -}; - -DERNode.prototype._encodeObjid = function encodeObjid(id, values, relative) { - if (typeof id === 'string') { - if (!values) - return this.reporter.error('string objid given, but no values map found'); - if (!values.hasOwnProperty(id)) - return this.reporter.error('objid not found in values map'); - id = values[id].split(/[\s.]+/g); - for (let i = 0; i < id.length; i++) - id[i] |= 0; - } else if (Array.isArray(id)) { - id = id.slice(); - for (let i = 0; i < id.length; i++) - id[i] |= 0; - } - - if (!Array.isArray(id)) { - return this.reporter.error('objid() should be either array or string, ' + - 'got: ' + JSON.stringify(id)); - } - - if (!relative) { - if (id[1] >= 40) - return this.reporter.error('Second objid identifier OOB'); - id.splice(0, 2, id[0] * 40 + id[1]); - } - - // Count number of octets - let size = 0; - for (let i = 0; i < id.length; i++) { - let ident = id[i]; - for (size++; ident >= 0x80; ident >>= 7) - size++; - } - - const objid = Buffer.alloc(size); - let offset = objid.length - 1; - for (let i = id.length - 1; i >= 0; i--) { - let ident = id[i]; - objid[offset--] = ident & 0x7f; - while ((ident >>= 7) > 0) - objid[offset--] = 0x80 | (ident & 0x7f); - } - - return this._createEncoderBuffer(objid); -}; - -function two(num) { - if (num < 10) - return '0' + num; - else - return num; -} - -DERNode.prototype._encodeTime = function encodeTime(time, tag) { - let str; - const date = new Date(time); - - if (tag === 'gentime') { - str = [ - two(date.getUTCFullYear()), - two(date.getUTCMonth() + 1), - two(date.getUTCDate()), - two(date.getUTCHours()), - two(date.getUTCMinutes()), - two(date.getUTCSeconds()), - 'Z' - ].join(''); - } else if (tag === 'utctime') { - str = [ - two(date.getUTCFullYear() % 100), - two(date.getUTCMonth() + 1), - two(date.getUTCDate()), - two(date.getUTCHours()), - two(date.getUTCMinutes()), - two(date.getUTCSeconds()), - 'Z' - ].join(''); - } else { - this.reporter.error('Encoding ' + tag + ' time is not supported yet'); - } - - return this._encodeStr(str, 'octstr'); -}; - -DERNode.prototype._encodeNull = function encodeNull() { - return this._createEncoderBuffer(''); -}; - -DERNode.prototype._encodeInt = function encodeInt(num, values) { - if (typeof num === 'string') { - if (!values) - return this.reporter.error('String int or enum given, but no values map'); - if (!values.hasOwnProperty(num)) { - return this.reporter.error('Values map doesn\'t contain: ' + - JSON.stringify(num)); - } - num = values[num]; - } - - // Bignum, assume big endian - if (typeof num !== 'number' && !Buffer.isBuffer(num)) { - const numArray = num.toArray(); - if (!num.sign && numArray[0] & 0x80) { - numArray.unshift(0); - } - num = Buffer.from(numArray); - } - - if (Buffer.isBuffer(num)) { - let size = num.length; - if (num.length === 0) - size++; - - const out = Buffer.alloc(size); - num.copy(out); - if (num.length === 0) - out[0] = 0; - return this._createEncoderBuffer(out); - } - - if (num < 0x80) - return this._createEncoderBuffer(num); - - if (num < 0x100) - return this._createEncoderBuffer([0, num]); - - let size = 1; - for (let i = num; i >= 0x100; i >>= 8) - size++; - - const out = new Array(size); - for (let i = out.length - 1; i >= 0; i--) { - out[i] = num & 0xff; - num >>= 8; - } - if(out[0] & 0x80) { - out.unshift(0); - } - - return this._createEncoderBuffer(Buffer.from(out)); -}; - -DERNode.prototype._encodeBool = function encodeBool(value) { - return this._createEncoderBuffer(value ? 0xff : 0); -}; - -DERNode.prototype._use = function use(entity, obj) { - if (typeof entity === 'function') - entity = entity(obj); - return entity._getEncoder('der').tree; -}; - -DERNode.prototype._skipDefault = function skipDefault(dataBuffer, reporter, parent) { - const state = this._baseState; - let i; - if (state['default'] === null) - return false; - - const data = dataBuffer.join(); - if (state.defaultBuffer === undefined) - state.defaultBuffer = this._encodeValue(state['default'], reporter, parent).join(); - - if (data.length !== state.defaultBuffer.length) - return false; - - for (i=0; i < data.length; i++) - if (data[i] !== state.defaultBuffer[i]) - return false; - - return true; -}; - -// Utility methods - -function encodeTag(tag, primitive, cls, reporter) { - let res; - - if (tag === 'seqof') - tag = 'seq'; - else if (tag === 'setof') - tag = 'set'; - - if (der.tagByName.hasOwnProperty(tag)) - res = der.tagByName[tag]; - else if (typeof tag === 'number' && (tag | 0) === tag) - res = tag; - else - return reporter.error('Unknown tag: ' + tag); - - if (res >= 0x1f) - return reporter.error('Multi-octet tag encoding unsupported'); - - if (!primitive) - res |= 0x20; - - res |= (der.tagClassByName[cls || 'universal'] << 6); - - return res; -} diff --git a/node_modules/asn1.js/lib/asn1/encoders/index.js b/node_modules/asn1.js/lib/asn1/encoders/index.js deleted file mode 100644 index bb8ea34..0000000 --- a/node_modules/asn1.js/lib/asn1/encoders/index.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -const encoders = exports; - -encoders.der = require('./der'); -encoders.pem = require('./pem'); diff --git a/node_modules/asn1.js/lib/asn1/encoders/pem.js b/node_modules/asn1.js/lib/asn1/encoders/pem.js deleted file mode 100644 index 77fbdb4..0000000 --- a/node_modules/asn1.js/lib/asn1/encoders/pem.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -const inherits = require('inherits'); - -const DEREncoder = require('./der'); - -function PEMEncoder(entity) { - DEREncoder.call(this, entity); - this.enc = 'pem'; -} -inherits(PEMEncoder, DEREncoder); -module.exports = PEMEncoder; - -PEMEncoder.prototype.encode = function encode(data, options) { - const buf = DEREncoder.prototype.encode.call(this, data); - - const p = buf.toString('base64'); - const out = [ '-----BEGIN ' + options.label + '-----' ]; - for (let i = 0; i < p.length; i += 64) - out.push(p.slice(i, i + 64)); - out.push('-----END ' + options.label + '-----'); - return out.join('\n'); -}; diff --git a/node_modules/asn1.js/package.json b/node_modules/asn1.js/package.json deleted file mode 100644 index 7b7d053..0000000 --- a/node_modules/asn1.js/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "asn1.js", - "version": "5.4.1", - "description": "ASN.1 encoder and decoder", - "main": "lib/asn1.js", - "scripts": { - "lint-2560": "eslint --fix rfc/2560/*.js rfc/2560/test/*.js", - "lint-5280": "eslint --fix rfc/5280/*.js rfc/5280/test/*.js", - "lint": "eslint --fix lib/*.js lib/**/*.js lib/**/**/*.js && npm run lint-2560 && npm run lint-5280", - "test": "mocha --reporter spec test/*-test.js && cd rfc/2560 && npm i && npm test && cd ../../rfc/5280 && npm i && npm test && cd ../../ && npm run lint" - }, - "repository": { - "type": "git", - "url": "git@github.com:indutny/asn1.js" - }, - "keywords": [ - "asn.1", - "der" - ], - "author": "Fedor Indutny", - "license": "MIT", - "bugs": { - "url": "https://github.com/indutny/asn1.js/issues" - }, - "homepage": "https://github.com/indutny/asn1.js", - "devDependencies": { - "eslint": "^4.10.0", - "mocha": "^7.0.0" - }, - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } -} diff --git a/node_modules/bn.js/LICENSE b/node_modules/bn.js/LICENSE deleted file mode 100644 index c328f04..0000000 --- a/node_modules/bn.js/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright Fedor Indutny, 2015. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/node_modules/bn.js/README.md b/node_modules/bn.js/README.md deleted file mode 100644 index aecc3ba..0000000 --- a/node_modules/bn.js/README.md +++ /dev/null @@ -1,200 +0,0 @@ -# bn.js - -> BigNum in pure javascript - -[![Build Status](https://secure.travis-ci.org/indutny/bn.js.png)](http://travis-ci.org/indutny/bn.js) - -## Install -`npm install --save bn.js` - -## Usage - -```js -const BN = require('bn.js'); - -var a = new BN('dead', 16); -var b = new BN('101010', 2); - -var res = a.add(b); -console.log(res.toString(10)); // 57047 -``` - -**Note**: decimals are not supported in this library. - -## Notation - -### Prefixes - -There are several prefixes to instructions that affect the way the work. Here -is the list of them in the order of appearance in the function name: - -* `i` - perform operation in-place, storing the result in the host object (on - which the method was invoked). Might be used to avoid number allocation costs -* `u` - unsigned, ignore the sign of operands when performing operation, or - always return positive value. Second case applies to reduction operations - like `mod()`. In such cases if the result will be negative - modulo will be - added to the result to make it positive - -### Postfixes - -The only available postfix at the moment is: - -* `n` - which means that the argument of the function must be a plain JavaScript - Number. Decimals are not supported. - -### Examples - -* `a.iadd(b)` - perform addition on `a` and `b`, storing the result in `a` -* `a.umod(b)` - reduce `a` modulo `b`, returning positive value -* `a.iushln(13)` - shift bits of `a` left by 13 - -## Instructions - -Prefixes/postfixes are put in parens at the of the line. `endian` - could be -either `le` (little-endian) or `be` (big-endian). - -### Utilities - -* `a.clone()` - clone number -* `a.toString(base, length)` - convert to base-string and pad with zeroes -* `a.toNumber()` - convert to Javascript Number (limited to 53 bits) -* `a.toJSON()` - convert to JSON compatible hex string (alias of `toString(16)`) -* `a.toArray(endian, length)` - convert to byte `Array`, and optionally zero - pad to length, throwing if already exceeding -* `a.toArrayLike(type, endian, length)` - convert to an instance of `type`, - which must behave like an `Array` -* `a.toBuffer(endian, length)` - convert to Node.js Buffer (if available). For - compatibility with browserify and similar tools, use this instead: - `a.toArrayLike(Buffer, endian, length)` -* `a.bitLength()` - get number of bits occupied -* `a.zeroBits()` - return number of less-significant consequent zero bits - (example: `1010000` has 4 zero bits) -* `a.byteLength()` - return number of bytes occupied -* `a.isNeg()` - true if the number is negative -* `a.isEven()` - no comments -* `a.isOdd()` - no comments -* `a.isZero()` - no comments -* `a.cmp(b)` - compare numbers and return `-1` (a `<` b), `0` (a `==` b), or `1` (a `>` b) - depending on the comparison result (`ucmp`, `cmpn`) -* `a.lt(b)` - `a` less than `b` (`n`) -* `a.lte(b)` - `a` less than or equals `b` (`n`) -* `a.gt(b)` - `a` greater than `b` (`n`) -* `a.gte(b)` - `a` greater than or equals `b` (`n`) -* `a.eq(b)` - `a` equals `b` (`n`) -* `a.toTwos(width)` - convert to two's complement representation, where `width` is bit width -* `a.fromTwos(width)` - convert from two's complement representation, where `width` is the bit width -* `BN.isBN(object)` - returns true if the supplied `object` is a BN.js instance - -### Arithmetics - -* `a.neg()` - negate sign (`i`) -* `a.abs()` - absolute value (`i`) -* `a.add(b)` - addition (`i`, `n`, `in`) -* `a.sub(b)` - subtraction (`i`, `n`, `in`) -* `a.mul(b)` - multiply (`i`, `n`, `in`) -* `a.sqr()` - square (`i`) -* `a.pow(b)` - raise `a` to the power of `b` -* `a.div(b)` - divide (`divn`, `idivn`) -* `a.mod(b)` - reduct (`u`, `n`) (but no `umodn`) -* `a.divRound(b)` - rounded division - -### Bit operations - -* `a.or(b)` - or (`i`, `u`, `iu`) -* `a.and(b)` - and (`i`, `u`, `iu`, `andln`) (NOTE: `andln` is going to be replaced - with `andn` in future) -* `a.xor(b)` - xor (`i`, `u`, `iu`) -* `a.setn(b)` - set specified bit to `1` -* `a.shln(b)` - shift left (`i`, `u`, `iu`) -* `a.shrn(b)` - shift right (`i`, `u`, `iu`) -* `a.testn(b)` - test if specified bit is set -* `a.maskn(b)` - clear bits with indexes higher or equal to `b` (`i`) -* `a.bincn(b)` - add `1 << b` to the number -* `a.notn(w)` - not (for the width specified by `w`) (`i`) - -### Reduction - -* `a.gcd(b)` - GCD -* `a.egcd(b)` - Extended GCD results (`{ a: ..., b: ..., gcd: ... }`) -* `a.invm(b)` - inverse `a` modulo `b` - -## Fast reduction - -When doing lots of reductions using the same modulo, it might be beneficial to -use some tricks: like [Montgomery multiplication][0], or using special algorithm -for [Mersenne Prime][1]. - -### Reduction context - -To enable this tricks one should create a reduction context: - -```js -var red = BN.red(num); -``` -where `num` is just a BN instance. - -Or: - -```js -var red = BN.red(primeName); -``` - -Where `primeName` is either of these [Mersenne Primes][1]: - -* `'k256'` -* `'p224'` -* `'p192'` -* `'p25519'` - -Or: - -```js -var red = BN.mont(num); -``` - -To reduce numbers with [Montgomery trick][0]. `.mont()` is generally faster than -`.red(num)`, but slower than `BN.red(primeName)`. - -### Converting numbers - -Before performing anything in reduction context - numbers should be converted -to it. Usually, this means that one should: - -* Convert inputs to reducted ones -* Operate on them in reduction context -* Convert outputs back from the reduction context - -Here is how one may convert numbers to `red`: - -```js -var redA = a.toRed(red); -``` -Where `red` is a reduction context created using instructions above - -Here is how to convert them back: - -```js -var a = redA.fromRed(); -``` - -### Red instructions - -Most of the instructions from the very start of this readme have their -counterparts in red context: - -* `a.redAdd(b)`, `a.redIAdd(b)` -* `a.redSub(b)`, `a.redISub(b)` -* `a.redShl(num)` -* `a.redMul(b)`, `a.redIMul(b)` -* `a.redSqr()`, `a.redISqr()` -* `a.redSqrt()` - square root modulo reduction context's prime -* `a.redInvm()` - modular inverse of the number -* `a.redNeg()` -* `a.redPow(b)` - modular exponentiation - -## LICENSE - -This software is licensed under the MIT License. - -[0]: https://en.wikipedia.org/wiki/Montgomery_modular_multiplication -[1]: https://en.wikipedia.org/wiki/Mersenne_prime diff --git a/node_modules/bn.js/lib/bn.js b/node_modules/bn.js/lib/bn.js deleted file mode 100644 index ee78646..0000000 --- a/node_modules/bn.js/lib/bn.js +++ /dev/null @@ -1,3446 +0,0 @@ -(function (module, exports) { - 'use strict'; - - // Utils - function assert (val, msg) { - if (!val) throw new Error(msg || 'Assertion failed'); - } - - // Could use `inherits` module, but don't want to move from single file - // architecture yet. - function inherits (ctor, superCtor) { - ctor.super_ = superCtor; - var TempCtor = function () {}; - TempCtor.prototype = superCtor.prototype; - ctor.prototype = new TempCtor(); - ctor.prototype.constructor = ctor; - } - - // BN - - function BN (number, base, endian) { - if (BN.isBN(number)) { - return number; - } - - this.negative = 0; - this.words = null; - this.length = 0; - - // Reduction context - this.red = null; - - if (number !== null) { - if (base === 'le' || base === 'be') { - endian = base; - base = 10; - } - - this._init(number || 0, base || 10, endian || 'be'); - } - } - if (typeof module === 'object') { - module.exports = BN; - } else { - exports.BN = BN; - } - - BN.BN = BN; - BN.wordSize = 26; - - var Buffer; - try { - if (typeof window !== 'undefined' && typeof window.Buffer !== 'undefined') { - Buffer = window.Buffer; - } else { - Buffer = require('buffer').Buffer; - } - } catch (e) { - } - - BN.isBN = function isBN (num) { - if (num instanceof BN) { - return true; - } - - return num !== null && typeof num === 'object' && - num.constructor.wordSize === BN.wordSize && Array.isArray(num.words); - }; - - BN.max = function max (left, right) { - if (left.cmp(right) > 0) return left; - return right; - }; - - BN.min = function min (left, right) { - if (left.cmp(right) < 0) return left; - return right; - }; - - BN.prototype._init = function init (number, base, endian) { - if (typeof number === 'number') { - return this._initNumber(number, base, endian); - } - - if (typeof number === 'object') { - return this._initArray(number, base, endian); - } - - if (base === 'hex') { - base = 16; - } - assert(base === (base | 0) && base >= 2 && base <= 36); - - number = number.toString().replace(/\s+/g, ''); - var start = 0; - if (number[0] === '-') { - start++; - this.negative = 1; - } - - if (start < number.length) { - if (base === 16) { - this._parseHex(number, start, endian); - } else { - this._parseBase(number, base, start); - if (endian === 'le') { - this._initArray(this.toArray(), base, endian); - } - } - } - }; - - BN.prototype._initNumber = function _initNumber (number, base, endian) { - if (number < 0) { - this.negative = 1; - number = -number; - } - if (number < 0x4000000) { - this.words = [ number & 0x3ffffff ]; - this.length = 1; - } else if (number < 0x10000000000000) { - this.words = [ - number & 0x3ffffff, - (number / 0x4000000) & 0x3ffffff - ]; - this.length = 2; - } else { - assert(number < 0x20000000000000); // 2 ^ 53 (unsafe) - this.words = [ - number & 0x3ffffff, - (number / 0x4000000) & 0x3ffffff, - 1 - ]; - this.length = 3; - } - - if (endian !== 'le') return; - - // Reverse the bytes - this._initArray(this.toArray(), base, endian); - }; - - BN.prototype._initArray = function _initArray (number, base, endian) { - // Perhaps a Uint8Array - assert(typeof number.length === 'number'); - if (number.length <= 0) { - this.words = [ 0 ]; - this.length = 1; - return this; - } - - this.length = Math.ceil(number.length / 3); - this.words = new Array(this.length); - for (var i = 0; i < this.length; i++) { - this.words[i] = 0; - } - - var j, w; - var off = 0; - if (endian === 'be') { - for (i = number.length - 1, j = 0; i >= 0; i -= 3) { - w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16); - this.words[j] |= (w << off) & 0x3ffffff; - this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; - off += 24; - if (off >= 26) { - off -= 26; - j++; - } - } - } else if (endian === 'le') { - for (i = 0, j = 0; i < number.length; i += 3) { - w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16); - this.words[j] |= (w << off) & 0x3ffffff; - this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff; - off += 24; - if (off >= 26) { - off -= 26; - j++; - } - } - } - return this.strip(); - }; - - function parseHex4Bits (string, index) { - var c = string.charCodeAt(index); - // 'A' - 'F' - if (c >= 65 && c <= 70) { - return c - 55; - // 'a' - 'f' - } else if (c >= 97 && c <= 102) { - return c - 87; - // '0' - '9' - } else { - return (c - 48) & 0xf; - } - } - - function parseHexByte (string, lowerBound, index) { - var r = parseHex4Bits(string, index); - if (index - 1 >= lowerBound) { - r |= parseHex4Bits(string, index - 1) << 4; - } - return r; - } - - BN.prototype._parseHex = function _parseHex (number, start, endian) { - // Create possibly bigger array to ensure that it fits the number - this.length = Math.ceil((number.length - start) / 6); - this.words = new Array(this.length); - for (var i = 0; i < this.length; i++) { - this.words[i] = 0; - } - - // 24-bits chunks - var off = 0; - var j = 0; - - var w; - if (endian === 'be') { - for (i = number.length - 1; i >= start; i -= 2) { - w = parseHexByte(number, start, i) << off; - this.words[j] |= w & 0x3ffffff; - if (off >= 18) { - off -= 18; - j += 1; - this.words[j] |= w >>> 26; - } else { - off += 8; - } - } - } else { - var parseLength = number.length - start; - for (i = parseLength % 2 === 0 ? start + 1 : start; i < number.length; i += 2) { - w = parseHexByte(number, start, i) << off; - this.words[j] |= w & 0x3ffffff; - if (off >= 18) { - off -= 18; - j += 1; - this.words[j] |= w >>> 26; - } else { - off += 8; - } - } - } - - this.strip(); - }; - - function parseBase (str, start, end, mul) { - var r = 0; - var len = Math.min(str.length, end); - for (var i = start; i < len; i++) { - var c = str.charCodeAt(i) - 48; - - r *= mul; - - // 'a' - if (c >= 49) { - r += c - 49 + 0xa; - - // 'A' - } else if (c >= 17) { - r += c - 17 + 0xa; - - // '0' - '9' - } else { - r += c; - } - } - return r; - } - - BN.prototype._parseBase = function _parseBase (number, base, start) { - // Initialize as zero - this.words = [ 0 ]; - this.length = 1; - - // Find length of limb in base - for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) { - limbLen++; - } - limbLen--; - limbPow = (limbPow / base) | 0; - - var total = number.length - start; - var mod = total % limbLen; - var end = Math.min(total, total - mod) + start; - - var word = 0; - for (var i = start; i < end; i += limbLen) { - word = parseBase(number, i, i + limbLen, base); - - this.imuln(limbPow); - if (this.words[0] + word < 0x4000000) { - this.words[0] += word; - } else { - this._iaddn(word); - } - } - - if (mod !== 0) { - var pow = 1; - word = parseBase(number, i, number.length, base); - - for (i = 0; i < mod; i++) { - pow *= base; - } - - this.imuln(pow); - if (this.words[0] + word < 0x4000000) { - this.words[0] += word; - } else { - this._iaddn(word); - } - } - - this.strip(); - }; - - BN.prototype.copy = function copy (dest) { - dest.words = new Array(this.length); - for (var i = 0; i < this.length; i++) { - dest.words[i] = this.words[i]; - } - dest.length = this.length; - dest.negative = this.negative; - dest.red = this.red; - }; - - BN.prototype.clone = function clone () { - var r = new BN(null); - this.copy(r); - return r; - }; - - BN.prototype._expand = function _expand (size) { - while (this.length < size) { - this.words[this.length++] = 0; - } - return this; - }; - - // Remove leading `0` from `this` - BN.prototype.strip = function strip () { - while (this.length > 1 && this.words[this.length - 1] === 0) { - this.length--; - } - return this._normSign(); - }; - - BN.prototype._normSign = function _normSign () { - // -0 = 0 - if (this.length === 1 && this.words[0] === 0) { - this.negative = 0; - } - return this; - }; - - BN.prototype.inspect = function inspect () { - return (this.red ? ''; - }; - - /* - - var zeros = []; - var groupSizes = []; - var groupBases = []; - - var s = ''; - var i = -1; - while (++i < BN.wordSize) { - zeros[i] = s; - s += '0'; - } - groupSizes[0] = 0; - groupSizes[1] = 0; - groupBases[0] = 0; - groupBases[1] = 0; - var base = 2 - 1; - while (++base < 36 + 1) { - var groupSize = 0; - var groupBase = 1; - while (groupBase < (1 << BN.wordSize) / base) { - groupBase *= base; - groupSize += 1; - } - groupSizes[base] = groupSize; - groupBases[base] = groupBase; - } - - */ - - var zeros = [ - '', - '0', - '00', - '000', - '0000', - '00000', - '000000', - '0000000', - '00000000', - '000000000', - '0000000000', - '00000000000', - '000000000000', - '0000000000000', - '00000000000000', - '000000000000000', - '0000000000000000', - '00000000000000000', - '000000000000000000', - '0000000000000000000', - '00000000000000000000', - '000000000000000000000', - '0000000000000000000000', - '00000000000000000000000', - '000000000000000000000000', - '0000000000000000000000000' - ]; - - var groupSizes = [ - 0, 0, - 25, 16, 12, 11, 10, 9, 8, - 8, 7, 7, 7, 7, 6, 6, - 6, 6, 6, 6, 6, 5, 5, - 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5 - ]; - - var groupBases = [ - 0, 0, - 33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216, - 43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625, - 16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632, - 6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149, - 24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176 - ]; - - BN.prototype.toString = function toString (base, padding) { - base = base || 10; - padding = padding | 0 || 1; - - var out; - if (base === 16 || base === 'hex') { - out = ''; - var off = 0; - var carry = 0; - for (var i = 0; i < this.length; i++) { - var w = this.words[i]; - var word = (((w << off) | carry) & 0xffffff).toString(16); - carry = (w >>> (24 - off)) & 0xffffff; - off += 2; - if (off >= 26) { - off -= 26; - i--; - } - if (carry !== 0 || i !== this.length - 1) { - out = zeros[6 - word.length] + word + out; - } else { - out = word + out; - } - } - if (carry !== 0) { - out = carry.toString(16) + out; - } - while (out.length % padding !== 0) { - out = '0' + out; - } - if (this.negative !== 0) { - out = '-' + out; - } - return out; - } - - if (base === (base | 0) && base >= 2 && base <= 36) { - // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base)); - var groupSize = groupSizes[base]; - // var groupBase = Math.pow(base, groupSize); - var groupBase = groupBases[base]; - out = ''; - var c = this.clone(); - c.negative = 0; - while (!c.isZero()) { - var r = c.modn(groupBase).toString(base); - c = c.idivn(groupBase); - - if (!c.isZero()) { - out = zeros[groupSize - r.length] + r + out; - } else { - out = r + out; - } - } - if (this.isZero()) { - out = '0' + out; - } - while (out.length % padding !== 0) { - out = '0' + out; - } - if (this.negative !== 0) { - out = '-' + out; - } - return out; - } - - assert(false, 'Base should be between 2 and 36'); - }; - - BN.prototype.toNumber = function toNumber () { - var ret = this.words[0]; - if (this.length === 2) { - ret += this.words[1] * 0x4000000; - } else if (this.length === 3 && this.words[2] === 0x01) { - // NOTE: at this stage it is known that the top bit is set - ret += 0x10000000000000 + (this.words[1] * 0x4000000); - } else if (this.length > 2) { - assert(false, 'Number can only safely store up to 53 bits'); - } - return (this.negative !== 0) ? -ret : ret; - }; - - BN.prototype.toJSON = function toJSON () { - return this.toString(16); - }; - - BN.prototype.toBuffer = function toBuffer (endian, length) { - assert(typeof Buffer !== 'undefined'); - return this.toArrayLike(Buffer, endian, length); - }; - - BN.prototype.toArray = function toArray (endian, length) { - return this.toArrayLike(Array, endian, length); - }; - - BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) { - var byteLength = this.byteLength(); - var reqLength = length || Math.max(1, byteLength); - assert(byteLength <= reqLength, 'byte array longer than desired length'); - assert(reqLength > 0, 'Requested array length <= 0'); - - this.strip(); - var littleEndian = endian === 'le'; - var res = new ArrayType(reqLength); - - var b, i; - var q = this.clone(); - if (!littleEndian) { - // Assume big-endian - for (i = 0; i < reqLength - byteLength; i++) { - res[i] = 0; - } - - for (i = 0; !q.isZero(); i++) { - b = q.andln(0xff); - q.iushrn(8); - - res[reqLength - i - 1] = b; - } - } else { - for (i = 0; !q.isZero(); i++) { - b = q.andln(0xff); - q.iushrn(8); - - res[i] = b; - } - - for (; i < reqLength; i++) { - res[i] = 0; - } - } - - return res; - }; - - if (Math.clz32) { - BN.prototype._countBits = function _countBits (w) { - return 32 - Math.clz32(w); - }; - } else { - BN.prototype._countBits = function _countBits (w) { - var t = w; - var r = 0; - if (t >= 0x1000) { - r += 13; - t >>>= 13; - } - if (t >= 0x40) { - r += 7; - t >>>= 7; - } - if (t >= 0x8) { - r += 4; - t >>>= 4; - } - if (t >= 0x02) { - r += 2; - t >>>= 2; - } - return r + t; - }; - } - - BN.prototype._zeroBits = function _zeroBits (w) { - // Short-cut - if (w === 0) return 26; - - var t = w; - var r = 0; - if ((t & 0x1fff) === 0) { - r += 13; - t >>>= 13; - } - if ((t & 0x7f) === 0) { - r += 7; - t >>>= 7; - } - if ((t & 0xf) === 0) { - r += 4; - t >>>= 4; - } - if ((t & 0x3) === 0) { - r += 2; - t >>>= 2; - } - if ((t & 0x1) === 0) { - r++; - } - return r; - }; - - // Return number of used bits in a BN - BN.prototype.bitLength = function bitLength () { - var w = this.words[this.length - 1]; - var hi = this._countBits(w); - return (this.length - 1) * 26 + hi; - }; - - function toBitArray (num) { - var w = new Array(num.bitLength()); - - for (var bit = 0; bit < w.length; bit++) { - var off = (bit / 26) | 0; - var wbit = bit % 26; - - w[bit] = (num.words[off] & (1 << wbit)) >>> wbit; - } - - return w; - } - - // Number of trailing zero bits - BN.prototype.zeroBits = function zeroBits () { - if (this.isZero()) return 0; - - var r = 0; - for (var i = 0; i < this.length; i++) { - var b = this._zeroBits(this.words[i]); - r += b; - if (b !== 26) break; - } - return r; - }; - - BN.prototype.byteLength = function byteLength () { - return Math.ceil(this.bitLength() / 8); - }; - - BN.prototype.toTwos = function toTwos (width) { - if (this.negative !== 0) { - return this.abs().inotn(width).iaddn(1); - } - return this.clone(); - }; - - BN.prototype.fromTwos = function fromTwos (width) { - if (this.testn(width - 1)) { - return this.notn(width).iaddn(1).ineg(); - } - return this.clone(); - }; - - BN.prototype.isNeg = function isNeg () { - return this.negative !== 0; - }; - - // Return negative clone of `this` - BN.prototype.neg = function neg () { - return this.clone().ineg(); - }; - - BN.prototype.ineg = function ineg () { - if (!this.isZero()) { - this.negative ^= 1; - } - - return this; - }; - - // Or `num` with `this` in-place - BN.prototype.iuor = function iuor (num) { - while (this.length < num.length) { - this.words[this.length++] = 0; - } - - for (var i = 0; i < num.length; i++) { - this.words[i] = this.words[i] | num.words[i]; - } - - return this.strip(); - }; - - BN.prototype.ior = function ior (num) { - assert((this.negative | num.negative) === 0); - return this.iuor(num); - }; - - // Or `num` with `this` - BN.prototype.or = function or (num) { - if (this.length > num.length) return this.clone().ior(num); - return num.clone().ior(this); - }; - - BN.prototype.uor = function uor (num) { - if (this.length > num.length) return this.clone().iuor(num); - return num.clone().iuor(this); - }; - - // And `num` with `this` in-place - BN.prototype.iuand = function iuand (num) { - // b = min-length(num, this) - var b; - if (this.length > num.length) { - b = num; - } else { - b = this; - } - - for (var i = 0; i < b.length; i++) { - this.words[i] = this.words[i] & num.words[i]; - } - - this.length = b.length; - - return this.strip(); - }; - - BN.prototype.iand = function iand (num) { - assert((this.negative | num.negative) === 0); - return this.iuand(num); - }; - - // And `num` with `this` - BN.prototype.and = function and (num) { - if (this.length > num.length) return this.clone().iand(num); - return num.clone().iand(this); - }; - - BN.prototype.uand = function uand (num) { - if (this.length > num.length) return this.clone().iuand(num); - return num.clone().iuand(this); - }; - - // Xor `num` with `this` in-place - BN.prototype.iuxor = function iuxor (num) { - // a.length > b.length - var a; - var b; - if (this.length > num.length) { - a = this; - b = num; - } else { - a = num; - b = this; - } - - for (var i = 0; i < b.length; i++) { - this.words[i] = a.words[i] ^ b.words[i]; - } - - if (this !== a) { - for (; i < a.length; i++) { - this.words[i] = a.words[i]; - } - } - - this.length = a.length; - - return this.strip(); - }; - - BN.prototype.ixor = function ixor (num) { - assert((this.negative | num.negative) === 0); - return this.iuxor(num); - }; - - // Xor `num` with `this` - BN.prototype.xor = function xor (num) { - if (this.length > num.length) return this.clone().ixor(num); - return num.clone().ixor(this); - }; - - BN.prototype.uxor = function uxor (num) { - if (this.length > num.length) return this.clone().iuxor(num); - return num.clone().iuxor(this); - }; - - // Not ``this`` with ``width`` bitwidth - BN.prototype.inotn = function inotn (width) { - assert(typeof width === 'number' && width >= 0); - - var bytesNeeded = Math.ceil(width / 26) | 0; - var bitsLeft = width % 26; - - // Extend the buffer with leading zeroes - this._expand(bytesNeeded); - - if (bitsLeft > 0) { - bytesNeeded--; - } - - // Handle complete words - for (var i = 0; i < bytesNeeded; i++) { - this.words[i] = ~this.words[i] & 0x3ffffff; - } - - // Handle the residue - if (bitsLeft > 0) { - this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft)); - } - - // And remove leading zeroes - return this.strip(); - }; - - BN.prototype.notn = function notn (width) { - return this.clone().inotn(width); - }; - - // Set `bit` of `this` - BN.prototype.setn = function setn (bit, val) { - assert(typeof bit === 'number' && bit >= 0); - - var off = (bit / 26) | 0; - var wbit = bit % 26; - - this._expand(off + 1); - - if (val) { - this.words[off] = this.words[off] | (1 << wbit); - } else { - this.words[off] = this.words[off] & ~(1 << wbit); - } - - return this.strip(); - }; - - // Add `num` to `this` in-place - BN.prototype.iadd = function iadd (num) { - var r; - - // negative + positive - if (this.negative !== 0 && num.negative === 0) { - this.negative = 0; - r = this.isub(num); - this.negative ^= 1; - return this._normSign(); - - // positive + negative - } else if (this.negative === 0 && num.negative !== 0) { - num.negative = 0; - r = this.isub(num); - num.negative = 1; - return r._normSign(); - } - - // a.length > b.length - var a, b; - if (this.length > num.length) { - a = this; - b = num; - } else { - a = num; - b = this; - } - - var carry = 0; - for (var i = 0; i < b.length; i++) { - r = (a.words[i] | 0) + (b.words[i] | 0) + carry; - this.words[i] = r & 0x3ffffff; - carry = r >>> 26; - } - for (; carry !== 0 && i < a.length; i++) { - r = (a.words[i] | 0) + carry; - this.words[i] = r & 0x3ffffff; - carry = r >>> 26; - } - - this.length = a.length; - if (carry !== 0) { - this.words[this.length] = carry; - this.length++; - // Copy the rest of the words - } else if (a !== this) { - for (; i < a.length; i++) { - this.words[i] = a.words[i]; - } - } - - return this; - }; - - // Add `num` to `this` - BN.prototype.add = function add (num) { - var res; - if (num.negative !== 0 && this.negative === 0) { - num.negative = 0; - res = this.sub(num); - num.negative ^= 1; - return res; - } else if (num.negative === 0 && this.negative !== 0) { - this.negative = 0; - res = num.sub(this); - this.negative = 1; - return res; - } - - if (this.length > num.length) return this.clone().iadd(num); - - return num.clone().iadd(this); - }; - - // Subtract `num` from `this` in-place - BN.prototype.isub = function isub (num) { - // this - (-num) = this + num - if (num.negative !== 0) { - num.negative = 0; - var r = this.iadd(num); - num.negative = 1; - return r._normSign(); - - // -this - num = -(this + num) - } else if (this.negative !== 0) { - this.negative = 0; - this.iadd(num); - this.negative = 1; - return this._normSign(); - } - - // At this point both numbers are positive - var cmp = this.cmp(num); - - // Optimization - zeroify - if (cmp === 0) { - this.negative = 0; - this.length = 1; - this.words[0] = 0; - return this; - } - - // a > b - var a, b; - if (cmp > 0) { - a = this; - b = num; - } else { - a = num; - b = this; - } - - var carry = 0; - for (var i = 0; i < b.length; i++) { - r = (a.words[i] | 0) - (b.words[i] | 0) + carry; - carry = r >> 26; - this.words[i] = r & 0x3ffffff; - } - for (; carry !== 0 && i < a.length; i++) { - r = (a.words[i] | 0) + carry; - carry = r >> 26; - this.words[i] = r & 0x3ffffff; - } - - // Copy rest of the words - if (carry === 0 && i < a.length && a !== this) { - for (; i < a.length; i++) { - this.words[i] = a.words[i]; - } - } - - this.length = Math.max(this.length, i); - - if (a !== this) { - this.negative = 1; - } - - return this.strip(); - }; - - // Subtract `num` from `this` - BN.prototype.sub = function sub (num) { - return this.clone().isub(num); - }; - - function smallMulTo (self, num, out) { - out.negative = num.negative ^ self.negative; - var len = (self.length + num.length) | 0; - out.length = len; - len = (len - 1) | 0; - - // Peel one iteration (compiler can't do it, because of code complexity) - var a = self.words[0] | 0; - var b = num.words[0] | 0; - var r = a * b; - - var lo = r & 0x3ffffff; - var carry = (r / 0x4000000) | 0; - out.words[0] = lo; - - for (var k = 1; k < len; k++) { - // Sum all words with the same `i + j = k` and accumulate `ncarry`, - // note that ncarry could be >= 0x3ffffff - var ncarry = carry >>> 26; - var rword = carry & 0x3ffffff; - var maxJ = Math.min(k, num.length - 1); - for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { - var i = (k - j) | 0; - a = self.words[i] | 0; - b = num.words[j] | 0; - r = a * b + rword; - ncarry += (r / 0x4000000) | 0; - rword = r & 0x3ffffff; - } - out.words[k] = rword | 0; - carry = ncarry | 0; - } - if (carry !== 0) { - out.words[k] = carry | 0; - } else { - out.length--; - } - - return out.strip(); - } - - // TODO(indutny): it may be reasonable to omit it for users who don't need - // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit - // multiplication (like elliptic secp256k1). - var comb10MulTo = function comb10MulTo (self, num, out) { - var a = self.words; - var b = num.words; - var o = out.words; - var c = 0; - var lo; - var mid; - var hi; - var a0 = a[0] | 0; - var al0 = a0 & 0x1fff; - var ah0 = a0 >>> 13; - var a1 = a[1] | 0; - var al1 = a1 & 0x1fff; - var ah1 = a1 >>> 13; - var a2 = a[2] | 0; - var al2 = a2 & 0x1fff; - var ah2 = a2 >>> 13; - var a3 = a[3] | 0; - var al3 = a3 & 0x1fff; - var ah3 = a3 >>> 13; - var a4 = a[4] | 0; - var al4 = a4 & 0x1fff; - var ah4 = a4 >>> 13; - var a5 = a[5] | 0; - var al5 = a5 & 0x1fff; - var ah5 = a5 >>> 13; - var a6 = a[6] | 0; - var al6 = a6 & 0x1fff; - var ah6 = a6 >>> 13; - var a7 = a[7] | 0; - var al7 = a7 & 0x1fff; - var ah7 = a7 >>> 13; - var a8 = a[8] | 0; - var al8 = a8 & 0x1fff; - var ah8 = a8 >>> 13; - var a9 = a[9] | 0; - var al9 = a9 & 0x1fff; - var ah9 = a9 >>> 13; - var b0 = b[0] | 0; - var bl0 = b0 & 0x1fff; - var bh0 = b0 >>> 13; - var b1 = b[1] | 0; - var bl1 = b1 & 0x1fff; - var bh1 = b1 >>> 13; - var b2 = b[2] | 0; - var bl2 = b2 & 0x1fff; - var bh2 = b2 >>> 13; - var b3 = b[3] | 0; - var bl3 = b3 & 0x1fff; - var bh3 = b3 >>> 13; - var b4 = b[4] | 0; - var bl4 = b4 & 0x1fff; - var bh4 = b4 >>> 13; - var b5 = b[5] | 0; - var bl5 = b5 & 0x1fff; - var bh5 = b5 >>> 13; - var b6 = b[6] | 0; - var bl6 = b6 & 0x1fff; - var bh6 = b6 >>> 13; - var b7 = b[7] | 0; - var bl7 = b7 & 0x1fff; - var bh7 = b7 >>> 13; - var b8 = b[8] | 0; - var bl8 = b8 & 0x1fff; - var bh8 = b8 >>> 13; - var b9 = b[9] | 0; - var bl9 = b9 & 0x1fff; - var bh9 = b9 >>> 13; - - out.negative = self.negative ^ num.negative; - out.length = 19; - /* k = 0 */ - lo = Math.imul(al0, bl0); - mid = Math.imul(al0, bh0); - mid = (mid + Math.imul(ah0, bl0)) | 0; - hi = Math.imul(ah0, bh0); - var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0; - w0 &= 0x3ffffff; - /* k = 1 */ - lo = Math.imul(al1, bl0); - mid = Math.imul(al1, bh0); - mid = (mid + Math.imul(ah1, bl0)) | 0; - hi = Math.imul(ah1, bh0); - lo = (lo + Math.imul(al0, bl1)) | 0; - mid = (mid + Math.imul(al0, bh1)) | 0; - mid = (mid + Math.imul(ah0, bl1)) | 0; - hi = (hi + Math.imul(ah0, bh1)) | 0; - var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0; - w1 &= 0x3ffffff; - /* k = 2 */ - lo = Math.imul(al2, bl0); - mid = Math.imul(al2, bh0); - mid = (mid + Math.imul(ah2, bl0)) | 0; - hi = Math.imul(ah2, bh0); - lo = (lo + Math.imul(al1, bl1)) | 0; - mid = (mid + Math.imul(al1, bh1)) | 0; - mid = (mid + Math.imul(ah1, bl1)) | 0; - hi = (hi + Math.imul(ah1, bh1)) | 0; - lo = (lo + Math.imul(al0, bl2)) | 0; - mid = (mid + Math.imul(al0, bh2)) | 0; - mid = (mid + Math.imul(ah0, bl2)) | 0; - hi = (hi + Math.imul(ah0, bh2)) | 0; - var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0; - w2 &= 0x3ffffff; - /* k = 3 */ - lo = Math.imul(al3, bl0); - mid = Math.imul(al3, bh0); - mid = (mid + Math.imul(ah3, bl0)) | 0; - hi = Math.imul(ah3, bh0); - lo = (lo + Math.imul(al2, bl1)) | 0; - mid = (mid + Math.imul(al2, bh1)) | 0; - mid = (mid + Math.imul(ah2, bl1)) | 0; - hi = (hi + Math.imul(ah2, bh1)) | 0; - lo = (lo + Math.imul(al1, bl2)) | 0; - mid = (mid + Math.imul(al1, bh2)) | 0; - mid = (mid + Math.imul(ah1, bl2)) | 0; - hi = (hi + Math.imul(ah1, bh2)) | 0; - lo = (lo + Math.imul(al0, bl3)) | 0; - mid = (mid + Math.imul(al0, bh3)) | 0; - mid = (mid + Math.imul(ah0, bl3)) | 0; - hi = (hi + Math.imul(ah0, bh3)) | 0; - var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0; - w3 &= 0x3ffffff; - /* k = 4 */ - lo = Math.imul(al4, bl0); - mid = Math.imul(al4, bh0); - mid = (mid + Math.imul(ah4, bl0)) | 0; - hi = Math.imul(ah4, bh0); - lo = (lo + Math.imul(al3, bl1)) | 0; - mid = (mid + Math.imul(al3, bh1)) | 0; - mid = (mid + Math.imul(ah3, bl1)) | 0; - hi = (hi + Math.imul(ah3, bh1)) | 0; - lo = (lo + Math.imul(al2, bl2)) | 0; - mid = (mid + Math.imul(al2, bh2)) | 0; - mid = (mid + Math.imul(ah2, bl2)) | 0; - hi = (hi + Math.imul(ah2, bh2)) | 0; - lo = (lo + Math.imul(al1, bl3)) | 0; - mid = (mid + Math.imul(al1, bh3)) | 0; - mid = (mid + Math.imul(ah1, bl3)) | 0; - hi = (hi + Math.imul(ah1, bh3)) | 0; - lo = (lo + Math.imul(al0, bl4)) | 0; - mid = (mid + Math.imul(al0, bh4)) | 0; - mid = (mid + Math.imul(ah0, bl4)) | 0; - hi = (hi + Math.imul(ah0, bh4)) | 0; - var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0; - w4 &= 0x3ffffff; - /* k = 5 */ - lo = Math.imul(al5, bl0); - mid = Math.imul(al5, bh0); - mid = (mid + Math.imul(ah5, bl0)) | 0; - hi = Math.imul(ah5, bh0); - lo = (lo + Math.imul(al4, bl1)) | 0; - mid = (mid + Math.imul(al4, bh1)) | 0; - mid = (mid + Math.imul(ah4, bl1)) | 0; - hi = (hi + Math.imul(ah4, bh1)) | 0; - lo = (lo + Math.imul(al3, bl2)) | 0; - mid = (mid + Math.imul(al3, bh2)) | 0; - mid = (mid + Math.imul(ah3, bl2)) | 0; - hi = (hi + Math.imul(ah3, bh2)) | 0; - lo = (lo + Math.imul(al2, bl3)) | 0; - mid = (mid + Math.imul(al2, bh3)) | 0; - mid = (mid + Math.imul(ah2, bl3)) | 0; - hi = (hi + Math.imul(ah2, bh3)) | 0; - lo = (lo + Math.imul(al1, bl4)) | 0; - mid = (mid + Math.imul(al1, bh4)) | 0; - mid = (mid + Math.imul(ah1, bl4)) | 0; - hi = (hi + Math.imul(ah1, bh4)) | 0; - lo = (lo + Math.imul(al0, bl5)) | 0; - mid = (mid + Math.imul(al0, bh5)) | 0; - mid = (mid + Math.imul(ah0, bl5)) | 0; - hi = (hi + Math.imul(ah0, bh5)) | 0; - var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0; - w5 &= 0x3ffffff; - /* k = 6 */ - lo = Math.imul(al6, bl0); - mid = Math.imul(al6, bh0); - mid = (mid + Math.imul(ah6, bl0)) | 0; - hi = Math.imul(ah6, bh0); - lo = (lo + Math.imul(al5, bl1)) | 0; - mid = (mid + Math.imul(al5, bh1)) | 0; - mid = (mid + Math.imul(ah5, bl1)) | 0; - hi = (hi + Math.imul(ah5, bh1)) | 0; - lo = (lo + Math.imul(al4, bl2)) | 0; - mid = (mid + Math.imul(al4, bh2)) | 0; - mid = (mid + Math.imul(ah4, bl2)) | 0; - hi = (hi + Math.imul(ah4, bh2)) | 0; - lo = (lo + Math.imul(al3, bl3)) | 0; - mid = (mid + Math.imul(al3, bh3)) | 0; - mid = (mid + Math.imul(ah3, bl3)) | 0; - hi = (hi + Math.imul(ah3, bh3)) | 0; - lo = (lo + Math.imul(al2, bl4)) | 0; - mid = (mid + Math.imul(al2, bh4)) | 0; - mid = (mid + Math.imul(ah2, bl4)) | 0; - hi = (hi + Math.imul(ah2, bh4)) | 0; - lo = (lo + Math.imul(al1, bl5)) | 0; - mid = (mid + Math.imul(al1, bh5)) | 0; - mid = (mid + Math.imul(ah1, bl5)) | 0; - hi = (hi + Math.imul(ah1, bh5)) | 0; - lo = (lo + Math.imul(al0, bl6)) | 0; - mid = (mid + Math.imul(al0, bh6)) | 0; - mid = (mid + Math.imul(ah0, bl6)) | 0; - hi = (hi + Math.imul(ah0, bh6)) | 0; - var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0; - w6 &= 0x3ffffff; - /* k = 7 */ - lo = Math.imul(al7, bl0); - mid = Math.imul(al7, bh0); - mid = (mid + Math.imul(ah7, bl0)) | 0; - hi = Math.imul(ah7, bh0); - lo = (lo + Math.imul(al6, bl1)) | 0; - mid = (mid + Math.imul(al6, bh1)) | 0; - mid = (mid + Math.imul(ah6, bl1)) | 0; - hi = (hi + Math.imul(ah6, bh1)) | 0; - lo = (lo + Math.imul(al5, bl2)) | 0; - mid = (mid + Math.imul(al5, bh2)) | 0; - mid = (mid + Math.imul(ah5, bl2)) | 0; - hi = (hi + Math.imul(ah5, bh2)) | 0; - lo = (lo + Math.imul(al4, bl3)) | 0; - mid = (mid + Math.imul(al4, bh3)) | 0; - mid = (mid + Math.imul(ah4, bl3)) | 0; - hi = (hi + Math.imul(ah4, bh3)) | 0; - lo = (lo + Math.imul(al3, bl4)) | 0; - mid = (mid + Math.imul(al3, bh4)) | 0; - mid = (mid + Math.imul(ah3, bl4)) | 0; - hi = (hi + Math.imul(ah3, bh4)) | 0; - lo = (lo + Math.imul(al2, bl5)) | 0; - mid = (mid + Math.imul(al2, bh5)) | 0; - mid = (mid + Math.imul(ah2, bl5)) | 0; - hi = (hi + Math.imul(ah2, bh5)) | 0; - lo = (lo + Math.imul(al1, bl6)) | 0; - mid = (mid + Math.imul(al1, bh6)) | 0; - mid = (mid + Math.imul(ah1, bl6)) | 0; - hi = (hi + Math.imul(ah1, bh6)) | 0; - lo = (lo + Math.imul(al0, bl7)) | 0; - mid = (mid + Math.imul(al0, bh7)) | 0; - mid = (mid + Math.imul(ah0, bl7)) | 0; - hi = (hi + Math.imul(ah0, bh7)) | 0; - var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0; - w7 &= 0x3ffffff; - /* k = 8 */ - lo = Math.imul(al8, bl0); - mid = Math.imul(al8, bh0); - mid = (mid + Math.imul(ah8, bl0)) | 0; - hi = Math.imul(ah8, bh0); - lo = (lo + Math.imul(al7, bl1)) | 0; - mid = (mid + Math.imul(al7, bh1)) | 0; - mid = (mid + Math.imul(ah7, bl1)) | 0; - hi = (hi + Math.imul(ah7, bh1)) | 0; - lo = (lo + Math.imul(al6, bl2)) | 0; - mid = (mid + Math.imul(al6, bh2)) | 0; - mid = (mid + Math.imul(ah6, bl2)) | 0; - hi = (hi + Math.imul(ah6, bh2)) | 0; - lo = (lo + Math.imul(al5, bl3)) | 0; - mid = (mid + Math.imul(al5, bh3)) | 0; - mid = (mid + Math.imul(ah5, bl3)) | 0; - hi = (hi + Math.imul(ah5, bh3)) | 0; - lo = (lo + Math.imul(al4, bl4)) | 0; - mid = (mid + Math.imul(al4, bh4)) | 0; - mid = (mid + Math.imul(ah4, bl4)) | 0; - hi = (hi + Math.imul(ah4, bh4)) | 0; - lo = (lo + Math.imul(al3, bl5)) | 0; - mid = (mid + Math.imul(al3, bh5)) | 0; - mid = (mid + Math.imul(ah3, bl5)) | 0; - hi = (hi + Math.imul(ah3, bh5)) | 0; - lo = (lo + Math.imul(al2, bl6)) | 0; - mid = (mid + Math.imul(al2, bh6)) | 0; - mid = (mid + Math.imul(ah2, bl6)) | 0; - hi = (hi + Math.imul(ah2, bh6)) | 0; - lo = (lo + Math.imul(al1, bl7)) | 0; - mid = (mid + Math.imul(al1, bh7)) | 0; - mid = (mid + Math.imul(ah1, bl7)) | 0; - hi = (hi + Math.imul(ah1, bh7)) | 0; - lo = (lo + Math.imul(al0, bl8)) | 0; - mid = (mid + Math.imul(al0, bh8)) | 0; - mid = (mid + Math.imul(ah0, bl8)) | 0; - hi = (hi + Math.imul(ah0, bh8)) | 0; - var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0; - w8 &= 0x3ffffff; - /* k = 9 */ - lo = Math.imul(al9, bl0); - mid = Math.imul(al9, bh0); - mid = (mid + Math.imul(ah9, bl0)) | 0; - hi = Math.imul(ah9, bh0); - lo = (lo + Math.imul(al8, bl1)) | 0; - mid = (mid + Math.imul(al8, bh1)) | 0; - mid = (mid + Math.imul(ah8, bl1)) | 0; - hi = (hi + Math.imul(ah8, bh1)) | 0; - lo = (lo + Math.imul(al7, bl2)) | 0; - mid = (mid + Math.imul(al7, bh2)) | 0; - mid = (mid + Math.imul(ah7, bl2)) | 0; - hi = (hi + Math.imul(ah7, bh2)) | 0; - lo = (lo + Math.imul(al6, bl3)) | 0; - mid = (mid + Math.imul(al6, bh3)) | 0; - mid = (mid + Math.imul(ah6, bl3)) | 0; - hi = (hi + Math.imul(ah6, bh3)) | 0; - lo = (lo + Math.imul(al5, bl4)) | 0; - mid = (mid + Math.imul(al5, bh4)) | 0; - mid = (mid + Math.imul(ah5, bl4)) | 0; - hi = (hi + Math.imul(ah5, bh4)) | 0; - lo = (lo + Math.imul(al4, bl5)) | 0; - mid = (mid + Math.imul(al4, bh5)) | 0; - mid = (mid + Math.imul(ah4, bl5)) | 0; - hi = (hi + Math.imul(ah4, bh5)) | 0; - lo = (lo + Math.imul(al3, bl6)) | 0; - mid = (mid + Math.imul(al3, bh6)) | 0; - mid = (mid + Math.imul(ah3, bl6)) | 0; - hi = (hi + Math.imul(ah3, bh6)) | 0; - lo = (lo + Math.imul(al2, bl7)) | 0; - mid = (mid + Math.imul(al2, bh7)) | 0; - mid = (mid + Math.imul(ah2, bl7)) | 0; - hi = (hi + Math.imul(ah2, bh7)) | 0; - lo = (lo + Math.imul(al1, bl8)) | 0; - mid = (mid + Math.imul(al1, bh8)) | 0; - mid = (mid + Math.imul(ah1, bl8)) | 0; - hi = (hi + Math.imul(ah1, bh8)) | 0; - lo = (lo + Math.imul(al0, bl9)) | 0; - mid = (mid + Math.imul(al0, bh9)) | 0; - mid = (mid + Math.imul(ah0, bl9)) | 0; - hi = (hi + Math.imul(ah0, bh9)) | 0; - var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0; - w9 &= 0x3ffffff; - /* k = 10 */ - lo = Math.imul(al9, bl1); - mid = Math.imul(al9, bh1); - mid = (mid + Math.imul(ah9, bl1)) | 0; - hi = Math.imul(ah9, bh1); - lo = (lo + Math.imul(al8, bl2)) | 0; - mid = (mid + Math.imul(al8, bh2)) | 0; - mid = (mid + Math.imul(ah8, bl2)) | 0; - hi = (hi + Math.imul(ah8, bh2)) | 0; - lo = (lo + Math.imul(al7, bl3)) | 0; - mid = (mid + Math.imul(al7, bh3)) | 0; - mid = (mid + Math.imul(ah7, bl3)) | 0; - hi = (hi + Math.imul(ah7, bh3)) | 0; - lo = (lo + Math.imul(al6, bl4)) | 0; - mid = (mid + Math.imul(al6, bh4)) | 0; - mid = (mid + Math.imul(ah6, bl4)) | 0; - hi = (hi + Math.imul(ah6, bh4)) | 0; - lo = (lo + Math.imul(al5, bl5)) | 0; - mid = (mid + Math.imul(al5, bh5)) | 0; - mid = (mid + Math.imul(ah5, bl5)) | 0; - hi = (hi + Math.imul(ah5, bh5)) | 0; - lo = (lo + Math.imul(al4, bl6)) | 0; - mid = (mid + Math.imul(al4, bh6)) | 0; - mid = (mid + Math.imul(ah4, bl6)) | 0; - hi = (hi + Math.imul(ah4, bh6)) | 0; - lo = (lo + Math.imul(al3, bl7)) | 0; - mid = (mid + Math.imul(al3, bh7)) | 0; - mid = (mid + Math.imul(ah3, bl7)) | 0; - hi = (hi + Math.imul(ah3, bh7)) | 0; - lo = (lo + Math.imul(al2, bl8)) | 0; - mid = (mid + Math.imul(al2, bh8)) | 0; - mid = (mid + Math.imul(ah2, bl8)) | 0; - hi = (hi + Math.imul(ah2, bh8)) | 0; - lo = (lo + Math.imul(al1, bl9)) | 0; - mid = (mid + Math.imul(al1, bh9)) | 0; - mid = (mid + Math.imul(ah1, bl9)) | 0; - hi = (hi + Math.imul(ah1, bh9)) | 0; - var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0; - w10 &= 0x3ffffff; - /* k = 11 */ - lo = Math.imul(al9, bl2); - mid = Math.imul(al9, bh2); - mid = (mid + Math.imul(ah9, bl2)) | 0; - hi = Math.imul(ah9, bh2); - lo = (lo + Math.imul(al8, bl3)) | 0; - mid = (mid + Math.imul(al8, bh3)) | 0; - mid = (mid + Math.imul(ah8, bl3)) | 0; - hi = (hi + Math.imul(ah8, bh3)) | 0; - lo = (lo + Math.imul(al7, bl4)) | 0; - mid = (mid + Math.imul(al7, bh4)) | 0; - mid = (mid + Math.imul(ah7, bl4)) | 0; - hi = (hi + Math.imul(ah7, bh4)) | 0; - lo = (lo + Math.imul(al6, bl5)) | 0; - mid = (mid + Math.imul(al6, bh5)) | 0; - mid = (mid + Math.imul(ah6, bl5)) | 0; - hi = (hi + Math.imul(ah6, bh5)) | 0; - lo = (lo + Math.imul(al5, bl6)) | 0; - mid = (mid + Math.imul(al5, bh6)) | 0; - mid = (mid + Math.imul(ah5, bl6)) | 0; - hi = (hi + Math.imul(ah5, bh6)) | 0; - lo = (lo + Math.imul(al4, bl7)) | 0; - mid = (mid + Math.imul(al4, bh7)) | 0; - mid = (mid + Math.imul(ah4, bl7)) | 0; - hi = (hi + Math.imul(ah4, bh7)) | 0; - lo = (lo + Math.imul(al3, bl8)) | 0; - mid = (mid + Math.imul(al3, bh8)) | 0; - mid = (mid + Math.imul(ah3, bl8)) | 0; - hi = (hi + Math.imul(ah3, bh8)) | 0; - lo = (lo + Math.imul(al2, bl9)) | 0; - mid = (mid + Math.imul(al2, bh9)) | 0; - mid = (mid + Math.imul(ah2, bl9)) | 0; - hi = (hi + Math.imul(ah2, bh9)) | 0; - var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0; - w11 &= 0x3ffffff; - /* k = 12 */ - lo = Math.imul(al9, bl3); - mid = Math.imul(al9, bh3); - mid = (mid + Math.imul(ah9, bl3)) | 0; - hi = Math.imul(ah9, bh3); - lo = (lo + Math.imul(al8, bl4)) | 0; - mid = (mid + Math.imul(al8, bh4)) | 0; - mid = (mid + Math.imul(ah8, bl4)) | 0; - hi = (hi + Math.imul(ah8, bh4)) | 0; - lo = (lo + Math.imul(al7, bl5)) | 0; - mid = (mid + Math.imul(al7, bh5)) | 0; - mid = (mid + Math.imul(ah7, bl5)) | 0; - hi = (hi + Math.imul(ah7, bh5)) | 0; - lo = (lo + Math.imul(al6, bl6)) | 0; - mid = (mid + Math.imul(al6, bh6)) | 0; - mid = (mid + Math.imul(ah6, bl6)) | 0; - hi = (hi + Math.imul(ah6, bh6)) | 0; - lo = (lo + Math.imul(al5, bl7)) | 0; - mid = (mid + Math.imul(al5, bh7)) | 0; - mid = (mid + Math.imul(ah5, bl7)) | 0; - hi = (hi + Math.imul(ah5, bh7)) | 0; - lo = (lo + Math.imul(al4, bl8)) | 0; - mid = (mid + Math.imul(al4, bh8)) | 0; - mid = (mid + Math.imul(ah4, bl8)) | 0; - hi = (hi + Math.imul(ah4, bh8)) | 0; - lo = (lo + Math.imul(al3, bl9)) | 0; - mid = (mid + Math.imul(al3, bh9)) | 0; - mid = (mid + Math.imul(ah3, bl9)) | 0; - hi = (hi + Math.imul(ah3, bh9)) | 0; - var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0; - w12 &= 0x3ffffff; - /* k = 13 */ - lo = Math.imul(al9, bl4); - mid = Math.imul(al9, bh4); - mid = (mid + Math.imul(ah9, bl4)) | 0; - hi = Math.imul(ah9, bh4); - lo = (lo + Math.imul(al8, bl5)) | 0; - mid = (mid + Math.imul(al8, bh5)) | 0; - mid = (mid + Math.imul(ah8, bl5)) | 0; - hi = (hi + Math.imul(ah8, bh5)) | 0; - lo = (lo + Math.imul(al7, bl6)) | 0; - mid = (mid + Math.imul(al7, bh6)) | 0; - mid = (mid + Math.imul(ah7, bl6)) | 0; - hi = (hi + Math.imul(ah7, bh6)) | 0; - lo = (lo + Math.imul(al6, bl7)) | 0; - mid = (mid + Math.imul(al6, bh7)) | 0; - mid = (mid + Math.imul(ah6, bl7)) | 0; - hi = (hi + Math.imul(ah6, bh7)) | 0; - lo = (lo + Math.imul(al5, bl8)) | 0; - mid = (mid + Math.imul(al5, bh8)) | 0; - mid = (mid + Math.imul(ah5, bl8)) | 0; - hi = (hi + Math.imul(ah5, bh8)) | 0; - lo = (lo + Math.imul(al4, bl9)) | 0; - mid = (mid + Math.imul(al4, bh9)) | 0; - mid = (mid + Math.imul(ah4, bl9)) | 0; - hi = (hi + Math.imul(ah4, bh9)) | 0; - var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0; - w13 &= 0x3ffffff; - /* k = 14 */ - lo = Math.imul(al9, bl5); - mid = Math.imul(al9, bh5); - mid = (mid + Math.imul(ah9, bl5)) | 0; - hi = Math.imul(ah9, bh5); - lo = (lo + Math.imul(al8, bl6)) | 0; - mid = (mid + Math.imul(al8, bh6)) | 0; - mid = (mid + Math.imul(ah8, bl6)) | 0; - hi = (hi + Math.imul(ah8, bh6)) | 0; - lo = (lo + Math.imul(al7, bl7)) | 0; - mid = (mid + Math.imul(al7, bh7)) | 0; - mid = (mid + Math.imul(ah7, bl7)) | 0; - hi = (hi + Math.imul(ah7, bh7)) | 0; - lo = (lo + Math.imul(al6, bl8)) | 0; - mid = (mid + Math.imul(al6, bh8)) | 0; - mid = (mid + Math.imul(ah6, bl8)) | 0; - hi = (hi + Math.imul(ah6, bh8)) | 0; - lo = (lo + Math.imul(al5, bl9)) | 0; - mid = (mid + Math.imul(al5, bh9)) | 0; - mid = (mid + Math.imul(ah5, bl9)) | 0; - hi = (hi + Math.imul(ah5, bh9)) | 0; - var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0; - w14 &= 0x3ffffff; - /* k = 15 */ - lo = Math.imul(al9, bl6); - mid = Math.imul(al9, bh6); - mid = (mid + Math.imul(ah9, bl6)) | 0; - hi = Math.imul(ah9, bh6); - lo = (lo + Math.imul(al8, bl7)) | 0; - mid = (mid + Math.imul(al8, bh7)) | 0; - mid = (mid + Math.imul(ah8, bl7)) | 0; - hi = (hi + Math.imul(ah8, bh7)) | 0; - lo = (lo + Math.imul(al7, bl8)) | 0; - mid = (mid + Math.imul(al7, bh8)) | 0; - mid = (mid + Math.imul(ah7, bl8)) | 0; - hi = (hi + Math.imul(ah7, bh8)) | 0; - lo = (lo + Math.imul(al6, bl9)) | 0; - mid = (mid + Math.imul(al6, bh9)) | 0; - mid = (mid + Math.imul(ah6, bl9)) | 0; - hi = (hi + Math.imul(ah6, bh9)) | 0; - var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0; - w15 &= 0x3ffffff; - /* k = 16 */ - lo = Math.imul(al9, bl7); - mid = Math.imul(al9, bh7); - mid = (mid + Math.imul(ah9, bl7)) | 0; - hi = Math.imul(ah9, bh7); - lo = (lo + Math.imul(al8, bl8)) | 0; - mid = (mid + Math.imul(al8, bh8)) | 0; - mid = (mid + Math.imul(ah8, bl8)) | 0; - hi = (hi + Math.imul(ah8, bh8)) | 0; - lo = (lo + Math.imul(al7, bl9)) | 0; - mid = (mid + Math.imul(al7, bh9)) | 0; - mid = (mid + Math.imul(ah7, bl9)) | 0; - hi = (hi + Math.imul(ah7, bh9)) | 0; - var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0; - w16 &= 0x3ffffff; - /* k = 17 */ - lo = Math.imul(al9, bl8); - mid = Math.imul(al9, bh8); - mid = (mid + Math.imul(ah9, bl8)) | 0; - hi = Math.imul(ah9, bh8); - lo = (lo + Math.imul(al8, bl9)) | 0; - mid = (mid + Math.imul(al8, bh9)) | 0; - mid = (mid + Math.imul(ah8, bl9)) | 0; - hi = (hi + Math.imul(ah8, bh9)) | 0; - var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0; - w17 &= 0x3ffffff; - /* k = 18 */ - lo = Math.imul(al9, bl9); - mid = Math.imul(al9, bh9); - mid = (mid + Math.imul(ah9, bl9)) | 0; - hi = Math.imul(ah9, bh9); - var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0; - c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0; - w18 &= 0x3ffffff; - o[0] = w0; - o[1] = w1; - o[2] = w2; - o[3] = w3; - o[4] = w4; - o[5] = w5; - o[6] = w6; - o[7] = w7; - o[8] = w8; - o[9] = w9; - o[10] = w10; - o[11] = w11; - o[12] = w12; - o[13] = w13; - o[14] = w14; - o[15] = w15; - o[16] = w16; - o[17] = w17; - o[18] = w18; - if (c !== 0) { - o[19] = c; - out.length++; - } - return out; - }; - - // Polyfill comb - if (!Math.imul) { - comb10MulTo = smallMulTo; - } - - function bigMulTo (self, num, out) { - out.negative = num.negative ^ self.negative; - out.length = self.length + num.length; - - var carry = 0; - var hncarry = 0; - for (var k = 0; k < out.length - 1; k++) { - // Sum all words with the same `i + j = k` and accumulate `ncarry`, - // note that ncarry could be >= 0x3ffffff - var ncarry = hncarry; - hncarry = 0; - var rword = carry & 0x3ffffff; - var maxJ = Math.min(k, num.length - 1); - for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) { - var i = k - j; - var a = self.words[i] | 0; - var b = num.words[j] | 0; - var r = a * b; - - var lo = r & 0x3ffffff; - ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0; - lo = (lo + rword) | 0; - rword = lo & 0x3ffffff; - ncarry = (ncarry + (lo >>> 26)) | 0; - - hncarry += ncarry >>> 26; - ncarry &= 0x3ffffff; - } - out.words[k] = rword; - carry = ncarry; - ncarry = hncarry; - } - if (carry !== 0) { - out.words[k] = carry; - } else { - out.length--; - } - - return out.strip(); - } - - function jumboMulTo (self, num, out) { - var fftm = new FFTM(); - return fftm.mulp(self, num, out); - } - - BN.prototype.mulTo = function mulTo (num, out) { - var res; - var len = this.length + num.length; - if (this.length === 10 && num.length === 10) { - res = comb10MulTo(this, num, out); - } else if (len < 63) { - res = smallMulTo(this, num, out); - } else if (len < 1024) { - res = bigMulTo(this, num, out); - } else { - res = jumboMulTo(this, num, out); - } - - return res; - }; - - // Cooley-Tukey algorithm for FFT - // slightly revisited to rely on looping instead of recursion - - function FFTM (x, y) { - this.x = x; - this.y = y; - } - - FFTM.prototype.makeRBT = function makeRBT (N) { - var t = new Array(N); - var l = BN.prototype._countBits(N) - 1; - for (var i = 0; i < N; i++) { - t[i] = this.revBin(i, l, N); - } - - return t; - }; - - // Returns binary-reversed representation of `x` - FFTM.prototype.revBin = function revBin (x, l, N) { - if (x === 0 || x === N - 1) return x; - - var rb = 0; - for (var i = 0; i < l; i++) { - rb |= (x & 1) << (l - i - 1); - x >>= 1; - } - - return rb; - }; - - // Performs "tweedling" phase, therefore 'emulating' - // behaviour of the recursive algorithm - FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) { - for (var i = 0; i < N; i++) { - rtws[i] = rws[rbt[i]]; - itws[i] = iws[rbt[i]]; - } - }; - - FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) { - this.permute(rbt, rws, iws, rtws, itws, N); - - for (var s = 1; s < N; s <<= 1) { - var l = s << 1; - - var rtwdf = Math.cos(2 * Math.PI / l); - var itwdf = Math.sin(2 * Math.PI / l); - - for (var p = 0; p < N; p += l) { - var rtwdf_ = rtwdf; - var itwdf_ = itwdf; - - for (var j = 0; j < s; j++) { - var re = rtws[p + j]; - var ie = itws[p + j]; - - var ro = rtws[p + j + s]; - var io = itws[p + j + s]; - - var rx = rtwdf_ * ro - itwdf_ * io; - - io = rtwdf_ * io + itwdf_ * ro; - ro = rx; - - rtws[p + j] = re + ro; - itws[p + j] = ie + io; - - rtws[p + j + s] = re - ro; - itws[p + j + s] = ie - io; - - /* jshint maxdepth : false */ - if (j !== l) { - rx = rtwdf * rtwdf_ - itwdf * itwdf_; - - itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_; - rtwdf_ = rx; - } - } - } - } - }; - - FFTM.prototype.guessLen13b = function guessLen13b (n, m) { - var N = Math.max(m, n) | 1; - var odd = N & 1; - var i = 0; - for (N = N / 2 | 0; N; N = N >>> 1) { - i++; - } - - return 1 << i + 1 + odd; - }; - - FFTM.prototype.conjugate = function conjugate (rws, iws, N) { - if (N <= 1) return; - - for (var i = 0; i < N / 2; i++) { - var t = rws[i]; - - rws[i] = rws[N - i - 1]; - rws[N - i - 1] = t; - - t = iws[i]; - - iws[i] = -iws[N - i - 1]; - iws[N - i - 1] = -t; - } - }; - - FFTM.prototype.normalize13b = function normalize13b (ws, N) { - var carry = 0; - for (var i = 0; i < N / 2; i++) { - var w = Math.round(ws[2 * i + 1] / N) * 0x2000 + - Math.round(ws[2 * i] / N) + - carry; - - ws[i] = w & 0x3ffffff; - - if (w < 0x4000000) { - carry = 0; - } else { - carry = w / 0x4000000 | 0; - } - } - - return ws; - }; - - FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) { - var carry = 0; - for (var i = 0; i < len; i++) { - carry = carry + (ws[i] | 0); - - rws[2 * i] = carry & 0x1fff; carry = carry >>> 13; - rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13; - } - - // Pad with zeroes - for (i = 2 * len; i < N; ++i) { - rws[i] = 0; - } - - assert(carry === 0); - assert((carry & ~0x1fff) === 0); - }; - - FFTM.prototype.stub = function stub (N) { - var ph = new Array(N); - for (var i = 0; i < N; i++) { - ph[i] = 0; - } - - return ph; - }; - - FFTM.prototype.mulp = function mulp (x, y, out) { - var N = 2 * this.guessLen13b(x.length, y.length); - - var rbt = this.makeRBT(N); - - var _ = this.stub(N); - - var rws = new Array(N); - var rwst = new Array(N); - var iwst = new Array(N); - - var nrws = new Array(N); - var nrwst = new Array(N); - var niwst = new Array(N); - - var rmws = out.words; - rmws.length = N; - - this.convert13b(x.words, x.length, rws, N); - this.convert13b(y.words, y.length, nrws, N); - - this.transform(rws, _, rwst, iwst, N, rbt); - this.transform(nrws, _, nrwst, niwst, N, rbt); - - for (var i = 0; i < N; i++) { - var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i]; - iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i]; - rwst[i] = rx; - } - - this.conjugate(rwst, iwst, N); - this.transform(rwst, iwst, rmws, _, N, rbt); - this.conjugate(rmws, _, N); - this.normalize13b(rmws, N); - - out.negative = x.negative ^ y.negative; - out.length = x.length + y.length; - return out.strip(); - }; - - // Multiply `this` by `num` - BN.prototype.mul = function mul (num) { - var out = new BN(null); - out.words = new Array(this.length + num.length); - return this.mulTo(num, out); - }; - - // Multiply employing FFT - BN.prototype.mulf = function mulf (num) { - var out = new BN(null); - out.words = new Array(this.length + num.length); - return jumboMulTo(this, num, out); - }; - - // In-place Multiplication - BN.prototype.imul = function imul (num) { - return this.clone().mulTo(num, this); - }; - - BN.prototype.imuln = function imuln (num) { - assert(typeof num === 'number'); - assert(num < 0x4000000); - - // Carry - var carry = 0; - for (var i = 0; i < this.length; i++) { - var w = (this.words[i] | 0) * num; - var lo = (w & 0x3ffffff) + (carry & 0x3ffffff); - carry >>= 26; - carry += (w / 0x4000000) | 0; - // NOTE: lo is 27bit maximum - carry += lo >>> 26; - this.words[i] = lo & 0x3ffffff; - } - - if (carry !== 0) { - this.words[i] = carry; - this.length++; - } - - return this; - }; - - BN.prototype.muln = function muln (num) { - return this.clone().imuln(num); - }; - - // `this` * `this` - BN.prototype.sqr = function sqr () { - return this.mul(this); - }; - - // `this` * `this` in-place - BN.prototype.isqr = function isqr () { - return this.imul(this.clone()); - }; - - // Math.pow(`this`, `num`) - BN.prototype.pow = function pow (num) { - var w = toBitArray(num); - if (w.length === 0) return new BN(1); - - // Skip leading zeroes - var res = this; - for (var i = 0; i < w.length; i++, res = res.sqr()) { - if (w[i] !== 0) break; - } - - if (++i < w.length) { - for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) { - if (w[i] === 0) continue; - - res = res.mul(q); - } - } - - return res; - }; - - // Shift-left in-place - BN.prototype.iushln = function iushln (bits) { - assert(typeof bits === 'number' && bits >= 0); - var r = bits % 26; - var s = (bits - r) / 26; - var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r); - var i; - - if (r !== 0) { - var carry = 0; - - for (i = 0; i < this.length; i++) { - var newCarry = this.words[i] & carryMask; - var c = ((this.words[i] | 0) - newCarry) << r; - this.words[i] = c | carry; - carry = newCarry >>> (26 - r); - } - - if (carry) { - this.words[i] = carry; - this.length++; - } - } - - if (s !== 0) { - for (i = this.length - 1; i >= 0; i--) { - this.words[i + s] = this.words[i]; - } - - for (i = 0; i < s; i++) { - this.words[i] = 0; - } - - this.length += s; - } - - return this.strip(); - }; - - BN.prototype.ishln = function ishln (bits) { - // TODO(indutny): implement me - assert(this.negative === 0); - return this.iushln(bits); - }; - - // Shift-right in-place - // NOTE: `hint` is a lowest bit before trailing zeroes - // NOTE: if `extended` is present - it will be filled with destroyed bits - BN.prototype.iushrn = function iushrn (bits, hint, extended) { - assert(typeof bits === 'number' && bits >= 0); - var h; - if (hint) { - h = (hint - (hint % 26)) / 26; - } else { - h = 0; - } - - var r = bits % 26; - var s = Math.min((bits - r) / 26, this.length); - var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); - var maskedWords = extended; - - h -= s; - h = Math.max(0, h); - - // Extended mode, copy masked part - if (maskedWords) { - for (var i = 0; i < s; i++) { - maskedWords.words[i] = this.words[i]; - } - maskedWords.length = s; - } - - if (s === 0) { - // No-op, we should not move anything at all - } else if (this.length > s) { - this.length -= s; - for (i = 0; i < this.length; i++) { - this.words[i] = this.words[i + s]; - } - } else { - this.words[0] = 0; - this.length = 1; - } - - var carry = 0; - for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) { - var word = this.words[i] | 0; - this.words[i] = (carry << (26 - r)) | (word >>> r); - carry = word & mask; - } - - // Push carried bits as a mask - if (maskedWords && carry !== 0) { - maskedWords.words[maskedWords.length++] = carry; - } - - if (this.length === 0) { - this.words[0] = 0; - this.length = 1; - } - - return this.strip(); - }; - - BN.prototype.ishrn = function ishrn (bits, hint, extended) { - // TODO(indutny): implement me - assert(this.negative === 0); - return this.iushrn(bits, hint, extended); - }; - - // Shift-left - BN.prototype.shln = function shln (bits) { - return this.clone().ishln(bits); - }; - - BN.prototype.ushln = function ushln (bits) { - return this.clone().iushln(bits); - }; - - // Shift-right - BN.prototype.shrn = function shrn (bits) { - return this.clone().ishrn(bits); - }; - - BN.prototype.ushrn = function ushrn (bits) { - return this.clone().iushrn(bits); - }; - - // Test if n bit is set - BN.prototype.testn = function testn (bit) { - assert(typeof bit === 'number' && bit >= 0); - var r = bit % 26; - var s = (bit - r) / 26; - var q = 1 << r; - - // Fast case: bit is much higher than all existing words - if (this.length <= s) return false; - - // Check bit and return - var w = this.words[s]; - - return !!(w & q); - }; - - // Return only lowers bits of number (in-place) - BN.prototype.imaskn = function imaskn (bits) { - assert(typeof bits === 'number' && bits >= 0); - var r = bits % 26; - var s = (bits - r) / 26; - - assert(this.negative === 0, 'imaskn works only with positive numbers'); - - if (this.length <= s) { - return this; - } - - if (r !== 0) { - s++; - } - this.length = Math.min(s, this.length); - - if (r !== 0) { - var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r); - this.words[this.length - 1] &= mask; - } - - return this.strip(); - }; - - // Return only lowers bits of number - BN.prototype.maskn = function maskn (bits) { - return this.clone().imaskn(bits); - }; - - // Add plain number `num` to `this` - BN.prototype.iaddn = function iaddn (num) { - assert(typeof num === 'number'); - assert(num < 0x4000000); - if (num < 0) return this.isubn(-num); - - // Possible sign change - if (this.negative !== 0) { - if (this.length === 1 && (this.words[0] | 0) < num) { - this.words[0] = num - (this.words[0] | 0); - this.negative = 0; - return this; - } - - this.negative = 0; - this.isubn(num); - this.negative = 1; - return this; - } - - // Add without checks - return this._iaddn(num); - }; - - BN.prototype._iaddn = function _iaddn (num) { - this.words[0] += num; - - // Carry - for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) { - this.words[i] -= 0x4000000; - if (i === this.length - 1) { - this.words[i + 1] = 1; - } else { - this.words[i + 1]++; - } - } - this.length = Math.max(this.length, i + 1); - - return this; - }; - - // Subtract plain number `num` from `this` - BN.prototype.isubn = function isubn (num) { - assert(typeof num === 'number'); - assert(num < 0x4000000); - if (num < 0) return this.iaddn(-num); - - if (this.negative !== 0) { - this.negative = 0; - this.iaddn(num); - this.negative = 1; - return this; - } - - this.words[0] -= num; - - if (this.length === 1 && this.words[0] < 0) { - this.words[0] = -this.words[0]; - this.negative = 1; - } else { - // Carry - for (var i = 0; i < this.length && this.words[i] < 0; i++) { - this.words[i] += 0x4000000; - this.words[i + 1] -= 1; - } - } - - return this.strip(); - }; - - BN.prototype.addn = function addn (num) { - return this.clone().iaddn(num); - }; - - BN.prototype.subn = function subn (num) { - return this.clone().isubn(num); - }; - - BN.prototype.iabs = function iabs () { - this.negative = 0; - - return this; - }; - - BN.prototype.abs = function abs () { - return this.clone().iabs(); - }; - - BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) { - var len = num.length + shift; - var i; - - this._expand(len); - - var w; - var carry = 0; - for (i = 0; i < num.length; i++) { - w = (this.words[i + shift] | 0) + carry; - var right = (num.words[i] | 0) * mul; - w -= right & 0x3ffffff; - carry = (w >> 26) - ((right / 0x4000000) | 0); - this.words[i + shift] = w & 0x3ffffff; - } - for (; i < this.length - shift; i++) { - w = (this.words[i + shift] | 0) + carry; - carry = w >> 26; - this.words[i + shift] = w & 0x3ffffff; - } - - if (carry === 0) return this.strip(); - - // Subtraction overflow - assert(carry === -1); - carry = 0; - for (i = 0; i < this.length; i++) { - w = -(this.words[i] | 0) + carry; - carry = w >> 26; - this.words[i] = w & 0x3ffffff; - } - this.negative = 1; - - return this.strip(); - }; - - BN.prototype._wordDiv = function _wordDiv (num, mode) { - var shift = this.length - num.length; - - var a = this.clone(); - var b = num; - - // Normalize - var bhi = b.words[b.length - 1] | 0; - var bhiBits = this._countBits(bhi); - shift = 26 - bhiBits; - if (shift !== 0) { - b = b.ushln(shift); - a.iushln(shift); - bhi = b.words[b.length - 1] | 0; - } - - // Initialize quotient - var m = a.length - b.length; - var q; - - if (mode !== 'mod') { - q = new BN(null); - q.length = m + 1; - q.words = new Array(q.length); - for (var i = 0; i < q.length; i++) { - q.words[i] = 0; - } - } - - var diff = a.clone()._ishlnsubmul(b, 1, m); - if (diff.negative === 0) { - a = diff; - if (q) { - q.words[m] = 1; - } - } - - for (var j = m - 1; j >= 0; j--) { - var qj = (a.words[b.length + j] | 0) * 0x4000000 + - (a.words[b.length + j - 1] | 0); - - // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max - // (0x7ffffff) - qj = Math.min((qj / bhi) | 0, 0x3ffffff); - - a._ishlnsubmul(b, qj, j); - while (a.negative !== 0) { - qj--; - a.negative = 0; - a._ishlnsubmul(b, 1, j); - if (!a.isZero()) { - a.negative ^= 1; - } - } - if (q) { - q.words[j] = qj; - } - } - if (q) { - q.strip(); - } - a.strip(); - - // Denormalize - if (mode !== 'div' && shift !== 0) { - a.iushrn(shift); - } - - return { - div: q || null, - mod: a - }; - }; - - // NOTE: 1) `mode` can be set to `mod` to request mod only, - // to `div` to request div only, or be absent to - // request both div & mod - // 2) `positive` is true if unsigned mod is requested - BN.prototype.divmod = function divmod (num, mode, positive) { - assert(!num.isZero()); - - if (this.isZero()) { - return { - div: new BN(0), - mod: new BN(0) - }; - } - - var div, mod, res; - if (this.negative !== 0 && num.negative === 0) { - res = this.neg().divmod(num, mode); - - if (mode !== 'mod') { - div = res.div.neg(); - } - - if (mode !== 'div') { - mod = res.mod.neg(); - if (positive && mod.negative !== 0) { - mod.iadd(num); - } - } - - return { - div: div, - mod: mod - }; - } - - if (this.negative === 0 && num.negative !== 0) { - res = this.divmod(num.neg(), mode); - - if (mode !== 'mod') { - div = res.div.neg(); - } - - return { - div: div, - mod: res.mod - }; - } - - if ((this.negative & num.negative) !== 0) { - res = this.neg().divmod(num.neg(), mode); - - if (mode !== 'div') { - mod = res.mod.neg(); - if (positive && mod.negative !== 0) { - mod.isub(num); - } - } - - return { - div: res.div, - mod: mod - }; - } - - // Both numbers are positive at this point - - // Strip both numbers to approximate shift value - if (num.length > this.length || this.cmp(num) < 0) { - return { - div: new BN(0), - mod: this - }; - } - - // Very short reduction - if (num.length === 1) { - if (mode === 'div') { - return { - div: this.divn(num.words[0]), - mod: null - }; - } - - if (mode === 'mod') { - return { - div: null, - mod: new BN(this.modn(num.words[0])) - }; - } - - return { - div: this.divn(num.words[0]), - mod: new BN(this.modn(num.words[0])) - }; - } - - return this._wordDiv(num, mode); - }; - - // Find `this` / `num` - BN.prototype.div = function div (num) { - return this.divmod(num, 'div', false).div; - }; - - // Find `this` % `num` - BN.prototype.mod = function mod (num) { - return this.divmod(num, 'mod', false).mod; - }; - - BN.prototype.umod = function umod (num) { - return this.divmod(num, 'mod', true).mod; - }; - - // Find Round(`this` / `num`) - BN.prototype.divRound = function divRound (num) { - var dm = this.divmod(num); - - // Fast case - exact division - if (dm.mod.isZero()) return dm.div; - - var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod; - - var half = num.ushrn(1); - var r2 = num.andln(1); - var cmp = mod.cmp(half); - - // Round down - if (cmp < 0 || r2 === 1 && cmp === 0) return dm.div; - - // Round up - return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1); - }; - - BN.prototype.modn = function modn (num) { - assert(num <= 0x3ffffff); - var p = (1 << 26) % num; - - var acc = 0; - for (var i = this.length - 1; i >= 0; i--) { - acc = (p * acc + (this.words[i] | 0)) % num; - } - - return acc; - }; - - // In-place division by number - BN.prototype.idivn = function idivn (num) { - assert(num <= 0x3ffffff); - - var carry = 0; - for (var i = this.length - 1; i >= 0; i--) { - var w = (this.words[i] | 0) + carry * 0x4000000; - this.words[i] = (w / num) | 0; - carry = w % num; - } - - return this.strip(); - }; - - BN.prototype.divn = function divn (num) { - return this.clone().idivn(num); - }; - - BN.prototype.egcd = function egcd (p) { - assert(p.negative === 0); - assert(!p.isZero()); - - var x = this; - var y = p.clone(); - - if (x.negative !== 0) { - x = x.umod(p); - } else { - x = x.clone(); - } - - // A * x + B * y = x - var A = new BN(1); - var B = new BN(0); - - // C * x + D * y = y - var C = new BN(0); - var D = new BN(1); - - var g = 0; - - while (x.isEven() && y.isEven()) { - x.iushrn(1); - y.iushrn(1); - ++g; - } - - var yp = y.clone(); - var xp = x.clone(); - - while (!x.isZero()) { - for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1); - if (i > 0) { - x.iushrn(i); - while (i-- > 0) { - if (A.isOdd() || B.isOdd()) { - A.iadd(yp); - B.isub(xp); - } - - A.iushrn(1); - B.iushrn(1); - } - } - - for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); - if (j > 0) { - y.iushrn(j); - while (j-- > 0) { - if (C.isOdd() || D.isOdd()) { - C.iadd(yp); - D.isub(xp); - } - - C.iushrn(1); - D.iushrn(1); - } - } - - if (x.cmp(y) >= 0) { - x.isub(y); - A.isub(C); - B.isub(D); - } else { - y.isub(x); - C.isub(A); - D.isub(B); - } - } - - return { - a: C, - b: D, - gcd: y.iushln(g) - }; - }; - - // This is reduced incarnation of the binary EEA - // above, designated to invert members of the - // _prime_ fields F(p) at a maximal speed - BN.prototype._invmp = function _invmp (p) { - assert(p.negative === 0); - assert(!p.isZero()); - - var a = this; - var b = p.clone(); - - if (a.negative !== 0) { - a = a.umod(p); - } else { - a = a.clone(); - } - - var x1 = new BN(1); - var x2 = new BN(0); - - var delta = b.clone(); - - while (a.cmpn(1) > 0 && b.cmpn(1) > 0) { - for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1); - if (i > 0) { - a.iushrn(i); - while (i-- > 0) { - if (x1.isOdd()) { - x1.iadd(delta); - } - - x1.iushrn(1); - } - } - - for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1); - if (j > 0) { - b.iushrn(j); - while (j-- > 0) { - if (x2.isOdd()) { - x2.iadd(delta); - } - - x2.iushrn(1); - } - } - - if (a.cmp(b) >= 0) { - a.isub(b); - x1.isub(x2); - } else { - b.isub(a); - x2.isub(x1); - } - } - - var res; - if (a.cmpn(1) === 0) { - res = x1; - } else { - res = x2; - } - - if (res.cmpn(0) < 0) { - res.iadd(p); - } - - return res; - }; - - BN.prototype.gcd = function gcd (num) { - if (this.isZero()) return num.abs(); - if (num.isZero()) return this.abs(); - - var a = this.clone(); - var b = num.clone(); - a.negative = 0; - b.negative = 0; - - // Remove common factor of two - for (var shift = 0; a.isEven() && b.isEven(); shift++) { - a.iushrn(1); - b.iushrn(1); - } - - do { - while (a.isEven()) { - a.iushrn(1); - } - while (b.isEven()) { - b.iushrn(1); - } - - var r = a.cmp(b); - if (r < 0) { - // Swap `a` and `b` to make `a` always bigger than `b` - var t = a; - a = b; - b = t; - } else if (r === 0 || b.cmpn(1) === 0) { - break; - } - - a.isub(b); - } while (true); - - return b.iushln(shift); - }; - - // Invert number in the field F(num) - BN.prototype.invm = function invm (num) { - return this.egcd(num).a.umod(num); - }; - - BN.prototype.isEven = function isEven () { - return (this.words[0] & 1) === 0; - }; - - BN.prototype.isOdd = function isOdd () { - return (this.words[0] & 1) === 1; - }; - - // And first word and num - BN.prototype.andln = function andln (num) { - return this.words[0] & num; - }; - - // Increment at the bit position in-line - BN.prototype.bincn = function bincn (bit) { - assert(typeof bit === 'number'); - var r = bit % 26; - var s = (bit - r) / 26; - var q = 1 << r; - - // Fast case: bit is much higher than all existing words - if (this.length <= s) { - this._expand(s + 1); - this.words[s] |= q; - return this; - } - - // Add bit and propagate, if needed - var carry = q; - for (var i = s; carry !== 0 && i < this.length; i++) { - var w = this.words[i] | 0; - w += carry; - carry = w >>> 26; - w &= 0x3ffffff; - this.words[i] = w; - } - if (carry !== 0) { - this.words[i] = carry; - this.length++; - } - return this; - }; - - BN.prototype.isZero = function isZero () { - return this.length === 1 && this.words[0] === 0; - }; - - BN.prototype.cmpn = function cmpn (num) { - var negative = num < 0; - - if (this.negative !== 0 && !negative) return -1; - if (this.negative === 0 && negative) return 1; - - this.strip(); - - var res; - if (this.length > 1) { - res = 1; - } else { - if (negative) { - num = -num; - } - - assert(num <= 0x3ffffff, 'Number is too big'); - - var w = this.words[0] | 0; - res = w === num ? 0 : w < num ? -1 : 1; - } - if (this.negative !== 0) return -res | 0; - return res; - }; - - // Compare two numbers and return: - // 1 - if `this` > `num` - // 0 - if `this` == `num` - // -1 - if `this` < `num` - BN.prototype.cmp = function cmp (num) { - if (this.negative !== 0 && num.negative === 0) return -1; - if (this.negative === 0 && num.negative !== 0) return 1; - - var res = this.ucmp(num); - if (this.negative !== 0) return -res | 0; - return res; - }; - - // Unsigned comparison - BN.prototype.ucmp = function ucmp (num) { - // At this point both numbers have the same sign - if (this.length > num.length) return 1; - if (this.length < num.length) return -1; - - var res = 0; - for (var i = this.length - 1; i >= 0; i--) { - var a = this.words[i] | 0; - var b = num.words[i] | 0; - - if (a === b) continue; - if (a < b) { - res = -1; - } else if (a > b) { - res = 1; - } - break; - } - return res; - }; - - BN.prototype.gtn = function gtn (num) { - return this.cmpn(num) === 1; - }; - - BN.prototype.gt = function gt (num) { - return this.cmp(num) === 1; - }; - - BN.prototype.gten = function gten (num) { - return this.cmpn(num) >= 0; - }; - - BN.prototype.gte = function gte (num) { - return this.cmp(num) >= 0; - }; - - BN.prototype.ltn = function ltn (num) { - return this.cmpn(num) === -1; - }; - - BN.prototype.lt = function lt (num) { - return this.cmp(num) === -1; - }; - - BN.prototype.lten = function lten (num) { - return this.cmpn(num) <= 0; - }; - - BN.prototype.lte = function lte (num) { - return this.cmp(num) <= 0; - }; - - BN.prototype.eqn = function eqn (num) { - return this.cmpn(num) === 0; - }; - - BN.prototype.eq = function eq (num) { - return this.cmp(num) === 0; - }; - - // - // A reduce context, could be using montgomery or something better, depending - // on the `m` itself. - // - BN.red = function red (num) { - return new Red(num); - }; - - BN.prototype.toRed = function toRed (ctx) { - assert(!this.red, 'Already a number in reduction context'); - assert(this.negative === 0, 'red works only with positives'); - return ctx.convertTo(this)._forceRed(ctx); - }; - - BN.prototype.fromRed = function fromRed () { - assert(this.red, 'fromRed works only with numbers in reduction context'); - return this.red.convertFrom(this); - }; - - BN.prototype._forceRed = function _forceRed (ctx) { - this.red = ctx; - return this; - }; - - BN.prototype.forceRed = function forceRed (ctx) { - assert(!this.red, 'Already a number in reduction context'); - return this._forceRed(ctx); - }; - - BN.prototype.redAdd = function redAdd (num) { - assert(this.red, 'redAdd works only with red numbers'); - return this.red.add(this, num); - }; - - BN.prototype.redIAdd = function redIAdd (num) { - assert(this.red, 'redIAdd works only with red numbers'); - return this.red.iadd(this, num); - }; - - BN.prototype.redSub = function redSub (num) { - assert(this.red, 'redSub works only with red numbers'); - return this.red.sub(this, num); - }; - - BN.prototype.redISub = function redISub (num) { - assert(this.red, 'redISub works only with red numbers'); - return this.red.isub(this, num); - }; - - BN.prototype.redShl = function redShl (num) { - assert(this.red, 'redShl works only with red numbers'); - return this.red.shl(this, num); - }; - - BN.prototype.redMul = function redMul (num) { - assert(this.red, 'redMul works only with red numbers'); - this.red._verify2(this, num); - return this.red.mul(this, num); - }; - - BN.prototype.redIMul = function redIMul (num) { - assert(this.red, 'redMul works only with red numbers'); - this.red._verify2(this, num); - return this.red.imul(this, num); - }; - - BN.prototype.redSqr = function redSqr () { - assert(this.red, 'redSqr works only with red numbers'); - this.red._verify1(this); - return this.red.sqr(this); - }; - - BN.prototype.redISqr = function redISqr () { - assert(this.red, 'redISqr works only with red numbers'); - this.red._verify1(this); - return this.red.isqr(this); - }; - - // Square root over p - BN.prototype.redSqrt = function redSqrt () { - assert(this.red, 'redSqrt works only with red numbers'); - this.red._verify1(this); - return this.red.sqrt(this); - }; - - BN.prototype.redInvm = function redInvm () { - assert(this.red, 'redInvm works only with red numbers'); - this.red._verify1(this); - return this.red.invm(this); - }; - - // Return negative clone of `this` % `red modulo` - BN.prototype.redNeg = function redNeg () { - assert(this.red, 'redNeg works only with red numbers'); - this.red._verify1(this); - return this.red.neg(this); - }; - - BN.prototype.redPow = function redPow (num) { - assert(this.red && !num.red, 'redPow(normalNum)'); - this.red._verify1(this); - return this.red.pow(this, num); - }; - - // Prime numbers with efficient reduction - var primes = { - k256: null, - p224: null, - p192: null, - p25519: null - }; - - // Pseudo-Mersenne prime - function MPrime (name, p) { - // P = 2 ^ N - K - this.name = name; - this.p = new BN(p, 16); - this.n = this.p.bitLength(); - this.k = new BN(1).iushln(this.n).isub(this.p); - - this.tmp = this._tmp(); - } - - MPrime.prototype._tmp = function _tmp () { - var tmp = new BN(null); - tmp.words = new Array(Math.ceil(this.n / 13)); - return tmp; - }; - - MPrime.prototype.ireduce = function ireduce (num) { - // Assumes that `num` is less than `P^2` - // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P) - var r = num; - var rlen; - - do { - this.split(r, this.tmp); - r = this.imulK(r); - r = r.iadd(this.tmp); - rlen = r.bitLength(); - } while (rlen > this.n); - - var cmp = rlen < this.n ? -1 : r.ucmp(this.p); - if (cmp === 0) { - r.words[0] = 0; - r.length = 1; - } else if (cmp > 0) { - r.isub(this.p); - } else { - if (r.strip !== undefined) { - // r is BN v4 instance - r.strip(); - } else { - // r is BN v5 instance - r._strip(); - } - } - - return r; - }; - - MPrime.prototype.split = function split (input, out) { - input.iushrn(this.n, 0, out); - }; - - MPrime.prototype.imulK = function imulK (num) { - return num.imul(this.k); - }; - - function K256 () { - MPrime.call( - this, - 'k256', - 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f'); - } - inherits(K256, MPrime); - - K256.prototype.split = function split (input, output) { - // 256 = 9 * 26 + 22 - var mask = 0x3fffff; - - var outLen = Math.min(input.length, 9); - for (var i = 0; i < outLen; i++) { - output.words[i] = input.words[i]; - } - output.length = outLen; - - if (input.length <= 9) { - input.words[0] = 0; - input.length = 1; - return; - } - - // Shift by 9 limbs - var prev = input.words[9]; - output.words[output.length++] = prev & mask; - - for (i = 10; i < input.length; i++) { - var next = input.words[i] | 0; - input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22); - prev = next; - } - prev >>>= 22; - input.words[i - 10] = prev; - if (prev === 0 && input.length > 10) { - input.length -= 10; - } else { - input.length -= 9; - } - }; - - K256.prototype.imulK = function imulK (num) { - // K = 0x1000003d1 = [ 0x40, 0x3d1 ] - num.words[num.length] = 0; - num.words[num.length + 1] = 0; - num.length += 2; - - // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390 - var lo = 0; - for (var i = 0; i < num.length; i++) { - var w = num.words[i] | 0; - lo += w * 0x3d1; - num.words[i] = lo & 0x3ffffff; - lo = w * 0x40 + ((lo / 0x4000000) | 0); - } - - // Fast length reduction - if (num.words[num.length - 1] === 0) { - num.length--; - if (num.words[num.length - 1] === 0) { - num.length--; - } - } - return num; - }; - - function P224 () { - MPrime.call( - this, - 'p224', - 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001'); - } - inherits(P224, MPrime); - - function P192 () { - MPrime.call( - this, - 'p192', - 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff'); - } - inherits(P192, MPrime); - - function P25519 () { - // 2 ^ 255 - 19 - MPrime.call( - this, - '25519', - '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed'); - } - inherits(P25519, MPrime); - - P25519.prototype.imulK = function imulK (num) { - // K = 0x13 - var carry = 0; - for (var i = 0; i < num.length; i++) { - var hi = (num.words[i] | 0) * 0x13 + carry; - var lo = hi & 0x3ffffff; - hi >>>= 26; - - num.words[i] = lo; - carry = hi; - } - if (carry !== 0) { - num.words[num.length++] = carry; - } - return num; - }; - - // Exported mostly for testing purposes, use plain name instead - BN._prime = function prime (name) { - // Cached version of prime - if (primes[name]) return primes[name]; - - var prime; - if (name === 'k256') { - prime = new K256(); - } else if (name === 'p224') { - prime = new P224(); - } else if (name === 'p192') { - prime = new P192(); - } else if (name === 'p25519') { - prime = new P25519(); - } else { - throw new Error('Unknown prime ' + name); - } - primes[name] = prime; - - return prime; - }; - - // - // Base reduction engine - // - function Red (m) { - if (typeof m === 'string') { - var prime = BN._prime(m); - this.m = prime.p; - this.prime = prime; - } else { - assert(m.gtn(1), 'modulus must be greater than 1'); - this.m = m; - this.prime = null; - } - } - - Red.prototype._verify1 = function _verify1 (a) { - assert(a.negative === 0, 'red works only with positives'); - assert(a.red, 'red works only with red numbers'); - }; - - Red.prototype._verify2 = function _verify2 (a, b) { - assert((a.negative | b.negative) === 0, 'red works only with positives'); - assert(a.red && a.red === b.red, - 'red works only with red numbers'); - }; - - Red.prototype.imod = function imod (a) { - if (this.prime) return this.prime.ireduce(a)._forceRed(this); - return a.umod(this.m)._forceRed(this); - }; - - Red.prototype.neg = function neg (a) { - if (a.isZero()) { - return a.clone(); - } - - return this.m.sub(a)._forceRed(this); - }; - - Red.prototype.add = function add (a, b) { - this._verify2(a, b); - - var res = a.add(b); - if (res.cmp(this.m) >= 0) { - res.isub(this.m); - } - return res._forceRed(this); - }; - - Red.prototype.iadd = function iadd (a, b) { - this._verify2(a, b); - - var res = a.iadd(b); - if (res.cmp(this.m) >= 0) { - res.isub(this.m); - } - return res; - }; - - Red.prototype.sub = function sub (a, b) { - this._verify2(a, b); - - var res = a.sub(b); - if (res.cmpn(0) < 0) { - res.iadd(this.m); - } - return res._forceRed(this); - }; - - Red.prototype.isub = function isub (a, b) { - this._verify2(a, b); - - var res = a.isub(b); - if (res.cmpn(0) < 0) { - res.iadd(this.m); - } - return res; - }; - - Red.prototype.shl = function shl (a, num) { - this._verify1(a); - return this.imod(a.ushln(num)); - }; - - Red.prototype.imul = function imul (a, b) { - this._verify2(a, b); - return this.imod(a.imul(b)); - }; - - Red.prototype.mul = function mul (a, b) { - this._verify2(a, b); - return this.imod(a.mul(b)); - }; - - Red.prototype.isqr = function isqr (a) { - return this.imul(a, a.clone()); - }; - - Red.prototype.sqr = function sqr (a) { - return this.mul(a, a); - }; - - Red.prototype.sqrt = function sqrt (a) { - if (a.isZero()) return a.clone(); - - var mod3 = this.m.andln(3); - assert(mod3 % 2 === 1); - - // Fast case - if (mod3 === 3) { - var pow = this.m.add(new BN(1)).iushrn(2); - return this.pow(a, pow); - } - - // Tonelli-Shanks algorithm (Totally unoptimized and slow) - // - // Find Q and S, that Q * 2 ^ S = (P - 1) - var q = this.m.subn(1); - var s = 0; - while (!q.isZero() && q.andln(1) === 0) { - s++; - q.iushrn(1); - } - assert(!q.isZero()); - - var one = new BN(1).toRed(this); - var nOne = one.redNeg(); - - // Find quadratic non-residue - // NOTE: Max is such because of generalized Riemann hypothesis. - var lpow = this.m.subn(1).iushrn(1); - var z = this.m.bitLength(); - z = new BN(2 * z * z).toRed(this); - - while (this.pow(z, lpow).cmp(nOne) !== 0) { - z.redIAdd(nOne); - } - - var c = this.pow(z, q); - var r = this.pow(a, q.addn(1).iushrn(1)); - var t = this.pow(a, q); - var m = s; - while (t.cmp(one) !== 0) { - var tmp = t; - for (var i = 0; tmp.cmp(one) !== 0; i++) { - tmp = tmp.redSqr(); - } - assert(i < m); - var b = this.pow(c, new BN(1).iushln(m - i - 1)); - - r = r.redMul(b); - c = b.redSqr(); - t = t.redMul(c); - m = i; - } - - return r; - }; - - Red.prototype.invm = function invm (a) { - var inv = a._invmp(this.m); - if (inv.negative !== 0) { - inv.negative = 0; - return this.imod(inv).redNeg(); - } else { - return this.imod(inv); - } - }; - - Red.prototype.pow = function pow (a, num) { - if (num.isZero()) return new BN(1).toRed(this); - if (num.cmpn(1) === 0) return a.clone(); - - var windowSize = 4; - var wnd = new Array(1 << windowSize); - wnd[0] = new BN(1).toRed(this); - wnd[1] = a; - for (var i = 2; i < wnd.length; i++) { - wnd[i] = this.mul(wnd[i - 1], a); - } - - var res = wnd[0]; - var current = 0; - var currentLen = 0; - var start = num.bitLength() % 26; - if (start === 0) { - start = 26; - } - - for (i = num.length - 1; i >= 0; i--) { - var word = num.words[i]; - for (var j = start - 1; j >= 0; j--) { - var bit = (word >> j) & 1; - if (res !== wnd[0]) { - res = this.sqr(res); - } - - if (bit === 0 && current === 0) { - currentLen = 0; - continue; - } - - current <<= 1; - current |= bit; - currentLen++; - if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue; - - res = this.mul(res, wnd[current]); - currentLen = 0; - current = 0; - } - start = 26; - } - - return res; - }; - - Red.prototype.convertTo = function convertTo (num) { - var r = num.umod(this.m); - - return r === num ? r.clone() : r; - }; - - Red.prototype.convertFrom = function convertFrom (num) { - var res = num.clone(); - res.red = null; - return res; - }; - - // - // Montgomery method engine - // - - BN.mont = function mont (num) { - return new Mont(num); - }; - - function Mont (m) { - Red.call(this, m); - - this.shift = this.m.bitLength(); - if (this.shift % 26 !== 0) { - this.shift += 26 - (this.shift % 26); - } - - this.r = new BN(1).iushln(this.shift); - this.r2 = this.imod(this.r.sqr()); - this.rinv = this.r._invmp(this.m); - - this.minv = this.rinv.mul(this.r).isubn(1).div(this.m); - this.minv = this.minv.umod(this.r); - this.minv = this.r.sub(this.minv); - } - inherits(Mont, Red); - - Mont.prototype.convertTo = function convertTo (num) { - return this.imod(num.ushln(this.shift)); - }; - - Mont.prototype.convertFrom = function convertFrom (num) { - var r = this.imod(num.mul(this.rinv)); - r.red = null; - return r; - }; - - Mont.prototype.imul = function imul (a, b) { - if (a.isZero() || b.isZero()) { - a.words[0] = 0; - a.length = 1; - return a; - } - - var t = a.imul(b); - var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); - var u = t.isub(c).iushrn(this.shift); - var res = u; - - if (u.cmp(this.m) >= 0) { - res = u.isub(this.m); - } else if (u.cmpn(0) < 0) { - res = u.iadd(this.m); - } - - return res._forceRed(this); - }; - - Mont.prototype.mul = function mul (a, b) { - if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this); - - var t = a.mul(b); - var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m); - var u = t.isub(c).iushrn(this.shift); - var res = u; - if (u.cmp(this.m) >= 0) { - res = u.isub(this.m); - } else if (u.cmpn(0) < 0) { - res = u.iadd(this.m); - } - - return res._forceRed(this); - }; - - Mont.prototype.invm = function invm (a) { - // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R - var res = this.imod(a._invmp(this.m).mul(this.r2)); - return res._forceRed(this); - }; -})(typeof module === 'undefined' || module, this); diff --git a/node_modules/bn.js/package.json b/node_modules/bn.js/package.json deleted file mode 100644 index a3c4ebc..0000000 --- a/node_modules/bn.js/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "bn.js", - "version": "4.12.1", - "description": "Big number implementation in pure javascript", - "main": "lib/bn.js", - "scripts": { - "lint": "semistandard", - "unit": "mocha --reporter=spec test/*-test.js", - "test": "npm run lint && npm run unit" - }, - "repository": { - "type": "git", - "url": "git@github.com:indutny/bn.js" - }, - "keywords": [ - "BN", - "BigNum", - "Big number", - "Modulo", - "Montgomery" - ], - "author": "Fedor Indutny ", - "license": "MIT", - "bugs": { - "url": "https://github.com/indutny/bn.js/issues" - }, - "homepage": "https://github.com/indutny/bn.js", - "browser": { - "buffer": false - }, - "devDependencies": { - "istanbul": "^0.3.5", - "mocha": "^2.1.0", - "semistandard": "^7.0.4" - } -} diff --git a/node_modules/bn.js/util/genCombMulTo.js b/node_modules/bn.js/util/genCombMulTo.js deleted file mode 100644 index 8b456c7..0000000 --- a/node_modules/bn.js/util/genCombMulTo.js +++ /dev/null @@ -1,65 +0,0 @@ -'use strict'; - -// NOTE: This could be potentionally used to generate loop-less multiplications -function genCombMulTo (alen, blen) { - var len = alen + blen - 1; - var src = [ - 'var a = self.words;', - 'var b = num.words;', - 'var o = out.words;', - 'var c = 0;', - 'var lo;', - 'var mid;', - 'var hi;' - ]; - for (var i = 0; i < alen; i++) { - src.push('var a' + i + ' = a[' + i + '] | 0;'); - src.push('var al' + i + ' = a' + i + ' & 0x1fff;'); - src.push('var ah' + i + ' = a' + i + ' >>> 13;'); - } - for (i = 0; i < blen; i++) { - src.push('var b' + i + ' = b[' + i + '] | 0;'); - src.push('var bl' + i + ' = b' + i + ' & 0x1fff;'); - src.push('var bh' + i + ' = b' + i + ' >>> 13;'); - } - src.push(''); - src.push('out.negative = self.negative ^ num.negative;'); - src.push('out.length = ' + len + ';'); - - for (var k = 0; k < len; k++) { - var minJ = Math.max(0, k - alen + 1); - var maxJ = Math.min(k, blen - 1); - - src.push('\/* k = ' + k + ' *\/'); - src.push('var w' + k + ' = c;'); - src.push('c = 0;'); - for (var j = minJ; j <= maxJ; j++) { - i = k - j; - - src.push('lo = Math.imul(al' + i + ', bl' + j + ');'); - src.push('mid = Math.imul(al' + i + ', bh' + j + ');'); - src.push('mid = (mid + Math.imul(ah' + i + ', bl' + j + ')) | 0;'); - src.push('hi = Math.imul(ah' + i + ', bh' + j + ');'); - - src.push('w' + k + ' = (w' + k + ' + lo) | 0;'); - src.push('w' + k + ' = (w' + k + ' + ((mid & 0x1fff) << 13)) | 0;'); - src.push('c = (c + hi) | 0;'); - src.push('c = (c + (mid >>> 13)) | 0;'); - src.push('c = (c + (w' + k + ' >>> 26)) | 0;'); - src.push('w' + k + ' &= 0x3ffffff;'); - } - } - // Store in separate step for better memory access - for (k = 0; k < len; k++) { - src.push('o[' + k + '] = w' + k + ';'); - } - src.push('if (c !== 0) {', - ' o[' + k + '] = c;', - ' out.length++;', - '}', - 'return out;'); - - return src.join('\n'); -} - -console.log(genCombMulTo(10, 10)); diff --git a/node_modules/bn.js/util/genCombMulTo10.js b/node_modules/bn.js/util/genCombMulTo10.js deleted file mode 100644 index cf2e6e8..0000000 --- a/node_modules/bn.js/util/genCombMulTo10.js +++ /dev/null @@ -1,65 +0,0 @@ -'use strict'; - -function genCombMulTo (alen, blen) { - var len = alen + blen - 1; - var src = [ - 'var a = self.words;', - 'var b = num.words;', - 'var o = out.words;', - 'var c = 0;', - 'var lo;', - 'var mid;', - 'var hi;' - ]; - for (var i = 0; i < alen; i++) { - src.push('var a' + i + ' = a[' + i + '] | 0;'); - src.push('var al' + i + ' = a' + i + ' & 0x1fff;'); - src.push('var ah' + i + ' = a' + i + ' >>> 13;'); - } - for (i = 0; i < blen; i++) { - src.push('var b' + i + ' = b[' + i + '] | 0;'); - src.push('var bl' + i + ' = b' + i + ' & 0x1fff;'); - src.push('var bh' + i + ' = b' + i + ' >>> 13;'); - } - src.push(''); - src.push('out.negative = self.negative ^ num.negative;'); - src.push('out.length = ' + len + ';'); - - for (var k = 0; k < len; k++) { - var minJ = Math.max(0, k - alen + 1); - var maxJ = Math.min(k, blen - 1); - - src.push('\/* k = ' + k + ' *\/'); - src.push('lo = Math.imul(al' + (k - minJ) + ', bl' + minJ + ');'); - src.push('mid = Math.imul(al' + (k - minJ) + ', bh' + minJ + ');'); - src.push( - 'mid = (mid + Math.imul(ah' + (k - minJ) + ', bl' + minJ + ')) | 0;'); - src.push('hi = Math.imul(ah' + (k - minJ) + ', bh' + minJ + ');'); - - for (var j = minJ + 1; j <= maxJ; j++) { - i = k - j; - - src.push('lo = (lo + Math.imul(al' + i + ', bl' + j + ')) | 0;'); - src.push('mid = (mid + Math.imul(al' + i + ', bh' + j + ')) | 0;'); - src.push('mid = (mid + Math.imul(ah' + i + ', bl' + j + ')) | 0;'); - src.push('hi = (hi + Math.imul(ah' + i + ', bh' + j + ')) | 0;'); - } - - src.push('var w' + k + ' = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;'); - src.push('c = (((hi + (mid >>> 13)) | 0) + (w' + k + ' >>> 26)) | 0;'); - src.push('w' + k + ' &= 0x3ffffff;'); - } - // Store in separate step for better memory access - for (k = 0; k < len; k++) { - src.push('o[' + k + '] = w' + k + ';'); - } - src.push('if (c !== 0) {', - ' o[' + k + '] = c;', - ' out.length++;', - '}', - 'return out;'); - - return src.join('\n'); -} - -console.log(genCombMulTo(10, 10)); diff --git a/node_modules/jose/CHANGELOG.md b/node_modules/jose/CHANGELOG.md deleted file mode 100644 index 94cb939..0000000 --- a/node_modules/jose/CHANGELOG.md +++ /dev/null @@ -1,400 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. - -## [1.10.2](https://github.com/panva/jose/compare/v1.10.1...v1.10.2) (2019-10-29) - - -### Bug Fixes - -* only use secp256k1 keys for signing/verification ([9588223](https://github.com/panva/jose/commit/95882232d6d409a321b6a8c168f5b78ebbdabf95)) - - - -## [1.10.1](https://github.com/panva/jose/compare/v1.10.0...v1.10.1) (2019-10-04) - - -### Bug Fixes - -* throw proper error when runtime doesn't support OKP ([0a16efb](https://github.com/panva/jose/commit/0a16efb)), closes [#48](https://github.com/panva/jose/issues/48) - - - -# [1.10.0](https://github.com/panva/jose/compare/v1.9.2...v1.10.0) (2019-10-01) - - -### Features - -* rename package ([26f4cf2](https://github.com/panva/jose/commit/26f4cf2)) - - - -## [1.9.2](https://github.com/panva/jose/compare/v1.9.1...v1.9.2) (2019-09-16) - - -### Bug Fixes - -* keystore.toJWKS(true) does not throw on public keys ([81abdfa](https://github.com/panva/jose/commit/81abdfa)), closes [#42](https://github.com/panva/jose/issues/42) - - - -## [1.9.1](https://github.com/panva/jose/compare/v1.9.0...v1.9.1) (2019-09-10) - - - -# [1.9.0](https://github.com/panva/jose/compare/v1.8.0...v1.9.0) (2019-08-24) - - -### Features - -* allow JWKS.asKeyStore to swallow errors ([78398d3](https://github.com/panva/jose/commit/78398d3)) - - - -# [1.8.0](https://github.com/panva/jose/compare/v1.7.0...v1.8.0) (2019-08-22) - - -### Features - -* added Node.js lts/dubnium support for runtime supported features ([67a8601](https://github.com/panva/jose/commit/67a8601)) - - - -# [1.7.0](https://github.com/panva/jose/compare/v1.6.1...v1.7.0) (2019-08-20) - - -### Features - -* add RSA-OAEP-256 support (when a node version supports it) ([28d7cf8](https://github.com/panva/jose/commit/28d7cf8)), closes [#29](https://github.com/panva/jose/issues/29) - - - -## [1.6.1](https://github.com/panva/jose/compare/v1.6.0...v1.6.1) (2019-07-29) - - -### Bug Fixes - -* properly pad calculated RSA primes ([dd121ce](https://github.com/panva/jose/commit/dd121ce)) - - - -# [1.6.0](https://github.com/panva/jose/compare/v1.5.2...v1.6.0) (2019-07-27) - - -### Bug Fixes - -* use the correct ECPrivateKey version when importing EC JWK ([24acd20](https://github.com/panva/jose/commit/24acd20)) - - -### Features - -* electron v6.x support ([e7ad82c](https://github.com/panva/jose/commit/e7ad82c)) - - - -## [1.5.2](https://github.com/panva/jose/compare/v1.5.1...v1.5.2) (2019-07-27) - - -### Bug Fixes - -* importing x5c in electron requires the input split ([181fd09](https://github.com/panva/jose/commit/181fd09)) - - - -## [1.5.1](https://github.com/panva/jose/compare/v1.5.0...v1.5.1) (2019-07-27) - - -### Bug Fixes - -* correctly pad integers when importing RSA JWK ([1dc7f35](https://github.com/panva/jose/commit/1dc7f35)) - - - -# [1.5.0](https://github.com/panva/jose/compare/v1.4.1...v1.5.0) (2019-07-23) - - -### Features - -* validate JWTs according to a JWT profile - ID Token ([6c98b61](https://github.com/panva/jose/commit/6c98b61)) - - - -## [1.4.1](https://github.com/panva/jose/compare/v1.4.0...v1.4.1) (2019-07-14) - - -### Bug Fixes - -* honour the JWT.sign `jti` option ([36c9ce2](https://github.com/panva/jose/commit/36c9ce2)), closes [#33](https://github.com/panva/jose/issues/33) - - - -# [1.4.0](https://github.com/panva/jose/compare/v1.3.0...v1.4.0) (2019-07-08) - - -### Features - -* add secp256k1 EC Key curve and ES256K ([211d7af](https://github.com/panva/jose/commit/211d7af)) - - - -# [1.3.0](https://github.com/panva/jose/compare/v1.0.2...c51dc28) (2019-06-21) - - -### Features - -* compute private RSA key p, q, dp, dq, qi when omitted ([6e3d6fd](https://github.com/panva/jose/commit/6e3d6fd)), closes [#26](https://github.com/panva/jose/issues/26) -* add support for JWK x5c, x5t and x5t#S256 ([9d46c48](https://github.com/panva/jose/commit/9d46c48)) -* instances of JWKS.KeyStore are now iterable (e.g. for ... of) ([2eae293](https://github.com/panva/jose/commit/2eae293)) - -### Bug Fixes - -* limit calculation of missing RSA private components ([5b53cb0](https://github.com/panva/jose/commit/5b53cb0)) -* reject rsa keys without all factors and exponents with a specific message ([b0ff436](https://github.com/panva/jose/commit/b0ff436)) - -### Deprecations - -- this deprecates the use of `JWK.importKey` in favor of -`JWK.asKey` -- this deprecates the use of `JWKS.KeyStore.fromJWKS` in favor of -`JWKS.asKeyStore` - -Both `JWK.importKey` and `JWKS.KeyStore.fromJWKS` could have resulted -in the process getting blocked when large bitsize RSA private keys -were missing their components and could also result in an endless -calculation loop when the private key's private exponent was outright -invalid or tampered with. - -The new methods still allow to import private RSA keys with these -optimization key parameters missing but it is disabled by default and one -should choose to enable it when working with keys from trusted sources - -It is recommended not to use `jose` versions with this feature in -its original on-by-default form - v1.1.0 and v1.2.0 - - - -## [1.0.2](https://github.com/panva/jose/compare/v1.0.1...v1.0.2) (2019-05-13) - - -### Bug Fixes - -* add missing keystore.toJWKS() .d.ts definition ([c7a8606](https://github.com/panva/jose/commit/c7a8606)), closes [#25](https://github.com/panva/jose/issues/25) - - - -## [1.0.1](https://github.com/panva/jose/compare/v1.0.0...v1.0.1) (2019-04-27) - - -### Bug Fixes - -* oct key ts "k" type fix ([0750d2c](https://github.com/panva/jose/commit/0750d2c)) - - - - -# [1.0.0](https://github.com/panva/jose/compare/v0.12.0...v1.0.0) (2019-04-23) - - -### Bug Fixes - -* fail to import invalid PEM formatted strings and buffers ([857dc2b](https://github.com/panva/jose/commit/857dc2b)) - - -### Features - -* add JWK key_ops support, fix .algorithms() op returns ([23b874c](https://github.com/panva/jose/commit/23b874c)) -* add key.toPEM() export function with optional encryption ([1159b0d](https://github.com/panva/jose/commit/1159b0d)) -* add OKP Key and EdDSA sign/verify support ([2dbd3ed](https://github.com/panva/jose/commit/2dbd3ed)), closes [#12](https://github.com/panva/jose/issues/12) - - -### BREAKING CHANGES - -* key.algorithms(op) un+wrapKey was split into correct -wrapKey/unwrapKey/deriveKey returns -* keystore.all and keystore.get `operation` option was -removed, `key_ops: string[]` supersedes it -* Node.js minimal version is now v12.0.0 due to its -added EdDSA support (crypto.sign, crypto.verify and eddsa key objects) - - - - -# [0.12.0](https://github.com/panva/jose/compare/v0.11.5...v0.12.0) (2019-04-07) - - -### Reverts - -* add EC P-256K JWK and ES256K sign/verify support ([e21fea1](https://github.com/panva/jose/commit/e21fea1)) - - -### BREAKING CHANGES - -* removing ES256K alg and EC P-256K crv support until the -IETF WG decides on what the final names will be. - - - - -## [0.11.5](https://github.com/panva/jose/compare/v0.11.4...v0.11.5) (2019-04-04) - - -### Features - -* add key.secret and key.type for completeness ([2dd7053](https://github.com/panva/jose/commit/2dd7053)) -* add key.thumbprint always returning the JWK Thumbprint (RFC7638) ([65db7e0](https://github.com/panva/jose/commit/65db7e0)) - - - - -## [0.11.4](https://github.com/panva/jose/compare/v0.11.3...v0.11.4) (2019-03-28) - - -### Bug Fixes - -* properly restrict EC curves in generate(Sync) ([764b863](https://github.com/panva/jose/commit/764b863)) -* remove unintended exposure of private material via enumerables ([946d9df](https://github.com/panva/jose/commit/946d9df)) - - - - -## [0.11.3](https://github.com/panva/jose/compare/v0.11.2...v0.11.3) (2019-03-27) - - -### Bug Fixes - -* throw on unsupported EC curves ([cfa4222](https://github.com/panva/jose/commit/cfa4222)) - - -### Features - -* add EC P-256K JWK and ES256K sign/verify support ([2e33e1c](https://github.com/panva/jose/commit/2e33e1c)) - - - - -## [0.11.2](https://github.com/panva/jose/compare/v0.11.1...v0.11.2) (2019-03-19) - - -### Bug Fixes - -* internal symbol method is now really a symbol ([925d47c](https://github.com/panva/jose/commit/925d47c)) -* key.toJWK() fixed on windows ([57f1692](https://github.com/panva/jose/commit/57f1692)), closes [#17](https://github.com/panva/jose/issues/17) - - -## [0.11.1](https://github.com/panva/jose/compare/v0.11.0...v0.11.1) (2019-03-17) - - -### Bug Fixes - -* restrict RS key algorithms by the key's bit size ([9af295b](https://github.com/panva/jose/commit/9af295b)) - - -# [0.11.0](https://github.com/panva/jose/compare/v0.10.0...v0.11.0) (2019-03-16) - - -### Bug Fixes - -* all JWA defined RSA operations require key of 2048 or more ([cc70c5d](https://github.com/panva/jose/commit/cc70c5d)) -* use correct salt length for RSASSA-PSS ([e936d54](https://github.com/panva/jose/commit/e936d54)) - - -### BREAKING CHANGES - -* all [JWA](https://tools.ietf.org/html/rfc7518) defined -RSA based operations require key size of 2048 bits or more. - - - -# [0.10.0](https://github.com/panva/jose/compare/v0.9.2...v0.10.0) (2019-03-12) - - -### Bug Fixes - -* do not list "dir" under wrap/unwrapKey operations ([17b37d3](https://github.com/panva/jose/commit/17b37d3)) - - -### Features - -* keystore .all and .get operation option ([d349ba9](https://github.com/panva/jose/commit/d349ba9)) - - -### BREAKING CHANGES - -* "dir" is no longer returned as wrap/unwrapKey key -operation - - - -## [0.9.2](https://github.com/panva/jose/compare/v0.9.1...v0.9.2) (2019-03-05) - - -### Bug Fixes - -* "dir" is only available on keys with correct lengths ([6854860](https://github.com/panva/jose/commit/6854860)) -* do not 'in' operator when importing keys as string ([be3f4e4](https://github.com/panva/jose/commit/be3f4e4)) - - - -## [0.9.1](https://github.com/panva/jose/compare/v0.9.0...v0.9.1) (2019-03-02) - - -### Bug Fixes - -* only import RSA, EC and oct successfully ([e5e02fc](https://github.com/panva/jose/commit/e5e02fc)) - - -# 0.9.0 (2019-03-02) - -Initial release - -### Implemented Features - -- JSON Web Signature (JWS) - [RFC7515][spec-jws] -- JSON Web Encryption (JWE) - [RFC7516][spec-jwe] -- JSON Web Key (JWK) - [RFC7517][spec-jwk] -- JSON Web Algorithms (JWA) - [RFC7518][spec-jwa] -- JSON Web Token (JWT) - [RFC7519][spec-jwt] -- JSON Web Key (JWK) Thumbprint - [RFC7638][spec-thumbprint] -- JWS Unencoded Payload Option - [RFC7797][spec-b64] - -| JWK Key Types | Supported || -| -- | -- | -- | -| RSA | ✓ | RSA | -| Elliptic Curve | ✓ | EC | -| Octet sequence | ✓ | oct | - -| Serialization | JWS Sign | JWS Verify | JWE Encrypt | JWE Decrypt | -| -- | -- | -- | -- | -- | -| Compact | ✓ | ✓ | ✓ | ✓ | -| General JSON | ✓ | ✓ | ✓ | ✓ | -| Flattened JSON | ✓ | ✓ | ✓ | ✓ | - -| JWS Algorithms | Supported || -| -- | -- | -- | -| RSASSA-PKCS1-v1_5 | ✓ | RS256, RS384, RS512 | -| RSASSA-PSS | ✓ | PS256, PS384, PS512 | -| ECDSA | ✓ | ES256, ES384, ES512 | -| HMAC with SHA-2 | ✓ | HS256, HS384, HS512 | - -| JWE Key Management Algorithms | Supported || -| -- | -- | -- | -| AES | ✓ | A128KW, A192KW, A256KW | -| AES GCM | ✓ | A128GCMKW, A192GCMKW, A256GCMKW | -| Direct Key Agreement | ✓ | dir | -| RSAES OAEP | ✓* | RSA-OAEP (*RSA-OAEP-256 is not supported due to its lack of support in Node.js) | -| RSAES-PKCS1-v1_5 | ✓ | RSA1_5 | -| PBES2 | ✓ | PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW | -| ECDH-ES | ✓ | ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW | - -| JWE Content Encryption Algorithms | Supported || -| -- | -- | -- | -| AES GCM | ✓ | A128GCM, A192GCM, A256GCM | -| AES_CBC_HMAC_SHA2 | ✓ | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 | - -[spec-b64]: https://tools.ietf.org/html/rfc7797 -[spec-jwa]: https://tools.ietf.org/html/rfc7518 -[spec-jwe]: https://tools.ietf.org/html/rfc7516 -[spec-jwk]: https://tools.ietf.org/html/rfc7517 -[spec-jws]: https://tools.ietf.org/html/rfc7515 -[spec-jwt]: https://tools.ietf.org/html/rfc7519 -[spec-thumbprint]: https://tools.ietf.org/html/rfc7638 diff --git a/node_modules/jose/README.md b/node_modules/jose/README.md index 8d2b2a4..a836013 100644 --- a/node_modules/jose/README.md +++ b/node_modules/jose/README.md @@ -4,6 +4,20 @@

+## New major version is available + +`v2.x` continues being supported. It will continue receiving +bug fixes until 2022-04-30. It will not be receiving any new +features. + +`v3.x` is [available](https://github.com/panva/jose) with + +- Revised API +- No dependencies +- Browser support +- Promise-based API +- experimental (non-blocking 🎉) Node.js libuv thread pool based runtime + ## Implemented specs & features The following specifications are implemented by `jose` @@ -15,8 +29,8 @@ The following specifications are implemented by `jose` - JSON Web Token (JWT) - [RFC7519][spec-jwt] - JSON Web Key Thumbprint - [RFC7638][spec-thumbprint] - JWS Unencoded Payload Option - [RFC7797][spec-b64] -- CFRG Elliptic Curve Signatures (EdDSA) - [RFC8037][spec-okp] -- secp256k1 curve EC Key support - [JOSE Registrations for WebAuthn Algorithms][draft-secp256k1] +- CFRG Elliptic Curve ECDH and Signatures - [RFC8037][spec-okp] +- secp256k1 EC Key curve support - [JOSE Registrations for WebAuthn Algorithms][spec-secp256k1] The test suite utilizes examples defined in [RFC7520][spec-cookbook] to confirm its JOSE implementation is correct. @@ -24,92 +38,9 @@ implementation is correct. Available JWT validation profiles - Generic JWT -- ID Token (id_token) - [OpenID Connect Core 1.0][spec-oidc-id_token] - -
- Detailed feature matrix (Click to expand)
- -Legend: -- **✓** Implemented -- **✕** Missing node crypto support / won't implement -- **◯** TBD - -| JWK Key Types | Supported || -| -- | -- | -- | -| RSA | ✓ | RSA | -| Elliptic Curve | ✓ | EC | -| Octet Key Pair | ✓ | OKP | -| Octet sequence | ✓ | oct | - -| Serialization | JWS Sign | JWS Verify | JWE Encrypt | JWE Decrypt | -| -- | -- | -- | -- | -- | -| Compact | ✓ | ✓ | ✓ | ✓ | -| General JSON | ✓ | ✓ | ✓ | ✓ | -| Flattened JSON | ✓ | ✓ | ✓ | ✓ | - -| JWS Algorithms | Supported || -| -- | -- | -- | -| RSASSA-PKCS1-v1_5 | ✓ | RS256, RS384, RS512 | -| RSASSA-PSS | ✓ | PS256, PS384, PS512 | -| ECDSA | ✓ | ES256, ES256K, ES384, ES512 | -| Edwards-curve DSA | ✓ | EdDSA | -| HMAC with SHA-2 | ✓ | HS256, HS384, HS512 | - -| JWE Key Management Algorithms | Supported || -| -- | -- | -- | -| AES | ✓ | A128KW, A192KW, A256KW | -| AES GCM | ✓ | A128GCMKW, A192GCMKW, A256GCMKW | -| Direct Key Agreement | ✓ | dir | -| RSAES OAEP | ✓ | RSA-OAEP, RSA-OAEP-256 | -| RSAES-PKCS1-v1_5 | ✓ | RSA1_5 | -| PBES2 | ✓ | PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW | -| ECDH-ES | ✓ | ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW | - -| JWE Content Encryption Algorithms | Supported || -| -- | -- | -- | -| AES GCM | ✓ | A128GCM, A192GCM, A256GCM | -| AES_CBC_HMAC_SHA2 | ✓ | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 | - -| JWT profile validation | Supported | profile option value | -| -- | -- | -- | -| ID Token - [OpenID Connect Core 1.0][spec-oidc-id_token] | ✓ | `id_token` | -| JWT Access Tokens [JWT Profile for OAuth 2.0 Access Tokens][draft-ietf-oauth-access-token-jwt] | ◯ || -| Logout Token - [OpenID Connect Back-Channel Logout 1.0][spec-oidc-logout_token] | ◯ || -| JARM - [JWT Secured Authorization Response Mode for OAuth 2.0][draft-jarm] | ◯ || - -Notes -- RSA-OAEP-256 JWE algorithm is only supported when Node.js >= 12.9.0 runtime is detected -- Importing X.509 certificates and handling `x5c` is only supported when Node.js >= 12.0.0 runtime is detected -- OKP keys are only supported when Node.js >= 12.0.0 runtime is detected -- See [#electron-support](#electron-support) for electron exceptions - ---- - -Pending Node.js Support 🤞: -- ECDH-ES with X25519 and X448 - see [nodejs/node#26626](https://github.com/nodejs/node/pull/26626) - -Won't implement: -- ✕ JWS embedded key / referenced verification - - one can decode the header and pass the (`x5c`, `jwk`) to `JWK.asKey` and validate with that - key, similarly the application can handle fetching and then instantiating the referenced `x5u` - or `jku` in its own code. This way you opt-in to these behaviours. -- ✕ JWS detached content - - one can remove/attach the payload after/before the respective operation -- ✕ "none" alg support - - no crypto, no use - -
- -
- -Have a question about using `jose`? - [ask][ask]. -Found a bug? - [report it][bug]. -Missing a feature? - If it wasn't already discussed before, [ask for it][suggest-feature]. -Found a vulnerability? - Reach out to us via email first, see [security vulnerability disclosure][security-vulnerability]. - -## Sponsor - -[auth0-logo][sponsor-auth0] If you want to quickly add secure token-based authentication to Node.js projects, feel free to check Auth0’s free plan at [auth0.com/overview][sponsor-auth0].

+- OIDC ID Token - [OpenID Connect Core 1.0][spec-oidc-id_token] +- (draft 04) OIDC Logout Token - [OpenID Connect Back-Channel Logout 1.0][spec-oidc-logout_token] +- (draft 06) OAuth 2.0 JWT Access Tokens - [JWT Profile for OAuth 2.0 Access Tokens][draft-ietf-oauth-access-token-jwt] ## Support @@ -132,7 +63,7 @@ is also supported. Installing `jose` ```console -npm install jose +npm install jose@2 ``` Usage @@ -162,7 +93,7 @@ const jwk = { kty: 'EC', y: 'QTwy27XgP7ZMOdGOSopAHB-FU1JMQn3J9GEWGtUXreQ' } const anotherKey = jose.JWK.asKey(jwk) -const keystore = new jose.JWKS.KeyStore(key, key2) +const keystore = new jose.JWKS.KeyStore(key, anotherKey) ``` ### JWT vs JWS @@ -213,19 +144,20 @@ jose.JWT.verify( ) ``` -#### ID Token Verifying +
+ Verifying OIDC ID Tokens (Click to expand)
ID Token is a JWT, but profiled, there are additional requirements to a JWT to be accepted as an -ID Token and it is pretty easy to omit some, use the `profile` option of `JWT.verify` to make sure -what you're accepting is really an ID Token meant to your Client. This will then perform all -doable validations given the input. See the [documentation][documentation-jwt] for more. +ID Token and it is pretty easy to omit some, use the +`JWT.IdToken.verify` API to make sure what you're accepting is really an ID Token meant to +your Client. This will then perform all doable validations given the input. See the +[documentation][documentation-jwt] for more. ```js -jose.JWT.verify( +jose.JWT.IdToken.verify( 'eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiJmb28iLCJub25jZSI6ImE1MWNjZjA4ZjRiYmIwNmU4ODcxNWRkYzRiYmI0MWQ4IiwiYXVkIjoidXJuOmV4YW1wbGU6Y2xpZW50X2lkIiwiZXhwIjoxNTYzODg4ODMwLCJpYXQiOjE1NjM4ODUyMzAsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20ifQ.RKCZczgICF5G9XdNDSwe4dolGauQHptpFKPzahA2wYGG2HKrKhyC8ZzqpeVc8cbntuqFBgABJVv6_9YICRx_dgwPYydTpZfZYjHnxrdWF9QsIPEGs672mrnhqIXUnXoseZ0TF6GOq6P7Qbf6gk1ru7TAbr_ieyJnNWcJhh5iHpz1k3mFz0TyTh7UNXshtQXftPUipqz4OBni5r9UaZXHw8B3QYOnms8__GJ3owOxaqkr1jgRs_EWqMlBNjPaj7ElVaeBWljDKuoK673tH0heSpgzUmUX_W8IDUVqs33uglpZwAQC7cAA5mGEg2odcRpvpP5M-WaP4RE9dl9jzcYmrw', - keystore, + keyOrStore, { - profile: 'id_token', issuer: 'https://op.example.com', audience: 'urn:example:client_id', nonce: 'a51ccf08f4bbb06e88715ddc4bbb41d8', @@ -238,6 +170,63 @@ Note: Depending on the channel you receive an ID Token from the following claims and must also be checked: `at_hash`, `c_hash` or `s_hash`. Use e.g. [`oidc-token-hash`][oidc-token-hash] to validate those hashes after getting the ID Token payload and signature validated by `jose` +
+ +
+ Verifying OAuth 2.0 JWT Access Tokens (Click to expand)
+ +Draft specification profiles are updated as minor versions of the library, therefore, +since they may have breaking changes use the `~` semver operator when using these and pay close +attention to changelog and the drafts themselves. + +When accepting a JWT-formatted OAuth 2.0 Access Token there are additional requirements for the JWT +to be accepted as an Access Token according to the [specification][draft-ietf-oauth-access-token-jwt] +and it is pretty easy to omit some. Use the +`JWT.AccessToken.verify` API to make sure what you're accepting is really a JWT Access Token +meant for your Resource Server. This will then perform all doable validations given the input. See +the [documentation][documentation-jwt] for more. + +```js +jose.JWT.AccessToken.verify( + 'eyJhbGciOiJQUzI1NiIsInR5cCI6ImF0K0pXVCIsImtpZCI6InIxTGtiQm8zOTI1UmIyWkZGckt5VTNNVmV4OVQyODE3S3gwdmJpNmlfS2MifQ.eyJzdWIiOiJmb28iLCJjbGllbnRfaWQiOiJ1cm46ZXhhbXBsZTpjbGllbnRfaWQiLCJhdWQiOiJ1cm46ZXhhbXBsZTpyZXNvdXJjZS1zZXJ2ZXIiLCJleHAiOjE1NjM4ODg4MzAsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20iLCJzY29wZSI6ImFwaTpyZWFkIn0.UYy8vEGWS0cS24giCYobMMy9-bqI45p807yV1l-2WXX2J4UO-eohV_R58LE2oM88gl414c6XydO6QSYXul5roNPoOs41jpEvreQIP-HmegjbWGutktWJKfvoOblE5FjYwjrwStjLQGUzkq6KWcnDLPGmpFy7n6gZ4LF8YVz4dLEaO335hMNVNrmSPSXYqr7bAWybnLVpLxjDYwNfCO1g0_TlFx8fHh2OftHoOOmJFltFwb8JypkSB-JXVVSEh43IOEjeeMJIG_ylWIOxfLLi5Q7vPWgub83ZTkuGNe4KmlQJKIsH5k0yZSshsLYUOOH0RiXqQ-SA4Ubh3Fowigdu-g', + keyOrStore, + { + issuer: 'https://op.example.com', + audience: 'urn:example:resource-server', + algorithms: ['PS256'] + } +) +``` + +
+ +
+ Verifying OIDC Logout Token (Click to expand)
+ +Draft specification profiles are updated as minor versions of the library, therefore, +since they may have breaking changes use the `~` semver operator when using these and pay close +attention to changelog and the drafts themselves. + +Logout Token is a JWT, but profiled, there are additional requirements to a JWT to be accepted as an +Logout Token and it is pretty easy to omit some, use the +`JWT.LogoutToken.verify` API to make sure what you're accepting is really an Logout Token meant to your +Client. This will then perform all doable validations given the input. See the +[documentation][documentation-jwt] for more. + +```js +jose.JWT.LogoutToken.verify( + 'eyJhbGciOiJQUzI1NiJ9.eyJzdWIiOiJmb28iLCJhdWQiOiJ1cm46ZXhhbXBsZTpjbGllbnRfaWQiLCJpYXQiOjE1NjM4ODg4MzAsImp0aSI6ImhqazMyN2RzYSIsImlzcyI6Imh0dHBzOi8vb3AuZXhhbXBsZS5jb20iLCJldmVudHMiOnsiaHR0cDovL3NjaGVtYXMub3BlbmlkLm5ldC9ldmVudC9iYWNrY2hhbm5lbC1sb2dvdXQiOnt9fX0.SBi7uNUvjHL9TFoFzautGgTQ1MjyeGUNYHL7inpgq3XgTv6xc9EAKuPRtpixmhdNhmInGwUvAeqDSJxomwv1KK1cTndrC9zAMZ7h657BGQAwGhu7nTm41fWMpKQdiLa9sqp3yit5_FNBmqUNeOoMPrYT_Vl9ytsoNO89MUQy2aqCd-Z7BrNJZH0QycdW6dmYlrmZL7w3t3TaAXoJDJ4Hgl2Itkkkb6_6gO-VoPIdVD8sDuf1zQzGhIkmcFrk0fXczVYOkeF2hNYBuvsM8LuO-EPA3oyE2In9djai3M7yceTQetRa1vwlqWkg_xmYS59ry-6wT44aN7-Y6p0TdXm-Zg', + keyOrStore, + { + issuer: 'https://op.example.com', + audience: 'urn:example:client_id', + algorithms: ['PS256'] + } +) +``` + +
+ #### JWS Signing Sign with a private or symmetric key using compact serialization. See the @@ -287,46 +276,78 @@ jose.JWE.decrypt( ) ``` -#### secp256k1 +## Detailed Support Matrix -Note: the secp256k1 JOSE parameters registration and the RFC is still in a draft state. If the WG -draft changes its mind about the parameter names again the new values will be propagated as a MINOR -library version. +| JWK Key Types | Supported | `kty` value | `crv` values | +| -- | -- | -- | -- | +| RSA | ✓ | RSA || +| Elliptic Curve | ✓ | EC | P-256, secp256k1[1], P-384, P-521 | +| Octet Key Pair | ✓ | OKP | Ed25519, Ed448[1], X25519[1], X448[1] | +| Octet sequence | ✓ | oct || -When you require `jose` you can work with `secp256k1` EC keys right away, the EC JWK `crv` -used is as per the specification `secp256k1`. +| Serialization | JWS Sign | JWS Verify | JWE Encrypt | JWE Decrypt | +| -- | -- | -- | -- | -- | +| Compact | ✓ | ✓ | ✓ | ✓ | +| General JSON | ✓ | ✓ | ✓ | ✓ | +| Flattened JSON | ✓ | ✓ | ✓ | ✓ | -```js -const jose = require('jose') -let key = jose.JWK.generateSync('EC', 'secp256k1') -key = jose.JWK.asKey(fs.readFileSync('path/to/key/file')) -key.crv === 'secp256k1' -``` +| JWS Algorithms | Supported || +| -- | -- | -- | +| RSASSA-PKCS1-v1_5 | ✓ | RS256, RS384, RS512 | +| RSASSA-PSS | ✓ | PS256, PS384, PS512 | +| ECDSA | ✓ | ES256, ES256K[1], ES384, ES512 | +| Edwards-curve DSA | ✓ | EdDSA | +| HMAC with SHA-2 | ✓ | HS256, HS384, HS512 | +| Unsecured JWS | ✓ | none[2] | -For legacy reasons the unregistered EC JWK `crv` value `P-256K` is also supported but you must -require `jose` like so to use it: +| JWE Key Management Algorithms | Supported || +| -- | -- | -- | +| AES | ✓ | A128KW[1], A192KW[1], A256KW[1] | +| AES GCM | ✓ | A128GCMKW, A192GCMKW, A256GCMKW | +| Direct Key Agreement | ✓ | dir | +| RSAES OAEP | ✓ | RSA-OAEP, RSA-OAEP-256[3], RSA-OAEP-384[3], RSA-OAEP-512[3] | +| RSAES-PKCS1-v1_5 | ✓ | RSA1_5 | +| PBES2 | ✓ | PBES2-HS256+A128KW[1], PBES2-HS384+A192KW[1], PBES2-HS512+A256KW[1] | +| ECDH-ES | ✓[4] | ECDH-ES, ECDH-ES+A128KW[1], ECDH-ES+A192KW[1], ECDH-ES+A256KW[1] | -```js -const jose = require('jose/P-256K') -let key = jose.JWK.generateSync('EC', 'P-256K') -key = jose.JWK.asKey(fs.readFileSync('path/to/key/file')) -key.crv === 'P-256K' -``` +| JWE Content Encryption Algorithms | Supported || +| -- | -- | -- | +| AES GCM | ✓ | A128GCM, A192GCM, A256GCM | +| AES_CBC_HMAC_SHA2 | ✓ | A128CBC-HS256, A192CBC-HS384, A256CBC-HS512 | -#### Electron Support +| JWT profile validation | Supported | Stable profile | | +| -- | -- | -- | -- | +| JWT Access Tokens - [JWT Profile for OAuth 2.0 Access Tokens][draft-ietf-oauth-access-token-jwt] | ✓ | ✕5 | see [`JWT.AccessToken.verify`]([/docs/README.md](https://github.com/panva/jose/blob/v2.x/docs/README.md)#jwtaccesstokenverifytoken-keyorstore-options) | +| ID Token - [OpenID Connect Core 1.0][spec-oidc-id_token] | ✓ | ✓ | see [`JWT.IdToken.verify`]([/docs/README.md](https://github.com/panva/jose/blob/v2.x/docs/README.md)#jwtidtokenverifytoken-keyorstore-options) | +| Logout Token - [OpenID Connect Back-Channel Logout 1.0][spec-oidc-logout_token] | ✓ | ✕5 | see [`JWT.LogoutToken.verify`]([/docs/README.md](https://github.com/panva/jose/blob/v2.x/docs/README.md)#jwtlogouttokenverifytoken-keyorstore-options) | +| JARM - [JWT Secured Authorization Response Mode for OAuth 2.0][draft-jarm] | ◯ ||| +| [JWT Response for OAuth Token Introspection][draft-jwtintrospection] | ◯ ||| +| [OAuth 2.0 DPoP][draft-dpop] | ◯ ||| -Electron >=6.0.0 runtime is supported to the extent of the crypto engine BoringSSL feature parity -with standard Node.js OpenSSL. The following is disabled in Electron runtime because of its lack of -[support](https://github.com/panva/jose/blob/master/test/electron/electron.test.js). +Legend: +- **✓** Implemented +- **✕** Missing node crypto support / won't implement +- **◯** TBD -- JWE `A128KW`, `A192KW` and `A256KW` algorithms are not available, this also means that other JWAs - depending on those are not working, those are `ECDH-ES+A128KW`, `ECDH-ES+A192KW`, - `ECDH-ES+A256KW`, `PBES2-HS256+A128KW`, `PBES2-HS384+A192KW`, `PBES2-HS512+A256KW`) -- OKP curves `Ed448`, `X25519` and `X448` are not supported -- EC curve `secp256k1` is not supported +1 Not supported in Electron due to Electron's use of BoringSSL +2 Unsecured JWS is [supported][documentation-none] for the JWS and JWT sign and verify +operations but it is an entirely opt-in behaviour, downgrade attacks are prevented by the required +use of a special `JWK.Key`-like object that cannot be instantiated through the key import API +3 RSAES OAEP using SHA-2 and MGF1 with SHA-2 is only supported when Node.js `>=12.9.0` runtime is detected +4 ECDH-ES with X25519 and X448 keys is only supported when Node.js `^12.17.0 || >=13.9.0` runtime is detected +5 Draft specification profiles are updated as minor versions of the library, therefore, +since they may have breaking changes use the `~` semver operator when using these and pay close +attention to changelog and the drafts themselves. ## FAQ +#### Supported Versions + +| Version | Bug Fixes 🐞 | New Features ⭐ | +| ------- | --------- | -------- | +| [3.x.x](https://github.com/panva/jose) | ✅ | ✅ | +| [2.x.x](https://github.com/panva/jose/tree/v2.x) | ✅ until 2022-04-30 | ❌ | + #### Semver? **Yes.** Everything that's either exported in the TypeScript definitions file or @@ -334,11 +355,14 @@ with standard Node.js OpenSSL. The following is disabled in Electron runtime bec [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html). The rest is to be considered private API and is subject to change between any versions. +**Although.** Draft specification profiles are updated as minor versions of the library, therefore, +since they may have breaking changes use the `~` semver operator when using these and pay close +attention to changelog and the drafts themselves. + #### How do I use it outside of Node.js -It is **only built for ^10.13.0 || >=12.0.0 Node.js** environment - including `jose` in -transpiled browser-environment targeted projects is not supported and may result in unexpected -results. +It is **only built for >=10.13.0 Node.js** environment - including `jose` in transpiled +browser-environment targeted projects is not supported and may result in unexpected results. #### How is it different from [`jws`](https://github.com/brianloveswords/node-jws), [`jwa`](https://github.com/brianloveswords/node-jwa) or [`jsonwebtoken`](https://github.com/auth0/node-jsonwebtoken)? @@ -374,16 +398,14 @@ in terms of performance and API (not having well defined errors). + this was an amazing opportunity to learn JOSE as a whole -[ask]: https://github.com/panva/jose/issues/new?labels=question&template=question.md&title=question%3A+ -[bug]: https://github.com/panva/jose/issues/new?labels=bug&template=bug-report.md&title=bug%3A+ -[documentation-jwe]: https://github.com/panva/jose/blob/master/docs/README.md#jwe-json-web-encryption -[documentation-jwk]: https://github.com/panva/jose/blob/master/docs/README.md#jwk-json-web-key -[documentation-jwks]: https://github.com/panva/jose/blob/master/docs/README.md#jwks-json-web-key-set -[documentation-jws]: https://github.com/panva/jose/blob/master/docs/README.md#jws-json-web-signature -[documentation-jwt]: https://github.com/panva/jose/blob/master/docs/README.md#jwt-json-web-token -[documentation]: https://github.com/panva/jose/blob/master/docs/README.md +[documentation-jwe]: https://github.com/panva/jose/blob/v2.x/docs/README.md#jwe-json-web-encryption +[documentation-jwk]: https://github.com/panva/jose/blob/v2.x/docs/README.md#jwk-json-web-key +[documentation-jwks]: https://github.com/panva/jose/blob/v2.x/docs/README.md#jwks-json-web-key-set +[documentation-jws]: https://github.com/panva/jose/blob/v2.x/docs/README.md#jws-json-web-signature +[documentation-jwt]: https://github.com/panva/jose/blob/v2.x/docs/README.md#jwt-json-web-token +[documentation-none]: https://github.com/panva/jose/blob/v2.x/docs/README.md#jwknone +[documentation]: https://github.com/panva/jose/blob/v2.x/docs/README.md [node-jose]: https://github.com/cisco/node-jose -[security-vulnerability]: https://github.com/panva/jose/issues/new?template=security-vulnerability.md [spec-b64]: https://tools.ietf.org/html/rfc7797 [spec-cookbook]: https://tools.ietf.org/html/rfc7520 [spec-jwa]: https://tools.ietf.org/html/rfc7518 @@ -392,13 +414,13 @@ in terms of performance and API (not having well defined errors). [spec-jws]: https://tools.ietf.org/html/rfc7515 [spec-jwt]: https://tools.ietf.org/html/rfc7519 [spec-okp]: https://tools.ietf.org/html/rfc8037 -[draft-secp256k1]: https://tools.ietf.org/html/draft-ietf-cose-webauthn-algorithms-01 -[draft-ietf-oauth-access-token-jwt]: https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt +[spec-secp256k1]: https://tools.ietf.org/html/rfc8812 +[draft-ietf-oauth-access-token-jwt]: https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-06 [draft-jarm]: https://openid.net/specs/openid-financial-api-jarm.html +[draft-jwtintrospection]: https://tools.ietf.org/html/draft-ietf-oauth-jwt-introspection-response +[draft-dpop]: https://tools.ietf.org/html/draft-ietf-oauth-dpop [spec-thumbprint]: https://tools.ietf.org/html/rfc7638 [spec-oidc-id_token]: https://openid.net/specs/openid-connect-core-1_0.html#IDToken -[spec-oidc-logout_token]: https://openid.net/specs/openid-connect-backchannel-1_0.html#LogoutToken +[spec-oidc-logout_token]: https://openid.net/specs/openid-connect-backchannel-1_0-04.html#LogoutToken [oidc-token-hash]: https://www.npmjs.com/package/oidc-token-hash -[suggest-feature]: https://github.com/panva/jose/issues/new?labels=enhancement&template=feature-request.md&title=proposal%3A+ [support-sponsor]: https://github.com/sponsors/panva -[sponsor-auth0]: https://auth0.com/overview?utm_source=GHsponsor&utm_medium=GHsponsor&utm_campaign=panva-jose&utm_content=auth diff --git a/node_modules/jose/lib/errors.js b/node_modules/jose/lib/errors.js index 7c7fa68..bc997cd 100644 --- a/node_modules/jose/lib/errors.js +++ b/node_modules/jose/lib/errors.js @@ -13,6 +13,7 @@ const CODES = { JWSInvalid: 'ERR_JWS_INVALID', JWSVerificationFailed: 'ERR_JWS_VERIFICATION_FAILED', JWTClaimInvalid: 'ERR_JWT_CLAIM_INVALID', + JWTExpired: 'ERR_JWT_EXPIRED', JWTMalformed: 'ERR_JWT_MALFORMED' } @@ -73,5 +74,13 @@ module.exports.JWKSNoMatchingKey = class JWKSNoMatchingKey extends JOSEError {} module.exports.JWSInvalid = class JWSInvalid extends JOSEError {} module.exports.JWSVerificationFailed = class JWSVerificationFailed extends JOSEError {} -module.exports.JWTClaimInvalid = class JWTClaimInvalid extends JOSEError {} +class JWTClaimInvalid extends JOSEError { + constructor (message, claim = 'unspecified', reason = 'unspecified') { + super(message) + this.claim = claim + this.reason = reason + } +} +module.exports.JWTClaimInvalid = JWTClaimInvalid +module.exports.JWTExpired = class JWTExpired extends JWTClaimInvalid {} module.exports.JWTMalformed = class JWTMalformed extends JOSEError {} diff --git a/node_modules/jose/lib/help/asn1/algorithm_identifier.js b/node_modules/jose/lib/help/asn1/algorithm_identifier.js index d2bd30f..6804d5b 100644 --- a/node_modules/jose/lib/help/asn1/algorithm_identifier.js +++ b/node_modules/jose/lib/help/asn1/algorithm_identifier.js @@ -1,6 +1,8 @@ +const oids = require('./oids') + module.exports = function () { this.seq().obj( - this.key('algorithm').objid(), - this.key('parameters').optional().any() + this.key('algorithm').objid(oids), + this.key('parameters').optional().choice({ namedCurve: this.objid(oids), null: this.null_() }) ) } diff --git a/node_modules/jose/lib/help/asn1/ec_private_key.js b/node_modules/jose/lib/help/asn1/ec_private_key.js index 8b3ef3d..169ab82 100644 --- a/node_modules/jose/lib/help/asn1/ec_private_key.js +++ b/node_modules/jose/lib/help/asn1/ec_private_key.js @@ -1,8 +1,10 @@ +const oids = require('./oids') + module.exports = function () { this.seq().obj( this.key('version').int(), this.key('privateKey').octstr(), - this.key('parameters').explicit(0).optional().choice({ namedCurve: this.objid() }), + this.key('parameters').explicit(0).optional().choice({ namedCurve: this.objid(oids) }), this.key('publicKey').explicit(1).optional().bitstr() ) } diff --git a/node_modules/jose/lib/help/asn1/index.js b/node_modules/jose/lib/help/asn1/index.js index 8872228..c4f7aee 100644 --- a/node_modules/jose/lib/help/asn1/index.js +++ b/node_modules/jose/lib/help/asn1/index.js @@ -1,4 +1,4 @@ -const asn1 = require('asn1.js') +const asn1 = require('@panva/asn1.js') const types = new Map() @@ -26,10 +26,4 @@ types.set('RSAPrivateKey', RSAPrivateKey) const RSAPublicKey = asn1.define('RSAPublicKey', require('./rsa_public_key')) types.set('RSAPublicKey', RSAPublicKey) -const OID = asn1.define('OID', function () { - return this.objid() -}) -types.set('OID', OID) - module.exports = types -module.exports.bignum = asn1.bignum diff --git a/node_modules/jose/lib/help/base64url.js b/node_modules/jose/lib/help/base64url.js index 07c875e..c8bfcae 100644 --- a/node_modules/jose/lib/help/base64url.js +++ b/node_modules/jose/lib/help/base64url.js @@ -1,57 +1,64 @@ -const { JOSEInvalidEncoding } = require('../errors') - -const b64uRegExp = /^[a-zA-Z0-9_-]*$/ - -const fromBase64 = (base64) => { - return base64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_') -} - -const toBase64 = (base64url) => { - return base64url.replace(/-/g, '+').replace(/_/g, '/') -} - -const encode = (input, encoding = 'utf8') => { - return fromBase64(Buffer.from(input, encoding).toString('base64')) -} - -const encodeBuffer = (buf) => { - return fromBase64(buf.toString('base64')) +let encode +let encodeBuffer +if (Buffer.isEncoding('base64url')) { + encode = (input, encoding = 'utf8') => Buffer.from(input, encoding).toString('base64url') + encodeBuffer = (buf) => buf.toString('base64url') +} else { + const fromBase64 = (base64) => base64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_') + encode = (input, encoding = 'utf8') => fromBase64(Buffer.from(input, encoding).toString('base64')) + encodeBuffer = (buf) => fromBase64(buf.toString('base64')) } const decodeToBuffer = (input) => { - if (!b64uRegExp.test(input)) { - throw new JOSEInvalidEncoding('input is not a valid base64url encoded string') - } - - return Buffer.from(toBase64(input), 'base64') + return Buffer.from(input, 'base64') } -const decode = (input) => { - return decodeToBuffer(input).toString('utf8') +const decode = (input, encoding = 'utf8') => { + return decodeToBuffer(input).toString(encoding) } const b64uJSON = { encode: (input) => { return encode(JSON.stringify(input)) }, - decode: (input) => { - return JSON.parse(decode(input)) + decode: (input, encoding = 'utf8') => { + return JSON.parse(decode(input, encoding)) } } -b64uJSON.decode.try = (input) => { +b64uJSON.decode.try = (input, encoding = 'utf8') => { try { - return b64uJSON.decode(input) + return b64uJSON.decode(input, encoding) } catch (err) { - return decode(input) + return decode(input, encoding) + } +} + +const bnToBuf = (bn) => { + let hex = BigInt(bn).toString(16) + if (hex.length % 2) { + hex = `0${hex}` } + + const len = hex.length / 2 + const u8 = new Uint8Array(len) + + let i = 0 + let j = 0 + while (i < len) { + u8[i] = parseInt(hex.slice(j, j + 2), 16) + i += 1 + j += 2 + } + + return u8 } -const encodeBN = (bn) => encodeBuffer(bn.toBuffer()) +const encodeBigInt = (bn) => encodeBuffer(Buffer.from(bnToBuf(bn))) module.exports.decode = decode module.exports.decodeToBuffer = decodeToBuffer module.exports.encode = encode module.exports.encodeBuffer = encodeBuffer module.exports.JSON = b64uJSON -module.exports.encodeBN = encodeBN +module.exports.encodeBigInt = encodeBigInt diff --git a/node_modules/jose/lib/help/consts.js b/node_modules/jose/lib/help/consts.js index 55f1d3f..ca9571b 100644 --- a/node_modules/jose/lib/help/consts.js +++ b/node_modules/jose/lib/help/consts.js @@ -1,5 +1,3 @@ -const { name: secp256k1 } = require('../jwk/key/secp256k1_crv') - module.exports.KEYOBJECT = Symbol('KEYOBJECT') module.exports.PRIVATE_MEMBERS = Symbol('PRIVATE_MEMBERS') module.exports.PUBLIC_MEMBERS = Symbol('PUBLIC_MEMBERS') @@ -18,24 +16,3 @@ const USES = new Set(Object.keys(USES_MAPPING)) module.exports.USES_MAPPING = USES_MAPPING module.exports.OPS = OPS module.exports.USES = USES - -module.exports.OKP_CURVES = new Set(['Ed25519', 'Ed448', 'X25519', 'X448']) -module.exports.EC_CURVES = new Set(['P-256', secp256k1, 'P-384', 'P-521']) -module.exports.ECDH_ALGS = ['ECDH-ES', 'ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW'] - -module.exports.KEYLENGTHS = { - 'A128CBC-HS256': 256, - 'A192CBC-HS384': 384, - 'A256CBC-HS512': 512, - A128GCM: 128, - A192GCM: 192, - A256GCM: 256 -} - -if ('electron' in process.versions) { - module.exports.OKP_CURVES.delete('Ed448') - module.exports.OKP_CURVES.delete('X25519') - module.exports.OKP_CURVES.delete('X448') - module.exports.EC_CURVES.delete(secp256k1) - module.exports.ECDH_ALGS.splice(1, module.exports.ECDH_ALGS.length - 1) -} diff --git a/node_modules/jose/lib/help/generate_iv.js b/node_modules/jose/lib/help/generate_iv.js index 260daf9..b9a58a2 100644 --- a/node_modules/jose/lib/help/generate_iv.js +++ b/node_modules/jose/lib/help/generate_iv.js @@ -1,15 +1,5 @@ const { randomBytes } = require('crypto') -const IVLENGTHS = { - 'A128CBC-HS256': 128 / 8, - A128GCM: 96 / 8, - A128GCMKW: 96 / 8, - 'A192CBC-HS384': 128 / 8, - A192GCM: 96 / 8, - A192GCMKW: 96 / 8, - 'A256CBC-HS512': 128 / 8, - A256GCM: 96 / 8, - A256GCMKW: 96 / 8 -} +const { IVLENGTHS } = require('../registry') -module.exports = alg => randomBytes(IVLENGTHS[alg]) +module.exports = alg => randomBytes(IVLENGTHS.get(alg) / 8) diff --git a/node_modules/jose/lib/help/key_object.js b/node_modules/jose/lib/help/key_object.js index 45b1b0e..82b6582 100644 --- a/node_modules/jose/lib/help/key_object.js +++ b/node_modules/jose/lib/help/key_object.js @@ -1,101 +1,107 @@ -let { createPublicKey, createPrivateKey, createSecretKey, KeyObject } = require('crypto') - -if (!createPublicKey || !createPrivateKey || !createSecretKey || !KeyObject) { +const { keyObjectSupported } = require('./runtime_support') + +let createPublicKey +let createPrivateKey +let createSecretKey +let KeyObject +let asInput + +if (keyObjectSupported) { + ({ createPublicKey, createPrivateKey, createSecretKey, KeyObject } = require('crypto')) + asInput = (input) => input +} else { const { EOL } = require('os') const errors = require('../errors') const isObject = require('./is_object') const asn1 = require('./asn1') + const toInput = Symbol('toInput') const namedCurve = Symbol('namedCurve') - const map = new WeakMap() - const i = (ctx) => { - if (!map.has(ctx)) { - map.set(ctx, {}) + asInput = (keyObject, needsPublic) => { + if (keyObject instanceof KeyObject) { + return keyObject[toInput](needsPublic) } - return map.get(ctx) + + return createSecretKey(keyObject)[toInput](needsPublic) } 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 derToPem = (der, label) => `-----BEGIN ${label}-----${EOL}${(der.toString('base64').match(/.{1,64}/g) || []).join(EOL)}${EOL}-----END ${label}-----` + const unsupported = (input) => { + const label = typeof input === 'string' ? input : `OID ${input.join('.')}` + throw new errors.JOSENotSupported(`${label} is not supported in your Node.js runtime version`) + } KeyObject = class KeyObject { export ({ cipher, passphrase, type, format } = {}) { - if (i(this).type === 'secret') { - return Buffer.from(i(this).buffer) + if (this._type === 'secret') { + return this._buffer } - if (i(this).type === 'public') { - if (format !== 'pem' && format !== 'der') { - throw new TypeError('format must be one of "pem" or "der"') - } - + if (this._type === 'public') { if (this.asymmetricKeyType === 'rsa') { switch (type) { case 'pkcs1': if (format === 'pem') { - return i(this).pem + return this._pem } - return pemToDer(i(this).pem) + return pemToDer(this._pem) case 'spki': { const PublicKeyInfo = asn1.get('PublicKeyInfo') const pem = PublicKeyInfo.encode({ algorithm: { - algorithm: '1.2.840.113549.1.1.1'.split('.'), - parameters: Buffer.from('BQA=', 'base64') + algorithm: 'rsaEncryption', + parameters: { type: 'null' } }, publicKey: { unused: 0, - data: pemToDer(i(this).pem) + data: pemToDer(this._pem) } }, 'pem', { label: 'PUBLIC KEY' }) return format === 'pem' ? pem : pemToDer(pem) } default: - throw new TypeError('type must be one of "pkcs1" or "spki"') + throw new TypeError(`The value ${type} is invalid for option "type"`) } } if (this.asymmetricKeyType === 'ec') { if (type !== 'spki') { - throw new TypeError('type must be "spki"') + throw new TypeError(`The value ${type} is invalid for option "type"`) } if (format === 'pem') { - return i(this).pem + return this._pem } - return pemToDer(i(this).pem) + return pemToDer(this._pem) } } - if (i(this).type === 'private') { - if (format !== 'pem' && format !== 'der') { - throw new TypeError('format must be one of "pem" or "der"') - } - + if (this._type === 'private') { if (passphrase !== undefined || cipher !== undefined) { throw new errors.JOSENotSupported('encrypted private keys are not supported in your Node.js runtime version') } if (type === 'pkcs8') { - if (i(this).pkcs8) { - if (format === 'der' && typeof i(this).pkcs8 === 'string') { - return pemToDer(i(this).pkcs8) + if (this._pkcs8) { + if (format === 'der' && typeof this._pkcs8 === 'string') { + return pemToDer(this._pkcs8) } - if (format === 'pem' && Buffer.isBuffer(i(this).pkcs8)) { - return derToPem(i(this).pkcs8, 'PRIVATE KEY') + if (format === 'pem' && Buffer.isBuffer(this._pkcs8)) { + return derToPem(this._pkcs8, 'PRIVATE KEY') } - return i(this).pkcs8 + return this._pkcs8 } if (this.asymmetricKeyType === 'rsa') { - const parsed = i(this).asn1 + const parsed = this._asn1 const RSAPrivateKey = asn1.get('RSAPrivateKey') const privateKey = RSAPrivateKey.encode(parsed) const PrivateKeyInfo = asn1.get('PrivateKeyInfo') @@ -103,18 +109,18 @@ if (!createPublicKey || !createPrivateKey || !createSecretKey || !KeyObject) { version: 0, privateKey, algorithm: { - algorithm: '1.2.840.113549.1.1.1'.split('.'), - parameters: Buffer.from('BQA=', 'base64') + algorithm: 'rsaEncryption', + parameters: { type: 'null' } } }) - i(this).pkcs8 = pkcs8 + this._pkcs8 = pkcs8 return this.export({ type, format }) } if (this.asymmetricKeyType === 'ec') { - const parsed = i(this).asn1 + const parsed = this._asn1 const ECPrivateKey = asn1.get('ECPrivateKey') const privateKey = ECPrivateKey.encode({ version: parsed.version, @@ -122,17 +128,16 @@ if (!createPublicKey || !createPrivateKey || !createSecretKey || !KeyObject) { publicKey: parsed.publicKey }) const PrivateKeyInfo = asn1.get('PrivateKeyInfo') - const OID = asn1.get('OID') const pkcs8 = PrivateKeyInfo.encode({ version: 0, privateKey, algorithm: { - algorithm: '1.2.840.10045.2.1'.split('.'), - parameters: OID.encode(i(this).asn1.parameters.value) + algorithm: 'ecPublicKey', + parameters: this._asn1.parameters } }) - i(this).pkcs8 = pkcs8 + this._pkcs8 = pkcs8 return this.export({ type, format }) } @@ -140,50 +145,50 @@ if (!createPublicKey || !createPrivateKey || !createSecretKey || !KeyObject) { if (this.asymmetricKeyType === 'rsa' && type === 'pkcs1') { if (format === 'pem') { - return i(this).pem + return this._pem } - return pemToDer(i(this).pem) + return pemToDer(this._pem) } else if (this.asymmetricKeyType === 'ec' && type === 'sec1') { if (format === 'pem') { - return i(this).pem + return this._pem } - return pemToDer(i(this).pem) + return pemToDer(this._pem) } else { - throw new TypeError(`type must be one of "spki" or "${this.asymmetricKeyType === 'rsa' ? 'pkcs1' : 'sec1'}"`) + throw new TypeError(`The value ${type} is invalid for option "type"`) } } } get type () { - return i(this).type + return this._type } get asymmetricKeyType () { - return i(this).asymmetricKeyType + return this._asymmetricKeyType } get symmetricKeySize () { - return i(this).symmetricKeySize + return this._symmetricKeySize } - asInput (needsPublic = false) { - switch (i(this).type) { + [toInput] (needsPublic) { + switch (this._type) { case 'secret': - return i(this).buffer + return this._buffer case 'public': - return i(this).pem + return this._pem default: if (needsPublic) { - if (!('pub' in i(this))) { - i(this).pub = createPublicKey(this) + if (!('_pub' in this)) { + this._pub = createPublicKey(this) } - return i(this).pub.asInput() + return this._pub[toInput](false) } - return i(this).pem + return this._pem } } } @@ -194,9 +199,9 @@ if (!createPublicKey || !createPrivateKey || !createSecretKey || !KeyObject) { } const keyObject = new KeyObject() - i(keyObject).buffer = Buffer.from(buffer) - i(keyObject).symmetricKeySize = buffer.length - i(keyObject).type = 'secret' + keyObject._buffer = Buffer.from(buffer) + keyObject._symmetricKeySize = buffer.length + keyObject._type = 'secret' return keyObject } @@ -204,26 +209,25 @@ if (!createPublicKey || !createPrivateKey || !createSecretKey || !KeyObject) { createPublicKey = (input) => { if (input instanceof KeyObject) { if (input.type !== 'private') { - throw new TypeError('expected a private key') + throw new TypeError(`Invalid key object type ${input.type}, expected private.`) } switch (input.asymmetricKeyType) { case 'ec': { const PublicKeyInfo = asn1.get('PublicKeyInfo') - const OID = asn1.get('OID') const key = PublicKeyInfo.encode({ algorithm: { - algorithm: '1.2.840.10045.2.1'.split('.'), - parameters: OID.encode(i(input).asn1.parameters.value) + algorithm: 'ecPublicKey', + parameters: input._asn1.parameters }, - publicKey: i(input).asn1.publicKey + publicKey: input._asn1.publicKey }) return createPublicKey({ key, format: 'der', type: 'spki' }) } case 'rsa': { const RSAPublicKey = asn1.get('RSAPublicKey') - const key = RSAPublicKey.encode(i(input).asn1) + const key = RSAPublicKey.encode(input._asn1) return createPublicKey({ key, format: 'der', type: 'pkcs1' }) } } @@ -237,7 +241,7 @@ if (!createPublicKey || !createPrivateKey || !createSecretKey || !KeyObject) { throw new TypeError('input must be a string, Buffer or an object') } - const { format } = input + const { format, passphrase } = input let { key, type } = input if (typeof key !== 'string' && !Buffer.isBuffer(key)) { @@ -261,7 +265,11 @@ if (!createPublicKey || !createPrivateKey || !createSecretKey || !KeyObject) { label = 'RSA PUBLIC KEY' break case '-----BEGIN CERTIFICATE-----': - throw new errors.JOSENotSupported('X.509 certificates are supported in your Node.js runtime version') + throw new errors.JOSENotSupported('X.509 certificates are not supported in your Node.js runtime version') + case '-----BEGIN PRIVATE KEY-----': + case '-----BEGIN EC PRIVATE KEY-----': + case '-----BEGIN RSA PRIVATE KEY-----': + return createPublicKey(createPrivateKey(key)) default: throw new TypeError('unknown/unsupported PEM type') } @@ -273,23 +281,23 @@ if (!createPublicKey || !createPrivateKey || !createSecretKey || !KeyObject) { const parsed = PublicKeyInfo.decode(key, format, { label }) let type, keyObject - switch (parsed.algorithm.algorithm.join('.')) { - case '1.2.840.10045.2.1': { + switch (parsed.algorithm.algorithm) { + case 'ecPublicKey': { keyObject = new KeyObject() - i(keyObject).asn1 = parsed - i(keyObject).asymmetricKeyType = 'ec' - i(keyObject).type = 'public' - i(keyObject).pem = PublicKeyInfo.encode(parsed, 'pem', { label: 'PUBLIC KEY' }) + keyObject._asn1 = parsed + keyObject._asymmetricKeyType = 'ec' + keyObject._type = 'public' + keyObject._pem = PublicKeyInfo.encode(parsed, 'pem', { label: 'PUBLIC KEY' }) break } - case '1.2.840.113549.1.1.1': { + case 'rsaEncryption': { type = 'pkcs1' keyObject = createPublicKey({ type, key: parsed.publicKey.data, format: 'der' }) break } default: - throw new errors.JOSENotSupported(`OID ${parsed.algorithm.algorithm.join('.')} is not supported in your Node.js runtime version`) + unsupported(parsed.algorithm.algorithm) } return keyObject @@ -298,16 +306,24 @@ if (!createPublicKey || !createPrivateKey || !createSecretKey || !KeyObject) { const RSAPublicKey = asn1.get('RSAPublicKey') const parsed = RSAPublicKey.decode(key, format, { label }) + // special case when private pkcs1 PEM / DER is used with createPublicKey + if (parsed.n === BigInt(0)) { + return createPublicKey(createPrivateKey({ key, format, type, passphrase })) + } + const keyObject = new KeyObject() - i(keyObject).asn1 = parsed - i(keyObject).asymmetricKeyType = 'rsa' - i(keyObject).type = 'public' - i(keyObject).pem = RSAPublicKey.encode(parsed, 'pem', { label: 'RSA PUBLIC KEY' }) + keyObject._asn1 = parsed + keyObject._asymmetricKeyType = 'rsa' + keyObject._type = 'public' + keyObject._pem = RSAPublicKey.encode(parsed, 'pem', { label: 'RSA PUBLIC KEY' }) return keyObject } + case 'pkcs8': + case 'sec1': + return createPublicKey(createPrivateKey({ format, key, type, passphrase })) default: - throw new TypeError('type must be one of "pkcs1" or "spki"') + throw new TypeError(`The value ${type} is invalid for option "type"`) } } @@ -362,23 +378,22 @@ if (!createPublicKey || !createPrivateKey || !createSecretKey || !KeyObject) { const parsed = PrivateKeyInfo.decode(key, format, { label }) let type, keyObject - switch (parsed.algorithm.algorithm.join('.')) { - case '1.2.840.10045.2.1': { - const OID = asn1.get('OID') + switch (parsed.algorithm.algorithm) { + case 'ecPublicKey': { type = 'sec1' - keyObject = createPrivateKey({ type, key: parsed.privateKey, format: 'der' }, { [namedCurve]: OID.decode(parsed.algorithm.parameters) }) + keyObject = createPrivateKey({ type, key: parsed.privateKey, format: 'der' }, { [namedCurve]: parsed.algorithm.parameters.value }) break } - case '1.2.840.113549.1.1.1': { + case 'rsaEncryption': { type = 'pkcs1' keyObject = createPrivateKey({ type, key: parsed.privateKey, format: 'der' }) break } default: - throw new errors.JOSENotSupported(`OID ${parsed.algorithm.algorithm.join('.')} is not supported in your Node.js runtime version`) + unsupported(parsed.algorithm.algorithm) } - i(keyObject).pkcs8 = key + keyObject._pkcs8 = key return keyObject } case 'pkcs1': { @@ -386,10 +401,10 @@ if (!createPublicKey || !createPrivateKey || !createSecretKey || !KeyObject) { const parsed = RSAPrivateKey.decode(key, format, { label }) const keyObject = new KeyObject() - i(keyObject).asn1 = parsed - i(keyObject).asymmetricKeyType = 'rsa' - i(keyObject).type = 'private' - i(keyObject).pem = RSAPrivateKey.encode(parsed, 'pem', { label: 'RSA PRIVATE KEY' }) + keyObject._asn1 = parsed + keyObject._asymmetricKeyType = 'rsa' + keyObject._type = 'private' + keyObject._pem = RSAPrivateKey.encode(parsed, 'pem', { label: 'RSA PRIVATE KEY' }) return keyObject } @@ -404,17 +419,17 @@ if (!createPublicKey || !createPrivateKey || !createSecretKey || !KeyObject) { } const keyObject = new KeyObject() - i(keyObject).asn1 = parsed - i(keyObject).asymmetricKeyType = 'ec' - i(keyObject).type = 'private' - i(keyObject).pem = ECPrivateKey.encode(parsed, 'pem', { label: 'EC PRIVATE KEY' }) + keyObject._asn1 = parsed + keyObject._asymmetricKeyType = 'ec' + keyObject._type = 'private' + keyObject._pem = ECPrivateKey.encode(parsed, 'pem', { label: 'EC PRIVATE KEY' }) return keyObject } default: - throw new TypeError('type must be one of "pkcs8", "pkcs1" or "sec1"') + throw new TypeError(`The value ${type} is invalid for option "type"`) } } } -module.exports = { createPublicKey, createPrivateKey, createSecretKey, KeyObject } +module.exports = { createPublicKey, createPrivateKey, createSecretKey, KeyObject, asInput } diff --git a/node_modules/jose/lib/help/key_utils.js b/node_modules/jose/lib/help/key_utils.js index 36b9578..598e388 100644 --- a/node_modules/jose/lib/help/key_utils.js +++ b/node_modules/jose/lib/help/key_utils.js @@ -1,36 +1,15 @@ const { EOL } = require('os') -const { name: secp256k1 } = require('../jwk/key/secp256k1_crv') const errors = require('../errors') +const { keyObjectSupported } = require('./runtime_support') const { createPublicKey } = require('./key_object') const base64url = require('./base64url') const asn1 = require('./asn1') const computePrimes = require('./rsa_primes') -const { OKP_CURVES, EC_CURVES } = require('./consts') - -const BN = asn1.bignum -const oidHexToCurve = new Map([ - ['06082a8648ce3d030107', 'P-256'], - ['06052b8104000a', secp256k1], - ['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('.')], - [secp256k1, '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')], - [secp256k1, Buffer.from('06052b8104000a', 'hex')], - ['P-384', Buffer.from('06052b81040022', 'hex')], - ['P-521', Buffer.from('06052b81040023', 'hex')] -]) - -const formatPem = (base64pem, descriptor) => `-----BEGIN ${descriptor} KEY-----${EOL}${base64pem.match(/.{1,64}/g).join(EOL)}${EOL}-----END ${descriptor} KEY-----` +const { OKP_CURVES, EC_CURVES } = require('../registry') + +const formatPem = (base64pem, descriptor) => `-----BEGIN ${descriptor} KEY-----${EOL}${(base64pem.match(/.{1,64}/g) || []).join(EOL)}${EOL}-----END ${descriptor} KEY-----` const okpToJWK = { private (crv, keyObject) { @@ -75,14 +54,14 @@ const keyObjectToJWK = { return { kty: 'RSA', - n: base64url.encodeBN(n), - e: base64url.encodeBN(e), - d: base64url.encodeBN(d), - p: base64url.encodeBN(p), - q: base64url.encodeBN(q), - dp: base64url.encodeBN(dp), - dq: base64url.encodeBN(dq), - qi: base64url.encodeBN(qi) + n: base64url.encodeBigInt(n), + e: base64url.encodeBigInt(e), + d: base64url.encodeBigInt(d), + p: base64url.encodeBigInt(p), + q: base64url.encodeBigInt(q), + dp: base64url.encodeBigInt(dp), + dq: base64url.encodeBigInt(dq), + qi: base64url.encodeBigInt(qi) } }, public (keyObject) { @@ -96,8 +75,8 @@ const keyObjectToJWK = { return { kty: 'RSA', - n: base64url.encodeBN(n), - e: base64url.encodeBN(e) + n: base64url.encodeBigInt(n), + e: base64url.encodeBigInt(e) } } }, @@ -108,12 +87,22 @@ const keyObjectToJWK = { const PrivateKeyInfo = asn1.get('PrivateKeyInfo') const ECPrivateKey = asn1.get('ECPrivateKey') - const { privateKey, algorithm: { parameters: curveOid } } = PrivateKeyInfo.decode(der) - const crv = oidHexToCurve.get(curveOid.toString('hex')) - const { privateKey: d, publicKey: { data: publicKey } } = ECPrivateKey.decode(privateKey) + const { privateKey, algorithm: { parameters: { value: crv } } } = PrivateKeyInfo.decode(der) + const { privateKey: d, publicKey } = ECPrivateKey.decode(privateKey) - const x = publicKey.slice(1, ((publicKey.length - 1) / 2) + 1) - const y = publicKey.slice(((publicKey.length - 1) / 2) + 1) + if (typeof publicKey === 'undefined') { + if (keyObjectSupported) { + return { + ...keyObjectToJWK.ec.public(createPublicKey(keyObject)), + d: base64url.encodeBuffer(d) + } + } + + throw new errors.JOSENotSupported('Private EC keys without the public key embedded are not supported in your Node.js runtime version') + } + + const x = publicKey.data.slice(1, ((publicKey.data.length - 1) / 2) + 1) + const y = publicKey.data.slice(((publicKey.data.length - 1) / 2) + 1) return { kty: 'EC', @@ -128,8 +117,7 @@ const keyObjectToJWK = { const PublicKeyInfo = asn1.get('PublicKeyInfo') - const { publicKey: { data: publicKey }, algorithm: { parameters: curveOid } } = PublicKeyInfo.decode(der) - const crv = oidHexToCurve.get(curveOid.toString('hex')) + const { publicKey: { data: publicKey }, algorithm: { parameters: { value: crv } } } = PublicKeyInfo.decode(der) const x = publicKey.slice(1, ((publicKey.length - 1) / 2) + 1) const y = publicKey.slice(((publicKey.length - 1) / 2) + 1) @@ -193,19 +181,6 @@ const concatEcPublicKey = (x, y) => ({ ]) }) -const okpCrvToOid = (crv) => { - switch (crv) { - case 'X25519': - return '1.3.101.110'.split('.') - case 'X448': - return '1.3.101.111'.split('.') - case 'Ed25519': - return '1.3.101.112'.split('.') - case 'Ed448': - return '1.3.101.113'.split('.') - } -} - const jwkToPem = { RSA: { private (jwk, { calculateMissingRSAPrimes }) { @@ -227,14 +202,14 @@ const jwkToPem = { return RSAPrivateKey.encode({ version: 0, - n: new BN(base64url.decodeToBuffer(jwk.n)), - e: new BN(base64url.decodeToBuffer(jwk.e)), - d: new BN(base64url.decodeToBuffer(jwk.d)), - p: new BN(base64url.decodeToBuffer(jwk.p)), - q: new BN(base64url.decodeToBuffer(jwk.q)), - dp: new BN(base64url.decodeToBuffer(jwk.dp)), - dq: new BN(base64url.decodeToBuffer(jwk.dq)), - qi: new BN(base64url.decodeToBuffer(jwk.qi)) + n: BigInt(`0x${base64url.decodeToBuffer(jwk.n).toString('hex')}`), + e: BigInt(`0x${base64url.decodeToBuffer(jwk.e).toString('hex')}`), + d: BigInt(`0x${base64url.decodeToBuffer(jwk.d).toString('hex')}`), + p: BigInt(`0x${base64url.decodeToBuffer(jwk.p).toString('hex')}`), + q: BigInt(`0x${base64url.decodeToBuffer(jwk.q).toString('hex')}`), + dp: BigInt(`0x${base64url.decodeToBuffer(jwk.dp).toString('hex')}`), + dq: BigInt(`0x${base64url.decodeToBuffer(jwk.dq).toString('hex')}`), + qi: BigInt(`0x${base64url.decodeToBuffer(jwk.qi).toString('hex')}`) }, 'pem', { label: 'RSA PRIVATE KEY' }) }, public (jwk) { @@ -242,8 +217,8 @@ const jwkToPem = { return RSAPublicKey.encode({ version: 0, - n: new BN(base64url.decodeToBuffer(jwk.n)), - e: new BN(base64url.decodeToBuffer(jwk.e)) + n: BigInt(`0x${base64url.decodeToBuffer(jwk.n).toString('hex')}`), + e: BigInt(`0x${base64url.decodeToBuffer(jwk.e).toString('hex')}`) }, 'pem', { label: 'RSA PUBLIC KEY' }) } }, @@ -254,10 +229,7 @@ const jwkToPem = { return ECPrivateKey.encode({ version: 1, privateKey: base64url.decodeToBuffer(jwk.d), - parameters: { - type: 'namedCurve', - value: crvToOid.get(jwk.crv) - }, + parameters: { type: 'namedCurve', value: jwk.crv }, publicKey: concatEcPublicKey(jwk.x, jwk.y) }, 'pem', { label: 'EC PRIVATE KEY' }) }, @@ -266,8 +238,8 @@ const jwkToPem = { return PublicKeyInfo.encode({ algorithm: { - algorithm: EC_KEY_OID, - parameters: crvToOidBuf.get(jwk.crv) + algorithm: 'ecPublicKey', + parameters: { type: 'namedCurve', value: jwk.crv } }, publicKey: concatEcPublicKey(jwk.x, jwk.y) }, 'pem', { label: 'PUBLIC KEY' }) @@ -280,7 +252,7 @@ const jwkToPem = { const b64 = OneAsymmetricKey.encode({ version: 0, privateKey: { privateKey: base64url.decodeToBuffer(jwk.d) }, - algorithm: { algorithm: okpCrvToOid(jwk.crv) } + algorithm: { algorithm: jwk.crv } }, 'der') // TODO: WHYYY? https://github.com/indutny/asn1.js/issues/110 @@ -292,7 +264,7 @@ const jwkToPem = { const PublicKeyInfo = asn1.get('PublicKeyInfo') return PublicKeyInfo.encode({ - algorithm: { algorithm: okpCrvToOid(jwk.crv) }, + algorithm: { algorithm: jwk.crv }, publicKey: { unused: 0, data: base64url.decodeToBuffer(jwk.x) diff --git a/node_modules/jose/lib/help/rsa_primes.js b/node_modules/jose/lib/help/rsa_primes.js index d7e132a..4e2d9a3 100644 --- a/node_modules/jose/lib/help/rsa_primes.js +++ b/node_modules/jose/lib/help/rsa_primes.js @@ -1,5 +1,3 @@ -/* global BigInt */ - const { randomBytes } = require('crypto') const base64url = require('./base64url') @@ -11,7 +9,7 @@ const TWO = BigInt(2) const toJWKParameter = (n) => { const hex = n.toString(16) - return base64url.encodeBuffer(Buffer.from(hex.length % 2 === 1 ? `0${hex}` : hex, 'hex')) + return base64url.encodeBuffer(Buffer.from(hex.length % 2 ? `0${hex}` : hex, 'hex')) } const fromBuffer = buf => BigInt(`0x${buf.toString('hex')}`) const bitLength = n => n.toString(2).length @@ -67,7 +65,7 @@ const modPow = (a, b, n) => { let result = ONE let x = a while (b > 0) { - var leastSignificantBit = b % TWO + const leastSignificantBit = b % TWO b = b / TWO if (leastSignificantBit === ONE) { result = result * x diff --git a/node_modules/jose/lib/help/runtime_support.js b/node_modules/jose/lib/help/runtime_support.js index 2a23491..300b268 100644 --- a/node_modules/jose/lib/help/runtime_support.js +++ b/node_modules/jose/lib/help/runtime_support.js @@ -1,9 +1,11 @@ -const { KeyObject, sign, verify } = require('crypto') +const { diffieHellman, KeyObject, sign, verify } = require('crypto') const [major, minor] = process.version.substr(1).split('.').map(x => parseInt(x, 10)) module.exports = { oaepHashSupported: major > 12 || (major === 12 && minor >= 9), - keyObjectSupported: !!KeyObject, - edDSASupported: !!sign && !!verify + keyObjectSupported: !!KeyObject && major >= 12, + edDSASupported: !!sign && !!verify, + dsaEncodingSupported: major > 13 || (major === 13 && minor >= 2) || (major === 12 && minor >= 16), + improvedDH: !!diffieHellman } diff --git a/node_modules/jose/lib/jwa/aes_cbc_hmac_sha2.js b/node_modules/jose/lib/jwa/aes_cbc_hmac_sha2.js index 11607a8..f63dc32 100644 --- a/node_modules/jose/lib/jwa/aes_cbc_hmac_sha2.js +++ b/node_modules/jose/lib/jwa/aes_cbc_hmac_sha2.js @@ -1,5 +1,4 @@ -const { strict: assert } = require('assert') -const { createCipheriv, createDecipheriv } = require('crypto') +const { createCipheriv, createDecipheriv, getCiphers } = require('crypto') const uint64be = require('../help/uint64be') const timingSafeEqual = require('../help/timing_safe_equal') @@ -45,27 +44,31 @@ const decrypt = (size, sign, { [KEYOBJECT]: keyObject }, ciphertext, { iv, tag = const expectedTag = sign({ [KEYOBJECT]: macKey }, macData, tag).slice(0, keySize) const macCheckPassed = timingSafeEqual(tag, expectedTag) + if (!macCheckPassed) { + throw new JWEDecryptionFailed() + } + let cleartext try { const cipher = createDecipheriv(`aes-${size}-cbc`, encKey, iv) cleartext = Buffer.concat([cipher.update(ciphertext), cipher.final()]) } catch (err) {} - if (!cleartext || !macCheckPassed) { + if (!cleartext) { throw new JWEDecryptionFailed() } return cleartext } -module.exports = (JWA) => { +module.exports = (JWA, JWK) => { ['A128CBC-HS256', 'A192CBC-HS384', 'A256CBC-HS512'].forEach((jwaAlg) => { const size = parseInt(jwaAlg.substr(1, 3), 10) - - assert(!JWA.encrypt.has(jwaAlg), `encrypt alg ${jwaAlg} already registered`) - assert(!JWA.decrypt.has(jwaAlg), `decrypt alg ${jwaAlg} already registered`) - - JWA.encrypt.set(jwaAlg, encrypt.bind(undefined, size, JWA.sign.get(`HS${size * 2}`))) - JWA.decrypt.set(jwaAlg, decrypt.bind(undefined, size, JWA.sign.get(`HS${size * 2}`))) + const sign = JWA.sign.get(`HS${size * 2}`) + if (getCiphers().includes(`aes-${size}-cbc`)) { + JWA.encrypt.set(jwaAlg, encrypt.bind(undefined, size, sign)) + JWA.decrypt.set(jwaAlg, decrypt.bind(undefined, size, sign)) + JWK.oct.encrypt[jwaAlg] = JWK.oct.decrypt[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.length / 2 === size + } }) } diff --git a/node_modules/jose/lib/jwa/aes_gcm.js b/node_modules/jose/lib/jwa/aes_gcm.js index 4a32699..1acc5ca 100644 --- a/node_modules/jose/lib/jwa/aes_gcm.js +++ b/node_modules/jose/lib/jwa/aes_gcm.js @@ -1,8 +1,8 @@ -const { strict: assert } = require('assert') -const { createCipheriv, createDecipheriv } = require('crypto') +const { createCipheriv, createDecipheriv, getCiphers } = require('crypto') const { KEYOBJECT } = require('../help/consts') const { JWEInvalid, JWEDecryptionFailed } = require('../errors') +const { asInput } = require('../help/key_object') const checkInput = function (size, iv, tag) { if (iv.length !== 12) { @@ -16,10 +16,10 @@ const checkInput = function (size, iv, tag) { } const encrypt = (size, { [KEYOBJECT]: keyObject }, cleartext, { iv, aad = Buffer.alloc(0) }) => { - const key = keyObject.asInput ? keyObject.asInput() : keyObject + const key = asInput(keyObject, false) checkInput(size, iv) - const cipher = createCipheriv(`aes-${size}-gcm`, key, iv) + const cipher = createCipheriv(`aes-${size}-gcm`, key, iv, { authTagLength: 16 }) cipher.setAAD(aad) const ciphertext = Buffer.concat([cipher.update(cleartext), cipher.final()]) @@ -29,11 +29,11 @@ const encrypt = (size, { [KEYOBJECT]: keyObject }, cleartext, { iv, aad = Buffer } const decrypt = (size, { [KEYOBJECT]: keyObject }, ciphertext, { iv, tag = Buffer.alloc(0), aad = Buffer.alloc(0) }) => { - const key = keyObject.asInput ? keyObject.asInput() : keyObject + const key = asInput(keyObject, false) checkInput(size, iv, tag) try { - const cipher = createDecipheriv(`aes-${size}-gcm`, key, iv) + const cipher = createDecipheriv(`aes-${size}-gcm`, key, iv, { authTagLength: 16 }) cipher.setAuthTag(tag) cipher.setAAD(aad) @@ -43,14 +43,13 @@ const decrypt = (size, { [KEYOBJECT]: keyObject }, ciphertext, { iv, tag = Buffe } } -module.exports = (JWA) => { +module.exports = (JWA, JWK) => { ['A128GCM', 'A192GCM', 'A256GCM'].forEach((jwaAlg) => { const size = parseInt(jwaAlg.substr(1, 3), 10) - - assert(!JWA.encrypt.has(jwaAlg), `encrypt alg ${jwaAlg} already registered`) - assert(!JWA.decrypt.has(jwaAlg), `decrypt alg ${jwaAlg} already registered`) - - JWA.encrypt.set(jwaAlg, encrypt.bind(undefined, size)) - JWA.decrypt.set(jwaAlg, decrypt.bind(undefined, size)) + if (getCiphers().includes(`aes-${size}-gcm`)) { + JWA.encrypt.set(jwaAlg, encrypt.bind(undefined, size)) + JWA.decrypt.set(jwaAlg, decrypt.bind(undefined, size)) + JWK.oct.encrypt[jwaAlg] = JWK.oct.decrypt[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.length === size + } }) } diff --git a/node_modules/jose/lib/jwa/aes_gcm_kw.js b/node_modules/jose/lib/jwa/aes_gcm_kw.js index eb51219..3a57bb9 100644 --- a/node_modules/jose/lib/jwa/aes_gcm_kw.js +++ b/node_modules/jose/lib/jwa/aes_gcm_kw.js @@ -1,25 +1,24 @@ -const { strict: assert } = require('assert') - const generateIV = require('../help/generate_iv') const base64url = require('../help/base64url') -module.exports = (JWA) => { +module.exports = (JWA, JWK) => { ['A128GCMKW', 'A192GCMKW', 'A256GCMKW'].forEach((jwaAlg) => { - assert(!JWA.keyManagementEncrypt.has(jwaAlg), `keyManagementEncrypt alg ${jwaAlg} already registered`) - assert(!JWA.keyManagementDecrypt.has(jwaAlg), `keyManagementDecrypt alg ${jwaAlg} already registered`) - const encAlg = jwaAlg.substr(0, 7) + const size = parseInt(jwaAlg.substr(1, 3), 10) const encrypt = JWA.encrypt.get(encAlg) const decrypt = JWA.decrypt.get(encAlg) - JWA.keyManagementEncrypt.set(jwaAlg, (key, payload) => { - const iv = generateIV(jwaAlg) - const { ciphertext, tag } = encrypt(key, payload, { iv }) - return { - wrapped: ciphertext, - header: { tag: base64url.encodeBuffer(tag), iv: base64url.encodeBuffer(iv) } - } - }) - JWA.keyManagementDecrypt.set(jwaAlg, decrypt) + if (encrypt && decrypt) { + JWA.keyManagementEncrypt.set(jwaAlg, (key, payload) => { + const iv = generateIV(jwaAlg) + const { ciphertext, tag } = encrypt(key, payload, { iv }) + return { + wrapped: ciphertext, + header: { tag: base64url.encodeBuffer(tag), iv: base64url.encodeBuffer(iv) } + } + }) + JWA.keyManagementDecrypt.set(jwaAlg, decrypt) + JWK.oct.wrapKey[jwaAlg] = JWK.oct.unwrapKey[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.length === size + } }) } diff --git a/node_modules/jose/lib/jwa/aes_kw.js b/node_modules/jose/lib/jwa/aes_kw.js index 0dd6e2e..c2e2d65 100644 --- a/node_modules/jose/lib/jwa/aes_kw.js +++ b/node_modules/jose/lib/jwa/aes_kw.js @@ -1,9 +1,7 @@ -const { strict: assert } = require('assert') -const { createCipheriv, createDecipheriv } = require('crypto') +const { createCipheriv, createDecipheriv, getCiphers } = require('crypto') -const uint64be = require('../help/uint64be') -const timingSafeEqual = require('../help/timing_safe_equal') const { KEYOBJECT } = require('../help/consts') +const { asInput } = require('../help/key_object') const checkInput = (data) => { if (data !== undefined && data.length % 8 !== 0) { @@ -11,90 +9,29 @@ const checkInput = (data) => { } } -const IV = Buffer.alloc(8, 'a6', 'hex') +const wrapKey = (alg, { [KEYOBJECT]: keyObject }, payload) => { + const key = asInput(keyObject, false) + const cipher = createCipheriv(alg, key, Buffer.alloc(8, 'a6', 'hex')) -const xor = (a, b) => { - const len = Math.max(a.length, b.length) - const result = Buffer.alloc(len) - for (let idx = 0; len > idx; idx++) { - result[idx] = (a[idx] || 0) ^ (b[idx] || 0) - } - - return result -} - -const split = (input, size) => { - const output = [] - for (let idx = 0; input.length > idx; idx += size) { - output.push(input.slice(idx, idx + size)) - } - return output -} - -const wrapKey = (size, { [KEYOBJECT]: keyObject }, payload) => { - const key = keyObject.asInput ? keyObject.asInput() : keyObject - const iv = Buffer.alloc(16) - let R = split(payload, 8) - let A - let B - let count - A = IV - for (let jdx = 0; jdx < 6; jdx++) { - for (let idx = 0; R.length > idx; idx++) { - count = (R.length * jdx) + idx + 1 - const cipher = createCipheriv(`aes${size}`, key, iv) - B = Buffer.concat([A, R[idx]]) - B = cipher.update(B) - - A = xor(B.slice(0, 8), uint64be(count)) - R[idx] = B.slice(8, 16) - } - } - R = [A].concat(R) - - return { wrapped: Buffer.concat(R) } + return { wrapped: Buffer.concat([cipher.update(payload), cipher.final()]) } } -const unwrapKey = (size, { [KEYOBJECT]: keyObject }, payload) => { - const key = keyObject.asInput ? keyObject.asInput() : keyObject +const unwrapKey = (alg, { [KEYOBJECT]: keyObject }, payload) => { + const key = asInput(keyObject, false) checkInput(payload) + const cipher = createDecipheriv(alg, key, Buffer.alloc(8, 'a6', 'hex')) - const iv = Buffer.alloc(16) - - let R = split(payload, 8) - let A - let B - let count - A = R[0] - R = R.slice(1) - for (let jdx = 5; jdx >= 0; --jdx) { - for (let idx = R.length - 1; idx >= 0; --idx) { - count = (R.length * jdx) + idx + 1 - B = xor(A, uint64be(count)) - B = Buffer.concat([B, R[idx], iv]) - const cipher = createDecipheriv(`aes${size}`, key, iv) - B = cipher.update(B) - - A = B.slice(0, 8) - R[idx] = B.slice(8, 16) - } - } - - if (!timingSafeEqual(IV, A)) { - throw new Error('unwrap failed') - } - - return Buffer.concat(R) + return Buffer.concat([cipher.update(payload), cipher.final()]) } -module.exports = (JWA) => { +module.exports = (JWA, JWK) => { ['A128KW', 'A192KW', 'A256KW'].forEach((jwaAlg) => { const size = parseInt(jwaAlg.substr(1, 3), 10) - - assert(!JWA.keyManagementEncrypt.has(jwaAlg), `keyManagementEncrypt alg ${jwaAlg} already registered`) - assert(!JWA.keyManagementDecrypt.has(jwaAlg), `keyManagementDecrypt alg ${jwaAlg} already registered`) - - JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, size)) - JWA.keyManagementDecrypt.set(jwaAlg, unwrapKey.bind(undefined, size)) + const alg = `aes${size}-wrap` + if (getCiphers().includes(alg)) { + JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, alg)) + JWA.keyManagementDecrypt.set(jwaAlg, unwrapKey.bind(undefined, alg)) + JWK.oct.wrapKey[jwaAlg] = JWK.oct.unwrapKey[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.length === size + } }) } diff --git a/node_modules/jose/lib/jwa/ecdh/derive.js b/node_modules/jose/lib/jwa/ecdh/derive.js index 755a946..a2166c6 100644 --- a/node_modules/jose/lib/jwa/ecdh/derive.js +++ b/node_modules/jose/lib/jwa/ecdh/derive.js @@ -1,39 +1,8 @@ -const { createECDH, createHash, constants: { POINT_CONVERSION_UNCOMPRESSED } } = require('crypto') - -const base64url = require('../../help/base64url') -const { name: secp256k1 } = require('../../jwk/key/secp256k1_crv') - -const crvToCurve = (crv) => { - switch (crv) { - case 'P-256': - return 'prime256v1' - case 'P-384': - return 'secp384r1' - case 'P-521': - return 'secp521r1' - case 'secp256k1': - case 'X448': - case 'X25519': - return crv - case secp256k1: - return 'secp256k1' - } -} - -const UNCOMPRESSED = Buffer.alloc(1, POINT_CONVERSION_UNCOMPRESSED) -const pubToBuffer = (x, y) => Buffer.concat([UNCOMPRESSED, base64url.decodeToBuffer(x), base64url.decodeToBuffer(y)]) - -const computeSecret = ({ crv, d }, { x, y = '' }) => { - const curve = crvToCurve(crv) - const exchange = createECDH(curve) - - exchange.setPrivateKey(base64url.decodeToBuffer(d)) - - return exchange.computeSecret(pubToBuffer(x, y)) -} +const { createHash } = require('crypto') +const ecdhComputeSecret = require('./compute_secret') const concat = (key, length, value) => { - const iterations = Math.ceil(length / 256) + const iterations = Math.ceil(length / 32) let res for (let iter = 1; iter <= iterations; iter++) { @@ -58,12 +27,7 @@ const uint32be = (value, buf = Buffer.allocUnsafe(4)) => { const lengthAndInput = input => Buffer.concat([uint32be(input.length), input]) -const concatDerive = (key, pubKey, length, value) => { - const shared = computeSecret(key, pubKey) - return concat(shared, length, value) -} - -const derive = (alg, keyLen, privKey, pubKey, { apu = Buffer.alloc(0), apv = Buffer.alloc(0) } = {}) => { +module.exports = (alg, keyLen, privKey, pubKey, { apu = Buffer.alloc(0), apv = Buffer.alloc(0) } = {}, computeSecret = ecdhComputeSecret) => { const value = Buffer.concat([ lengthAndInput(Buffer.from(alg)), lengthAndInput(apu), @@ -71,7 +35,6 @@ const derive = (alg, keyLen, privKey, pubKey, { apu = Buffer.alloc(0), apv = Buf uint32be(keyLen) ]) - return concatDerive(privKey, pubKey, keyLen / 8, value) + const sharedSecret = computeSecret(privKey, pubKey) + return concat(sharedSecret, keyLen / 8, value) } - -module.exports = derive diff --git a/node_modules/jose/lib/jwa/ecdh/dir.js b/node_modules/jose/lib/jwa/ecdh/dir.js index 9aae306..5185f19 100644 --- a/node_modules/jose/lib/jwa/ecdh/dir.js +++ b/node_modules/jose/lib/jwa/ecdh/dir.js @@ -1,6 +1,5 @@ -const { strict: assert } = require('assert') - -const { KEYLENGTHS } = require('../../help/consts') +const { improvedDH } = require('../../help/runtime_support') +const { KEYLENGTHS } = require('../../registry') const { generateSync } = require('../../jwk/generate') const derive = require('./derive') @@ -8,7 +7,7 @@ const derive = require('./derive') const wrapKey = (key, payload, { enc }) => { const epk = generateSync(key.kty, key.crv) - const derivedKey = derive(enc, KEYLENGTHS[enc], epk, key) + const derivedKey = derive(enc, KEYLENGTHS.get(enc), epk, key) return { wrapped: derivedKey, @@ -16,16 +15,17 @@ const wrapKey = (key, payload, { enc }) => { } } -const unwrapKey = (key, payload, { apu, apv, epk, enc }) => { - return derive(enc, KEYLENGTHS[enc], key, epk, { apu, apv }) +const unwrapKey = (key, payload, header) => { + const { enc, epk } = header + return derive(enc, KEYLENGTHS.get(enc), key, epk, header) } -const ALG = 'ECDH-ES' - -module.exports = (JWA) => { - assert(!JWA.keyManagementEncrypt.has(ALG), `keyManagementEncrypt alg ${ALG} already registered`) - assert(!JWA.keyManagementDecrypt.has(ALG), `keyManagementDecrypt alg ${ALG} already registered`) +module.exports = (JWA, JWK) => { + JWA.keyManagementEncrypt.set('ECDH-ES', wrapKey) + JWA.keyManagementDecrypt.set('ECDH-ES', unwrapKey) + JWK.EC.deriveKey['ECDH-ES'] = key => (key.use === 'enc' || key.use === undefined) && key.crv !== 'secp256k1' - JWA.keyManagementEncrypt.set(ALG, wrapKey) - JWA.keyManagementDecrypt.set(ALG, unwrapKey) + if (improvedDH) { + JWK.OKP.deriveKey['ECDH-ES'] = key => (key.use === 'enc' || key.use === undefined) && key.keyObject.asymmetricKeyType.startsWith('x') + } } diff --git a/node_modules/jose/lib/jwa/ecdh/kw.js b/node_modules/jose/lib/jwa/ecdh/kw.js index 12990b6..237a893 100644 --- a/node_modules/jose/lib/jwa/ecdh/kw.js +++ b/node_modules/jose/lib/jwa/ecdh/kw.js @@ -1,7 +1,7 @@ -const { strict: assert } = require('assert') - +const { improvedDH } = require('../../help/runtime_support') const { KEYOBJECT } = require('../../help/consts') const { generateSync } = require('../../jwk/generate') +const { ECDH_DERIVE_LENGTHS } = require('../../registry') const derive = require('./derive') @@ -11,28 +11,37 @@ const wrapKey = (wrap, derive, key, payload) => { const derivedKey = derive(epk, key, payload) const result = wrap({ [KEYOBJECT]: derivedKey }, payload) - result.header = { epk: { kty: key.kty, crv: key.crv, x: epk.x, y: epk.y } } + result.header = result.header || {} + Object.assign(result.header, { epk: { kty: key.kty, crv: key.crv, x: epk.x, y: epk.y } }) return result } -const unwrapKey = (unwrap, derive, key, payload, { apu, apv, epk }) => { - const derivedKey = derive(key, epk, { apu, apv }) +const unwrapKey = (unwrap, derive, key, payload, header) => { + const { epk } = header + const derivedKey = derive(key, epk, header) - return unwrap({ [KEYOBJECT]: derivedKey }, payload) + return unwrap({ [KEYOBJECT]: derivedKey }, payload, header) } -module.exports = (JWA) => { +module.exports = (JWA, JWK) => { ['ECDH-ES+A128KW', 'ECDH-ES+A192KW', 'ECDH-ES+A256KW'].forEach((jwaAlg) => { - assert(!JWA.keyManagementEncrypt.has(jwaAlg), `keyManagementEncrypt alg ${jwaAlg} already registered`) - assert(!JWA.keyManagementDecrypt.has(jwaAlg), `keyManagementDecrypt alg ${jwaAlg} already registered`) - const kw = jwaAlg.substr(-6) const kwWrap = JWA.keyManagementEncrypt.get(kw) const kwUnwrap = JWA.keyManagementDecrypt.get(kw) const keylen = parseInt(jwaAlg.substr(9, 3), 10) + ECDH_DERIVE_LENGTHS.set(jwaAlg, keylen) + + if (kwWrap && kwUnwrap) { + JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, kwWrap, derive.bind(undefined, jwaAlg, keylen))) + JWA.keyManagementDecrypt.set(jwaAlg, unwrapKey.bind(undefined, kwUnwrap, derive.bind(undefined, jwaAlg, keylen))) + JWK.EC.deriveKey[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.crv !== 'secp256k1' - JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, kwWrap, derive.bind(undefined, jwaAlg, keylen))) - JWA.keyManagementDecrypt.set(jwaAlg, unwrapKey.bind(undefined, kwUnwrap, derive.bind(undefined, jwaAlg, keylen))) + if (improvedDH) { + JWK.OKP.deriveKey[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.keyObject.asymmetricKeyType.startsWith('x') + } + } }) } +module.exports.wrapKey = wrapKey +module.exports.unwrapKey = unwrapKey diff --git a/node_modules/jose/lib/jwa/ecdsa.js b/node_modules/jose/lib/jwa/ecdsa.js index e75e9f3..fd114ab 100644 --- a/node_modules/jose/lib/jwa/ecdsa.js +++ b/node_modules/jose/lib/jwa/ecdsa.js @@ -1,48 +1,77 @@ -const { strict: assert } = require('assert') -const { sign: signOneShot, verify: verifyOneShot, createSign, createVerify } = require('crypto') +const { sign: signOneShot, verify: verifyOneShot, createSign, createVerify, getCurves } = require('crypto') const { derToJose, joseToDer } = require('../help/ecdsa_signatures') const { KEYOBJECT } = require('../help/consts') const resolveNodeAlg = require('../help/node_alg') +const { asInput } = require('../help/key_object') +const { dsaEncodingSupported } = require('../help/runtime_support') let sign, verify -if (signOneShot) { +if (dsaEncodingSupported) { sign = (jwaAlg, nodeAlg, { [KEYOBJECT]: keyObject }, payload) => { - return derToJose(signOneShot(nodeAlg, payload, keyObject), jwaAlg) - } -} else { - sign = (jwaAlg, nodeAlg, { [KEYOBJECT]: keyObject }, payload) => { - return derToJose(createSign(nodeAlg).update(payload).sign(keyObject.asInput()), jwaAlg) + if (typeof payload === 'string') { + payload = Buffer.from(payload) + } + return signOneShot(nodeAlg, payload, { key: asInput(keyObject, false), dsaEncoding: 'ieee-p1363' }) } -} - -if (verifyOneShot) { verify = (jwaAlg, nodeAlg, { [KEYOBJECT]: keyObject }, payload, signature) => { try { - return verifyOneShot(nodeAlg, payload, keyObject, joseToDer(signature, jwaAlg)) + return verifyOneShot(nodeAlg, payload, { key: asInput(keyObject, true), dsaEncoding: 'ieee-p1363' }, signature) } catch (err) { return false } } } else { + sign = (jwaAlg, nodeAlg, { [KEYOBJECT]: keyObject }, payload) => { + return derToJose(createSign(nodeAlg).update(payload).sign(asInput(keyObject, false)), jwaAlg) + } verify = (jwaAlg, nodeAlg, { [KEYOBJECT]: keyObject }, payload, signature) => { try { - return createVerify(nodeAlg).update(payload).verify(keyObject.asInput(true), joseToDer(signature, jwaAlg)) + return createVerify(nodeAlg).update(payload).verify(asInput(keyObject, true), joseToDer(signature, jwaAlg)) } catch (err) { return false } } } -module.exports = (JWA) => { - ['ES256', 'ES384', 'ES512', 'ES256K'].forEach((jwaAlg) => { - const nodeAlg = resolveNodeAlg(jwaAlg) +const crvToAlg = (crv) => { + switch (crv) { + case 'P-256': + return 'ES256' + case 'secp256k1': + return 'ES256K' + case 'P-384': + return 'ES384' + case 'P-521': + return 'ES512' + } +} + +module.exports = (JWA, JWK) => { + const algs = [] + + if (getCurves().includes('prime256v1')) { + algs.push('ES256') + } + + if (getCurves().includes('secp256k1')) { + algs.push('ES256K') + } - assert(!JWA.sign.has(jwaAlg), `sign alg ${jwaAlg} already registered`) - assert(!JWA.verify.has(jwaAlg), `verify alg ${jwaAlg} already registered`) + if (getCurves().includes('secp384r1')) { + algs.push('ES384') + } + if (getCurves().includes('secp521r1')) { + algs.push('ES512') + } + + algs.forEach((jwaAlg) => { + const nodeAlg = resolveNodeAlg(jwaAlg) JWA.sign.set(jwaAlg, sign.bind(undefined, jwaAlg, nodeAlg)) JWA.verify.set(jwaAlg, verify.bind(undefined, jwaAlg, nodeAlg)) + JWK.EC.sign[jwaAlg] = key => key.private && JWK.EC.verify[jwaAlg](key) + JWK.EC.verify[jwaAlg] = key => (key.use === 'sig' || key.use === undefined) && crvToAlg(key.crv) === jwaAlg }) } diff --git a/node_modules/jose/lib/jwa/eddsa.js b/node_modules/jose/lib/jwa/eddsa.js index 7ebf188..e19d523 100644 --- a/node_modules/jose/lib/jwa/eddsa.js +++ b/node_modules/jose/lib/jwa/eddsa.js @@ -1,9 +1,12 @@ -const { strict: assert } = require('assert') const { sign: signOneShot, verify: verifyOneShot } = require('crypto') const { KEYOBJECT } = require('../help/consts') +const { edDSASupported } = require('../help/runtime_support') const sign = ({ [KEYOBJECT]: keyObject }, payload) => { + if (typeof payload === 'string') { + payload = Buffer.from(payload) + } return signOneShot(undefined, payload, keyObject) } @@ -11,12 +14,11 @@ const verify = ({ [KEYOBJECT]: keyObject }, payload, signature) => { return verifyOneShot(undefined, payload, keyObject, signature) } -const ALG = 'EdDSA' - -module.exports = (JWA) => { - assert(!JWA.sign.has(ALG), `sign alg ${ALG} already registered`) - assert(!JWA.verify.has(ALG), `verify alg ${ALG} already registered`) - - JWA.sign.set(ALG, sign) - JWA.verify.set(ALG, verify) +module.exports = (JWA, JWK) => { + if (edDSASupported) { + JWA.sign.set('EdDSA', sign) + JWA.verify.set('EdDSA', verify) + JWK.OKP.sign.EdDSA = key => key.private && JWK.OKP.verify.EdDSA(key) + JWK.OKP.verify.EdDSA = key => (key.use === 'sig' || key.use === undefined) && key.keyObject.asymmetricKeyType.startsWith('ed') + } } diff --git a/node_modules/jose/lib/jwa/hmac.js b/node_modules/jose/lib/jwa/hmac.js index 766b0b1..a00770a 100644 --- a/node_modules/jose/lib/jwa/hmac.js +++ b/node_modules/jose/lib/jwa/hmac.js @@ -1,33 +1,28 @@ -const { strict: assert } = require('assert') const { createHmac } = require('crypto') const { KEYOBJECT } = require('../help/consts') const timingSafeEqual = require('../help/timing_safe_equal') const resolveNodeAlg = require('../help/node_alg') +const { asInput } = require('../help/key_object') const sign = (jwaAlg, hmacAlg, { [KEYOBJECT]: keyObject }, payload) => { - const hmac = createHmac(hmacAlg, keyObject.asInput ? keyObject.asInput() : keyObject) + const hmac = createHmac(hmacAlg, asInput(keyObject, false)) hmac.update(payload) return hmac.digest() } -const verify = (jwaAlg, hmacAlg, { [KEYOBJECT]: keyObject }, payload, signature) => { - const hmac = createHmac(hmacAlg, keyObject.asInput ? keyObject.asInput() : keyObject) - hmac.update(payload) - const expected = hmac.digest() +const verify = (jwaAlg, hmacAlg, key, payload, signature) => { + const expected = sign(jwaAlg, hmacAlg, key, payload) const actual = signature return timingSafeEqual(actual, expected) } -module.exports = (JWA) => { +module.exports = (JWA, JWK) => { ['HS256', 'HS384', 'HS512'].forEach((jwaAlg) => { const hmacAlg = resolveNodeAlg(jwaAlg) - - assert(!JWA.sign.has(jwaAlg), `sign alg ${jwaAlg} already registered`) - assert(!JWA.verify.has(jwaAlg), `verify alg ${jwaAlg} already registered`) - JWA.sign.set(jwaAlg, sign.bind(undefined, jwaAlg, hmacAlg)) JWA.verify.set(jwaAlg, verify.bind(undefined, jwaAlg, hmacAlg)) + JWK.oct.sign[jwaAlg] = JWK.oct.verify[jwaAlg] = key => key.use === 'sig' || key.use === undefined }) } diff --git a/node_modules/jose/lib/jwa/index.js b/node_modules/jose/lib/jwa/index.js index 1d35cfc..589fdf2 100644 --- a/node_modules/jose/lib/jwa/index.js +++ b/node_modules/jose/lib/jwa/index.js @@ -1,37 +1,33 @@ const { JWKKeySupport, JOSENotSupported } = require('../errors') const { KEY_MANAGEMENT_ENCRYPT, KEY_MANAGEMENT_DECRYPT } = require('../help/consts') -const JWA = { - sign: new Map(), - verify: new Map(), - keyManagementEncrypt: new Map(), - keyManagementDecrypt: new Map(), - encrypt: new Map(), - decrypt: new Map() -} +const { JWA, JWK } = require('../registry') // sign, verify -require('./hmac')(JWA) -require('./ecdsa')(JWA) -require('./eddsa')(JWA) -require('./rsassa')(JWA) -require('./rsassa_pss')(JWA) +require('./hmac')(JWA, JWK) +require('./ecdsa')(JWA, JWK) +require('./eddsa')(JWA, JWK) +require('./rsassa_pss')(JWA, JWK) +require('./rsassa')(JWA, JWK) +require('./none')(JWA) // encrypt, decrypt -require('./aes_cbc_hmac_sha2')(JWA) -require('./aes_gcm')(JWA) +require('./aes_cbc_hmac_sha2')(JWA, JWK) +require('./aes_gcm')(JWA, JWK) // wrapKey, unwrapKey -require('./rsaes')(JWA) -require('./aes_gcm_kw')(JWA) -require('./aes_kw')(JWA) +require('./rsaes')(JWA, JWK) +require('./aes_kw')(JWA, JWK) +require('./aes_gcm_kw')(JWA, JWK) // deriveKey -require('./pbes2')(JWA) -require('./ecdh/kw')(JWA) -require('./ecdh/dir')(JWA) +require('./pbes2')(JWA, JWK) +require('./ecdh/dir')(JWA, JWK) +require('./ecdh/kw')(JWA, JWK) const check = (key, op, alg) => { + const cache = `_${op}_${alg}` + let label let keyOp if (op === 'keyManagementEncrypt') { @@ -42,12 +38,24 @@ const check = (key, op, alg) => { keyOp = KEY_MANAGEMENT_DECRYPT } - if (JWA[op].has(alg)) { - if (!key.algorithms(keyOp).has(alg)) { - throw new JWKKeySupport(`the key does not support ${alg} ${label || op} algorithm`) + if (cache in key) { + if (key[cache]) { + return } - } else { + throw new JWKKeySupport(`the key does not support ${alg} ${label || op} algorithm`) + } + + let value = true + if (!JWA[op].has(alg)) { throw new JOSENotSupported(`unsupported ${label || op} alg: ${alg}`) + } else if (!key.algorithms(keyOp).has(alg)) { + value = false + } + + Object.defineProperty(key, cache, { value, enumerable: false }) + + if (!value) { + return check(key, op, alg) } } diff --git a/node_modules/jose/lib/jwa/pbes2.js b/node_modules/jose/lib/jwa/pbes2.js index f716936..9468627 100644 --- a/node_modules/jose/lib/jwa/pbes2.js +++ b/node_modules/jose/lib/jwa/pbes2.js @@ -1,4 +1,3 @@ -const { strict: assert } = require('assert') const { pbkdf2Sync: pbkdf2, randomBytes } = require('crypto') const { KEYOBJECT } = require('../help/consts') @@ -27,29 +26,31 @@ const wrapKey = (keylen, sha, concat, wrap, { [KEYOBJECT]: keyObject }, payload) const derivedKey = pbkdf2(keyObject.export(), salt, p2c, keylen, sha) const result = wrap({ [KEYOBJECT]: derivedKey }, payload) - result.header = { p2c, p2s: base64url.encodeBuffer(p2s) } + result.header = result.header || {} + Object.assign(result.header, { p2c, p2s: base64url.encodeBuffer(p2s) }) return result } -const unwrapKey = (keylen, sha, concat, unwrap, { [KEYOBJECT]: keyObject }, payload, { p2c, p2s }) => { +const unwrapKey = (keylen, sha, concat, unwrap, { [KEYOBJECT]: keyObject }, payload, header) => { + const { p2s, p2c } = header const salt = concat(p2s) const derivedKey = pbkdf2(keyObject.export(), salt, p2c, keylen, sha) - return unwrap({ [KEYOBJECT]: derivedKey }, payload) + return unwrap({ [KEYOBJECT]: derivedKey }, payload, header) } -module.exports = (JWA) => { +module.exports = (JWA, JWK) => { ['PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW'].forEach((jwaAlg) => { - assert(!JWA.keyManagementEncrypt.has(jwaAlg), `keyManagementEncrypt alg ${jwaAlg} already registered`) - assert(!JWA.keyManagementDecrypt.has(jwaAlg), `keyManagementDecrypt alg ${jwaAlg} already registered`) - const kw = jwaAlg.substr(-6) const kwWrap = JWA.keyManagementEncrypt.get(kw) const kwUnwrap = JWA.keyManagementDecrypt.get(kw) const keylen = parseInt(jwaAlg.substr(13, 3), 10) / 8 const sha = `sha${jwaAlg.substr(8, 3)}` - JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, keylen, sha, concatSalt.bind(undefined, jwaAlg), kwWrap)) - JWA.keyManagementDecrypt.set(jwaAlg, unwrapKey.bind(undefined, keylen, sha, concatSalt.bind(undefined, jwaAlg), kwUnwrap)) + if (kwWrap && kwUnwrap) { + JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, keylen, sha, concatSalt.bind(undefined, jwaAlg), kwWrap)) + JWA.keyManagementDecrypt.set(jwaAlg, unwrapKey.bind(undefined, keylen, sha, concatSalt.bind(undefined, jwaAlg), kwUnwrap)) + JWK.oct.deriveKey[jwaAlg] = key => key.use === 'enc' || key.use === undefined + } }) } diff --git a/node_modules/jose/lib/jwa/rsaes.js b/node_modules/jose/lib/jwa/rsaes.js index 4cba7e2..f688543 100644 --- a/node_modules/jose/lib/jwa/rsaes.js +++ b/node_modules/jose/lib/jwa/rsaes.js @@ -1,12 +1,15 @@ -const { strict: assert } = require('assert') const { publicEncrypt, privateDecrypt, constants } = require('crypto') +const { oaepHashSupported } = require('../help/runtime_support') const { KEYOBJECT } = require('../help/consts') +const { asInput } = require('../help/key_object') const resolvePadding = (alg) => { switch (alg) { - case 'RSA-OAEP-256': case 'RSA-OAEP': + case 'RSA-OAEP-256': + case 'RSA-OAEP-384': + case 'RSA-OAEP-512': return constants.RSA_PKCS1_OAEP_PADDING case 'RSA1_5': return constants.RSA_PKCS1_PADDING @@ -15,34 +18,50 @@ const resolvePadding = (alg) => { const resolveOaepHash = (alg) => { switch (alg) { - case 'RSA-OAEP-256': - return 'sha256' case 'RSA-OAEP': return 'sha1' + case 'RSA-OAEP-256': + return 'sha256' + case 'RSA-OAEP-384': + return 'sha384' + case 'RSA-OAEP-512': + return 'sha512' default: return undefined } } const wrapKey = (padding, oaepHash, { [KEYOBJECT]: keyObject }, payload) => { - const key = keyObject.asInput ? keyObject.asInput(true) : keyObject + const key = asInput(keyObject, true) return { wrapped: publicEncrypt({ key, oaepHash, padding }, payload) } } const unwrapKey = (padding, oaepHash, { [KEYOBJECT]: keyObject }, payload) => { - const key = keyObject.asInput ? keyObject.asInput(false) : keyObject + const key = asInput(keyObject, false) return privateDecrypt({ key, oaepHash, padding }, payload) } -module.exports = (JWA) => { - ['RSA1_5', 'RSA-OAEP', 'RSA-OAEP-256'].forEach((jwaAlg) => { - const padding = resolvePadding(jwaAlg) - const oaepHash = resolveOaepHash(jwaAlg) +const LENGTHS = { + RSA1_5: 0, + 'RSA-OAEP': 592, + 'RSA-OAEP-256': 784, + 'RSA-OAEP-384': 1040, + 'RSA-OAEP-512': 1296 +} + +module.exports = (JWA, JWK) => { + const algs = ['RSA-OAEP', 'RSA1_5'] - assert(!JWA.keyManagementEncrypt.has(jwaAlg), `keyManagementEncrypt alg ${jwaAlg} already registered`) - assert(!JWA.keyManagementDecrypt.has(jwaAlg), `keyManagementDecrypt alg ${jwaAlg} already registered`) + if (oaepHashSupported) { + algs.splice(1, 0, 'RSA-OAEP-256', 'RSA-OAEP-384', 'RSA-OAEP-512') + } + algs.forEach((jwaAlg) => { + const padding = resolvePadding(jwaAlg) + const oaepHash = resolveOaepHash(jwaAlg) JWA.keyManagementEncrypt.set(jwaAlg, wrapKey.bind(undefined, padding, oaepHash)) JWA.keyManagementDecrypt.set(jwaAlg, unwrapKey.bind(undefined, padding, oaepHash)) + JWK.RSA.wrapKey[jwaAlg] = key => (key.use === 'enc' || key.use === undefined) && key.length >= LENGTHS[jwaAlg] + JWK.RSA.unwrapKey[jwaAlg] = key => key.private && (key.use === 'enc' || key.use === undefined) && key.length >= LENGTHS[jwaAlg] }) } diff --git a/node_modules/jose/lib/jwa/rsassa.js b/node_modules/jose/lib/jwa/rsassa.js index a64d906..47e64da 100644 --- a/node_modules/jose/lib/jwa/rsassa.js +++ b/node_modules/jose/lib/jwa/rsassa.js @@ -1,43 +1,29 @@ -const { strict: assert } = require('assert') -const { sign: signOneShot, verify: verifyOneShot, createSign, createVerify } = require('crypto') +const { createSign, createVerify } = require('crypto') const { KEYOBJECT } = require('../help/consts') const resolveNodeAlg = require('../help/node_alg') +const { asInput } = require('../help/key_object') -let sign, verify +const sign = (nodeAlg, { [KEYOBJECT]: keyObject }, payload) => { + return createSign(nodeAlg).update(payload).sign(asInput(keyObject, false)) +} -if (signOneShot) { - sign = (nodeAlg, { [KEYOBJECT]: keyObject }, payload) => { - return signOneShot(nodeAlg, payload, keyObject) - } -} else { - sign = (nodeAlg, { [KEYOBJECT]: keyObject }, payload) => { - return createSign(nodeAlg).update(payload).sign(keyObject.asInput()) - } +const verify = (nodeAlg, { [KEYOBJECT]: keyObject }, payload, signature) => { + return createVerify(nodeAlg).update(payload).verify(asInput(keyObject, true), signature) } -if (verifyOneShot) { - verify = (nodeAlg, { [KEYOBJECT]: keyObject }, payload, signature) => { - return verifyOneShot(nodeAlg, payload, keyObject, signature) - } -} else { - verify = (nodeAlg, { [KEYOBJECT]: keyObject }, payload, signature) => { - try { - return createVerify(nodeAlg).update(payload).verify(keyObject.asInput(true), signature) - } catch (err) { - return false - } - } +const LENGTHS = { + RS256: 0, + RS384: 624, + RS512: 752 } -module.exports = (JWA) => { +module.exports = (JWA, JWK) => { ['RS256', 'RS384', 'RS512'].forEach((jwaAlg) => { const nodeAlg = resolveNodeAlg(jwaAlg) - - assert(!JWA.sign.has(jwaAlg), `sign alg ${jwaAlg} already registered`) - assert(!JWA.verify.has(jwaAlg), `verify alg ${jwaAlg} already registered`) - JWA.sign.set(jwaAlg, sign.bind(undefined, nodeAlg)) JWA.verify.set(jwaAlg, verify.bind(undefined, nodeAlg)) + JWK.RSA.sign[jwaAlg] = key => key.private && JWK.RSA.verify[jwaAlg](key) + JWK.RSA.verify[jwaAlg] = key => (key.use === 'sig' || key.use === undefined) && key.length >= LENGTHS[jwaAlg] }) } diff --git a/node_modules/jose/lib/jwa/rsassa_pss.js b/node_modules/jose/lib/jwa/rsassa_pss.js index b96ce34..bdb8289 100644 --- a/node_modules/jose/lib/jwa/rsassa_pss.js +++ b/node_modules/jose/lib/jwa/rsassa_pss.js @@ -1,7 +1,4 @@ -const { strict: assert } = require('assert') const { - sign: signOneShot, - verify: verifyOneShot, createSign, createVerify, constants @@ -9,55 +6,38 @@ const { const { KEYOBJECT } = require('../help/consts') const resolveNodeAlg = require('../help/node_alg') +const { asInput } = require('../help/key_object') -let sign, verify +const sign = (nodeAlg, { [KEYOBJECT]: keyObject }, payload) => { + const key = asInput(keyObject, false) + return createSign(nodeAlg).update(payload).sign({ + key, + padding: constants.RSA_PKCS1_PSS_PADDING, + saltLength: constants.RSA_PSS_SALTLEN_DIGEST + }) +} -if (signOneShot) { - sign = (nodeAlg, { [KEYOBJECT]: keyObject }, payload) => { - return signOneShot(nodeAlg, payload, { - key: keyObject, - padding: constants.RSA_PKCS1_PSS_PADDING, - saltLength: constants.RSA_PSS_SALTLEN_DIGEST - }) - } -} else { - sign = (nodeAlg, { [KEYOBJECT]: keyObject }, payload) => { - const key = keyObject.asInput() - return createSign(nodeAlg).update(payload).sign({ - key, - padding: constants.RSA_PKCS1_PSS_PADDING, - saltLength: constants.RSA_PSS_SALTLEN_DIGEST - }) - } +const verify = (nodeAlg, { [KEYOBJECT]: keyObject }, payload, signature) => { + const key = asInput(keyObject, true) + return createVerify(nodeAlg).update(payload).verify({ + key, + padding: constants.RSA_PKCS1_PSS_PADDING, + saltLength: constants.RSA_PSS_SALTLEN_DIGEST + }, signature) } -if (verifyOneShot) { - verify = (nodeAlg, { [KEYOBJECT]: keyObject }, payload, signature) => { - return verifyOneShot(nodeAlg, payload, { - key: keyObject, - padding: constants.RSA_PKCS1_PSS_PADDING, - saltLength: constants.RSA_PSS_SALTLEN_DIGEST - }, signature) - } -} else { - verify = (nodeAlg, { [KEYOBJECT]: keyObject }, payload, signature) => { - const key = keyObject.asInput(true) - return createVerify(nodeAlg).update(payload).verify({ - key, - padding: constants.RSA_PKCS1_PSS_PADDING, - saltLength: constants.RSA_PSS_SALTLEN_DIGEST - }, signature) - } +const LENGTHS = { + PS256: 528, + PS384: 784, + PS512: 1040 } -module.exports = (JWA) => { +module.exports = (JWA, JWK) => { ['PS256', 'PS384', 'PS512'].forEach((jwaAlg) => { const nodeAlg = resolveNodeAlg(jwaAlg) - - assert(!JWA.sign.has(jwaAlg), `sign alg ${jwaAlg} already registered`) - assert(!JWA.verify.has(jwaAlg), `verify alg ${jwaAlg} already registered`) - JWA.sign.set(jwaAlg, sign.bind(undefined, nodeAlg)) JWA.verify.set(jwaAlg, verify.bind(undefined, nodeAlg)) + JWK.RSA.sign[jwaAlg] = key => key.private && JWK.RSA.verify[jwaAlg](key) + JWK.RSA.verify[jwaAlg] = key => (key.use === 'sig' || key.use === undefined) && key.length >= LENGTHS[jwaAlg] }) } diff --git a/node_modules/jose/lib/jwe/decrypt.js b/node_modules/jose/lib/jwe/decrypt.js index 214a00f..358d084 100644 --- a/node_modules/jose/lib/jwe/decrypt.js +++ b/node_modules/jose/lib/jwe/decrypt.js @@ -1,8 +1,8 @@ const { inflateRawSync } = require('zlib') const base64url = require('../help/base64url') +const getKey = require('../help/get_key') const { KeyStore } = require('../jwks') -const Key = require('../jwk/key/base') const errors = require('../errors') const { check, decrypt, keyManagementDecrypt } = require('../jwa') const JWK = require('../jwk') @@ -37,19 +37,26 @@ const combineHeader = (prot = {}, unprotected = {}, header = {}) => { } } +const validateAlgorithms = (algorithms, option) => { + if (algorithms !== undefined && (!Array.isArray(algorithms) || algorithms.some(s => typeof s !== 'string' || !s))) { + throw new TypeError(`"${option}" option must be an array of non-empty strings`) + } + + if (!algorithms) { + return undefined + } + + return new Set(algorithms) +} + /* * @public */ -const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], complete = false, algorithms } = {}) => { - if (!(key instanceof Key) && !(key instanceof KeyStore)) { - throw new TypeError('key must be an instance of a key instantiated by JWK.asKey or a JWKS.KeyStore') - } +const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], complete = false, keyManagementAlgorithms, contentEncryptionAlgorithms, maxPBES2Count = 10000, inflateRawSyncLimit = 250000 } = {}) => { + key = getKey(key, true) - if (algorithms !== undefined && (!Array.isArray(algorithms) || algorithms.some(s => typeof s !== 'string' || !s))) { - throw new TypeError('"algorithms" option must be an array of non-empty strings') - } else if (algorithms) { - algorithms = new Set(algorithms) - } + keyManagementAlgorithms = validateAlgorithms(keyManagementAlgorithms, 'keyManagementAlgorithms') + contentEncryptionAlgorithms = validateAlgorithms(contentEncryptionAlgorithms, 'contentEncryptionAlgorithms') if (!Array.isArray(crit) || crit.some(s => typeof s !== 'string' || !s)) { throw new TypeError('"crit" option must be an array of non-empty strings') @@ -57,8 +64,6 @@ const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], c if (!serialization) { serialization = resolveSerialization(jwe) - } else if (serialization !== resolveSerialization(jwe)) { - throw new errors.JWEInvalid() } let alg, ciphertext, enc, encryptedKey, iv, opts, prot, tag, unprotected, cek, aad, header @@ -86,8 +91,12 @@ const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], c ;({ alg, enc } = opts) - if (algorithms && !algorithms.has(alg === 'dir' ? enc : alg)) { - throw new errors.JOSEAlgNotWhitelisted('alg not whitelisted') + if (keyManagementAlgorithms && !keyManagementAlgorithms.has(alg)) { + throw new errors.JOSEAlgNotWhitelisted('key management algorithm not whitelisted') + } + + if (contentEncryptionAlgorithms && !contentEncryptionAlgorithms.has(enc)) { + throw new errors.JOSEAlgNotWhitelisted('content encryption algorithm not whitelisted') } if (key instanceof KeyStore) { @@ -110,7 +119,12 @@ const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], c const errs = [] for (const key of keys) { try { - return jweDecrypt(true, serialization, jwe, key, { crit, complete, algorithms: algorithms ? [...algorithms] : undefined }) + return jweDecrypt(true, serialization, jwe, key, { + crit, + complete, + contentEncryptionAlgorithms: contentEncryptionAlgorithms ? [...contentEncryptionAlgorithms] : undefined, + keyManagementAlgorithms: keyManagementAlgorithms ? [...keyManagementAlgorithms] : undefined + }) } catch (err) { errs.push(err) continue @@ -128,6 +142,12 @@ const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], c check(key, ...(alg === 'dir' ? ['decrypt', enc] : ['keyManagementDecrypt', alg])) + if (alg.startsWith('PBES2')) { + if (opts && opts.p2c > maxPBES2Count) { + throw new errors.JWEInvalid('JOSE Header "p2c" (PBES2 Count) out is of acceptable bounds') + } + } + try { if (alg === 'dir') { cek = JWK.asKey(key, { alg: enc, use: 'enc' }) @@ -169,11 +189,11 @@ const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], c let cleartext = decrypt(enc, cek, base64url.decodeToBuffer(ciphertext), { iv, tag, aad: adata }) if (opts.zip) { - cleartext = inflateRawSync(cleartext) + cleartext = inflateRawSync(cleartext, { maxOutputLength: inflateRawSyncLimit }) } if (complete) { - const result = { cleartext, key } + const result = { cleartext, key, cek } if (aad) result.aad = aad if (header) result.header = header if (unprotected) result.unprotected = unprotected @@ -191,7 +211,12 @@ const jweDecrypt = (skipValidateHeaders, serialization, jwe, key, { crit = [], c const errs = [] for (const recipient of recipients) { try { - return jweDecrypt(true, 'flattened', { ...root, ...recipient }, key, { crit, complete, algorithms: algorithms ? [...algorithms] : undefined }) + return jweDecrypt(true, 'flattened', { ...root, ...recipient }, key, { + crit, + complete, + contentEncryptionAlgorithms: contentEncryptionAlgorithms ? [...contentEncryptionAlgorithms] : undefined, + keyManagementAlgorithms: keyManagementAlgorithms ? [...keyManagementAlgorithms] : undefined + }) } catch (err) { errs.push(err) continue diff --git a/node_modules/jose/lib/jwe/encrypt.js b/node_modules/jose/lib/jwe/encrypt.js index 0b937c1..9851f39 100644 --- a/node_modules/jose/lib/jwe/encrypt.js +++ b/node_modules/jose/lib/jwe/encrypt.js @@ -3,10 +3,10 @@ const { deflateRawSync } = require('zlib') const { KEYOBJECT } = require('../help/consts') const generateIV = require('../help/generate_iv') const base64url = require('../help/base64url') +const getKey = require('../help/get_key') const isObject = require('../help/is_object') const { createSecretKey } = require('../help/key_object') const deepClone = require('../help/deep_clone') -const Key = require('../jwk/key/base') const importKey = require('../jwk/import') const { JWEInvalid } = require('../errors') const { check, keyManagementEncrypt, encrypt } = require('../jwa') @@ -17,17 +17,8 @@ const validateHeaders = require('./validate_headers') const PROCESS_RECIPIENT = Symbol('PROCESS_RECIPIENT') -const map = new WeakMap() - -const i = (ctx) => { - if (!map.has(ctx)) { - map.set(ctx, {}) - } - return map.get(ctx) -} - class Encrypt { - constructor (cleartext, protectedHeader, unprotectedHeader, aad) { + constructor (cleartext, protectedHeader, aad, unprotectedHeader) { if (!Buffer.isBuffer(cleartext) && typeof cleartext !== 'string') { throw new TypeError('cleartext argument must be a Buffer or a string') } @@ -46,26 +37,24 @@ class Encrypt { throw new TypeError('unprotectedHeader argument must be a plain object when provided') } - i(this).recipients = [] - i(this).cleartext = cleartext - i(this).aad = aad - i(this).unprotected = unprotectedHeader ? deepClone(unprotectedHeader) : undefined - i(this).protected = protectedHeader ? deepClone(protectedHeader) : undefined + this._recipients = [] + this._cleartext = cleartext + this._aad = aad + this._unprotected = unprotectedHeader ? deepClone(unprotectedHeader) : undefined + this._protected = protectedHeader ? deepClone(protectedHeader) : undefined } /* * @public */ recipient (key, header) { - if (!(key instanceof Key)) { - throw new TypeError('key must be an instance of a key instantiated by JWK.asKey') - } + key = getKey(key) if (header !== undefined && !isObject(header)) { throw new TypeError('header argument must be a plain object when provided') } - i(this).recipients.push({ + this._recipients.push({ key, header: header ? deepClone(header) : undefined }) @@ -77,9 +66,9 @@ class Encrypt { * @private */ [PROCESS_RECIPIENT] (recipient) { - const unprotectedHeader = i(this).unprotected - const protectedHeader = i(this).protected - const { length: recipientCount } = i(this).recipients + const unprotectedHeader = this._unprotected + const protectedHeader = this._protected + const { length: recipientCount } = this._recipients const jweHeader = { ...protectedHeader, @@ -91,13 +80,16 @@ class Encrypt { const enc = jweHeader.enc let alg = jweHeader.alg + if (key.use === 'sig') { + throw new TypeError('a key with "use":"sig" is not usable for encryption') + } + if (alg === 'dir') { check(key, 'encrypt', enc) } else if (alg) { check(key, 'keyManagementEncrypt', alg) } else { - alg = [...key.algorithms('wrapKey')][0] - alg = alg || [...key.algorithms('deriveKey')][0] + alg = key.alg || [...key.algorithms('wrapKey')][0] || [...key.algorithms('deriveKey')][0] if (alg === 'ECDH-ES' && recipientCount !== 1) { alg = [...key.algorithms('deriveKey')][1] @@ -111,7 +103,7 @@ class Encrypt { if (protectedHeader) { protectedHeader.alg = alg } else { - i(this).protected = { alg } + this._protected = { alg } } } else { if (recipient.header) { @@ -126,11 +118,12 @@ class Encrypt { let generatedHeader if (key.kty === 'oct' && alg === 'dir') { - i(this).cek = importKey(key[KEYOBJECT], { use: 'enc', alg: enc }) + this._cek = importKey(key[KEYOBJECT], { use: 'enc', alg: enc }) } else { - ({ wrapped, header: generatedHeader } = keyManagementEncrypt(alg, key, i(this).cek[KEYOBJECT].export(), { enc, alg })) + check(this._cek, 'encrypt', enc) + ;({ wrapped, header: generatedHeader } = keyManagementEncrypt(alg, key, this._cek[KEYOBJECT].export(), { enc, alg })) if (alg === 'ECDH-ES') { - i(this).cek = importKey(createSecretKey(wrapped), { use: 'enc', alg: enc }) + this._cek = importKey(createSecretKey(wrapped), { use: 'enc', alg: enc }) } } @@ -154,61 +147,67 @@ class Encrypt { throw new TypeError('serialization must be one of "compact", "flattened", "general"') } - if (!i(this).recipients.length) { + if (!this._recipients.length) { throw new JWEInvalid('missing recipients') } - serializer.validate(i(this).protected, i(this).unprotected, i(this).aad, i(this).recipients) + serializer.validate(this._protected, this._unprotected, this._aad, this._recipients) - let enc = validateHeaders(i(this).protected, i(this).unprotected, i(this).recipients, false, i(this).protected ? i(this).protected.crit : undefined) + let enc = validateHeaders(this._protected, this._unprotected, this._recipients, false, this._protected ? this._protected.crit : undefined) if (!enc) { enc = 'A128CBC-HS256' - if (i(this).protected) { - i(this).protected.enc = enc + if (this._protected) { + this._protected.enc = enc } else { - i(this).protected = { enc } + this._protected = { enc } } } const final = {} - i(this).cek = generateCEK(enc) + this._cek = generateCEK(enc) - i(this).recipients.forEach(this[PROCESS_RECIPIENT].bind(this)) + for (const recipient of this._recipients) { + this[PROCESS_RECIPIENT](recipient) + } const iv = generateIV(enc) final.iv = base64url.encodeBuffer(iv) - if (i(this).recipients.length === 1 && i(this).recipients[0].generatedHeader) { - const [{ generatedHeader }] = i(this).recipients - delete i(this).recipients[0].generatedHeader - i(this).protected = { - ...i(this).protected, + if (this._recipients.length === 1 && this._recipients[0].generatedHeader) { + const [{ generatedHeader }] = this._recipients + delete this._recipients[0].generatedHeader + this._protected = { + ...this._protected, ...generatedHeader } } - if (i(this).protected) { - final.protected = base64url.JSON.encode(i(this).protected) + if (this._protected) { + final.protected = base64url.JSON.encode(this._protected) } - final.unprotected = i(this).unprotected + final.unprotected = this._unprotected let aad - if (i(this).aad) { - final.aad = base64url.encode(i(this).aad) - aad = Buffer.concat([Buffer.from(final.protected || ''), Buffer.from('.'), Buffer.from(final.aad)]) + if (this._aad) { + final.aad = base64url.encode(this._aad) + aad = Buffer.concat([ + Buffer.from(final.protected || ''), + Buffer.from('.'), + Buffer.from(final.aad) + ]) } else { aad = Buffer.from(final.protected || '') } - let cleartext = i(this).cleartext - if (i(this).protected && 'zip' in i(this).protected) { + let cleartext = this._cleartext + if (this._protected && 'zip' in this._protected) { cleartext = deflateRawSync(cleartext) } - const { ciphertext, tag } = encrypt(enc, i(this).cek, cleartext, { iv, aad }) + const { ciphertext, tag } = encrypt(enc, this._cek, cleartext, { iv, aad }) final.tag = base64url.encodeBuffer(tag) final.ciphertext = base64url.encodeBuffer(ciphertext) - return serializer(final, i(this).recipients) + return serializer(final, this._recipients) } } diff --git a/node_modules/jose/lib/jwe/generate_cek.js b/node_modules/jose/lib/jwe/generate_cek.js index d87d4ef..15392af 100644 --- a/node_modules/jose/lib/jwe/generate_cek.js +++ b/node_modules/jose/lib/jwe/generate_cek.js @@ -1,7 +1,15 @@ const { randomBytes } = require('crypto') const { createSecretKey } = require('../help/key_object') -const { KEYLENGTHS } = require('../help/consts') -const importKey = require('../jwk/import') +const { KEYLENGTHS } = require('../registry') +const Key = require('../jwk/key/oct') -module.exports = alg => importKey(createSecretKey(randomBytes(KEYLENGTHS[alg] / 8)), { use: 'enc', alg }) +module.exports = (alg) => { + const keyLength = KEYLENGTHS.get(alg) + + if (!keyLength) { + return new Key({ type: 'secret' }) + } + + return new Key(createSecretKey(randomBytes(keyLength / 8)), { use: 'enc', alg }) +} diff --git a/node_modules/jose/lib/jwe/index.js b/node_modules/jose/lib/jwe/index.js index c4ba26b..68bf292 100644 --- a/node_modules/jose/lib/jwe/index.js +++ b/node_modules/jose/lib/jwe/index.js @@ -1,10 +1,10 @@ const Encrypt = require('./encrypt') const decrypt = require('./decrypt') -const single = (serialization, cleartext, key, protectedHeader, unprotectedHeader, aad) => { - const jwe = new Encrypt(cleartext, protectedHeader, unprotectedHeader, aad) - jwe.recipient(key) - return jwe.encrypt(serialization) +const single = (serialization, cleartext, key, protectedHeader, aad, unprotectedHeader) => { + return new Encrypt(cleartext, protectedHeader, aad, unprotectedHeader) + .recipient(key) + .encrypt(serialization) } module.exports.Encrypt = Encrypt diff --git a/node_modules/jose/lib/jwk/import.js b/node_modules/jose/lib/jwk/import.js index e5dd747..160d3f4 100644 --- a/node_modules/jose/lib/jwk/import.js +++ b/node_modules/jose/lib/jwk/import.js @@ -1,5 +1,3 @@ -const { deprecate } = require('util') - const { createPublicKey, createPrivateKey, createSecretKey, KeyObject } = require('../help/key_object') const base64url = require('../help/base64url') const isObject = require('../help/is_object') @@ -26,6 +24,8 @@ const mergedParameters = (target = {}, source = {}) => { } } +const openSSHpublicKey = /^[a-zA-Z0-9-]+ AAAA(?:[0-9A-Za-z+/])+(?:==|=)?(?: .*)?$/ + const asKey = (key, parameters, { calculateMissingRSAPrimes = false } = {}) => { let privateKey, publicKey, secret @@ -49,20 +49,16 @@ const asKey = (key, parameters, { calculateMissingRSAPrimes = false } = {}) => { secret = key break } - } else if (typeof key === 'object' && 'kty' in key && key.kty === 'oct') { // symmetric key + } else if (typeof key === 'object' && key && 'kty' in key && key.kty === 'oct') { // symmetric key try { secret = createSecretKey(base64url.decodeToBuffer(key.k)) } catch (err) { - if (err instanceof errors.JOSEError) { - throw err - } - if (!('k' in key)) { secret = { type: 'secret' } } } parameters = mergedParameters(parameters, key) - } else if (typeof key === 'object' && 'kty' in key) { // assume JWK formatted asymmetric key + } else if (typeof key === 'object' && key && 'kty' in key) { // assume JWK formatted asymmetric key ({ calculateMissingRSAPrimes = false } = parameters || { calculateMissingRSAPrimes }) let pem @@ -81,19 +77,32 @@ const asKey = (key, parameters, { calculateMissingRSAPrimes = false } = {}) => { } parameters = mergedParameters({}, key) - } else { // | | passed to crypto.createPrivateKey or crypto.createPublicKey or passed to crypto.createSecretKey + } else if (key && (typeof key === 'object' || typeof key === 'string')) { // | | passed to crypto.createPrivateKey or crypto.createPublicKey or passed to crypto.createSecretKey try { privateKey = createPrivateKey(key) - } catch (err) {} + } catch (err) { + if (err instanceof errors.JOSEError) { + throw err + } + } try { publicKey = createPublicKey(key) - } catch (err) {} + if (key.startsWith('-----BEGIN CERTIFICATE-----') && (!parameters || !('x5c' in parameters))) { + parameters = mergedParameters(parameters, { + x5c: [key.replace(/(?:-----(?:BEGIN|END) CERTIFICATE-----|\s)/g, '')] + }) + } + } 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 // have them imported as symmetric "oct" keys - if (!key.includes('-----BEGIN')) { + if (!key.includes('-----BEGIN') && !openSSHpublicKey.test(key.toString('ascii').replace(/[\r\n]/g, ''))) { secret = createSecretKey(Buffer.isBuffer(key) ? key : Buffer.from(key)) } } catch (err) {} @@ -119,11 +128,7 @@ const asKey = (key, parameters, { calculateMissingRSAPrimes = false } = {}) => { return new OctKey(keyObject, parameters) } - throw new errors.JWKImportFailed('import failed') + throw new errors.JWKImportFailed('key import failed') } module.exports = asKey -Object.defineProperty(asKey, 'deprecated', { - value: deprecate((key, parameters) => { return asKey(key, parameters, { calculateMissingRSAPrimes: true }) }, 'JWK.importKey() is deprecated, use JWK.asKey() instead'), - enumerable: false -}) diff --git a/node_modules/jose/lib/jwk/index.js b/node_modules/jose/lib/jwk/index.js index 580908d..6d0d41c 100644 --- a/node_modules/jose/lib/jwk/index.js +++ b/node_modules/jose/lib/jwk/index.js @@ -1,14 +1,15 @@ const Key = require('./key/base') +const None = require('./key/none') +const EmbeddedJWK = require('./key/embedded.jwk') +const EmbeddedX5C = require('./key/embedded.x5c') const importKey = require('./import') -const { generate, generateSync } = require('./generate') +const generate = require('./generate') -module.exports.asKey = importKey -module.exports.generate = generate -module.exports.generateSync = generateSync -module.exports.isKey = input => input instanceof Key - -/* deprecated */ -Object.defineProperty(module.exports, 'importKey', { - value: importKey.deprecated, - enumerable: false -}) +module.exports = { + ...generate, + asKey: importKey, + isKey: input => input instanceof Key, + None, + EmbeddedJWK, + EmbeddedX5C +} diff --git a/node_modules/jose/lib/jwk/key/base.js b/node_modules/jose/lib/jwk/key/base.js index 5709e7e..0773b7f 100644 --- a/node_modules/jose/lib/jwk/key/base.js +++ b/node_modules/jose/lib/jwk/key/base.js @@ -13,6 +13,9 @@ const isObject = require('../../help/is_object') const thumbprint = require('../thumbprint') const errors = require('../../errors') +const privateApi = Symbol('privateApi') +const { JWK } = require('../../registry') + class Key { constructor (keyObject, { alg, use, kid, key_ops: ops, x5c, x5t, 'x5t#S256': x5t256 } = {}) { if (use !== undefined) { @@ -58,7 +61,7 @@ class Key { let publicKey try { publicKey = createPublicKey({ - key: `-----BEGIN CERTIFICATE-----${EOL}${cert.match(/.{1,64}/g).join(EOL)}${EOL}-----END CERTIFICATE-----`, format: 'pem' + key: `-----BEGIN CERTIFICATE-----${EOL}${(cert.match(/.{1,64}/g) || []).join(EOL)}${EOL}-----END CERTIFICATE-----`, format: 'pem' }) } catch (err) { throw new errors.JWKInvalid(`\`x5c\` member at index ${i} is not a valid base64-encoded DER PKIX certificate`) @@ -78,51 +81,73 @@ 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' }, secret: { value: keyObject.type === 'secret' }, alg: { value: alg, enumerable: alg !== undefined }, use: { value: use, enumerable: use !== undefined }, - x5c: { value: x5c, enumerable: x5c !== undefined }, + x5c: { + enumerable: x5c !== undefined, + ...(x5c ? { get () { return [...x5c] } } : { value: undefined }) + }, key_ops: { enumerable: ops !== undefined, ...(ops ? { get () { return [...ops] } } : { value: undefined }) }, kid: { enumerable: true, - ...(kid ? { value: kid } : { - get () { - Object.defineProperty(this, 'kid', { value: this.thumbprint, configurable: false }) - return this.kid - }, - configurable: true - }) + ...(kid + ? { value: kid } + : { + get () { + Object.defineProperty(this, 'kid', { value: this.thumbprint, configurable: false }) + return this.kid + }, + configurable: true + }) }, - ...(x5c ? { - x5t: { - enumerable: true, - ...(x5t ? { value: x5t } : { - get () { - Object.defineProperty(this, 'x5t', { value: thumbprint.x5t(this.x5c[0]), configurable: false }) - return this.x5t - }, - configurable: true - }) - } - } : undefined), - ...(x5c ? { - 'x5t#S256': { - enumerable: true, - ...(x5t256 ? { value: x5t256 } : { - get () { - Object.defineProperty(this, 'x5t#S256', { value: thumbprint['x5t#S256'](this.x5c[0]), configurable: false }) - return this['x5t#S256'] - }, - configurable: true - }) - } - } : undefined), + ...(x5c + ? { + x5t: { + enumerable: true, + ...(x5t + ? { value: x5t } + : { + get () { + Object.defineProperty(this, 'x5t', { value: thumbprint.x5t(this.x5c[0]), configurable: false }) + return this.x5t + }, + configurable: true + }) + } + } + : undefined), + ...(x5c + ? { + 'x5t#S256': { + enumerable: true, + ...(x5t256 + ? { value: x5t256 } + : { + get () { + Object.defineProperty(this, 'x5t#S256', { value: thumbprint['x5t#S256'](this.x5c[0]), configurable: false }) + return this['x5t#S256'] + }, + configurable: true + }) + } + } + : undefined), thumbprint: { get () { Object.defineProperty(this, 'thumbprint', { value: thumbprint.kid(this[THUMBPRINT_MATERIAL]()), configurable: false }) @@ -248,9 +273,46 @@ class Key { throw new Error(`"[THUMBPRINT_MATERIAL]()" is not implemented on ${this.constructor.name}`) } - /* c8 ignore next 3 */ - algorithms () { - throw new Error(`"algorithms()" is not implemented on ${this.constructor.name}`) + algorithms (operation, /* the rest is private API */ int, opts) { + const { use = this.use, alg = this.alg, key_ops: ops = this.key_ops } = int === privateApi ? opts : {} + if (alg) { + return new Set(this.algorithms(operation, privateApi, { alg: null, use, key_ops: ops }).has(alg) ? [alg] : undefined) + } + + if (typeof operation === 'symbol') { + try { + return this[operation]() + } catch (err) { + return new Set() + } + } + + if (operation && ops && !ops.includes(operation)) { + return new Set() + } + + switch (operation) { + case 'decrypt': + case 'deriveKey': + case 'encrypt': + case 'sign': + case 'unwrapKey': + case 'verify': + case 'wrapKey': + return new Set(Object.entries(JWK[this.kty][operation]).map(([alg, fn]) => fn(this) ? alg : undefined).filter(Boolean)) + case undefined: + return new Set([ + ...this.algorithms('sign'), + ...this.algorithms('verify'), + ...this.algorithms('decrypt'), + ...this.algorithms('encrypt'), + ...this.algorithms('unwrapKey'), + ...this.algorithms('wrapKey'), + ...this.algorithms('deriveKey') + ]) + default: + throw new TypeError('invalid key operation') + } } /* c8 ignore next 3 */ diff --git a/node_modules/jose/lib/jwk/key/ec.js b/node_modules/jose/lib/jwk/key/ec.js index 563feb6..0a5848a 100644 --- a/node_modules/jose/lib/jwk/key/ec.js +++ b/node_modules/jose/lib/jwk/key/ec.js @@ -2,14 +2,14 @@ const { generateKeyPairSync, generateKeyPair: async } = require('crypto') const { promisify } = require('util') const { - THUMBPRINT_MATERIAL, JWK_MEMBERS, PUBLIC_MEMBERS, EC_CURVES, - PRIVATE_MEMBERS, KEY_MANAGEMENT_DECRYPT, KEY_MANAGEMENT_ENCRYPT, ECDH_ALGS + THUMBPRINT_MATERIAL, JWK_MEMBERS, PUBLIC_MEMBERS, + PRIVATE_MEMBERS, KEY_MANAGEMENT_DECRYPT, KEY_MANAGEMENT_ENCRYPT } = require('../../help/consts') +const { EC_CURVES } = require('../../registry') const { keyObjectSupported } = require('../../help/runtime_support') const { createPublicKey, createPrivateKey } = require('../../help/key_object') const errors = require('../../errors') -const { name: secp256k1 } = require('./secp256k1_crv') const Key = require('./base') @@ -20,29 +20,13 @@ Object.freeze(EC_PUBLIC) const EC_PRIVATE = new Set([...EC_PUBLIC, 'd']) Object.freeze(EC_PRIVATE) -const crvToDSA = (crv) => { - switch (crv) { - case 'P-256': - return 'ES256' - case secp256k1: - return 'ES256K' - case 'P-384': - return 'ES384' - case 'P-521': - return 'ES512' - } -} - // Elliptic Curve Key Type class ECKey extends Key { constructor (...args) { super(...args) this[JWK_MEMBERS]() - Object.defineProperty(this, 'kty', { - value: 'EC', - enumerable: true - }) - if (!this.crv) { + Object.defineProperty(this, 'kty', { value: 'EC', enumerable: true }) + if (!EC_CURVES.has(this.crv)) { throw new errors.JOSENotSupported('unsupported EC key curve') } } @@ -61,58 +45,15 @@ class ECKey extends Key { return { crv: this.crv, kty: 'EC', x: this.x, y: this.y } } - algorithms (operation, /* second argument is private API */ { use = this.use, alg = this.alg, key_ops: ops = this.key_ops } = {}) { - if (alg) { - return new Set(this.algorithms(operation, { alg: null }).has(alg) ? [alg] : undefined) - } - - if (operation === KEY_MANAGEMENT_ENCRYPT) { - operation = 'deriveKey' - } else if (operation === KEY_MANAGEMENT_DECRYPT) { - if (this.public) { - return new Set() - } - operation = 'deriveKey' - } + [KEY_MANAGEMENT_ENCRYPT] () { + return this.algorithms('deriveKey') + } - if (operation && ops && !ops.includes(operation)) { + [KEY_MANAGEMENT_DECRYPT] () { + if (this.public) { return new Set() } - - switch (operation) { - case 'wrapKey': - case 'unwrapKey': - case 'encrypt': - case 'decrypt': - return new Set() - case 'sign': - if (this.public || use === 'enc') { - return new Set() - } - - return new Set([crvToDSA(this.crv)]) - case 'verify': - if (use === 'enc') { - return new Set() - } - - return new Set([crvToDSA(this.crv)]) - case 'deriveKey': - if (use === 'sig' || this.crv === secp256k1) { - return new Set() - } - - return new Set(ECDH_ALGS) - case undefined: - // just the ops needed to return all algs regardless of its use - return new Set([ - ...this.algorithms('sign'), - ...this.algorithms('verify'), - ...this.algorithms('deriveKey') - ]) - default: - throw new TypeError('invalid key operation') - } + return this.algorithms('deriveKey') } static async generate (crv = 'P-256', privat = true) { @@ -120,10 +61,6 @@ class ECKey extends Key { throw new errors.JOSENotSupported(`unsupported EC key curve: ${crv}`) } - if (crv === secp256k1 && crv !== 'secp256k1') { - crv = 'secp256k1' - } - let privateKey, publicKey if (keyObjectSupported) { @@ -149,10 +86,6 @@ class ECKey extends Key { throw new errors.JOSENotSupported(`unsupported EC key curve: ${crv}`) } - if (crv === secp256k1 && crv !== 'secp256k1') { - crv = 'secp256k1' - } - let privateKey, publicKey if (keyObjectSupported) { diff --git a/node_modules/jose/lib/jwk/key/oct.js b/node_modules/jose/lib/jwk/key/oct.js index f565638..9bb9567 100644 --- a/node_modules/jose/lib/jwk/key/oct.js +++ b/node_modules/jose/lib/jwk/key/oct.js @@ -2,18 +2,13 @@ const { randomBytes } = require('crypto') const { createSecretKey } = require('../../help/key_object') const base64url = require('../../help/base64url') -const { KEYOBJECT } = require('../../help/consts') const { THUMBPRINT_MATERIAL, PUBLIC_MEMBERS, PRIVATE_MEMBERS, - KEY_MANAGEMENT_DECRYPT, KEY_MANAGEMENT_ENCRYPT + KEY_MANAGEMENT_DECRYPT, KEY_MANAGEMENT_ENCRYPT, KEYOBJECT } = require('../../help/consts') const Key = require('./base') -const ENC_ALGS = new Set(['A128CBC-HS256', 'A128GCM', 'A192CBC-HS384', 'A192GCM', 'A256CBC-HS512', 'A256GCM']) -const ENC_LEN = new Set([128, 192, 256, 384, 512]) -const WRAP_LEN = new Set([128, 192, 256]) - const OCT_PUBLIC = new Set() Object.freeze(OCT_PUBLIC) const OCT_PRIVATE = new Set(['k']) @@ -70,72 +65,23 @@ class OctKey extends Key { return { k: this.k, kty: 'oct' } } - algorithms (operation, /* second argument is private API */ { use = this.use, alg = this.alg, key_ops: ops = this.key_ops } = {}) { - if (!this[KEYOBJECT]) { - return new Set() - } + [KEY_MANAGEMENT_ENCRYPT] () { + return new Set([ + ...this.algorithms('wrapKey'), + ...this.algorithms('deriveKey') + ]) + } - if (operation === KEY_MANAGEMENT_ENCRYPT || operation === KEY_MANAGEMENT_DECRYPT) { - return new Set([ - ...this.algorithms('wrapKey'), - ...this.algorithms('deriveKey') - ]) - } + [KEY_MANAGEMENT_DECRYPT] () { + return this[KEY_MANAGEMENT_ENCRYPT]() + } - if (operation && ops && !ops.includes(operation)) { + algorithms (...args) { + if (!this[KEYOBJECT]) { return new Set() } - if (alg) { - return new Set(this.algorithms(operation, { alg: null }).has(alg) ? [alg] : undefined) - } - - switch (operation) { - case 'deriveKey': - if (use === 'sig' || 'electron' in process.versions) { - return new Set() - } - - return new Set(['PBES2-HS256+A128KW', 'PBES2-HS384+A192KW', 'PBES2-HS512+A256KW']) - case 'encrypt': - case 'decrypt': - if (this.use === 'sig' || !ENC_LEN.has(this.length)) { - return new Set() - } - - return new Set([`A${this.length / 2}CBC-HS${this.length}`, `A${this.length}GCM`].filter(a => ENC_ALGS.has(a))) - case 'sign': - case 'verify': - if (use === 'enc') { - return new Set() - } - - return new Set(['HS256', 'HS384', 'HS512']) - case 'wrapKey': - case 'unwrapKey': - if (use === 'sig' || !WRAP_LEN.has(this.length)) { - return new Set() - } - - if ('electron' in process.versions) { - return new Set([`A${this.length}GCMKW`]) - } - - return new Set([`A${this.length}KW`, `A${this.length}GCMKW`]) - case undefined: - return new Set([ - // just the ops needed to return all algs regardless of its use - symmetric keys - ...this.algorithms('encrypt'), - ...this.algorithms('decrypt'), - ...this.algorithms('sign'), - ...this.algorithms('verify'), - ...this.algorithms('wrapKey'), - ...this.algorithms('unwrapKey'), - ...this.algorithms('deriveKey') - ]) - default: - throw new TypeError('invalid key operation') - } + return Key.prototype.algorithms.call(this, ...args) } static async generate (...args) { diff --git a/node_modules/jose/lib/jwk/key/okp.js b/node_modules/jose/lib/jwk/key/okp.js index 61662f7..4c12d2a 100644 --- a/node_modules/jose/lib/jwk/key/okp.js +++ b/node_modules/jose/lib/jwk/key/okp.js @@ -3,8 +3,9 @@ const { promisify } = require('util') const { THUMBPRINT_MATERIAL, JWK_MEMBERS, PUBLIC_MEMBERS, - PRIVATE_MEMBERS, KEY_MANAGEMENT_DECRYPT, KEY_MANAGEMENT_ENCRYPT, OKP_CURVES + PRIVATE_MEMBERS, KEY_MANAGEMENT_DECRYPT, KEY_MANAGEMENT_ENCRYPT } = require('../../help/consts') +const { OKP_CURVES } = require('../../registry') const { edDSASupported } = require('../../help/runtime_support') const errors = require('../../errors') @@ -21,14 +22,11 @@ Object.freeze(OKP_PRIVATE) class OKPKey extends Key { constructor (...args) { super(...args) - - Object.defineProperties(this, { - kty: { - value: 'OKP', - enumerable: true - } - }) this[JWK_MEMBERS]() + Object.defineProperty(this, 'kty', { value: 'OKP', enumerable: true }) + if (!OKP_CURVES.has(this.crv)) { + throw new errors.JOSENotSupported('unsupported OKP key curve') + } } static get [PUBLIC_MEMBERS] () { @@ -45,58 +43,15 @@ class OKPKey extends Key { return { crv: this.crv, kty: 'OKP', x: this.x } } - algorithms (operation, /* second argument is private API */ { use = this.use, alg = this.alg, key_ops: ops = this.key_ops } = {}) { - if (alg) { - return new Set(this.algorithms(operation, { alg: null }).has(alg) ? [alg] : undefined) - } - - if (operation === KEY_MANAGEMENT_ENCRYPT) { - operation = 'deriveKey' - } else if (operation === KEY_MANAGEMENT_DECRYPT) { - if (this.public) { - return new Set() - } - operation = 'deriveKey' - } + [KEY_MANAGEMENT_ENCRYPT] () { + return this.algorithms('deriveKey') + } - if (operation && ops && !ops.includes(operation)) { + [KEY_MANAGEMENT_DECRYPT] () { + if (this.public) { return new Set() } - - switch (operation) { - case 'wrapKey': - case 'unwrapKey': - case 'encrypt': - case 'decrypt': - return new Set() - case 'sign': - if (this.public || use === 'enc' || this.crv.startsWith('X')) { - return new Set() - } - - return new Set(['EdDSA']) - case 'verify': - if (use === 'enc' || this.crv.startsWith('X')) { - return new Set() - } - - return new Set(['EdDSA']) - case 'deriveKey': - if (use === 'sig' || this.crv.startsWith('Ed')) { - return new Set() - } - - // return new Set(ECDH_ALGS) - return new Set() - case undefined: - return new Set([ - ...this.algorithms('sign'), - ...this.algorithms('verify'), - ...this.algorithms('deriveKey') - ]) - default: - throw new TypeError('invalid key operation') - } + return this.algorithms('deriveKey') } static async generate (crv = 'Ed25519', privat = true) { diff --git a/node_modules/jose/lib/jwk/key/rsa.js b/node_modules/jose/lib/jwk/key/rsa.js index 02cfda1..210441c 100644 --- a/node_modules/jose/lib/jwk/key/rsa.js +++ b/node_modules/jose/lib/jwk/key/rsa.js @@ -5,53 +5,18 @@ const { THUMBPRINT_MATERIAL, JWK_MEMBERS, PUBLIC_MEMBERS, PRIVATE_MEMBERS, KEY_MANAGEMENT_DECRYPT, KEY_MANAGEMENT_ENCRYPT } = require('../../help/consts') -const { oaepHashSupported, keyObjectSupported } = require('../../help/runtime_support') +const { keyObjectSupported } = require('../../help/runtime_support') const { createPublicKey, createPrivateKey } = require('../../help/key_object') const Key = require('./base') const generateKeyPair = promisify(async) -const SIG_ALGS = ['PS256', 'RS256', 'PS384', 'RS384', 'PS512', 'RS512'] -const WRAP_ALGS = ['RSA-OAEP', 'RSA1_5'] - -if (oaepHashSupported) { - WRAP_ALGS.splice(1, 0, 'RSA-OAEP-256') -} - const RSA_PUBLIC = new Set(['e', 'n']) 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(SIG_ALGS) - 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) => { - switch (true) { - case length >= 784: - return new Set(WRAP_ALGS) - case length >= 592: - return new Set(['RSA-OAEP', 'RSA1_5']) - default: - return new Set(['RSA1_5']) - } -} - // RSA Key Type class RSAKey extends Key { constructor (...args) { @@ -90,61 +55,12 @@ class RSAKey extends Key { return { e: this.e, kty: 'RSA', n: this.n } } - algorithms (operation, /* second argument is private API */ { use = this.use, alg = this.alg, key_ops: ops = this.key_ops } = {}) { - if (alg) { - return new Set(this.algorithms(operation, { alg: null }).has(alg) ? [alg] : undefined) - } - - if (operation === KEY_MANAGEMENT_ENCRYPT) { - operation = 'wrapKey' - } else if (operation === KEY_MANAGEMENT_DECRYPT) { - operation = 'unwrapKey' - } - - if (operation && ops && !ops.includes(operation)) { - return new Set() - } + [KEY_MANAGEMENT_ENCRYPT] () { + return this.algorithms('wrapKey') + } - switch (operation) { - case 'deriveKey': - case 'encrypt': - case 'decrypt': - return new Set() - case 'sign': - if (this.public || use === 'enc') { - return new Set() - } - - return sigAlgsAvailableFor(this.length) - case 'verify': - if (use === 'enc') { - return new Set() - } - - return sigAlgsAvailableFor(this.length) - case 'wrapKey': - if (use === 'sig') { - return new Set() - } - - return wrapAlgsAvailableFor(this.length) - case 'unwrapKey': - if (this.public || use === 'sig') { - return new Set() - } - - return wrapAlgsAvailableFor(this.length) - case undefined: - // just the ops needed to return all algs regardless of its use - return new Set([ - ...this.algorithms('sign'), - ...this.algorithms('verify'), - ...this.algorithms('wrapKey'), - ...this.algorithms('unwrapKey') - ]) - default: - throw new TypeError('invalid key operation') - } + [KEY_MANAGEMENT_DECRYPT] () { + return this.algorithms('unwrapKey') } static async generate (len = 2048, privat = true) { diff --git a/node_modules/jose/lib/jwk/key/secp256k1_crv.js b/node_modules/jose/lib/jwk/key/secp256k1_crv.js deleted file mode 100644 index 4dc4d2d..0000000 --- a/node_modules/jose/lib/jwk/key/secp256k1_crv.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - name: 'secp256k1', - rename (value) { - module.exports.name = value - } -} diff --git a/node_modules/jose/lib/jwks/keystore.js b/node_modules/jose/lib/jwks/keystore.js index b6ee1ae..1af0349 100644 --- a/node_modules/jose/lib/jwks/keystore.js +++ b/node_modules/jose/lib/jwks/keystore.js @@ -1,30 +1,17 @@ -const { deprecate, inspect } = require('util') +const { inspect } = require('util') const isObject = require('../help/is_object') const { generate, generateSync } = require('../jwk/generate') -const Key = require('../jwk/key/base') -const importKey = require('../jwk/import') const { USES_MAPPING } = require('../help/consts') +const { isKey, asKey: importKey } = require('../jwk') -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++ } @@ -36,49 +23,42 @@ const keyscore = (key, { alg, kid, use, ops, x5t, x5t256 }) => { return score } -const map = new WeakMap() - -const i = (ctx) => { - if (!map.has(ctx)) { - map.set(ctx, {}) - } - return map.get(ctx) -} - class KeyStore { constructor (...keys) { while (keys.some(Array.isArray)) { - keys = keys.flat ? keys.flat() : keys.reduce((acc, val) => { - if (Array.isArray(val)) { - return [...acc, ...val] - } + keys = keys.flat + ? keys.flat() + : keys.reduce((acc, val) => { + if (Array.isArray(val)) { + return [...acc, ...val] + } - acc.push(val) - return acc - }, []) + acc.push(val) + return acc + }, []) } - if (keys.some(k => !(k instanceof Key))) { - throw new TypeError('all keys must be an instances of a key instantiated by JWK.asKey') + if (keys.some(k => !isKey(k) || !k.kty)) { + throw new TypeError('all keys must be instances of a key instantiated by JWK.asKey') } - i(this).keys = new Set(keys) + this._keys = new Set(keys) } - all ({ alg, kid, use, kty, key_ops: ops, x5t, 'x5t#S256': x5t256 } = {}) { + all ({ alg, kid, thumbprint, 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 } - return [...i(this).keys] + const search = { alg, use, ops } + return [...this._keys] .filter((key) => { let candidate = true - if (alg !== undefined && !key.algorithms().has(alg)) { + if (candidate && kid !== undefined && key.kid !== kid) { candidate = false } - if (candidate && kid !== undefined && key.kid !== kid) { + if (candidate && thumbprint !== undefined && key.thumbprint !== thumbprint) { candidate = false } @@ -94,10 +74,19 @@ 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 } + // TODO: if (candidate && ops !== undefined && (key.key_ops !== undefined || key.use !== undefined)) { let keyOps if (key.key_ops) { @@ -120,39 +109,39 @@ class KeyStore { } add (key) { - if (!(key instanceof Key)) { + if (!isKey(key) || !key.kty) { throw new TypeError('key must be an instance of a key instantiated by JWK.asKey') } - i(this).keys.add(key) + this._keys.add(key) } remove (key) { - if (!(key instanceof Key)) { + if (!isKey(key)) { throw new TypeError('key must be an instance of a key instantiated by JWK.asKey') } - i(this).keys.delete(key) + this._keys.delete(key) } toJWKS (priv = false) { return { - keys: [...i(this).keys.values()].map( + keys: [...this._keys.values()].map( key => key.toJWK(priv && (key.private || (key.secret && key.k))) ) } } async generate (...args) { - i(this).keys.add(await generate(...args)) + this._keys.add(await generate(...args)) } generateSync (...args) { - i(this).keys.add(generateSync(...args)) + this._keys.add(generateSync(...args)) } get size () { - return i(this).keys.size + return this._keys.size } /* c8 ignore next 8 */ @@ -166,7 +155,7 @@ class KeyStore { } * [Symbol.iterator] () { - for (const key of i(this).keys) { + for (const key of this._keys) { yield key } } @@ -184,15 +173,11 @@ function asKeyStore (jwks, { ignoreErrors = false, calculateMissingRSAPrimes = f if (!ignoreErrors) { throw err } + return undefined } }).filter(Boolean) return new KeyStore(...keys) } -Object.defineProperty(KeyStore, 'fromJWKS', { - value: deprecate(jwks => asKeyStore(jwks, { calculateMissingRSAPrimes: true }), 'JWKS.KeyStore.fromJWKS() is deprecated, use JWKS.asKeyStore() instead'), - enumerable: false -}) - module.exports = { KeyStore, asKeyStore } diff --git a/node_modules/jose/lib/jws/index.js b/node_modules/jose/lib/jws/index.js index ba1fe74..3b0662f 100644 --- a/node_modules/jose/lib/jws/index.js +++ b/node_modules/jose/lib/jws/index.js @@ -1,10 +1,10 @@ const Sign = require('./sign') -const verify = require('./verify') +const { verify } = require('./verify') const single = (serialization, payload, key, protectedHeader, unprotectedHeader) => { - const jws = new Sign(payload) - jws.recipient(key, protectedHeader, unprotectedHeader) - return jws.sign(serialization) + return new Sign(payload) + .recipient(key, protectedHeader, unprotectedHeader) + .sign(serialization) } module.exports.Sign = Sign diff --git a/node_modules/jose/lib/jws/serializers.js b/node_modules/jose/lib/jws/serializers.js index b42ecf5..fee5303 100644 --- a/node_modules/jose/lib/jws/serializers.js +++ b/node_modules/jose/lib/jws/serializers.js @@ -44,13 +44,24 @@ const generalSerializer = (payload, recipients) => { } } generalSerializer.validate = (jws, recipients) => { + let validateB64 = false recipients.forEach(({ protectedHeader, unprotectedHeader }) => { + if (protectedHeader && !validateB64 && 'b64' in protectedHeader) { + validateB64 = true + } validateCrit(protectedHeader, unprotectedHeader, protectedHeader ? protectedHeader.crit : undefined) }) + + if (validateB64) { + const values = recipients.map(({ protectedHeader }) => protectedHeader && protectedHeader.b64) + if (!values.every((actual, i, [expected]) => actual === expected)) { + throw new JWSInvalid('the "b64" Header Parameter value MUST be the same for all recipients') + } + } } const isJSON = (input) => { - return isObject(input) && typeof input.payload === 'string' + return isObject(input) && (typeof input.payload === 'string' || Buffer.isBuffer(input.payload)) } const isValidRecipient = (recipient) => { diff --git a/node_modules/jose/lib/jws/sign.js b/node_modules/jose/lib/jws/sign.js index d7c8adf..d809fd5 100644 --- a/node_modules/jose/lib/jws/sign.js +++ b/node_modules/jose/lib/jws/sign.js @@ -2,46 +2,36 @@ const base64url = require('../help/base64url') const isDisjoint = require('../help/is_disjoint') const isObject = require('../help/is_object') const deepClone = require('../help/deep_clone') -const Key = require('../jwk/key/base') const { JWSInvalid } = require('../errors') -const { check, sign } = require('../jwa') +const { sign } = require('../jwa') +const getKey = require('../help/get_key') const serializers = require('./serializers') const PROCESS_RECIPIENT = Symbol('PROCESS_RECIPIENT') -const map = new WeakMap() - -const i = (ctx) => { - if (!map.has(ctx)) { - map.set(ctx, {}) - } - return map.get(ctx) -} - class Sign { constructor (payload) { if (typeof payload === 'string') { payload = base64url.encode(payload) } else if (Buffer.isBuffer(payload)) { payload = base64url.encodeBuffer(payload) + this._binary = true } else if (isObject(payload)) { payload = base64url.JSON.encode(payload) } else { throw new TypeError('payload argument must be a Buffer, string or an object') } - i(this).payload = payload - i(this).recipients = [] + this._payload = payload + this._recipients = [] } /* * @public */ recipient (key, protectedHeader, unprotectedHeader) { - if (!(key instanceof Key)) { - throw new TypeError('key must be an instance of a key instantiated by JWK.asKey') - } + key = getKey(key) if (protectedHeader !== undefined && !isObject(protectedHeader)) { throw new TypeError('protectedHeader argument must be a plain object when provided') @@ -55,7 +45,7 @@ class Sign { throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint') } - i(this).recipients.push({ + this._recipients.push({ key, protectedHeader: protectedHeader ? deepClone(protectedHeader) : undefined, unprotectedHeader: unprotectedHeader ? deepClone(unprotectedHeader) : undefined @@ -67,9 +57,13 @@ class Sign { /* * @private */ - [PROCESS_RECIPIENT] (recipient) { + [PROCESS_RECIPIENT] (recipient, first) { const { key, protectedHeader, unprotectedHeader } = recipient + if (key.use === 'enc') { + throw new TypeError('a key with "use":"enc" is not usable for signing') + } + const joseHeader = { protected: protectedHeader || {}, unprotected: unprotectedHeader || {} @@ -77,10 +71,8 @@ class Sign { let alg = joseHeader.protected.alg || joseHeader.unprotected.alg - if (alg) { - check(key, 'sign', alg) - } else { - alg = [...key.algorithms('sign')][0] + if (!alg) { + alg = key.alg || [...key.algorithms('sign')][0] if (recipient.protectedHeader) { joseHeader.protected.alg = recipient.protectedHeader.alg = alg } else { @@ -92,20 +84,24 @@ class Sign { throw new JWSInvalid('could not resolve a usable "alg" for a recipient') } - if (joseHeader.protected.crit && joseHeader.protected.crit.includes('b64')) { - if (i(this).b64 !== undefined && i(this).b64 !== joseHeader.protected.b64) { - throw new JWSInvalid('the "b64" Header Parameter value MUST be the same for all recipients') + recipient.header = unprotectedHeader + recipient.protected = Object.keys(joseHeader.protected).length ? base64url.JSON.encode(joseHeader.protected) : '' + + if (first && joseHeader.protected.crit && joseHeader.protected.crit.includes('b64') && joseHeader.protected.b64 === false) { + if (this._binary) { + this._payload = base64url.decodeToBuffer(this._payload) } else { - i(this).b64 = joseHeader.protected.b64 - } - if (!joseHeader.protected.b64) { - i(this).payload = base64url.decode(i(this).payload) + this._payload = base64url.decode(this._payload) } } - recipient.header = unprotectedHeader - recipient.protected = Object.keys(joseHeader.protected).length ? base64url.JSON.encode(joseHeader.protected) : '' - recipient.signature = base64url.encodeBuffer(sign(alg, key, Buffer.from(`${recipient.protected}.${i(this).payload}`))) + const data = Buffer.concat([ + Buffer.from(recipient.protected || ''), + Buffer.from('.'), + Buffer.from(this._payload) + ]) + + recipient.signature = base64url.encodeBuffer(sign(alg, key, data)) } /* @@ -117,15 +113,17 @@ class Sign { throw new TypeError('serialization must be one of "compact", "flattened", "general"') } - if (!i(this).recipients.length) { + if (!this._recipients.length) { throw new JWSInvalid('missing recipients') } - serializer.validate(this, i(this).recipients) + serializer.validate(this, this._recipients) - i(this).recipients.forEach(this[PROCESS_RECIPIENT].bind(this)) + this._recipients.forEach((recipient, i) => { + this[PROCESS_RECIPIENT](recipient, i === 0) + }) - return serializer(i(this).payload, i(this).recipients) + return serializer(this._payload, this._recipients) } } diff --git a/node_modules/jose/lib/jws/verify.js b/node_modules/jose/lib/jws/verify.js index 823a277..6fadecc 100644 --- a/node_modules/jose/lib/jws/verify.js +++ b/node_modules/jose/lib/jws/verify.js @@ -1,23 +1,25 @@ +const { EOL } = require('os') + const base64url = require('../help/base64url') const isDisjoint = require('../help/is_disjoint') +const isObject = require('../help/is_object') let validateCrit = require('../help/validate_crit') +const getKey = require('../help/get_key') const { KeyStore } = require('../jwks') -const Key = require('../jwk/key/base') const errors = require('../errors') const { check, verify } = require('../jwa') +const JWK = require('../jwk') const { detect: resolveSerialization } = require('./serializers') validateCrit = validateCrit.bind(undefined, errors.JWSInvalid) -const SINGLE_RECIPIENT = new Set(['compact', 'flattened']) +const SINGLE_RECIPIENT = new Set(['compact', 'flattened', 'preparsed']) /* * @public */ const jwsVerify = (skipDisjointCheck, serialization, jws, key, { crit = [], complete = false, algorithms } = {}) => { - if (!(key instanceof Key) && !(key instanceof KeyStore)) { - throw new TypeError('key must be an instance of a key instantiated by JWK.asKey or a JWKS.KeyStore') - } + key = getKey(key, true) if (algorithms !== undefined && (!Array.isArray(algorithms) || algorithms.some(s => typeof s !== 'string' || !s))) { throw new TypeError('"algorithms" option must be an array of non-empty strings') @@ -31,8 +33,6 @@ const jwsVerify = (skipDisjointCheck, serialization, jws, key, { crit = [], comp if (!serialization) { serialization = resolveSerialization(jws) - } else if (serialization !== resolveSerialization(jws)) { - throw new errors.JWSInvalid() } let prot // protected header @@ -49,26 +49,35 @@ const jwsVerify = (skipDisjointCheck, serialization, jws, key, { crit = [], comp jws = { ...root, ...signatures[0] } } + let decoded + if (SINGLE_RECIPIENT.has(serialization)) { - if (serialization === 'compact') { // compact serialization format - ([prot, payload, signature] = jws.split('.')) - } else { // flattened serialization format - ({ protected: prot, payload, signature, header } = jws) + let parsedProt = {} + + switch (serialization) { + case 'compact': // compact serialization format + ([prot, payload, signature] = jws.split('.')) + break + case 'flattened': // flattened serialization format + ({ protected: prot, payload, signature, header } = jws) + break + case 'preparsed': { // from the JWT module + ({ decoded } = jws); + ([prot, payload, signature] = jws.token.split('.')) + break + } } if (!header) { skipDisjointCheck = true } - let parsedProt = {} - if (prot) { + if (decoded) { + parsedProt = decoded.header + } else if (prot) { try { parsedProt = base64url.JSON.decode(prot) } catch (err) { - if (err instanceof errors.JOSEError) { - throw err - } - throw new errors.JWSInvalid('could not parse JWS protected header') } } else { @@ -120,14 +129,40 @@ const jwsVerify = (skipDisjointCheck, serialization, jws, key, { crit = [], comp } } + if (key === JWK.EmbeddedJWK) { + if (!isObject(combinedHeader.jwk)) { + throw new errors.JWSInvalid('JWS Header Parameter "jwk" must be a JSON object') + } + key = JWK.asKey(combinedHeader.jwk) + if (key.type !== 'public') { + throw new errors.JWSInvalid('JWS Header Parameter "jwk" must be a public key') + } + } else if (key === JWK.EmbeddedX5C) { + if (!Array.isArray(combinedHeader.x5c) || !combinedHeader.x5c.length || combinedHeader.x5c.some(c => typeof c !== 'string' || !c)) { + throw new errors.JWSInvalid('JWS Header Parameter "x5c" must be a JSON array of certificate value strings') + } + key = JWK.asKey( + `-----BEGIN CERTIFICATE-----${EOL}${(combinedHeader.x5c[0].match(/.{1,64}/g) || []).join(EOL)}${EOL}-----END CERTIFICATE-----`, + { x5c: combinedHeader.x5c } + ) + } + check(key, 'verify', alg) - if (!verify(alg, key, Buffer.from([prot, payload].join('.')), base64url.decodeToBuffer(signature))) { + const toBeVerified = Buffer.concat([ + Buffer.from(prot || ''), + Buffer.from('.'), + Buffer.isBuffer(payload) ? payload : Buffer.from(payload) + ]) + + if (!verify(alg, key, toBeVerified, base64url.decodeToBuffer(signature))) { throw new errors.JWSVerificationFailed() } - if (!combinedHeader.crit || !combinedHeader.crit.includes('b64') || combinedHeader.b64) { - payload = base64url.JSON.decode.try(payload) + if (combinedHeader.b64 === false) { + payload = Buffer.from(payload) + } else { + payload = base64url.decodeToBuffer(payload) } if (complete) { @@ -161,4 +196,7 @@ const jwsVerify = (skipDisjointCheck, serialization, jws, key, { crit = [], comp throw multi } -module.exports = jwsVerify.bind(undefined, false, undefined) +module.exports = { + bare: jwsVerify, + verify: jwsVerify.bind(undefined, false, undefined) +} diff --git a/node_modules/jose/lib/jwt/decode.js b/node_modules/jose/lib/jwt/decode.js index 7bfb85f..022266f 100644 --- a/node_modules/jose/lib/jwt/decode.js +++ b/node_modules/jose/lib/jwt/decode.js @@ -9,7 +9,7 @@ module.exports = (token, { complete = false } = {}) => { const { 0: header, 1: payload, 2: signature, length } = token.split('.') if (length === 5) { - throw new TypeError('JWTs must be decrypted first') + throw new TypeError('encrypted JWTs cannot be decoded') } if (length !== 3) { @@ -25,10 +25,6 @@ module.exports = (token, { complete = false } = {}) => { return complete ? result : result.payload } catch (err) { - if (err instanceof errors.JOSEError) { - throw err - } - throw new errors.JWTMalformed('JWT is malformed') } } diff --git a/node_modules/jose/lib/jwt/index.js b/node_modules/jose/lib/jwt/index.js index 953b686..84d24c3 100644 --- a/node_modules/jose/lib/jwt/index.js +++ b/node_modules/jose/lib/jwt/index.js @@ -1,9 +1,16 @@ const decode = require('./decode') const sign = require('./sign') const verify = require('./verify') +const profiles = require('./profiles') module.exports = { - decode, sign, - verify + verify, + ...profiles } + +Object.defineProperty(module.exports, 'decode', { + enumerable: false, + configurable: true, + value: decode +}) diff --git a/node_modules/jose/lib/jwt/shared_validations.js b/node_modules/jose/lib/jwt/shared_validations.js index 099a64b..fffc4ee 100644 --- a/node_modules/jose/lib/jwt/shared_validations.js +++ b/node_modules/jose/lib/jwt/shared_validations.js @@ -1,12 +1,45 @@ +const { JWTClaimInvalid } = require('../errors') + const isNotString = val => typeof val !== 'string' || val.length === 0 +const isNotArrayOfStrings = val => !Array.isArray(val) || val.length === 0 || val.some(isNotString) +const isRequired = (Err, value, label, claim) => { + if (value === undefined) { + throw new Err(`${label} is missing`, claim, 'missing') + } +} +const isString = (Err, value, label, claim, required = false) => { + if (required) { + isRequired(Err, value, label, claim) + } -module.exports.isNotString = isNotString -module.exports.isString = function isString (Err, value, label, required = false) { + if (value !== undefined && isNotString(value)) { + throw new Err(`${label} must be a string`, claim, 'invalid') + } +} +const isTimestamp = (value, label, required = false) => { if (required && value === undefined) { - throw new Err(`${label} is missing`) + throw new JWTClaimInvalid(`"${label}" claim is missing`, label, 'missing') } - if (value !== undefined && isNotString(value)) { - throw new Err(`${label} must be a string`) + if (value !== undefined && (typeof value !== 'number')) { + throw new JWTClaimInvalid(`"${label}" claim must be a JSON numeric value`, label, 'invalid') } } +const isStringOrArrayOfStrings = (value, label, required = false) => { + if (required && value === undefined) { + throw new JWTClaimInvalid(`"${label}" claim is missing`, label, 'missing') + } + + if (value !== undefined && (isNotString(value) && isNotArrayOfStrings(value))) { + throw new JWTClaimInvalid(`"${label}" claim must be a string or array of strings`, label, 'invalid') + } +} + +module.exports = { + isNotArrayOfStrings, + isRequired, + isNotString, + isString, + isTimestamp, + isStringOrArrayOfStrings +} diff --git a/node_modules/jose/lib/jwt/sign.js b/node_modules/jose/lib/jwt/sign.js index d1104b5..5f3416a 100644 --- a/node_modules/jose/lib/jwt/sign.js +++ b/node_modules/jose/lib/jwt/sign.js @@ -1,6 +1,7 @@ const isObject = require('../help/is_object') const secs = require('../help/secs') const epoch = require('../help/epoch') +const getKey = require('../help/get_key') const JWS = require('../jws') const isString = require('./shared_validations').isString.bind(undefined, TypeError) @@ -27,7 +28,7 @@ const validateOptions = (options) => { throw new TypeError('options.audience must be a string or an array of strings') } - if (options.header !== undefined && !isObject(options.header)) { + if (!isObject(options.header)) { throw new TypeError('options.header must be an object') } @@ -35,9 +36,8 @@ const validateOptions = (options) => { isString(options.expiresIn, 'options.expiresIn') isString(options.notBefore, 'options.notBefore') isString(options.jti, 'options.jti') - isString(options.nonce, 'options.nonce') - if (!(options.now instanceof Date) || !options.now.getTime()) { + if (options.now !== undefined && (!(options.now instanceof Date) || !options.now.getTime())) { throw new TypeError('options.now must be a valid Date object') } } @@ -49,18 +49,21 @@ module.exports = (payload, key, options = {}) => { const { algorithm, audience, expiresIn, header = {}, iat = true, - issuer, jti, kid = true, nonce, notBefore, subject, now = new Date() + issuer, jti, kid = true, notBefore, subject, now } = options validateOptions({ - algorithm, audience, expiresIn, header, iat, issuer, jti, kid, nonce, notBefore, now, subject + algorithm, audience, expiresIn, header, iat, issuer, jti, kid, notBefore, now, subject }) if (!isObject(payload)) { throw new TypeError('payload must be an object') } - const unix = epoch(now) + let unix + if (expiresIn || notBefore || iat) { + unix = epoch(now || new Date()) + } payload = { ...payload, @@ -69,14 +72,23 @@ module.exports = (payload, key, options = {}) => { iss: issuer || payload.iss, jti: jti || payload.jti, iat: iat ? unix : payload.iat, - nonce: nonce || payload.nonce, exp: expiresIn ? unix + secs(expiresIn) : payload.exp, nbf: notBefore ? unix + secs(notBefore) : payload.nbf } - return JWS.sign(payload, key, { + key = getKey(key) + + let includeKid + + if (typeof options.kid === 'boolean') { + includeKid = kid + } else { + includeKid = !key.secret + } + + return JWS.sign(JSON.stringify(payload), key, { ...header, alg: algorithm || header.alg, - kid: kid ? key.kid : header.kid + kid: includeKid ? key.kid : header.kid }) } diff --git a/node_modules/jose/lib/jwt/verify.js b/node_modules/jose/lib/jwt/verify.js index 0cdb5fc..db34160 100644 --- a/node_modules/jose/lib/jwt/verify.js +++ b/node_modules/jose/lib/jwt/verify.js @@ -1,117 +1,104 @@ const isObject = require('../help/is_object') const epoch = require('../help/epoch') const secs = require('../help/secs') -const JWS = require('../jws') -const { KeyStore } = require('../jwks') -const { JWTClaimInvalid } = require('../errors') - -const { isString, isNotString } = require('./shared_validations') +const getKey = require('../help/get_key') +const { bare: verify } = require('../jws/verify') +const { JWTClaimInvalid, JWTExpired } = require('../errors') + +const { + isString, + isNotString, + isNotArrayOfStrings, + isTimestamp, + isStringOrArrayOfStrings +} = require('./shared_validations') const decode = require('./decode') const isPayloadString = isString.bind(undefined, JWTClaimInvalid) const isOptionString = isString.bind(undefined, TypeError) -const isTimestamp = (value, label, required = false) => { - if (required && value === undefined) { - throw new JWTClaimInvalid(`"${label}" claim is missing`) - } - - if (value !== undefined && (typeof value !== 'number' || !Number.isSafeInteger(value))) { - throw new JWTClaimInvalid(`"${label}" claim must be a unix timestamp`) - } -} - -const isStringOrArrayOfStrings = (value, label, required = false) => { - if (required && value === undefined) { - throw new JWTClaimInvalid(`"${label}" claim is missing`) - } - - if (value !== undefined && (isNotString(value) && isNotArrayOfStrings(value))) { - throw new JWTClaimInvalid(`"${label}" claim must be a string or array of strings`) - } -} - -const isNotArrayOfStrings = val => !Array.isArray(val) || val.length === 0 || val.some(isNotString) - -const validateOptions = (options) => { - isOptionString(options.profile, 'options.profile') +const normalizeTyp = (value) => value.toLowerCase().replace(/^application\//, '') - if (typeof options.complete !== 'boolean') { +const validateOptions = ({ + algorithms, audience, clockTolerance, complete = false, crit, ignoreExp = false, + ignoreIat = false, ignoreNbf = false, issuer, jti, maxTokenAge, now = new Date(), + subject, typ +}) => { + if (typeof complete !== 'boolean') { throw new TypeError('options.complete must be a boolean') } - if (typeof options.ignoreExp !== 'boolean') { + if (typeof ignoreExp !== 'boolean') { throw new TypeError('options.ignoreExp must be a boolean') } - if (typeof options.ignoreNbf !== 'boolean') { + if (typeof ignoreNbf !== 'boolean') { throw new TypeError('options.ignoreNbf must be a boolean') } - if (typeof options.ignoreIat !== 'boolean') { + if (typeof ignoreIat !== 'boolean') { throw new TypeError('options.ignoreIat must be a boolean') } - isOptionString(options.maxTokenAge, 'options.maxTokenAge') - isOptionString(options.subject, 'options.subject') - isOptionString(options.issuer, 'options.issuer') - isOptionString(options.maxAuthAge, 'options.maxAuthAge') - isOptionString(options.jti, 'options.jti') - isOptionString(options.clockTolerance, 'options.clockTolerance') + isOptionString(maxTokenAge, 'options.maxTokenAge') + isOptionString(subject, 'options.subject') + isOptionString(jti, 'options.jti') + isOptionString(clockTolerance, 'options.clockTolerance') + isOptionString(typ, 'options.typ') - if (options.audience !== undefined && (isNotString(options.audience) && isNotArrayOfStrings(options.audience))) { + if (issuer !== undefined && (isNotString(issuer) && isNotArrayOfStrings(issuer))) { + throw new TypeError('options.issuer must be a string or an array of strings') + } + + if (audience !== undefined && (isNotString(audience) && isNotArrayOfStrings(audience))) { throw new TypeError('options.audience must be a string or an array of strings') } - if (options.algorithms !== undefined && isNotArrayOfStrings(options.algorithms)) { + if (algorithms !== undefined && isNotArrayOfStrings(algorithms)) { throw new TypeError('options.algorithms must be an array of strings') } - isOptionString(options.nonce, 'options.nonce') - - if (!(options.now instanceof Date) || !options.now.getTime()) { + if (!(now instanceof Date) || !now.getTime()) { throw new TypeError('options.now must be a valid Date object') } - if (options.ignoreIat && options.maxTokenAge !== undefined) { + if (ignoreIat && maxTokenAge !== undefined) { throw new TypeError('options.ignoreIat and options.maxTokenAge cannot used together') } - if (options.crit !== undefined && isNotArrayOfStrings(options.crit)) { + if (crit !== undefined && isNotArrayOfStrings(crit)) { throw new TypeError('options.crit must be an array of strings') } - switch (options.profile) { - case 'id_token': - if (!options.issuer) { - throw new TypeError('"issuer" option is required to validate an ID Token') - } - - if (!options.audience) { - throw new TypeError('"audience" option is required to validate an ID Token') - } - - break - case undefined: - break - default: - throw new TypeError(`unsupported options.profile value "${options.profile}"`) + return { + algorithms, + audience, + clockTolerance, + complete, + crit, + ignoreExp, + ignoreIat, + ignoreNbf, + issuer, + jti, + maxTokenAge, + now, + subject, + typ } } -const validatePayloadTypes = (payload, profile) => { - isTimestamp(payload.iat, 'iat', profile === 'id_token') - isTimestamp(payload.exp, 'exp', profile === 'id_token') - isTimestamp(payload.auth_time, 'auth_time') +const validateTypes = ({ header, payload }, options) => { + isPayloadString(header.alg, '"alg" header parameter', 'alg', true) + + isTimestamp(payload.iat, 'iat', !!options.maxTokenAge) + isTimestamp(payload.exp, 'exp') isTimestamp(payload.nbf, 'nbf') - isPayloadString(payload.jti, '"jti" claim') - isPayloadString(payload.acr, '"acr" claim') - isPayloadString(payload.nonce, '"nonce" claim') - isPayloadString(payload.iss, '"iss" claim', profile === 'id_token') - isPayloadString(payload.sub, '"sub" claim', profile === 'id_token') - isStringOrArrayOfStrings(payload.aud, 'aud', profile === 'id_token') - isPayloadString(payload.azp, '"azp" claim', profile === 'id_token' && Array.isArray(payload.aud) && payload.aud.length > 1) - isStringOrArrayOfStrings(payload.amr, 'amr') + isPayloadString(payload.jti, '"jti" claim', 'jti', !!options.jti) + isStringOrArrayOfStrings(payload.iss, 'iss', !!options.issuer) + isPayloadString(payload.sub, '"sub" claim', 'sub', !!options.subject) + isStringOrArrayOfStrings(payload.aud, 'aud', !!options.audience) + isPayloadString(header.typ, '"typ" header parameter', 'typ', !!options.typ) } const checkAudiencePresence = (audPayload, audOption) => { @@ -119,6 +106,8 @@ const checkAudiencePresence = (audPayload, audOption) => { return audOption.includes(audPayload) } + // Each principal intended to process the JWT MUST + // identify itself with a value in the audience claim audPayload = new Set(audPayload) return audOption.some(Set.prototype.has.bind(audPayload)) } @@ -129,99 +118,69 @@ module.exports = (token, key, options = {}) => { } const { - algorithms, audience, clockTolerance, complete = false, crit, ignoreExp = false, - ignoreIat = false, ignoreNbf = false, issuer, jti, maxAuthAge, maxTokenAge, nonce, now = new Date(), - subject, profile - } = options - - validateOptions({ - algorithms, - audience, - clockTolerance, - complete, - crit, - ignoreExp, - ignoreIat, - ignoreNbf, - issuer, - jti, - maxAuthAge, - maxTokenAge, - nonce, - now, - profile, - subject - }) - - const unix = epoch(now) + algorithms, audience, clockTolerance, complete, crit, ignoreExp, ignoreIat, ignoreNbf, issuer, + jti, maxTokenAge, now, subject, typ + } = options = validateOptions(options) const decoded = decode(token, { complete: true }) - validatePayloadTypes(decoded.payload, profile) + key = getKey(key, true) - if (issuer && decoded.payload.iss !== issuer) { - throw new JWTClaimInvalid('issuer mismatch') + if (complete) { + ({ key } = verify(true, 'preparsed', { decoded, token }, key, { crit, algorithms, complete: true })) + decoded.key = key + } else { + verify(true, 'preparsed', { decoded, token }, key, { crit, algorithms }) } - if (nonce && decoded.payload.nonce !== nonce) { - throw new JWTClaimInvalid('nonce mismatch') + const unix = epoch(now) + validateTypes(decoded, options) + + if (issuer && (typeof decoded.payload.iss !== 'string' || !(typeof issuer === 'string' ? [issuer] : issuer).includes(decoded.payload.iss))) { + throw new JWTClaimInvalid('unexpected "iss" claim value', 'iss', 'check_failed') } if (subject && decoded.payload.sub !== subject) { - throw new JWTClaimInvalid('subject mismatch') + throw new JWTClaimInvalid('unexpected "sub" claim value', 'sub', 'check_failed') } if (jti && decoded.payload.jti !== jti) { - throw new JWTClaimInvalid('jti mismatch') + throw new JWTClaimInvalid('unexpected "jti" claim value', 'jti', 'check_failed') } if (audience && !checkAudiencePresence(decoded.payload.aud, typeof audience === 'string' ? [audience] : audience)) { - throw new JWTClaimInvalid('audience mismatch') + throw new JWTClaimInvalid('unexpected "aud" claim value', 'aud', 'check_failed') } - const tolerance = clockTolerance ? secs(clockTolerance) : 0 - - if (maxAuthAge) { - if (!('auth_time' in decoded.payload)) { - throw new JWTClaimInvalid('missing auth_time') - } - - const maxAuthAgeSeconds = secs(maxAuthAge) - if (decoded.payload.auth_time + maxAuthAgeSeconds < unix - tolerance) { - throw new JWTClaimInvalid('too much time has elapsed since the last End-User authentication') - } + if (typ && normalizeTyp(decoded.header.typ) !== normalizeTyp(typ)) { + throw new JWTClaimInvalid('unexpected "typ" JWT header value', 'typ', 'check_failed') } - if (!ignoreIat && 'iat' in decoded.payload && decoded.payload.iat > unix + tolerance) { - throw new JWTClaimInvalid('token issued in the future') + const tolerance = clockTolerance ? secs(clockTolerance) : 0 + + if (!ignoreIat && !('exp' in decoded.payload) && 'iat' in decoded.payload && decoded.payload.iat > unix + tolerance) { + throw new JWTClaimInvalid('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed') } if (!ignoreNbf && 'nbf' in decoded.payload && decoded.payload.nbf > unix + tolerance) { - throw new JWTClaimInvalid('token is not active yet') + throw new JWTClaimInvalid('"nbf" claim timestamp check failed', 'nbf', 'check_failed') } if (!ignoreExp && 'exp' in decoded.payload && decoded.payload.exp <= unix - tolerance) { - throw new JWTClaimInvalid('token is expired') + throw new JWTExpired('"exp" claim timestamp check failed', 'exp', 'check_failed') } if (maxTokenAge) { - if (!('iat' in decoded.payload)) { - throw new JWTClaimInvalid('missing iat claim') - } + const age = unix - decoded.payload.iat + const max = secs(maxTokenAge) - if (decoded.payload.iat + secs(maxTokenAge) < unix + tolerance) { - throw new JWTClaimInvalid('maxTokenAge exceeded') + if (age - tolerance > max) { + throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', 'iat', 'check_failed') } - } - if (profile === 'id_token' && Array.isArray(decoded.payload.aud) && decoded.payload.aud.length > 1 && decoded.payload.azp !== audience) { - throw new JWTClaimInvalid('azp mismatch') - } - - if (complete && key instanceof KeyStore) { - ({ key } = JWS.verify(token, key, { crit, algorithms, complete: true })) - } else { - JWS.verify(token, key, { crit, algorithms }) + if (age < 0 - tolerance) { + throw new JWTClaimInvalid('"iat" claim timestamp check failed (it should be in the past)', 'iat', 'check_failed') + } } - return complete ? { ...decoded, key } : decoded.payload + return complete ? decoded : decoded.payload } diff --git a/node_modules/jose/package.json b/node_modules/jose/package.json index 0c2f6b5..131c064 100644 --- a/node_modules/jose/package.json +++ b/node_modules/jose/package.json @@ -1,13 +1,19 @@ { "name": "jose", - "version": "1.10.2", + "version": "2.0.7", "description": "JSON Web Almost Everything - JWA, JWS, JWE, JWK, JWT, JWKS for Node.js with minimal dependencies", "keywords": [ + "access token", + "access_token", "compact", "decode", "decrypt", + "detached", + "ec", + "ecdsa", "eddsa", "electron", + "embedded", "encrypt", "flattened", "general", @@ -22,26 +28,43 @@ "jwks", "jws", "jwt", + "logout token", + "logout_token", + "oct", + "okp", + "payload", + "rsa", "secp256k1", "sign", + "signature", "validate", "verify" ], "homepage": "https://github.com/panva/jose", "repository": "panva/jose", + "funding": "https://github.com/sponsors/panva", "license": "MIT", "author": "Filip Skokan ", + "exports": { + ".": { + "import": "./lib/index.mjs", + "require": "./lib/index.js" + }, + "./": "./" + }, + "main": "lib/index.js", + "types": "types/index.d.ts", "files": [ - "lib", + "lib/**/*.js", + "lib/**/*.mjs", "LICENSE_THIRD_PARTY", "types/index.d.ts" ], - "main": "lib/index.js", - "types": "types/index.d.ts", "scripts": { "coverage": "c8 ava", - "lint": "standard && dtslint types", + "lint": "standard", "lint-fix": "standard --fix", + "lint-ts": "npx typescript@~3.6.0 --build types", "test": "ava", "watch": "ava --watch" }, @@ -55,31 +78,66 @@ "@commitlint/config-conventional" ] }, + "ava": { + "babel": false, + "compileEnhancements": false, + "files": [ + "test/**/*.test.js" + ] + }, "dependencies": { - "asn1.js": "^5.2.0" + "@panva/asn1.js": "^1.0.0" }, "devDependencies": { - "@commitlint/cli": "^8.2.0", - "@commitlint/config-conventional": "^8.2.0", + "@commitlint/cli": "^11.0.0", + "@commitlint/config-conventional": "^11.0.0", "ava": "^2.4.0", - "babel-eslint": "^10.0.3", - "c8": "^6.0.1", - "dtslint": "^0.9.8", - "husky": "^3.0.7", - "standard": "^14.3.1", - "typescript": "^3.6.3" + "c8": "^7.3.5", + "husky": "^4.3.0", + "standard": "^16.0.0" }, "engines": { - "node": "^10.13.0 || >=12.0.0" + "node": ">=10.13.0 < 13 || >=13.7.0" }, - "ava": { - "babel": false, - "compileEnhancements": false, - "files": [ - "test/**/*.test.js" + "standard-version": { + "scripts": { + "postchangelog": "sed -i '' -e 's/### \\[/## [/g' CHANGELOG.md" + }, + "types": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "chore", + "hidden": true + }, + { + "type": "docs", + "hidden": true + }, + { + "type": "style", + "hidden": true + }, + { + "type": "refactor", + "section": "Refactor", + "hidden": true + }, + { + "type": "perf", + "section": "Performance", + "hidden": false + }, + { + "type": "test", + "hidden": true + } ] - }, - "standard": { - "parser": "babel-eslint" } } diff --git a/node_modules/jose/types/index.d.ts b/node_modules/jose/types/index.d.ts index 5d52635..ec33082 100644 --- a/node_modules/jose/types/index.d.ts +++ b/node_modules/jose/types/index.d.ts @@ -1,8 +1,6 @@ /// // TypeScript Version: 3.6 -/* tslint:disable:strict-export-declare-modifiers */ - import { KeyObject, PrivateKeyInput, PublicKeyInput } from 'crypto'; export type use = 'sig' | 'enc'; @@ -20,10 +18,19 @@ export interface KeyParameters extends BasicParameters { } export type ECCurve = 'P-256' | 'secp256k1' | 'P-384' | 'P-521'; export type OKPCurve = 'Ed25519' | 'Ed448' | 'X25519' | 'X448'; +export type Curves = OKPCurve | ECCurve; export type keyType = 'RSA' | 'EC' | 'OKP' | 'oct'; export type asymmetricKeyObjectTypes = 'private' | 'public'; export type keyObjectTypes = asymmetricKeyObjectTypes | 'secret'; -export type JWTProfiles = 'id_token'; +export type KeyInput = PrivateKeyInput | PublicKeyInput | string | Buffer; +export type ProduceKeyInput = JWK.Key | KeyObject | KeyInput | JWKOctKey | JWKRSAKey | JWKECKey | JWKOKPKey; +export type ConsumeKeyInput = ProduceKeyInput | JWKS.KeyStore; +export type NoneKey = JWK.NoneKey; +export type EmbeddedJWK = JWK.EmbeddedJWK; +export type EmbeddedX5C = JWK.EmbeddedX5C; +export type EmbeddedVerifyKeys = EmbeddedJWK | EmbeddedX5C; +export type ProduceKeyInputWithNone = ProduceKeyInput | NoneKey; +export type ConsumeKeyInputWithNone = ConsumeKeyInput | NoneKey; export interface JWKOctKey extends BasicParameters { // no x5c kty: 'oct'; @@ -74,77 +81,156 @@ export namespace JWK { passphrase?: string; } - class Key { - kty: keyType; - type: keyObjectTypes; - private: boolean; - public: boolean; - secret: boolean; - alg?: string; - use?: use; - key_ops?: keyOperation[]; - kid: string; - thumbprint: string; - x5c?: string[]; - x5t?: string; - 'x5t#S256'?: string; + interface Key { + readonly private: boolean; + readonly public: boolean; + readonly secret: boolean; + readonly type: keyObjectTypes; + + readonly kty: keyType; + readonly alg?: string; + readonly use?: use; + readonly key_ops?: ReadonlyArray; + readonly kid: string; + readonly thumbprint: string; + readonly x5c?: ReadonlyArray; + readonly x5t?: string; + readonly 'x5t#S256'?: string; + readonly keyObject: KeyObject; + + readonly crv?: ECCurve | OKPCurve; + readonly d?: string; + readonly dp?: string; + readonly dq?: string; + readonly e?: string; + readonly k?: string; + readonly n?: string; + readonly p?: string; + readonly q?: string; + readonly qi?: string; + readonly x?: string; + readonly y?: string; toPEM(private?: boolean, encoding?: pemEncodingOptions): string; algorithms(operation?: keyOperation): Set; } - class RSAKey extends Key { - kty: 'RSA'; - type: asymmetricKeyObjectTypes; - secret: false; - e: string; - n: string; - d?: string; - p?: string; - q?: string; - dp?: string; - dq?: string; - qi?: string; + interface RSAKey extends Key { + readonly secret: false; + readonly type: asymmetricKeyObjectTypes; + + readonly kty: 'RSA'; + + readonly e: string; + readonly n: string; + readonly d?: string; + readonly p?: string; + readonly q?: string; + readonly dp?: string; + readonly dq?: string; + readonly qi?: string; + + readonly crv: undefined; + readonly k: undefined; + readonly x: undefined; + readonly y: undefined; toJWK(private?: boolean): JWKRSAKey; } - class ECKey extends Key { - kty: 'EC'; - secret: false; - type: asymmetricKeyObjectTypes; - crv: ECCurve; - x: string; - y: string; - d?: string; + interface ECKey extends Key { + readonly secret: false; + readonly type: asymmetricKeyObjectTypes; + + readonly kty: 'EC'; + + readonly crv: ECCurve; + readonly x: string; + readonly y: string; + readonly d?: string; + + readonly dp: undefined; + readonly dq: undefined; + readonly e: undefined; + readonly k: undefined; + readonly n: undefined; + readonly p: undefined; + readonly q: undefined; + readonly qi: undefined; toJWK(private?: boolean): JWKECKey; } - class OKPKey extends Key { - kty: 'OKP'; - secret: false; - type: asymmetricKeyObjectTypes; - crv: OKPCurve; - x: string; - d?: string; + interface OKPKey extends Key { + readonly secret: false; + readonly type: asymmetricKeyObjectTypes; + + readonly kty: 'OKP'; + + readonly crv: OKPCurve; + readonly x: string; + readonly d?: string; + + readonly dp: undefined; + readonly dq: undefined; + readonly e: undefined; + readonly k: undefined; + readonly n: undefined; + readonly p: undefined; + readonly q: undefined; + readonly qi: undefined; + readonly y: undefined; toJWK(private?: boolean): JWKOKPKey; } - class OctKey extends Key { - kty: 'oct'; - type: 'secret'; - private: false; - public: false; - secret: true; - k?: string; + interface OctKey extends Key { + readonly private: false; + readonly public: false; + readonly secret: true; + readonly type: 'secret'; + + readonly kty: 'oct'; + + readonly k?: string; + + readonly crv: undefined; + readonly d: undefined; + readonly dp: undefined; + readonly dq: undefined; + readonly e: undefined; + readonly n: undefined; + readonly p: undefined; + readonly q: undefined; + readonly qi: undefined; + readonly x: undefined; + readonly y: undefined; toJWK(private?: boolean): JWKOctKey; } - type KeyInput = PrivateKeyInput | PublicKeyInput | string | Buffer; + interface NoneKey { + readonly type: 'unsecured'; + readonly alg: 'none'; + algorithms(operation?: keyOperation): Set; + } + + const None: NoneKey; + + interface EmbeddedJWK { + readonly type: 'embedded'; + algorithms(operation?: keyOperation): Set; + } + + const EmbeddedJWK: EmbeddedJWK; + + interface EmbeddedX5C { + readonly type: 'embedded'; + algorithms(operation?: keyOperation): Set; + } + + const EmbeddedX5C: EmbeddedX5C; function isKey(object: any): boolean; @@ -163,11 +249,13 @@ export namespace JWK { function importKey(jwk: JWKECKey): ECKey; function importKey(jwk: JWKOKPKey): OKPKey; + function generate(kty: keyType, crvOrSize?: Curves | number, parameters?: BasicParameters, private?: boolean): Promise; function generate(kty: 'EC', crv?: ECCurve, parameters?: BasicParameters, private?: boolean): Promise; function generate(kty: 'OKP', crv?: OKPCurve, parameters?: BasicParameters, private?: boolean): Promise; function generate(kty: 'RSA', bitlength?: number, parameters?: BasicParameters, private?: boolean): Promise; function generate(kty: 'oct', bitlength?: number, parameters?: BasicParameters): Promise; + function generateSync(kty: keyType, crvOrSize?: Curves | number, parameters?: BasicParameters, private?: boolean): JWK.Key; function generateSync(kty: 'EC', crv?: ECCurve, parameters?: BasicParameters, private?: boolean): ECKey; function generateSync(kty: 'OKP', crv?: OKPCurve, parameters?: BasicParameters, private?: boolean): OKPKey; function generateSync(kty: 'RSA', bitlength?: number, parameters?: BasicParameters, private?: boolean): RSAKey; @@ -179,12 +267,14 @@ export namespace JWKS { kty?: keyType; x5t?: string; 'x5t#S256'?: string; + crv?: string; + thumbprint?: string; } class KeyStore { constructor(keys?: JWK.Key[]); - size: number; + readonly size: number; add(key: JWK.Key): void; remove(key: JWK.Key): void; @@ -193,11 +283,13 @@ export namespace JWKS { toJWKS(private?: boolean): JSONWebKeySet; - generate(kty: 'EC', crv?: ECCurve, parameters?: BasicParameters, private?: boolean): void; - generate(kty: 'OKP', crv?: OKPCurve, parameters?: BasicParameters, private?: boolean): void; - generate(kty: 'RSA', bitlength?: number, parameters?: BasicParameters, private?: boolean): void; - generate(kty: 'oct', bitlength?: number, parameters?: BasicParameters): void; + generate(kty: keyType, crvOrSize?: Curves | number, parameters?: BasicParameters, private?: boolean): Promise; + generate(kty: 'EC', crv?: ECCurve, parameters?: BasicParameters, private?: boolean): Promise; + generate(kty: 'OKP', crv?: OKPCurve, parameters?: BasicParameters, private?: boolean): Promise; + generate(kty: 'RSA', bitlength?: number, parameters?: BasicParameters, private?: boolean): Promise; + generate(kty: 'oct', bitlength?: number, parameters?: BasicParameters): Promise; + generateSync(kty: keyType, crvOrSize?: Curves | number, parameters?: BasicParameters, private?: boolean): void; generateSync(kty: 'EC', crv?: ECCurve, parameters?: BasicParameters, private?: boolean): void; generateSync(kty: 'OKP', crv?: OKPCurve, parameters?: BasicParameters, private?: boolean): void; generateSync(kty: 'RSA', bitlength?: number, parameters?: BasicParameters, private?: boolean): void; @@ -218,7 +310,7 @@ export namespace JWKS { export namespace JWS { interface JWSJSON { - payload: string; + payload: string | Buffer; } interface JWSRecipient { @@ -236,34 +328,35 @@ export namespace JWS { class Sign { constructor(payload: string | Buffer | object); - recipient(key: JWK.Key, protected?: object, header?: object): void; + recipient(key: ProduceKeyInputWithNone, protected?: object, header?: object): void; sign(serialization: 'compact'): string; sign(serialization: 'flattened'): FlattenedJWS; sign(serialization: 'general'): GeneralJWS; } - function sign(payload: string | Buffer | object, key: JWK.Key, protected?: object): string; + function sign(payload: string | Buffer | object, key: ProduceKeyInputWithNone, protected?: object): string; namespace sign { - function flattened(payload: string | Buffer | object, key: JWK.Key, protected?: object, header?: object): FlattenedJWS; - function general(payload: string | Buffer | object, key: JWK.Key, protected?: object, header?: object): GeneralJWS; + function flattened(payload: string | Buffer | object, key: ProduceKeyInputWithNone, protected?: object, header?: object): FlattenedJWS; + function general(payload: string | Buffer | object, key: ProduceKeyInputWithNone, protected?: object, header?: object): GeneralJWS; } - interface VerifyOptions { - complete?: komplet; + interface VerifyOptions { + complete?: boolean; crit?: string[]; algorithms?: string[]; } - interface completeVerification { - payload: string | object; - key: JWK.Key; + interface completeVerification { + payload: Buffer; + key: T; protected?: object; header?: object; } - function verify(jws: string | FlattenedJWS | GeneralJWS, key: JWK.Key | JWKS.KeyStore, options?: VerifyOptions): string | object; - function verify(jws: string | FlattenedJWS | GeneralJWS, key: JWK.Key | JWKS.KeyStore, options?: VerifyOptions): completeVerification; + function verify(jws: string | FlattenedJWS | GeneralJWS, key: ConsumeKeyInput | EmbeddedVerifyKeys, options: VerifyOptions & { complete: true }): completeVerification; + function verify(jws: string | FlattenedJWS | GeneralJWS, key: NoneKey, options: VerifyOptions & { complete: true }): completeVerification; + function verify(jws: string | FlattenedJWS | GeneralJWS, key: ConsumeKeyInputWithNone | EmbeddedVerifyKeys, options?: VerifyOptions): Buffer; } export namespace JWE { @@ -288,75 +381,83 @@ export namespace JWE { } class Encrypt { - constructor(cleartext: string | Buffer, protected?: object, unprotected?: object, aad?: string); + constructor(cleartext: string | Buffer, protected?: object, aad?: string, unprotected?: object); - recipient(key: JWK.Key, header?: object): void; + recipient(key: ProduceKeyInput, header?: object): void; encrypt(serialization: 'compact'): string; encrypt(serialization: 'flattened'): FlattenedJWE; encrypt(serialization: 'general'): GeneralJWE; } - function encrypt(payload: string | Buffer, key: JWK.Key, protected?: object): string; + function encrypt(payload: string | Buffer, key: ProduceKeyInput, protected?: object): string; namespace encrypt { - function flattened(payload: string | Buffer, key: JWK.Key, protected?: object, header?: object, aad?: string): FlattenedJWE; - function general(payload: string | Buffer, key: JWK.Key, protected?: object, header?: object, aad?: string): GeneralJWE; + function flattened(payload: string | Buffer, key: ProduceKeyInput, protected?: object, aad?: string, header?: object): FlattenedJWE; + function general(payload: string | Buffer, key: ProduceKeyInput, protected?: object, aad?: string, header?: object): GeneralJWE; } - interface DecryptOptions { - complete?: komplet; + interface DecryptOptions { + complete?: boolean; crit?: string[]; - algorithms?: string[]; + contentEncryptionAlgorithms?: string[]; + keyManagementAlgorithms?: string[]; + maxPBES2Count?: number; + inflateRawSyncLimit?: number; } interface completeDecrypt { cleartext: Buffer; key: JWK.Key; + cek: JWK.OctKey; aad?: string; header?: object; unprotected?: object; protected?: object; } - function decrypt(jwe: string | FlattenedJWE | GeneralJWE, key: JWK.Key | JWKS.KeyStore, options?: DecryptOptions): Buffer; - function decrypt(jwe: string | FlattenedJWE | GeneralJWE, key: JWK.Key | JWKS.KeyStore, options?: DecryptOptions): completeDecrypt; + function decrypt(jwe: string | FlattenedJWE | GeneralJWE, key: ConsumeKeyInput, options: DecryptOptions & { complete: true }): completeDecrypt; + function decrypt(jwe: string | FlattenedJWE | GeneralJWE, key: ConsumeKeyInput, options?: DecryptOptions): Buffer; } export namespace JWT { - interface completeResult { + interface completeResult { payload: object; header: object; signature: string; - key: JWK.Key; + key: T; } - interface DecodeOptions { - complete?: komplet; + interface DecodeOptions { + complete?: boolean; } - function decode(jwt: string, options?: DecodeOptions): object; - function decode(jwt: string, options?: DecodeOptions): completeResult; + /** + * Decodes the JWT **without verifying the token**. For JWT verification/validation use + * `jose.JWT.verify`. + */ + function decode(jwt: string, options: DecodeOptions & { complete: true }): completeResult; + function decode(jwt: string, options?: DecodeOptions): object; - interface VerifyOptions { - complete?: komplet; + interface VerifyOptions { + complete?: boolean; ignoreExp?: boolean; ignoreNbf?: boolean; ignoreIat?: boolean; maxTokenAge?: string; subject?: string; - issuer?: string; - maxAuthAge?: string; + issuer?: string | string[]; jti?: string; clockTolerance?: string; audience?: string | string[]; algorithms?: string[]; - nonce?: string; + typ?: string; now?: Date; crit?: string[]; - profile?: JWTProfiles; } - function verify(jwt: string, key: JWK.Key | JWKS.KeyStore, options?: VerifyOptions): object; - function verify(jwt: string, key: JWK.Key | JWKS.KeyStore, options?: VerifyOptions): completeResult; + + function verify(jwt: string, key: NoneKey, options: VerifyOptions & { complete: true }): completeResult; + function verify(jwt: string, key: ConsumeKeyInput | EmbeddedVerifyKeys, options: VerifyOptions & { complete: true }): completeResult; + function verify(jwt: string, key: ConsumeKeyInputWithNone | EmbeddedVerifyKeys, options?: VerifyOptions): object; interface SignOptions { iat?: boolean; @@ -369,32 +470,76 @@ export namespace JWT { expiresIn?: string; notBefore?: string; jti?: string; - nonce?: string; now?: Date; } - function sign(payload: object, key: JWK.Key, options?: SignOptions): string; + + function sign(payload: object, key: ProduceKeyInputWithNone, options?: SignOptions): string; + + interface ProfiledVerifyOptions { + issuer: string | string[]; + audience: string | string[]; + } + + interface IdTokenVerifyOptions extends ProfiledVerifyOptions { + nonce?: string; + maxAuthAge?: string; + } + + interface AccessTokenVerifyOptions extends ProfiledVerifyOptions { + maxAuthAge?: string; + } + + interface LogoutTokenVerifyOptions extends ProfiledVerifyOptions {} + + namespace IdToken { + function verify(jwt: string, key: ConsumeKeyInput | EmbeddedVerifyKeys, options: VerifyOptions & { complete: true } & IdTokenVerifyOptions): completeResult; + function verify(jwt: string, key: NoneKey, options: VerifyOptions & { complete: true } & IdTokenVerifyOptions): completeResult; + function verify(jwt: string, key: ConsumeKeyInputWithNone | EmbeddedVerifyKeys, options: VerifyOptions & IdTokenVerifyOptions): object; + } + + namespace LogoutToken { + function verify(jwt: string, key: ConsumeKeyInput | EmbeddedVerifyKeys, options: VerifyOptions & { complete: true } & LogoutTokenVerifyOptions): completeResult; + function verify(jwt: string, key: NoneKey, options: VerifyOptions & { complete: true } & LogoutTokenVerifyOptions): completeResult; + function verify(jwt: string, key: ConsumeKeyInputWithNone | EmbeddedVerifyKeys, options: VerifyOptions & LogoutTokenVerifyOptions): object; + } + + namespace AccessToken { + function verify(jwt: string, key: ConsumeKeyInput | EmbeddedVerifyKeys, options: VerifyOptions & { complete: true } & AccessTokenVerifyOptions): completeResult; + function verify(jwt: string, key: NoneKey, options: VerifyOptions & { complete: true } & AccessTokenVerifyOptions): completeResult; + function verify(jwt: string, key: ConsumeKeyInputWithNone | EmbeddedVerifyKeys, options: VerifyOptions & AccessTokenVerifyOptions): object; + } } export namespace errors { - class JOSEError extends Error {} - class JOSEMultiError extends JOSEError {} + class JOSEError extends Error { + code: T; + } - class JOSEAlgNotWhitelisted extends JOSEError {} - class JOSECritNotUnderstood extends JOSEError {} - class JOSENotSupported extends JOSEError {} + class JOSEInvalidEncoding extends JOSEError<'ERR_JOSE_INVALID_ENCODING'> {} + class JOSEMultiError extends JOSEError<'ERR_JOSE_MULTIPLE_ERRORS'> {} - class JWEDecryptionFailed extends JOSEError {} - class JWEInvalid extends JOSEError {} + class JOSEAlgNotWhitelisted extends JOSEError<'ERR_JOSE_ALG_NOT_WHITELISTED'> {} + class JOSECritNotUnderstood extends JOSEError<'ERR_JOSE_CRIT_NOT_UNDERSTOOD'> {} + class JOSENotSupported extends JOSEError<'ERR_JOSE_NOT_SUPPORTED'> {} - class JWKImportFailed extends JOSEError {} - class JWKInvalid extends JOSEError {} - class JWKKeySupport extends JOSEError {} + class JWEDecryptionFailed extends JOSEError<'ERR_JWE_DECRYPTION_FAILED'> {} + class JWEInvalid extends JOSEError<'ERR_JWE_INVALID'> {} - class JWKSNoMatchingKey extends JOSEError {} + class JWKImportFailed extends JOSEError<'ERR_JWK_IMPORT_FAILED'> {} + class JWKInvalid extends JOSEError<'ERR_JWK_INVALID'> {} + class JWKKeySupport extends JOSEError<'ERR_JWK_KEY_SUPPORT'> {} - class JWSInvalid extends JOSEError {} - class JWSVerificationFailed extends JOSEError {} + class JWKSNoMatchingKey extends JOSEError<'ERR_JWKS_NO_MATCHING_KEY'> {} - class JWTClaimInvalid extends JOSEError {} - class JWTMalformed extends JOSEError {} + class JWSInvalid extends JOSEError<'ERR_JWS_INVALID'> {} + class JWSVerificationFailed extends JOSEError<'ERR_JWS_VERIFICATION_FAILED'> {} + + class JWTClaimInvalid extends JOSEError { + constructor(message?: string, claim?: string, reason?: string); + + claim: string; + reason: 'prohibited' | 'missing' | 'invalid' | 'check_failed' | 'unspecified'; + } + class JWTExpired extends JWTClaimInvalid<'ERR_JWT_EXPIRED'> {} + class JWTMalformed extends JOSEError<'ERR_JWT_MALFORMED'> {} } diff --git a/node_modules/minimalistic-assert/LICENSE b/node_modules/minimalistic-assert/LICENSE deleted file mode 100644 index adca66b..0000000 --- a/node_modules/minimalistic-assert/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2015 Calvin Metcalf - -Permission to use, copy, modify, and/or distribute this software for any purpose -with or without fee is hereby granted, provided that the above copyright notice -and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/node_modules/minimalistic-assert/index.js b/node_modules/minimalistic-assert/index.js deleted file mode 100644 index 70b4ea5..0000000 --- a/node_modules/minimalistic-assert/index.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = assert; - -function assert(val, msg) { - if (!val) - throw new Error(msg || 'Assertion failed'); -} - -assert.equal = function assertEqual(l, r, msg) { - if (l != r) - throw new Error(msg || ('Assertion failed: ' + l + ' != ' + r)); -}; diff --git a/node_modules/minimalistic-assert/package.json b/node_modules/minimalistic-assert/package.json deleted file mode 100644 index f8de10d..0000000 --- a/node_modules/minimalistic-assert/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "minimalistic-assert", - "version": "1.0.1", - "description": "minimalistic-assert ===", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "https://github.com/calvinmetcalf/minimalistic-assert.git" - }, - "author": "", - "license": "ISC", - "bugs": { - "url": "https://github.com/calvinmetcalf/minimalistic-assert/issues" - }, - "homepage": "https://github.com/calvinmetcalf/minimalistic-assert" -} diff --git a/node_modules/minimalistic-assert/readme.md b/node_modules/minimalistic-assert/readme.md deleted file mode 100644 index 2ca0d25..0000000 --- a/node_modules/minimalistic-assert/readme.md +++ /dev/null @@ -1,4 +0,0 @@ -minimalistic-assert -=== - -very minimalistic assert module. diff --git a/package-lock.json b/package-lock.json index ca72681..b8a7f6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "ISC", "dependencies": { "express": "^4.21.1", - "jose": "1.10", + "jose": "^2.0.7", "log4j": "^1.0.0" } }, @@ -32,6 +32,15 @@ "kuler": "^2.0.0" } }, + "node_modules/@panva/asn1.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", + "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", @@ -54,27 +63,11 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, - "node_modules/asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } - }, "node_modules/async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" }, - "node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" - }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -630,15 +623,18 @@ } }, "node_modules/jose": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/jose/-/jose-1.10.2.tgz", - "integrity": "sha512-xpH8tqepxOv1wlG5gwScZEJxbSPZKzIhPud7cvv1avNDexsF4zK3vCjKmMIs9Fs7Sgo46tcH3lXlwu2UiO/4Ew==", - "deprecated": "this version is no longer supported", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.7.tgz", + "integrity": "sha512-5hFWIigKqC+e/lRyQhfnirrAqUdIPMB7SJRqflJaO29dW7q5DFvH1XCSTmv6PQ6pb++0k6MJlLRoS0Wv4s38Wg==", + "license": "MIT", "dependencies": { - "asn1.js": "^5.2.0" + "@panva/asn1.js": "^1.0.0" }, "engines": { - "node": "^10.13.0 || >=12.0.0" + "node": ">=10.13.0 < 13 || >=13.7.0" + }, + "funding": { + "url": "https://github.com/sponsors/panva" } }, "node_modules/keygrip": { @@ -852,11 +848,6 @@ "node": ">= 0.6" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", diff --git a/package.json b/package.json index 54f1d4b..c56ce69 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "license": "ISC", "dependencies": { "express": "^4.21.1", - "jose": "1.10", + "jose": "^2.0.7", "log4j": "^1.0.0" } }