From 57edc8641bed69adfb49298f8bd69cc66aedb361 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Fri, 23 Nov 2018 12:18:13 -0700 Subject: [PATCH] expose importSync and exportSync --- lib/rasha.js | 156 +++++++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 85 insertions(+), 73 deletions(-) diff --git a/lib/rasha.js b/lib/rasha.js index 7306709..83dda7b 100644 --- a/lib/rasha.js +++ b/lib/rasha.js @@ -7,33 +7,39 @@ var x509 = require('./x509.js'); var ASN1 = require('./asn1.js'); /*global Promise*/ +RSA.importSync = function (opts) { + if (!opts || !opts.pem || 'string' !== typeof opts.pem) { + throw new Error("must pass { pem: pem } as a string"); + } + + var jwk = { kty: 'RSA', n: null, e: null }; + if (0 === opts.pem.indexOf('ssh-rsa ')) { + return SSH.parse(opts.pem, jwk); + } + var pem = opts.pem; + var block = PEM.parseBlock(pem); + //var hex = toHex(u8); + var asn1 = ASN1.parse(block.der); + + var meta = x509.guess(block.der, asn1); + + if ('pkcs1' === meta.format) { + jwk = x509.parsePkcs1(block.der, asn1, jwk); + } else { + jwk = x509.parsePkcs8(block.der, asn1, jwk); + } + + if (opts.public) { + jwk = RSA.nueter(jwk); + } + return jwk; +}; RSA.parse = function parseRsa(opts) { + // wrapped in a promise for API compatibility + // with the forthcoming browser version + // (and potential future native node capability) return Promise.resolve().then(function () { - if (!opts || !opts.pem || 'string' !== typeof opts.pem) { - throw new Error("must pass { pem: pem } as a string"); - } - - var jwk = { kty: 'RSA', n: null, e: null }; - if (0 === opts.pem.indexOf('ssh-rsa ')) { - return SSH.parse(opts.pem, jwk); - } - var pem = opts.pem; - var block = PEM.parseBlock(pem); - //var hex = toHex(u8); - var asn1 = ASN1.parse(block.der); - - var meta = x509.guess(block.der, asn1); - - if ('pkcs1' === meta.format) { - jwk = x509.parsePkcs1(block.der, asn1, jwk); - } else { - jwk = x509.parsePkcs8(block.der, asn1, jwk); - } - - if (opts.public) { - jwk = RSA.nueter(jwk); - } - return jwk; + return RSA.importSync(opts); }); }; RSA.toJwk = RSA.import = RSA.parse; @@ -53,57 +59,63 @@ RSAPrivateKey ::= SEQUENCE { } */ -RSA.pack = function (opts) { - return Promise.resolve().then(function () { - if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) { - throw new Error("must pass { jwk: jwk }"); - } - var jwk = JSON.parse(JSON.stringify(opts.jwk)); - var format = opts.format; - var pub = opts.public; - if (pub || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) { - jwk = RSA.nueter(jwk); - } - if ('RSA' !== jwk.kty) { - throw new Error("options.jwk.kty must be 'RSA' for RSA keys"); - } - if (!jwk.p) { - // TODO test for n and e - pub = true; - if (!format || 'pkcs1' === format) { - format = 'pkcs1'; - } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) { - format = 'spki'; - } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) { - format = 'ssh'; - } else { - throw new Error("options.format must be 'spki', 'pkcs1', or 'ssh' for public RSA keys, not (" - + typeof format + ") " + format); - } - } else { - // TODO test for all necessary keys (d, p, q ...) - if (!format || 'pkcs1' === format) { - format = 'pkcs1'; - } else if ('pkcs8' !== format) { - throw new Error("options.format must be 'pkcs1' or 'pkcs8' for private RSA keys"); - } - } - - if ('pkcs1' === format) { - if (jwk.d) { - return PEM.packBlock({ type: "RSA PRIVATE KEY", bytes: x509.packPkcs1(jwk) }); - } else { - return PEM.packBlock({ type: "RSA PUBLIC KEY", bytes: x509.packPkcs1(jwk) }); - } - } else if ('pkcs8' === format) { - return PEM.packBlock({ type: "PRIVATE KEY", bytes: x509.packPkcs8(jwk) }); +RSA.exportSync = function (opts) { + if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) { + throw new Error("must pass { jwk: jwk }"); + } + var jwk = JSON.parse(JSON.stringify(opts.jwk)); + var format = opts.format; + var pub = opts.public; + if (pub || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) { + jwk = RSA.nueter(jwk); + } + if ('RSA' !== jwk.kty) { + throw new Error("options.jwk.kty must be 'RSA' for RSA keys"); + } + if (!jwk.p) { + // TODO test for n and e + pub = true; + if (!format || 'pkcs1' === format) { + format = 'pkcs1'; } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) { - return PEM.packBlock({ type: "PUBLIC KEY", bytes: x509.packSpki(jwk) }); + format = 'spki'; } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) { - return SSH.pack({ jwk: jwk, comment: opts.comment }); + format = 'ssh'; } else { - throw new Error("Sanity Error: reached unreachable code block with format: " + format); + throw new Error("options.format must be 'spki', 'pkcs1', or 'ssh' for public RSA keys, not (" + + typeof format + ") " + format); } + } else { + // TODO test for all necessary keys (d, p, q ...) + if (!format || 'pkcs1' === format) { + format = 'pkcs1'; + } else if ('pkcs8' !== format) { + throw new Error("options.format must be 'pkcs1' or 'pkcs8' for private RSA keys"); + } + } + + if ('pkcs1' === format) { + if (jwk.d) { + return PEM.packBlock({ type: "RSA PRIVATE KEY", bytes: x509.packPkcs1(jwk) }); + } else { + return PEM.packBlock({ type: "RSA PUBLIC KEY", bytes: x509.packPkcs1(jwk) }); + } + } else if ('pkcs8' === format) { + return PEM.packBlock({ type: "PRIVATE KEY", bytes: x509.packPkcs8(jwk) }); + } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) { + return PEM.packBlock({ type: "PUBLIC KEY", bytes: x509.packSpki(jwk) }); + } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) { + return SSH.pack({ jwk: jwk, comment: opts.comment }); + } else { + throw new Error("Sanity Error: reached unreachable code block with format: " + format); + } +}; +RSA.pack = function (opts) { + // wrapped in a promise for API compatibility + // with the forthcoming browser version + // (and potential future native node capability) + return Promise.resolve().then(function () { + return RSA.exportSync(opts); }); }; RSA.toPem = RSA.export = RSA.pack; diff --git a/package.json b/package.json index 2ed37b7..bbb5ed6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rasha", - "version": "1.0.1", + "version": "1.0.2", "description": "💯 PEM-to-JWK and JWK-to-PEM for RSA keys in a lightweight, zero-dependency library focused on perfect universal compatibility.", "homepage": "https://git.coolaj86.com/coolaj86/rasha.js", "main": "index.js",