diff --git a/package-lock.json b/package-lock.json index b8f99878..86bb0252 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,6 @@ "name": "openpgp", "version": "6.0.0-alpha.0", "license": "LGPL-3.0+", - "dependencies": { - "asn1.js": "^5.0.0" - }, "devDependencies": { "@openpgp/asmcrypto.js": "^3.0.0", "@openpgp/jsdoc": "^3.6.11", @@ -28,10 +25,10 @@ "@types/chai": "^4.2.14", "argon2id": "^1.0.1", "benchmark": "^2.1.4", - "bn.js": "^4.11.8", "c8": "^8.0.1", "chai": "^4.3.7", "chai-as-promised": "^7.1.1", + "eckey-utils": "^0.7.14", "eslint": "^8.34.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-base": "^15.0.0", @@ -1775,16 +1772,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/asn1.js": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.0.0.tgz", - "integrity": "sha512-Y+FKviD0uyIWWo/xE0XkUl0x1allKFhzEVJ+//2Dgqpy+n+B77MlPNqvyk7Vx50M9XyVzjnRhDqJAEAsyivlbA==", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -1882,7 +1869,8 @@ "node_modules/bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true }, "node_modules/body-parser": { "version": "1.19.2", @@ -2683,6 +2671,12 @@ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, + "node_modules/eckey-utils": { + "version": "0.7.14", + "resolved": "https://registry.npmjs.org/eckey-utils/-/eckey-utils-0.7.14.tgz", + "integrity": "sha512-s/mENS+mMnJjDSydy0muBQQHMTWJ1nPe8EiphANZrf+lv/1u35aP9WvWHTWqCBJ21blNIurGF7UoLjtaOpoCFw==", + "dev": true + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4147,7 +4141,8 @@ "node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "node_modules/internal-slot": { "version": "1.0.3", @@ -5216,11 +5211,6 @@ "node": ">=4" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", - "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=" - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -8589,16 +8579,6 @@ "es-shim-unscopables": "^1.0.0" } }, - "asn1.js": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.0.0.tgz", - "integrity": "sha512-Y+FKviD0uyIWWo/xE0XkUl0x1allKFhzEVJ+//2Dgqpy+n+B77MlPNqvyk7Vx50M9XyVzjnRhDqJAEAsyivlbA==", - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -8681,7 +8661,8 @@ "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true }, "body-parser": { "version": "1.19.2", @@ -9292,6 +9273,12 @@ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, + "eckey-utils": { + "version": "0.7.14", + "resolved": "https://registry.npmjs.org/eckey-utils/-/eckey-utils-0.7.14.tgz", + "integrity": "sha512-s/mENS+mMnJjDSydy0muBQQHMTWJ1nPe8EiphANZrf+lv/1u35aP9WvWHTWqCBJ21blNIurGF7UoLjtaOpoCFw==", + "dev": true + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -10420,7 +10407,8 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "internal-slot": { "version": "1.0.3", @@ -11255,11 +11243,6 @@ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true }, - "minimalistic-assert": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", - "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=" - }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", diff --git a/package.json b/package.json index d370f10e..3f203334 100644 --- a/package.json +++ b/package.json @@ -78,10 +78,10 @@ "@types/chai": "^4.2.14", "argon2id": "^1.0.1", "benchmark": "^2.1.4", - "bn.js": "^4.11.8", "c8": "^8.0.1", "chai": "^4.3.7", "chai-as-promised": "^7.1.1", + "eckey-utils": "^0.7.14", "eslint": "^8.34.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-base": "^15.0.0", @@ -106,9 +106,6 @@ "typescript": "^5.3.3", "web-streams-polyfill": "^3.2.0" }, - "dependencies": { - "asn1.js": "^5.0.0" - }, "repository": { "type": "git", "url": "https://github.com/openpgpjs/openpgpjs" diff --git a/rollup.config.js b/rollup.config.js index 22a1b6c5..c29e0e51 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -14,7 +14,7 @@ import { wasm } from '@rollup/plugin-wasm'; // import pkg from './package.json' assert { type: 'json' }; const pkg = JSON.parse(readFileSync('./package.json')); -const nodeDependencies = Object.keys(pkg.dependencies); +const nodeDependencies = Object.keys(pkg.dependencies || {}); const nodeBuiltinModules = builtinModules.concat(['module']); const wasmOptions = { diff --git a/src/crypto/public_key/elliptic/ecdsa.js b/src/crypto/public_key/elliptic/ecdsa.js index 44d63755..f7ac7d50 100644 --- a/src/crypto/public_key/elliptic/ecdsa.js +++ b/src/crypto/public_key/elliptic/ecdsa.js @@ -24,7 +24,7 @@ import enums from '../../../enums'; import util from '../../../util'; import { getRandomBytes } from '../../random'; import hash from '../../hash'; -import { CurveWithOID, webCurves, privateToJWK, rawPublicToJWK, validateStandardParams } from './oid_curves'; +import { CurveWithOID, webCurves, privateToJWK, rawPublicToJWK, validateStandardParams, nodeCurves } from './oid_curves'; const webCrypto = util.getWebCrypto(); const nodeCrypto = util.getNodeCrypto(); @@ -63,13 +63,8 @@ export async function sign(oid, hashAlgo, message, publicKey, privateKey, hashed util.printDebugError('Browser did not support signing: ' + err.message); } break; - case 'node': { - const signature = await nodeSign(curve, hashAlgo, message, keyPair); - return { - r: signature.r.toArrayLike(Uint8Array), - s: signature.s.toArrayLike(Uint8Array) - }; - } + case 'node': + return nodeSign(curve, hashAlgo, message, privateKey); } } @@ -247,85 +242,45 @@ async function webVerify(curve, hashAlgo, { r, s }, message, publicKey) { ); } -async function nodeSign(curve, hashAlgo, message, keyPair) { +async function nodeSign(curve, hashAlgo, message, privateKey) { + // JWT encoding cannot be used for now, as Brainpool curves are not supported + const ecKeyUtils = util.nodeRequire('eckey-utils'); + const nodeBuffer = util.getNodeBuffer(); + const { privateKey: derPrivateKey } = ecKeyUtils.generateDer({ + curveName: nodeCurves[curve.name], + privateKey: nodeBuffer.from(privateKey) + }); + const sign = nodeCrypto.createSign(enums.read(enums.hash, hashAlgo)); sign.write(message); sign.end(); - const key = ECPrivateKey.encode({ - version: 1, - parameters: curve.oid, - privateKey: Array.from(keyPair.privateKey), - publicKey: { unused: 0, data: Array.from(keyPair.publicKey) } - }, 'pem', { - label: 'EC PRIVATE KEY' - }); - return ECDSASignature.decode(sign.sign(key), 'der'); + const signature = new Uint8Array(sign.sign({ key: derPrivateKey, format: 'der', type: 'sec1', dsaEncoding: 'ieee-p1363' })); + const len = curve.payloadSize; + + return { + r: signature.slice(0, len), + s: signature.slice(len, len << 1) + }; } async function nodeVerify(curve, hashAlgo, { r, s }, message, publicKey) { - const { default: BN } = await import('bn.js'); + const ecKeyUtils = util.nodeRequire('eckey-utils'); + const nodeBuffer = util.getNodeBuffer(); + const { publicKey: derPublicKey } = ecKeyUtils.generateDer({ + curveName: nodeCurves[curve.name], + publicKey: nodeBuffer.from(publicKey) + }); const verify = nodeCrypto.createVerify(enums.read(enums.hash, hashAlgo)); verify.write(message); verify.end(); - const key = SubjectPublicKeyInfo.encode({ - algorithm: { - algorithm: [1, 2, 840, 10045, 2, 1], - parameters: curve.oid - }, - subjectPublicKey: { unused: 0, data: Array.from(publicKey) } - }, 'pem', { - label: 'PUBLIC KEY' - }); - const signature = ECDSASignature.encode({ - r: new BN(r), s: new BN(s) - }, 'der'); + + const signature = util.concatUint8Array([r, s]); try { - return verify.verify(key, signature); + return verify.verify({ key: derPublicKey, format: 'der', type: 'spki', dsaEncoding: 'ieee-p1363' }, signature); } catch (err) { return false; } } - -// Originally written by Owen Smith https://github.com/omsmith -// Adapted on Feb 2018 from https://github.com/Brightspace/node-jwk-to-pem/ - -/* eslint-disable no-invalid-this */ - -const asn1 = nodeCrypto ? util.nodeRequire('asn1.js') : undefined; - -const ECDSASignature = nodeCrypto ? - asn1.define('ECDSASignature', function() { - this.seq().obj( - this.key('r').int(), - this.key('s').int() - ); - }) : undefined; - -const ECPrivateKey = nodeCrypto ? - asn1.define('ECPrivateKey', function() { - this.seq().obj( - this.key('version').int(), - this.key('privateKey').octstr(), - this.key('parameters').explicit(0).optional().any(), - this.key('publicKey').explicit(1).optional().bitstr() - ); - }) : undefined; - -const AlgorithmIdentifier = nodeCrypto ? - asn1.define('AlgorithmIdentifier', function() { - this.seq().obj( - this.key('algorithm').objid(), - this.key('parameters').optional().any() - ); - }) : undefined; - -const SubjectPublicKeyInfo = nodeCrypto ? - asn1.define('SubjectPublicKeyInfo', function() { - this.seq().obj( - this.key('algorithm').use(AlgorithmIdentifier), - this.key('subjectPublicKey').bitstr() - ); - }) : undefined;