142 lines
3.9 KiB
JavaScript
142 lines
3.9 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');
|
|
|
|
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);
|
|
}
|
|
}
|
|
if (opts.ssh) {
|
|
jwk = SSH.parse(opts.ssh);
|
|
}
|
|
if (jwk) {
|
|
// 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 });
|
|
};
|