'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 }); };