jwk-to-pem
Advanced tools
Comparing version 1.1.4 to 1.2.0
{ | ||
"name": "jwk-to-pem", | ||
"version": "1.1.4", | ||
"version": "1.2.0", | ||
"description": "Convert a JSON Web Key to a PEM", | ||
@@ -27,6 +27,5 @@ "main": "src/jwk-to-pem.js", | ||
"dependencies": { | ||
"asn1.js": "^2.0.3", | ||
"asn1.js": "^2.2.0", | ||
"asn1.js-rfc3280": "^2.1.0", | ||
"elliptic": "^3.0.4", | ||
"rsa-pem-from-mod-exp": "^0.8.4" | ||
"elliptic": "^3.0.4" | ||
}, | ||
@@ -37,4 +36,5 @@ "devDependencies": { | ||
"istanbul": "^0.3.15", | ||
"jwa": "^1.1.0", | ||
"mocha": "^2.2.5" | ||
} | ||
} |
@@ -30,2 +30,20 @@ # jwk-to-pem | ||
### API | ||
--- | ||
#### `jwkToPem(Object jwk[, Object options])` -> `String` | ||
The first parameter should be an Object representing the jwk, it may be public | ||
or private. By default, either of the two will be made into a public PEM. The | ||
call will throw if the input jwk is malformed or does not represent a valid | ||
key. | ||
##### Option: private `Boolean` _(false)_ | ||
You may optionally specify that you would like a private PEM. This can be done | ||
by passing `true` to the `private` option. The call will throw if the necessary | ||
private parameters are not available. | ||
## Contributing | ||
@@ -32,0 +50,0 @@ |
112
src/ec.js
'use strict'; | ||
var asn1 = require('asn1.js'), | ||
BN = asn1.bignum, | ||
curves = require('./ec-curves'), | ||
rfc3280 = require('asn1.js-rfc3280'); | ||
function jwkParamToBigNum (val) { | ||
val = new Buffer(val, 'base64'); | ||
val = new BN(val, 10, 'be').iabs(); | ||
return val; | ||
} | ||
var b64ToBn = require('./b64-to-bn'); | ||
function ecJwkToBuffer (jwk) { | ||
function ecJwkToBuffer (jwk, opts) { | ||
if ('string' !== typeof jwk.crv) { | ||
@@ -19,10 +14,19 @@ throw new TypeError('Expected "jwk.crv" to be a String'); | ||
if ('string' !== typeof jwk.x) { | ||
var hasD = 'string' === typeof jwk.d; | ||
var xyTypes = hasD | ||
? ['undefined', 'string'] | ||
: ['string']; | ||
if (-1 === xyTypes.indexOf(typeof jwk.x)) { | ||
throw new TypeError('Expected "jwk.x" to be a String'); | ||
} | ||
if ('string' !== typeof jwk.y) { | ||
if (-1 === xyTypes.indexOf(typeof jwk.y)) { | ||
throw new TypeError('Expected "jwk.y" to be a String'); | ||
} | ||
if (opts.private && !hasD) { | ||
throw new TypeError('Expected "jwk.d" to be a String'); | ||
} | ||
var curve = curves[jwk.crv]; | ||
@@ -33,7 +37,18 @@ if (!curve) { | ||
var x = jwkParamToBigNum(jwk.x), | ||
y = jwkParamToBigNum(jwk.y); | ||
var key = {}; | ||
var key = curve.keyFromPublic({ x: x, y: y }); | ||
var hasPub = jwk.x && jwk.y; | ||
if (hasPub) { | ||
key.pub = { | ||
x: b64ToBn(jwk.x), | ||
y: b64ToBn(jwk.y) | ||
}; | ||
} | ||
if (opts.private || !hasPub) { | ||
key.priv = b64ToBn(jwk.d); | ||
} | ||
key = curve.keyPair(key); | ||
var keyValidation = key.validate(); | ||
@@ -44,3 +59,3 @@ if (!keyValidation.result) { | ||
var result = keyToPem(jwk.crv, key); | ||
var result = keyToPem(jwk.crv, key, opts); | ||
@@ -50,3 +65,3 @@ return result; | ||
function keyToPem (crv, key) { | ||
function keyToPem (crv, key, opts) { | ||
var oid; | ||
@@ -74,31 +89,43 @@ switch (crv) { | ||
subjectPublicKey = new Buffer(subjectPublicKey, 'hex'); | ||
subjectPublicKey = { | ||
unused: 0, | ||
data: subjectPublicKey | ||
}; | ||
var result = rfc3280.SubjectPublicKeyInfo.encode({ | ||
algorithm: { | ||
algorithm: [1, 2, 840, 10045, 2, 1], | ||
parameters: ECParameters.encode({ | ||
type: 'namedCurve', | ||
value: oid | ||
}, 'der') | ||
}, | ||
subjectPublicKey: { | ||
unused: 0, | ||
data: subjectPublicKey | ||
} | ||
var parameters = ECParameters.encode({ | ||
type: 'namedCurve', | ||
value: oid | ||
}, 'der'); | ||
result = result.toString('base64'); | ||
result = guardDer(result); | ||
var result; | ||
if (opts.private) { | ||
var privateKey = key.getPrivate('hex'); | ||
privateKey = new Buffer(privateKey, 'hex'); | ||
return result; | ||
} | ||
result = ECPrivateKey.encode({ | ||
version: ecPrivkeyVer1, | ||
privateKey: privateKey, | ||
parameters: parameters, | ||
publicKey: subjectPublicKey | ||
}, 'pem', { | ||
label: 'EC PRIVATE KEY' | ||
}); | ||
} else { | ||
result = rfc3280.SubjectPublicKeyInfo.encode({ | ||
algorithm: { | ||
algorithm: [1, 2, 840, 10045, 2, 1], | ||
parameters: parameters | ||
}, | ||
subjectPublicKey: subjectPublicKey | ||
}, 'pem', { | ||
label: 'PUBLIC KEY' | ||
}); | ||
} | ||
function guardDer (der) { | ||
var openGuard = '-----BEGIN PUBLIC KEY-----\n', | ||
endGuard = '-----END PUBLIC KEY-----\n'; | ||
// This is in an if incase asn1.js adds a trailing \n | ||
// istanbul ignore else | ||
if ('\n' !== result.slice(-1)) { | ||
result += '\n'; | ||
} | ||
der = der.match(/.{1,64}/g).join('\n') + '\n'; | ||
var result = openGuard + der + endGuard; | ||
return result; | ||
@@ -113,2 +140,13 @@ } | ||
var ecPrivkeyVer1 = 1; | ||
var ECPrivateKey = asn1.define('ECPrivateKey', function () { | ||
this.seq().obj( | ||
this.key('version').int(), | ||
this.key('privateKey').octstr(), | ||
this.key('parameters').explicit(0).optional().any(), | ||
this.key('publicKey').explicit(1).optional().bitstr() | ||
); | ||
}); | ||
module.exports = ecJwkToBuffer; |
@@ -6,3 +6,3 @@ 'use strict'; | ||
function jwkToBuffer (jwk) { | ||
function jwkToBuffer (jwk, opts) { | ||
if ('object' !== typeof jwk || null === jwk) { | ||
@@ -17,8 +17,11 @@ throw new TypeError('Expected "jwk" to be an Object'); | ||
opts = opts || {}; | ||
opts.private = opts.private === true; | ||
switch (kty) { | ||
case 'EC': { | ||
return ec(jwk); | ||
return ec(jwk, opts); | ||
} | ||
case 'RSA': { | ||
return rsa(jwk); | ||
return rsa(jwk, opts); | ||
} | ||
@@ -25,0 +28,0 @@ default: { |
'use strict'; | ||
var getPem = require('rsa-pem-from-mod-exp'); | ||
var asn1 = require('asn1.js'); | ||
function rsaJwkToBuffer (jwk) { | ||
var b64ToBn = require('./b64-to-bn'); | ||
var Version = asn1.define('Version', function () { | ||
this.int(); | ||
}); | ||
var RSAPrivateKey = asn1.define('RSAPrivateKey', function () { | ||
this.seq().obj( | ||
this.key('version').use(Version), | ||
this.key('modulus').int(), | ||
this.key('publicExponent').int(), | ||
this.key('privateExponent').int(), | ||
this.key('prime1').int(), | ||
this.key('prime2').int(), | ||
this.key('exponent1').int(), | ||
this.key('exponent2').int(), | ||
this.key('coefficient').int() | ||
); | ||
}); | ||
var RSAPublicKey = asn1.define('RSAPublicKey', function () { | ||
this.seq().obj( | ||
this.key('modulus').int(), | ||
this.key('publicExponent').int() | ||
); | ||
}); | ||
function rsaJwkToBuffer (jwk, opts) { | ||
if ('string' !== typeof jwk.e) { | ||
@@ -14,4 +41,58 @@ throw new TypeError('Expected "jwk.e" to be a String'); | ||
var pem = getPem(jwk.n, jwk.e); | ||
if (opts.private) { | ||
if ('string' !== typeof jwk.d) { | ||
throw new TypeError('Expected "jwk.d" to be a String'); | ||
} | ||
if ('string' !== typeof jwk.p) { | ||
throw new TypeError('Expected "jwk.p" to be a String'); | ||
} | ||
if ('string' !== typeof jwk.q) { | ||
throw new TypeError('Expected "jwk.q" to be a String'); | ||
} | ||
if ('string' !== typeof jwk.dp) { | ||
throw new TypeError('Expected "jwk.dp" to be a String'); | ||
} | ||
if ('string' !== typeof jwk.dq) { | ||
throw new TypeError('Expected "jwk.dq" to be a String'); | ||
} | ||
if ('string' !== typeof jwk.qi) { | ||
throw new TypeError('Expected "jwk.qi" to be a String'); | ||
} | ||
} | ||
var pem; | ||
if (opts.private) { | ||
pem = RSAPrivateKey.encode({ | ||
version: 0, | ||
modulus: b64ToBn(jwk.n), | ||
publicExponent: b64ToBn(jwk.e), | ||
privateExponent: b64ToBn(jwk.d), | ||
prime1: b64ToBn(jwk.p), | ||
prime2: b64ToBn(jwk.q), | ||
exponent1: b64ToBn(jwk.dp), | ||
exponent2: b64ToBn(jwk.dq), | ||
coefficient: b64ToBn(jwk.qi) | ||
}, 'pem', { | ||
label: 'RSA PRIVATE KEY' | ||
}); | ||
} else { | ||
pem = RSAPublicKey.encode({ | ||
modulus: b64ToBn(jwk.n), | ||
publicExponent: b64ToBn(jwk.e) | ||
}, 'pem', { | ||
label: 'RSA PUBLIC KEY' | ||
}); | ||
} | ||
// This is in an if incase asn1.js adds a trailing \n | ||
// istanbul ignore else | ||
if ('\n' !== pem.slice(-1)) { | ||
pem += '\n'; | ||
} | ||
return pem; | ||
@@ -18,0 +99,0 @@ } |
22738
3
8
287
73
5
- Removedrsa-pem-from-mod-exp@^0.8.4
- Removedrsa-pem-from-mod-exp@0.8.6(transitive)
Updatedasn1.js@^2.2.0