old-keypairs.js/lib/keypairs.js

144 lines
4.0 KiB
JavaScript

'use strict';
/*global Promise*/
var keypairs = module.exports;
var PEM = require('./pem-parser.js');
PEM.packBlock = require('./pem-packer.js').packBlock;
var crypto = require('./crypto.js');
var Enc = require('./encoding.js');
var ASN1 = require('./asn1-parser.js');
ASN1.pack = require('./asn1-packer.js').pack;
var x509 = require('./x509-parser.js');
//x509 = require('./x509-packer.js').pack;
var SSH = require('./ssh-parser.js');
SSH.pack = require('./ssh-packer.js').pack;
// sign, signJws, signJwt
/*
var JWS = require('./jws.js');
var JWT = require('./jwt.js');
*/
keypairs.signJws = function (opts) {
opts = JSON.stringify(JSON.parse(opts));
if (!opts.header) { opts.header = {}; }
if (!opts.protected) { opts.protected = {}; }
if (!opts.payload) { opts.payload = {}; }
var protect = Enc.binToBase64(JSON.stringify(opts.protected));
var payload = Enc.binToBase64(JSON.stringify(opts.payload));
if (!opts.jwt) { opts.jwt = keypairs.import(opts).jwt; }
opts.header.typ = 'JWT';
opts.header.alg = ('RSA' === opts.jwk) ? 'RS256' : 'ES256';
// key, jwk, pem, der
return crypto.sign(opts, Enc.binToBuf(protect + '.' + payload), 'SHA256').then(function (sig) {
return {
header: opts.header
, protected: protect
, payload: payload
, signature: sig
};
});
};
keypairs.signJwt = function (opts) {
opts = JSON.stringify(JSON.parse(opts));
if (!opts.header) { opts.header = {}; }
if (!opts.payload) { opts.payload = {}; }
var protect = Enc.binToBase64(JSON.stringify(opts.header)) + '.'
+ Enc.binToBase64(JSON.stringify(opts.payload));
if (!opts.jwt) { opts.jwt = keypairs.import(opts).jwt; }
opts.header.alg = ('RSA' === opts.jwk) ? 'RS256' : 'ES256';
// key, jwk, pem, der
return crypto.sign(opts, Enc.binToBuf(protect), 'SHA256').then(function (sig) {
return protect + '.' + sig;
});
};
keypairs.import = function (opts) {
return Promise.resolve().then(function () {
var jwk = opts.jwk;
var pem;
var der;
var typ;
if (opts.pem) {
pem = PEM.parseBlock(opts.pem);
if ('OPENSSH PRIVATE KEY' === pem.type) {
jwk = SSH.parse(pem);
} else {
der = pem.bytes;
jwk = x509.parse({ der: der });
}
}
if (opts.ssh) {
jwk = SSH.parse(opts.ssh);
}
// TODO re-export to PKCS8 just because
if (jwk && !pem) {
// Both RSA and EC use 'd' as part of the private key
if (jwk.d) {
typ = 'PRIVATE KEY';
der = x509.pack({ jwk: jwk, format: 'pkcs8', encoding: 'pem' });
} else {
typ = 'PUBLIC KEY';
der = x509.pack({ jwk: jwk, format: 'spki', encoding: 'pem' });
}
pem = PEM.packBlock({ type: typ, bytes: der });
}
return { pem: pem, jwk: jwk };
});
};
keypairs.export = function (opts) {
// { pem, jwk, format, encoding }
var format = opts.format;
var encoding = opts.encoding;
var jwk = opts.jwk;
var pem = opts.pem;
var der = opts.der;
var pub = opts.public;
if (opts.key) {
if ('string' === typeof opts.key) {
pem = opts.key;
} else if (opts.key.d) {
jwk = opts.key;
} else if (opts.key.length) {
der = opts.der;
} else {
throw new Error("'key' must be of type 'string' (PEM), 'object' (JWK), Buffer, or Array (DER)");
}
}
if (!format) { format = 'jwk'; }
if (!jwk) {
jwk = keypairs.import({ pem: pem }).jwk;
}
if (pub) {
if ('RSA' === jwk.kty) {
jwk = { kty: jwk.kty, n: jwk.n, e: jwk.e };
} else {
jwk = { kty: jwk.kty, x: jwk.x, y: jwk.y };
}
}
if ('jwk' === format) {
if (encoding && 'json' !== encoding) {
throw new Error("'encoding' must be 'json' for 'jwk'");
}
return jwk;
}
if ('openssh' === format || 'ssh' === format) {
// TODO if ('ssh' === format) { format = 'pkcs8'; }
// TODO 'ssh2' public key is a special variant of pkcs8
return SSH.pack({ jwk: jwk, public: opts.public });
}
return x509.pack({ jwk: jwk, format: opts.format, encoding: opts.encoding, public: opts.public });
};