Browse Source

make Prettier v2

main
AJ ONeal 4 years ago
parent
commit
b1df7af626
  1. 8
      .prettierrc
  2. 12
      bin/eckles.js
  3. 12
      bin/rasha.js
  4. 26
      ecdsa.js
  5. 66
      keypairs.js
  6. 6
      lib/browser/ecdsa.js
  7. 16
      lib/browser/keypairs.js
  8. 6
      lib/browser/rsa.js
  9. 2
      lib/browser/sha2.js
  10. 16
      lib/node/ecdsa.js
  11. 2
      lib/node/generate-privkey-forge.js
  12. 2
      lib/node/generate-privkey-node.js
  13. 7
      lib/node/generate-privkey-ursa.js
  14. 2
      lib/node/generate-privkey.js
  15. 13
      lib/node/keypairs.js
  16. 12
      lib/node/rsa.js
  17. 9
      lib/node/sha2.js
  18. 26
      rsa.js
  19. 50
      tests/index.js

8
.prettierrc

@ -0,0 +1,8 @@
{
"bracketSpacing": true,
"printWidth": 80,
"singleQuote": true,
"tabWidth": 4,
"trailingComma": "none",
"useTabs": true
}

12
bin/eckles.js

@ -23,7 +23,7 @@ if (
namedCurve: format === 'P-384' ? 'P-384' : 'P-256', namedCurve: format === 'P-384' ? 'P-384' : 'P-256',
encoding: format === 'der' ? 'der' : 'pem' encoding: format === 'der' ? 'der' : 'pem'
}) })
.then(function(key) { .then(function (key) {
if ('der' === infile || 'der' === format) { if ('der' === infile || 'der' === format) {
key.private = key.private.toString('binary'); key.private = key.private.toString('binary');
key.public = key.public.toString('binary'); key.public = key.public.toString('binary');
@ -31,7 +31,7 @@ if (
console.log(key.private); console.log(key.private);
console.log(key.public); console.log(key.public);
}) })
.catch(function(err) { .catch(function (err) {
console.error(err); console.error(err);
process.exit(1); process.exit(1);
}); });
@ -58,10 +58,10 @@ if ('string' === typeof key) {
} }
var pub = -1 !== ['public', 'spki', 'pkix'].indexOf(format); var pub = -1 !== ['public', 'spki', 'pkix'].indexOf(format);
Eckles.import({ pem: key, public: pub || format }) Eckles.import({ pem: key, public: pub || format })
.then(function(jwk) { .then(function (jwk) {
console.log(JSON.stringify(jwk, null, 2)); console.log(JSON.stringify(jwk, null, 2));
}) })
.catch(function(err) { .catch(function (err) {
console.error(err); console.error(err);
process.exit(1); process.exit(1);
}); });
@ -71,10 +71,10 @@ if ('string' === typeof key) {
return; return;
} }
Eckles.export({ jwk: key, format: format }) Eckles.export({ jwk: key, format: format })
.then(function(pem) { .then(function (pem) {
console.log(pem); console.log(pem);
}) })
.catch(function(err) { .catch(function (err) {
console.error(err); console.error(err);
process.exit(2); process.exit(2);
}); });

12
bin/rasha.js

@ -29,7 +29,7 @@ if (
modulusLength: parseInt(format, 10) || 2048, modulusLength: parseInt(format, 10) || 2048,
encoding: parseInt(format, 10) ? null : format encoding: parseInt(format, 10) ? null : format
}) })
.then(function(key) { .then(function (key) {
if ('der' === infile || 'der' === format) { if ('der' === infile || 'der' === format) {
key.private = key.private.toString('binary'); key.private = key.private.toString('binary');
key.public = key.public.toString('binary'); key.public = key.public.toString('binary');
@ -37,7 +37,7 @@ if (
console.info(key.private); console.info(key.private);
console.info(key.public); console.info(key.public);
}) })
.catch(function(err) { .catch(function (err) {
console.error(err); console.error(err);
process.exit(1); process.exit(1);
}); });
@ -74,10 +74,10 @@ if ('string' === typeof key) {
var pub = -1 !== ['public', 'spki', 'pkix'].indexOf(format); var pub = -1 !== ['public', 'spki', 'pkix'].indexOf(format);
Rasha.import({ pem: key, public: pub || format }) Rasha.import({ pem: key, public: pub || format })
.then(function(jwk) { .then(function (jwk) {
console.info(JSON.stringify(jwk, null, 2)); console.info(JSON.stringify(jwk, null, 2));
}) })
.catch(function(err) { .catch(function (err) {
console.error(err); console.error(err);
process.exit(1); process.exit(1);
}); });
@ -87,14 +87,14 @@ if ('string' === typeof key) {
return; return;
} }
Rasha.export({ jwk: key, format: format }) Rasha.export({ jwk: key, format: format })
.then(function(pem) { .then(function (pem) {
if (sign) { if (sign) {
signMessage(pem, msg); signMessage(pem, msg);
return; return;
} }
console.info(pem); console.info(pem);
}) })
.catch(function(err) { .catch(function (err) {
console.error(err); console.error(err);
process.exit(2); process.exit(2);
}); });

26
ecdsa.js

@ -29,8 +29,8 @@ EC._universal =
'Bluecrypt only supports crypto with standard cross-browser and cross-platform support.'; 'Bluecrypt only supports crypto with standard cross-browser and cross-platform support.';
EC.generate = native.generate; EC.generate = native.generate;
EC.export = function(opts) { EC.export = function (opts) {
return Promise.resolve().then(function() { return Promise.resolve().then(function () {
if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) { if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) {
throw new Error('must pass { jwk: jwk } as a JSON object'); throw new Error('must pass { jwk: jwk } as a JSON object');
} }
@ -109,8 +109,8 @@ EC.export = function(opts) {
}; };
native.export = EC.export; native.export = EC.export;
EC.import = function(opts) { EC.import = function (opts) {
return Promise.resolve().then(function() { return Promise.resolve().then(function () {
if (!opts || !opts.pem || 'string' !== typeof opts.pem) { if (!opts || !opts.pem || 'string' !== typeof opts.pem) {
throw new Error('must pass { pem: pem } as a string'); throw new Error('must pass { pem: pem } as a string');
} }
@ -178,18 +178,18 @@ EC.import = function(opts) {
}; };
native.import = EC.import; native.import = EC.import;
EC.pack = function(opts) { EC.pack = function (opts) {
return Promise.resolve().then(function() { return Promise.resolve().then(function () {
return EC.export(opts); return EC.export(opts);
}); });
}; };
// Chopping off the private parts is now part of the public API. // Chopping off the private parts is now part of the public API.
// I thought it sounded a little too crude at first, but it really is the best name in every possible way. // I thought it sounded a little too crude at first, but it really is the best name in every possible way.
EC.neuter = function(opts) { EC.neuter = function (opts) {
// trying to find the best balance of an immutable copy with custom attributes // trying to find the best balance of an immutable copy with custom attributes
var jwk = {}; var jwk = {};
Object.keys(opts.jwk).forEach(function(k) { Object.keys(opts.jwk).forEach(function (k) {
if ('undefined' === typeof opts.jwk[k]) { if ('undefined' === typeof opts.jwk[k]) {
return; return;
} }
@ -204,7 +204,7 @@ EC.neuter = function(opts) {
native.neuter = EC.neuter; native.neuter = EC.neuter;
// https://stackoverflow.com/questions/42588786/how-to-fingerprint-a-jwk // https://stackoverflow.com/questions/42588786/how-to-fingerprint-a-jwk
EC.__thumbprint = function(jwk) { EC.__thumbprint = function (jwk) {
// Use the same entropy for SHA as for key // Use the same entropy for SHA as for key
var alg = 'SHA-256'; var alg = 'SHA-256';
if (/384/.test(jwk.crv)) { if (/384/.test(jwk.crv)) {
@ -218,20 +218,20 @@ EC.__thumbprint = function(jwk) {
'","y":"' + '","y":"' +
jwk.y + jwk.y +
'"}'; '"}';
return sha2.sum(alg, payload).then(function(hash) { return sha2.sum(alg, payload).then(function (hash) {
return Enc.bufToUrlBase64(Uint8Array.from(hash)); return Enc.bufToUrlBase64(Uint8Array.from(hash));
}); });
}; };
EC.thumbprint = function(opts) { EC.thumbprint = function (opts) {
return Promise.resolve().then(function() { return Promise.resolve().then(function () {
var jwk; var jwk;
if ('EC' === opts.kty) { if ('EC' === opts.kty) {
jwk = opts; jwk = opts;
} else if (opts.jwk) { } else if (opts.jwk) {
jwk = opts.jwk; jwk = opts.jwk;
} else { } else {
return native.import(opts).then(function(jwk) { return native.import(opts).then(function (jwk) {
return EC.__thumbprint(jwk); return EC.__thumbprint(jwk);
}); });
} }

66
keypairs.js

@ -9,7 +9,7 @@ var Rasha = require('./rsa.js');
var Eckles = require('./ecdsa.js'); var Eckles = require('./ecdsa.js');
var native = require('./lib/node/keypairs.js'); var native = require('./lib/node/keypairs.js');
Keypairs.parse = function(opts) { Keypairs.parse = function (opts) {
opts = opts || {}; opts = opts || {};
var err; var err;
@ -21,7 +21,7 @@ Keypairs.parse = function(opts) {
try { try {
jwk = JSON.parse(opts.key); jwk = JSON.parse(opts.key);
p = Keypairs.export({ jwk: jwk }) p = Keypairs.export({ jwk: jwk })
.catch(function(e) { .catch(function (e) {
pem = opts.key; pem = opts.key;
err = new Error( err = new Error(
"Not a valid jwk '" + "Not a valid jwk '" +
@ -32,11 +32,11 @@ Keypairs.parse = function(opts) {
err.code = 'EINVALID'; err.code = 'EINVALID';
return Promise.reject(err); return Promise.reject(err);
}) })
.then(function() { .then(function () {
return jwk; return jwk;
}); });
} catch (e) { } catch (e) {
p = Keypairs.import({ pem: opts.key }).catch(function(e) { p = Keypairs.import({ pem: opts.key }).catch(function (e) {
err = new Error( err = new Error(
'Could not parse key (type ' + 'Could not parse key (type ' +
typeof opts.key + typeof opts.key +
@ -53,10 +53,10 @@ Keypairs.parse = function(opts) {
p = Promise.resolve(opts.key); p = Promise.resolve(opts.key);
} }
return p.then(function(jwk) { return p.then(function (jwk) {
var pubopts = JSON.parse(JSON.stringify(opts)); var pubopts = JSON.parse(JSON.stringify(opts));
pubopts.jwk = jwk; pubopts.jwk = jwk;
return Keypairs.publish(pubopts).then(function(pub) { return Keypairs.publish(pubopts).then(function (pub) {
// 'd' happens to be the name of a private part of both RSA and ECDSA keys // 'd' happens to be the name of a private part of both RSA and ECDSA keys
if (opts.public || opts.publish || !jwk.d) { if (opts.public || opts.publish || !jwk.d) {
if (opts.private) { if (opts.private) {
@ -75,13 +75,13 @@ Keypairs.parse = function(opts) {
}); });
}; };
Keypairs.parseOrGenerate = function(opts) { Keypairs.parseOrGenerate = function (opts) {
if (!opts.key) { if (!opts.key) {
return Keypairs.generate(opts); return Keypairs.generate(opts);
} }
opts.private = true; opts.private = true;
return Keypairs.parse(opts).catch(function(e) { return Keypairs.parse(opts).catch(function (e) {
return Keypairs.generate(opts).then(function(pair) { return Keypairs.generate(opts).then(function (pair) {
pair.parseError = e; pair.parseError = e;
return pair; return pair;
}); });
@ -93,7 +93,7 @@ Keypairs._stance =
" properly and securely use non-standard crypto then you shouldn't need Bluecrypt anyway."; " properly and securely use non-standard crypto then you shouldn't need Bluecrypt anyway.";
Keypairs._universal = Keypairs._universal =
'Bluecrypt only supports crypto with standard cross-browser and cross-platform support.'; 'Bluecrypt only supports crypto with standard cross-browser and cross-platform support.';
Keypairs.generate = function(opts) { Keypairs.generate = function (opts) {
opts = opts || {}; opts = opts || {};
var p; var p;
if (!opts.kty) { if (!opts.kty) {
@ -117,8 +117,8 @@ Keypairs.generate = function(opts) {
) )
); );
} }
return p.then(function(pair) { return p.then(function (pair) {
return Keypairs.thumbprint({ jwk: pair.public }).then(function(thumb) { return Keypairs.thumbprint({ jwk: pair.public }).then(function (thumb) {
pair.private.kid = thumb; // maybe not the same id on the private key? pair.private.kid = thumb; // maybe not the same id on the private key?
pair.public.kid = thumb; pair.public.kid = thumb;
return pair; return pair;
@ -126,22 +126,22 @@ Keypairs.generate = function(opts) {
}); });
}; };
Keypairs.import = function(opts) { Keypairs.import = function (opts) {
return Eckles.import(opts) return Eckles.import(opts)
.catch(function() { .catch(function () {
return Rasha.import(opts); return Rasha.import(opts);
}) })
.then(function(jwk) { .then(function (jwk) {
return Keypairs.thumbprint({ jwk: jwk }).then(function(thumb) { return Keypairs.thumbprint({ jwk: jwk }).then(function (thumb) {
jwk.kid = thumb; jwk.kid = thumb;
return jwk; return jwk;
}); });
}); });
}; };
Keypairs.export = function(opts) { Keypairs.export = function (opts) {
return Eckles.export(opts).catch(function(err) { return Eckles.export(opts).catch(function (err) {
return Rasha.export(opts).catch(function() { return Rasha.export(opts).catch(function () {
return Promise.reject(err); return Promise.reject(err);
}); });
}); });
@ -153,10 +153,10 @@ native.export = Keypairs.export;
* Chopping off the private parts is now part of the public API. * Chopping off the private parts is now part of the public API.
* I thought it sounded a little too crude at first, but it really is the best name in every possible way. * I thought it sounded a little too crude at first, but it really is the best name in every possible way.
*/ */
Keypairs.neuter = function(opts) { Keypairs.neuter = function (opts) {
/** trying to find the best balance of an immutable copy with custom attributes */ /** trying to find the best balance of an immutable copy with custom attributes */
var jwk = {}; var jwk = {};
Object.keys(opts.jwk).forEach(function(k) { Object.keys(opts.jwk).forEach(function (k) {
if ('undefined' === typeof opts.jwk[k]) { if ('undefined' === typeof opts.jwk[k]) {
return; return;
} }
@ -169,8 +169,8 @@ Keypairs.neuter = function(opts) {
return jwk; return jwk;
}; };
Keypairs.thumbprint = function(opts) { Keypairs.thumbprint = function (opts) {
return Promise.resolve().then(function() { return Promise.resolve().then(function () {
if (/EC/i.test(opts.jwk.kty)) { if (/EC/i.test(opts.jwk.kty)) {
return Eckles.thumbprint(opts); return Eckles.thumbprint(opts);
} else { } else {
@ -179,7 +179,7 @@ Keypairs.thumbprint = function(opts) {
}); });
}; };
Keypairs.publish = function(opts) { Keypairs.publish = function (opts) {
if ('object' !== typeof opts.jwk || !opts.jwk.kty) { if ('object' !== typeof opts.jwk || !opts.jwk.kty) {
throw new Error('invalid jwk: ' + JSON.stringify(opts.jwk)); throw new Error('invalid jwk: ' + JSON.stringify(opts.jwk));
} }
@ -205,15 +205,15 @@ Keypairs.publish = function(opts) {
if (jwk.kid) { if (jwk.kid) {
return Promise.resolve(jwk); return Promise.resolve(jwk);
} }
return Keypairs.thumbprint({ jwk: jwk }).then(function(thumb) { return Keypairs.thumbprint({ jwk: jwk }).then(function (thumb) {
jwk.kid = thumb; jwk.kid = thumb;
return jwk; return jwk;
}); });
}; };
// JWT a.k.a. JWS with Claims using Compact Serialization // JWT a.k.a. JWS with Claims using Compact Serialization
Keypairs.signJwt = function(opts) { Keypairs.signJwt = function (opts) {
return Keypairs.thumbprint({ jwk: opts.jwk }).then(function(thumb) { return Keypairs.thumbprint({ jwk: opts.jwk }).then(function (thumb) {
var header = opts.header || {}; var header = opts.header || {};
var claims = JSON.parse(JSON.stringify(opts.claims || {})); var claims = JSON.parse(JSON.stringify(opts.claims || {}));
header.typ = 'JWT'; header.typ = 'JWT';
@ -260,14 +260,14 @@ Keypairs.signJwt = function(opts) {
protected: header, protected: header,
header: undefined, header: undefined,
payload: claims payload: claims
}).then(function(jws) { }).then(function (jws) {
return [jws.protected, jws.payload, jws.signature].join('.'); return [jws.protected, jws.payload, jws.signature].join('.');
}); });
}); });
}; };
Keypairs.signJws = function(opts) { Keypairs.signJws = function (opts) {
return Keypairs.thumbprint(opts).then(function(thumb) { return Keypairs.thumbprint(opts).then(function (thumb) {
function alg() { function alg() {
if (!opts.jwk) { if (!opts.jwk) {
throw new Error("opts.jwk must exist and must declare 'typ'"); throw new Error("opts.jwk must exist and must declare 'typ'");
@ -321,7 +321,7 @@ Keypairs.signJws = function(opts) {
var payload64 = Enc.bufToUrlBase64(payload); var payload64 = Enc.bufToUrlBase64(payload);
var msg = protected64 + '.' + payload64; var msg = protected64 + '.' + payload64;
return native._sign(opts, msg).then(function(buf) { return native._sign(opts, msg).then(function (buf) {
var signedMsg = { var signedMsg = {
protected: protected64, protected: protected64,
payload: payload64, payload: payload64,
@ -335,7 +335,7 @@ Keypairs.signJws = function(opts) {
if (opts.jwk) { if (opts.jwk) {
return sign(); return sign();
} else { } else {
return Keypairs.import({ pem: opts.pem }).then(function(pair) { return Keypairs.import({ pem: opts.pem }).then(function (pair) {
opts.jwk = pair.private; opts.jwk = pair.private;
return sign(); return sign();
}); });
@ -346,7 +346,7 @@ Keypairs.signJws = function(opts) {
// TODO expose consistently // TODO expose consistently
Keypairs.sign = native._sign; Keypairs.sign = native._sign;
Keypairs._getBits = function(opts) { Keypairs._getBits = function (opts) {
if (opts.alg) { if (opts.alg) {
return opts.alg.replace(/[a-z\-]/gi, ''); return opts.alg.replace(/[a-z\-]/gi, '');
} }

6
lib/browser/ecdsa.js

@ -4,7 +4,7 @@ var native = module.exports;
// XXX received from caller // XXX received from caller
var EC = native; var EC = native;
native.generate = function(opts) { native.generate = function (opts) {
var wcOpts = {}; var wcOpts = {};
if (!opts) { if (!opts) {
opts = {}; opts = {};
@ -41,10 +41,10 @@ native.generate = function(opts) {
var extractable = true; var extractable = true;
return window.crypto.subtle return window.crypto.subtle
.generateKey(wcOpts, extractable, ['sign', 'verify']) .generateKey(wcOpts, extractable, ['sign', 'verify'])
.then(function(result) { .then(function (result) {
return window.crypto.subtle return window.crypto.subtle
.exportKey('jwk', result.privateKey) .exportKey('jwk', result.privateKey)
.then(function(privJwk) { .then(function (privJwk) {
privJwk.key_ops = undefined; privJwk.key_ops = undefined;
privJwk.ext = undefined; privJwk.ext = undefined;
return { return {

16
lib/browser/keypairs.js

@ -2,8 +2,8 @@
var Keypairs = module.exports; var Keypairs = module.exports;
Keypairs._sign = function(opts, payload) { Keypairs._sign = function (opts, payload) {
return Keypairs._import(opts).then(function(privkey) { return Keypairs._import(opts).then(function (privkey) {
if ('string' === typeof payload) { if ('string' === typeof payload) {
payload = new TextEncoder().encode(payload); payload = new TextEncoder().encode(payload);
} }
@ -17,7 +17,7 @@ Keypairs._sign = function(opts, payload) {
privkey, privkey,
payload payload
) )
.then(function(signature) { .then(function (signature) {
signature = new Uint8Array(signature); // ArrayBuffer -> u8 signature = new Uint8Array(signature); // ArrayBuffer -> u8
// This will come back into play for CSRs, but not for JOSE // This will come back into play for CSRs, but not for JOSE
if ('EC' === opts.jwk.kty && /x509|asn1/i.test(opts.format)) { if ('EC' === opts.jwk.kty && /x509|asn1/i.test(opts.format)) {
@ -30,8 +30,8 @@ Keypairs._sign = function(opts, payload) {
}); });
}; };
Keypairs._import = function(opts) { Keypairs._import = function (opts) {
return Promise.resolve().then(function() { return Promise.resolve().then(function () {
var ops; var ops;
// all private keys just happen to have a 'd' // all private keys just happen to have a 'd'
if (opts.jwk.d) { if (opts.jwk.d) {
@ -55,7 +55,7 @@ Keypairs._import = function(opts) {
true, true,
ops ops
) )
.then(function(privkey) { .then(function (privkey) {
delete opts.jwk.ext; delete opts.jwk.ext;
return privkey; return privkey;
}); });
@ -64,7 +64,7 @@ Keypairs._import = function(opts) {
// ECDSA JOSE / JWS / JWT signatures differ from "normal" ASN1/X509 ECDSA signatures // ECDSA JOSE / JWS / JWT signatures differ from "normal" ASN1/X509 ECDSA signatures
// https://tools.ietf.org/html/rfc7518#section-3.4 // https://tools.ietf.org/html/rfc7518#section-3.4
Keypairs._ecdsaJoseSigToAsn1Sig = function(bufsig) { Keypairs._ecdsaJoseSigToAsn1Sig = function (bufsig) {
// it's easier to do the manipulation in the browser with an array // it's easier to do the manipulation in the browser with an array
bufsig = Array.from(bufsig); bufsig = Array.from(bufsig);
var hlen = bufsig.length / 2; // should be even var hlen = bufsig.length / 2; // should be even
@ -99,7 +99,7 @@ Keypairs._ecdsaJoseSigToAsn1Sig = function(bufsig) {
); );
}; };
Keypairs._getName = function(opts) { Keypairs._getName = function (opts) {
if (/EC/i.test(opts.jwk.kty)) { if (/EC/i.test(opts.jwk.kty)) {
return 'ECDSA'; return 'ECDSA';
} else { } else {

6
lib/browser/rsa.js

@ -4,7 +4,7 @@ var native = module.exports;
// XXX added by caller: _stance, neuter // XXX added by caller: _stance, neuter
var RSA = native; var RSA = native;
native.generate = function(opts) { native.generate = function (opts) {
var wcOpts = {}; var wcOpts = {};
if (!opts) { if (!opts) {
opts = {}; opts = {};
@ -46,10 +46,10 @@ native.generate = function(opts) {
var extractable = true; var extractable = true;
return window.crypto.subtle return window.crypto.subtle
.generateKey(wcOpts, extractable, ['sign', 'verify']) .generateKey(wcOpts, extractable, ['sign', 'verify'])
.then(function(result) { .then(function (result) {
return window.crypto.subtle return window.crypto.subtle
.exportKey('jwk', result.privateKey) .exportKey('jwk', result.privateKey)
.then(function(privJwk) { .then(function (privJwk) {
return { return {
private: privJwk, private: privJwk,
public: RSA.neuter({ jwk: privJwk }) public: RSA.neuter({ jwk: privJwk })

2
lib/browser/sha2.js

@ -3,7 +3,7 @@
var sha2 = module.exports; var sha2 = module.exports;
var encoder = new TextEncoder(); var encoder = new TextEncoder();
sha2.sum = function(alg, str) { sha2.sum = function (alg, str) {
var data = str; var data = str;
if ('string' === typeof data) { if ('string' === typeof data) {
data = encoder.encode(str); data = encoder.encode(str);

16
lib/node/ecdsa.js

@ -5,8 +5,8 @@ var native = module.exports;
var EC = native; var EC = native;
// TODO SSH // TODO SSH
native.generate = function(opts) { native.generate = function (opts) {
return Promise.resolve().then(function() { return Promise.resolve().then(function () {
var typ = 'ec'; var typ = 'ec';
var format = opts.format; var format = opts.format;
var encoding = opts.encoding; var encoding = opts.encoding;
@ -48,7 +48,7 @@ native.generate = function(opts) {
pub = { type: 'spki', format: 'pem' }; pub = { type: 'spki', format: 'pem' };
} }
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
return require('crypto').generateKeyPair( return require('crypto').generateKeyPair(
typ, typ,
{ {
@ -56,7 +56,7 @@ native.generate = function(opts) {
privateKeyEncoding: priv, privateKeyEncoding: priv,
publicKeyEncoding: pub publicKeyEncoding: pub
}, },
function(err, pubkey, privkey) { function (err, pubkey, privkey) {
if (err) { if (err) {
reject(err); reject(err);
} }
@ -66,7 +66,7 @@ native.generate = function(opts) {
}); });
} }
); );
}).then(function(keypair) { }).then(function (keypair) {
if ('jwk' === format) { if ('jwk' === format) {
return Promise.all([ return Promise.all([
native.import({ native.import({
@ -78,7 +78,7 @@ native.generate = function(opts) {
format: pub.type, format: pub.type,
public: true public: true
}) })
]).then(function(pair) { ]).then(function (pair) {
return { return {
private: pair[0], private: pair[0],
public: pair[1] public: pair[1]
@ -96,12 +96,12 @@ native.generate = function(opts) {
format: format, format: format,
public: true public: true
}) })
.then(function(jwk) { .then(function (jwk) {
return EC.export({ return EC.export({
jwk: jwk, jwk: jwk,
format: opts.format, format: opts.format,
public: true public: true
}).then(function(pub) { }).then(function (pub) {
return { return {
private: keypair.private, private: keypair.private,
public: pub public: pub

2
lib/node/generate-privkey-forge.js

@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict'; 'use strict';
module.exports = function(bitlen, exp) { module.exports = function (bitlen, exp) {
var k = require('node-forge').pki.rsa.generateKeyPair({ var k = require('node-forge').pki.rsa.generateKeyPair({
bits: bitlen || 2048, bits: bitlen || 2048,
e: exp || 0x10001 e: exp || 0x10001

2
lib/node/generate-privkey-node.js

@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict'; 'use strict';
module.exports = function(bitlen, exp) { module.exports = function (bitlen, exp) {
var keypair = require('crypto').generateKeyPairSync('rsa', { var keypair = require('crypto').generateKeyPairSync('rsa', {
modulusLength: bitlen, modulusLength: bitlen,
publicExponent: exp, publicExponent: exp,

7
lib/node/generate-privkey-ursa.js

@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict'; 'use strict';
module.exports = function(bitlen, exp) { module.exports = function (bitlen, exp) {
var ursa; var ursa;
try { try {
ursa = require('ursa'); ursa = require('ursa');
@ -13,10 +13,7 @@ module.exports = function(bitlen, exp) {
} }
var keypair = ursa.generatePrivateKey(bitlen, exp); var keypair = ursa.generatePrivateKey(bitlen, exp);
var result = { var result = {
privateKeyPem: keypair privateKeyPem: keypair.toPrivatePem().toString('ascii').trim()
.toPrivatePem()
.toString('ascii')
.trim()
}; };
return result; return result;
}; };

2
lib/node/generate-privkey.js

@ -6,7 +6,7 @@
var oldver = false; var oldver = false;
module.exports = function(bitlen, exp) { module.exports = function (bitlen, exp) {
bitlen = parseInt(bitlen, 10) || 2048; bitlen = parseInt(bitlen, 10) || 2048;
exp = parseInt(exp, 10) || 65537; exp = parseInt(exp, 10) || 65537;

13
lib/node/keypairs.js

@ -3,17 +3,14 @@
var Keypairs = module.exports; var Keypairs = module.exports;
var crypto = require('crypto'); var crypto = require('crypto');
Keypairs._sign = function(opts, payload) { Keypairs._sign = function (opts, payload) {
return Keypairs._import(opts).then(function(pem) { return Keypairs._import(opts).then(function (pem) {
payload = Buffer.from(payload); payload = Buffer.from(payload);
// node specifies RSA-SHAxxx even when it's actually ecdsa (it's all encoded x509 shasums anyway) // node specifies RSA-SHAxxx even when it's actually ecdsa (it's all encoded x509 shasums anyway)
// TODO opts.alg = (protect||header).alg // TODO opts.alg = (protect||header).alg
var nodeAlg = 'SHA' + Keypairs._getBits(opts); var nodeAlg = 'SHA' + Keypairs._getBits(opts);
var binsig = crypto var binsig = crypto.createSign(nodeAlg).update(payload).sign(pem);
.createSign(nodeAlg)
.update(payload)
.sign(pem);
if ('EC' === opts.jwk.kty && !/x509|asn1/i.test(opts.format)) { if ('EC' === opts.jwk.kty && !/x509|asn1/i.test(opts.format)) {
// ECDSA JWT signatures differ from "normal" ECDSA signatures // ECDSA JWT signatures differ from "normal" ECDSA signatures
@ -25,7 +22,7 @@ Keypairs._sign = function(opts, payload) {
}); });
}; };
Keypairs._import = function(opts) { Keypairs._import = function (opts) {
if (opts.pem && opts.jwk) { if (opts.pem && opts.jwk) {
return Promise.resolve(opts.pem); return Promise.resolve(opts.pem);
} else { } else {
@ -34,7 +31,7 @@ Keypairs._import = function(opts) {
} }
}; };
Keypairs._ecdsaAsn1SigToJoseSig = function(binsig) { Keypairs._ecdsaAsn1SigToJoseSig = function (binsig) {
// should have asn1 sequence header of 0x30 // should have asn1 sequence header of 0x30
if (0x30 !== binsig[0]) { if (0x30 !== binsig[0]) {
throw new Error('Impossible EC SHA head marker'); throw new Error('Impossible EC SHA head marker');

12
lib/node/rsa.js

@ -7,9 +7,9 @@ var RSA = native;
var PEM = require('@root/pem'); var PEM = require('@root/pem');
var X509 = require('@root/x509'); var X509 = require('@root/x509');
native.generate = function(opts) { native.generate = function (opts) {
opts.kty = 'RSA'; opts.kty = 'RSA';
return native._generate(opts).then(function(pair) { return native._generate(opts).then(function (pair) {
var format = opts.format; var format = opts.format;
var encoding = opts.encoding; var encoding = opts.encoding;
@ -74,23 +74,23 @@ native.generate = function(opts) {
} }
var exOpts = { jwk: pair.private, format: format, encoding: encoding }; var exOpts = { jwk: pair.private, format: format, encoding: encoding };
return RSA.export(exOpts).then(function(priv) { return RSA.export(exOpts).then(function (priv) {
exOpts.public = true; exOpts.public = true;
if ('pkcs8' === exOpts.format) { if ('pkcs8' === exOpts.format) {
exOpts.format = 'spki'; exOpts.format = 'spki';
} }
return RSA.export(exOpts).then(function(pub) { return RSA.export(exOpts).then(function (pub) {
return { private: priv, public: pub }; return { private: priv, public: pub };
}); });
}); });
}); });
}; };
native._generate = function(opts) { native._generate = function (opts) {
if (!opts) { if (!opts) {
opts = {}; opts = {};
} }
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
try { try {
var modlen = opts.modulusLength || 2048; var modlen = opts.modulusLength || 2048;
var exp = opts.publicExponent || 0x10001; var exp = opts.publicExponent || 0x10001;

9
lib/node/sha2.js

@ -4,14 +4,11 @@
var sha2 = module.exports; var sha2 = module.exports;
var crypto = require('crypto'); var crypto = require('crypto');
sha2.sum = function(alg, str) { sha2.sum = function (alg, str) {
return Promise.resolve().then(function() { return Promise.resolve().then(function () {
var sha = 'sha' + String(alg).replace(/^sha-?/i, ''); var sha = 'sha' + String(alg).replace(/^sha-?/i, '');
// utf8 is the default for strings // utf8 is the default for strings
var buf = Buffer.from(str); var buf = Buffer.from(str);
return crypto return crypto.createHash(sha).update(buf).digest();
.createHash(sha)
.update(buf)
.digest();
}); });
}; };

26
rsa.js

@ -20,10 +20,10 @@ RSA.generate = native.generate;
// Chopping off the private parts is now part of the public API. // Chopping off the private parts is now part of the public API.
// I thought it sounded a little too crude at first, but it really is the best name in every possible way. // I thought it sounded a little too crude at first, but it really is the best name in every possible way.
RSA.neuter = function(opts) { RSA.neuter = function (opts) {
// trying to find the best balance of an immutable copy with custom attributes // trying to find the best balance of an immutable copy with custom attributes
var jwk = {}; var jwk = {};
Object.keys(opts.jwk).forEach(function(k) { Object.keys(opts.jwk).forEach(function (k) {
if ('undefined' === typeof opts.jwk[k]) { if ('undefined' === typeof opts.jwk[k]) {
return; return;
} }
@ -38,7 +38,7 @@ RSA.neuter = function(opts) {
native.neuter = RSA.neuter; native.neuter = RSA.neuter;
// https://stackoverflow.com/questions/42588786/how-to-fingerprint-a-jwk // https://stackoverflow.com/questions/42588786/how-to-fingerprint-a-jwk
RSA.__thumbprint = function(jwk) { RSA.__thumbprint = function (jwk) {
// Use the same entropy for SHA as for key // Use the same entropy for SHA as for key
var len = Math.floor(jwk.n.length * 0.75); var len = Math.floor(jwk.n.length * 0.75);
var alg = 'SHA-256'; var alg = 'SHA-256';
@ -51,20 +51,20 @@ RSA.__thumbprint = function(jwk) {
} }
return sha2 return sha2
.sum(alg, '{"e":"' + jwk.e + '","kty":"RSA","n":"' + jwk.n + '"}') .sum(alg, '{"e":"' + jwk.e + '","kty":"RSA","n":"' + jwk.n + '"}')
.then(function(hash) { .then(function (hash) {
return Enc.bufToUrlBase64(Uint8Array.from(hash)); return Enc.bufToUrlBase64(Uint8Array.from(hash));
}); });
}; };
RSA.thumbprint = function(opts) { RSA.thumbprint = function (opts) {
return Promise.resolve().then(function() { return Promise.resolve().then(function () {
var jwk; var jwk;
if ('EC' === opts.kty) { if ('EC' === opts.kty) {
jwk = opts; jwk = opts;
} else if (opts.jwk) { } else if (opts.jwk) {
jwk = opts.jwk; jwk = opts.jwk;
} else { } else {
return RSA.import(opts).then(function(jwk) { return RSA.import(opts).then(function (jwk) {
return RSA.__thumbprint(jwk); return RSA.__thumbprint(jwk);
}); });
} }
@ -72,8 +72,8 @@ RSA.thumbprint = function(opts) {
}); });
}; };
RSA.export = function(opts) { RSA.export = function (opts) {
return Promise.resolve().then(function() { return Promise.resolve().then(function () {
if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) { if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) {
throw new Error('must pass { jwk: jwk }'); throw new Error('must pass { jwk: jwk }');
} }
@ -152,16 +152,16 @@ RSA.export = function(opts) {
}; };
native.export = RSA.export; native.export = RSA.export;
RSA.pack = function(opts) { RSA.pack = function (opts) {
// wrapped in a promise for API compatibility // wrapped in a promise for API compatibility
// with the forthcoming browser version // with the forthcoming browser version
// (and potential future native node capability) // (and potential future native node capability)
return Promise.resolve().then(function() { return Promise.resolve().then(function () {
return RSA.export(opts); return RSA.export(opts);
}); });
}; };
RSA._importSync = function(opts) { RSA._importSync = function (opts) {
if (!opts || !opts.pem || 'string' !== typeof opts.pem) { if (!opts || !opts.pem || 'string' !== typeof opts.pem) {
throw new Error('must pass { pem: pem } as a string'); throw new Error('must pass { pem: pem } as a string');
} }
@ -185,7 +185,7 @@ RSA.parse = function parseRsa(opts) {
// wrapped in a promise for API compatibility // wrapped in a promise for API compatibility
// with the forthcoming browser version // with the forthcoming browser version
// (and potential future native node capability) // (and potential future native node capability)
return Promise.resolve().then(function() { return Promise.resolve().then(function () {
return RSA._importSync(opts); return RSA._importSync(opts);
}); });
}; };

50
tests/index.js

@ -4,7 +4,7 @@ var Keypairs = require('../');
/* global Promise*/ /* global Promise*/
Keypairs.parseOrGenerate({ key: null }) Keypairs.parseOrGenerate({ key: null })
.then(function(pair) { .then(function (pair) {
// should NOT have any warning output // should NOT have any warning output
if (!pair.private || !pair.public) { if (!pair.private || !pair.public) {
throw new Error('missing key pairs'); throw new Error('missing key pairs');
@ -12,42 +12,42 @@ Keypairs.parseOrGenerate({ key: null })
return Promise.all([ return Promise.all([
// Testing Public Part of key // Testing Public Part of key
Keypairs.export({ jwk: pair.public }).then(function(pem) { Keypairs.export({ jwk: pair.public }).then(function (pem) {
if (!/--BEGIN PUBLIC/.test(pem)) { if (!/--BEGIN PUBLIC/.test(pem)) {
throw new Error('did not export public pem'); throw new Error('did not export public pem');
} }
return Promise.all([ return Promise.all([
Keypairs.parse({ key: pem }).then(function(pair) { Keypairs.parse({ key: pem }).then(function (pair) {
if (pair.private) { if (pair.private) {
throw new Error("shouldn't have private part"); throw new Error("shouldn't have private part");
} }
return true; return true;
}), }),
Keypairs.parse({ key: pem, private: true }) Keypairs.parse({ key: pem, private: true })
.then(function() { .then(function () {
var err = new Error( var err = new Error(
'should have thrown an error when private key was required and public pem was given' 'should have thrown an error when private key was required and public pem was given'
); );
err.code = 'NOERR'; err.code = 'NOERR';
throw err; throw err;
}) })
.catch(function(e) { .catch(function (e) {
if ('NOERR' === e.code) { if ('NOERR' === e.code) {
throw e; throw e;
} }
return true; return true;
}) })
]).then(function() { ]).then(function () {
return true; return true;
}); });
}), }),
// Testing Private Part of Key // Testing Private Part of Key
Keypairs.export({ jwk: pair.private }).then(function(pem) { Keypairs.export({ jwk: pair.private }).then(function (pem) {
if (!/--BEGIN .*PRIVATE KEY--/.test(pem)) { if (!/--BEGIN .*PRIVATE KEY--/.test(pem)) {
throw new Error('did not export private pem: ' + pem); throw new Error('did not export private pem: ' + pem);
} }
return Promise.all([ return Promise.all([
Keypairs.parse({ key: pem }).then(function(pair) { Keypairs.parse({ key: pem }).then(function (pair) {
if (!pair.private) { if (!pair.private) {
throw new Error('should have private part'); throw new Error('should have private part');
} }
@ -56,7 +56,7 @@ Keypairs.parseOrGenerate({ key: null })
} }
return true; return true;
}), }),
Keypairs.parse({ key: pem, public: true }).then(function( Keypairs.parse({ key: pem, public: true }).then(function (
pair pair
) { ) {
if (pair.private) { if (pair.private) {
@ -69,12 +69,12 @@ Keypairs.parseOrGenerate({ key: null })
} }
return true; return true;
}) })
]).then(function() { ]).then(function () {
return true; return true;
}); });
}), }),
Keypairs.parseOrGenerate({ key: 'not a key', public: true }).then( Keypairs.parseOrGenerate({ key: 'not a key', public: true }).then(
function(pair) { function (pair) {
// SHOULD have warning output // SHOULD have warning output
if (!pair.private || !pair.public) { if (!pair.private || !pair.public) {
throw new Error( throw new Error(
@ -89,18 +89,18 @@ Keypairs.parseOrGenerate({ key: null })
return true; return true;
} }
), ),
Keypairs.parse({ key: JSON.stringify(pair.private) }).then(function( Keypairs.parse({ key: JSON.stringify(pair.private) }).then(
pair function (pair) {
) { if (!pair.private || !pair.public) {
if (!pair.private || !pair.public) { throw new Error('missing key pairs (stringified jwt)');
throw new Error('missing key pairs (stringified jwt)'); }
return true;
} }
return true; ),
}),
Keypairs.parse({ Keypairs.parse({
key: JSON.stringify(pair.private), key: JSON.stringify(pair.private),
public: true public: true
}).then(function(pair) { }).then(function (pair) {
if (pair.private) { if (pair.private) {
throw new Error("has private key when it shouldn't"); throw new Error("has private key when it shouldn't");
} }
@ -110,14 +110,14 @@ Keypairs.parseOrGenerate({ key: null })
return true; return true;
}), }),
Keypairs.parse({ key: JSON.stringify(pair.public), private: true }) Keypairs.parse({ key: JSON.stringify(pair.public), private: true })
.then(function() { .then(function () {
var err = new Error( var err = new Error(
'should have thrown an error when private key was required and public jwk was given' 'should have thrown an error when private key was required and public jwk was given'
); );
err.code = 'NOERR'; err.code = 'NOERR';
throw err; throw err;
}) })
.catch(function(e) { .catch(function (e) {
if ('NOERR' === e.code) { if ('NOERR' === e.code) {
throw e; throw e;
} }
@ -130,7 +130,7 @@ Keypairs.parseOrGenerate({ key: null })
alg: 'ES256', alg: 'ES256',
iss: 'https://example.com/', iss: 'https://example.com/',
exp: '1h' exp: '1h'
}).then(function(jwt) { }).then(function (jwt) {
var parts = jwt.split('.'); var parts = jwt.split('.');
var now = Math.round(Date.now() / 1000); var now = Math.round(Date.now() / 1000);
var token = { var token = {
@ -144,10 +144,10 @@ Keypairs.parseOrGenerate({ key: null })
} }
throw new Error('token was not properly generated'); throw new Error('token was not properly generated');
}) })
]).then(function(results) { ]).then(function (results) {
if ( if (
results.length && results.length &&
results.every(function(v) { results.every(function (v) {
return true === v; return true === v;
}) })
) { ) {
@ -158,7 +158,7 @@ Keypairs.parseOrGenerate({ key: null })
} }
}); });
}) })
.catch(function(e) { .catch(function (e) {
console.error('Caught an unexpected (failing) error:'); console.error('Caught an unexpected (failing) error:');
console.error(e); console.error(e);
process.exit(1); process.exit(1);

Loading…
Cancel
Save