v1.0.0: full PEM-to-JWK support

This commit is contained in:
AJ ONeal 2018-11-19 23:17:39 -07:00
parent ea13bda056
commit 130a98677c
8 changed files with 102 additions and 28 deletions

View File

@ -1,19 +1,19 @@
eckles.js
=========
ECDSA tools. Lightweight. Zero Dependencies. Universal compatibility.
ECDSA (elliptic curve) tools. Lightweight. Zero Dependencies. Universal compatibility.
* [x] PEM-to-JWK
* [ ] JWK-to-PEM (partial)
* [x] JWK-to-PEM
### PEM-to-JWK
## PEM-to-JWK
* [x] SEC1/X9.62, PKCS#8, SPKI/PKIX
* [x] P-256 (prime256v1, secp256r1), P-384 (secp384r1)
```js
var eckles = require('eckles');
var pem = require('fs').readFileSync('./fixtures/privkey-ec-p256.sec1.pem', 'ascii')
var pem = require('fs').readFileSync('eckles/fixtures/privkey-ec-p256.sec1.pem', 'ascii');
eckles.import({ pem: pem }).then(function (jwk) {
console.log(jwk);
@ -30,15 +30,17 @@ eckles.import({ pem: pem }).then(function (jwk) {
}
```
### JWK-to-PEM
## JWK-to-PEM
* [x] SEC1/X9.62
* [x] SEC1/X9.62, PKCS#8, SPKI/PKIX
* [x] P-256 (prime256v1, secp256r1), P-384 (secp384r1)
```js
var eckles = require('eckles');
var jwk = require('eckles/fixtures/privkey-ec-p256.jwk.json');
eckles.export({ jwk: jwk }).then(function (pem) {
// PEM in sec1 (x9.62) format
// PEM in SEC1 (x9.62) format
console.log(pem);
});
```
@ -51,14 +53,32 @@ yZe7CnFsqeDcpnPbubP6cpYiVcnevNIYyg==
-----END EC PRIVATE KEY-----
```
<!--
#### Advanced
`format: 'pkcs8'`:
The default output format is `sec1`/`x9.62` (EC-specific format) is used for private keys.
Use `format: 'pkcs8'` to output in PKCS#8 format instead.
```js
eckles.exportSEC1(jwk).then(function (pem) {
// PEM in sec1 (x9.62) format
eckles.export({ jwk: jwk, format: 'pkcs8' }).then(function (pem) {
// PEM in PKCS#8 format
console.log(pem);
});
```
`public: 'true'`:
If a private key is used as input, a private key will be output.
If you'd like to output a public key instead you can pass `public: true` or `format: 'spki'`.
```js
eckles.export({ jwk: jwk, public: true }).then(function (pem) {
// PEM in SPKI/PKIX format
console.log(pem);
});
```
-->
Goals
-----

View File

@ -14,7 +14,7 @@ var OBJ_ID_EC_384 = '06 05 2B81040022'.replace(/\s+/g, '').toLowerCase();
// 1.2.840.10045.2.1
// ecPublicKey (ANSI X9.62 public key type)
//var OBJ_ID_EC_PUB = '06 07 2A8648CE3D0201'.replace(/\s+/g, '').toLowerCase();
var OBJ_ID_EC_PUB = '06 07 2A8648CE3D0201'.replace(/\s+/g, '').toLowerCase();
// The one good thing that came from the b***kchain hysteria: good EC documentation
@ -325,9 +325,9 @@ EC.pack = function (opts) {
if ('sec1' === format) {
return PEM.packBlock({ type: "EC PRIVATE KEY", bytes: EC.packSec1(jwk) });
} else if ('pkcs8' === format) {
throw new Error("pkcs8 output not implemented");
return PEM.packBlock({ type: "EC PRIVATE KEY", bytes: EC.packPkcs8(jwk) });
} else {
throw new Error("spki not implemented");
return PEM.packBlock({ type: "PUBLIC KEY", bytes: EC.packSpki(jwk) });
}
});
};
@ -350,10 +350,32 @@ EC.packPkcs8 = function (jwk) {
var x = toHex(base64ToUint8(urlBase64ToBase64(jwk.x)));
var y = toHex(base64ToUint8(urlBase64ToBase64(jwk.y)));
var objId = ('P-256' === jwk.crv) ? OBJ_ID_EC : OBJ_ID_EC_384;
return Hex.toUint8(
ASN1('30'
, ASN1.UInt('00')
, ASN1('30'
, OBJ_ID_EC_PUB
, objId
)
, ASN1('04'
, ASN1('30'
, ASN1.UInt('01')
, ASN1('04', d)
, ASN1('A1', ASN1.BitStr('04' + x + y)))))
);
};
EC.packSpki = function (jwk) {
var x = toHex(base64ToUint8(urlBase64ToBase64(jwk.x)));
var y = toHex(base64ToUint8(urlBase64ToBase64(jwk.y)));
var objId = ('P-256' === jwk.crv) ? OBJ_ID_EC : OBJ_ID_EC_384;
return Hex.toUint8(
ASN1('30'
, ASN1('30'
, OBJ_ID_EC_PUB
, objId
)
, ASN1.BitStr('04' + x + y))
);
};
EC.packPkix = EC.packSpki;

View File

@ -1,12 +1,17 @@
{
"name": "eckles",
"version": "0.7.2",
"version": "1.0.0",
"description": "PEM-to-JWK and JWK-to-PEM for ECDSA keys in a lightweight, zero-dependency library focused on perfect universal compatibility.",
"homepage": "https://git.coolaj86.com/coolaj86/eckles.js",
"main": "index.js",
"bin": {
"eckles": "bin/eckles.js"
},
"files": [
"bin",
"fixtures",
"lib"
],
"directories": {
"lib": "lib"
},

51
test.sh
View File

@ -3,26 +3,53 @@ set -e
echo ""
echo ""
node bin/eckles.js fixtures/privkey-ec-p256.sec1.pem
node bin/eckles.js fixtures/privkey-ec-p256.pkcs8.pem
node bin/eckles.js fixtures/pub-ec-p256.spki.pem
echo "Testing PEM-to-JWK P-256"
echo ""
node bin/eckles.js fixtures/privkey-ec-p256.sec1.pem | tee fixtures/privkey-ec-p256.jwk.2
diff fixtures/privkey-ec-p256.jwk.json fixtures/privkey-ec-p256.jwk.2
node bin/eckles.js fixtures/privkey-ec-p256.pkcs8.pem | tee fixtures/privkey-ec-p256.jwk.2
diff fixtures/privkey-ec-p256.jwk.json fixtures/privkey-ec-p256.jwk.2
node bin/eckles.js fixtures/pub-ec-p256.spki.pem | tee fixtures/pub-ec-p256.jwk.2
diff fixtures/pub-ec-p256.jwk.json fixtures/pub-ec-p256.jwk.2
echo ""
echo ""
node bin/eckles.js fixtures/privkey-ec-p384.sec1.pem
node bin/eckles.js fixtures/privkey-ec-p384.pkcs8.pem
node bin/eckles.js fixtures/pub-ec-p384.spki.pem
echo "Testing PEM-to-JWK P-384"
echo ""
node bin/eckles.js fixtures/privkey-ec-p384.sec1.pem | tee fixtures/privkey-ec-p384.jwk.2
diff fixtures/privkey-ec-p384.jwk.json fixtures/privkey-ec-p384.jwk.2
node bin/eckles.js fixtures/privkey-ec-p384.pkcs8.pem | tee fixtures/privkey-ec-p384.jwk.2.2
diff fixtures/privkey-ec-p384.jwk.json fixtures/privkey-ec-p384.jwk.2.2
node bin/eckles.js fixtures/pub-ec-p384.spki.pem | tee fixtures/pub-ec-p384.jwk.2
diff fixtures/pub-ec-p384.jwk.json fixtures/pub-ec-p384.jwk.2
echo ""
echo ""
node bin/eckles.js fixtures/privkey-ec-p256.jwk sec1
node bin/eckles.js fixtures/privkey-ec-p256.jwk pkcs8
node bin/eckles.js fixtures/pub-ec-p256.jwk spki
echo "Testing JWK-to-PEM P-256"
echo ""
node bin/eckles.js fixtures/privkey-ec-p256.jwk.json sec1 | tee fixtures/privkey-ec-p256.sec1.pem.2
diff fixtures/privkey-ec-p256.sec1.pem fixtures/privkey-ec-p256.sec1.pem.2
node bin/eckles.js fixtures/privkey-ec-p256.jwk.json pkcs8 | tee fixtures/privkey-ec-p256.pkcs8.pem.2
diff fixtures/privkey-ec-p256.pkcs8.pem fixtures/privkey-ec-p256.pkcs8.pem.2
node bin/eckles.js fixtures/pub-ec-p256.jwk.json spki | tee fixtures/pub-ec-p256.spki.pem.2
diff fixtures/pub-ec-p256.spki.pem fixtures/pub-ec-p256.spki.pem.2
echo ""
echo ""
node bin/eckles.js fixtures/privkey-ec-p384.jwk sec1
node bin/eckles.js fixtures/privkey-ec-p384.jwk pkcs8
node bin/eckles.js fixtures/pub-ec-p384.jwk spki
echo "Testing JWK-to-PEM P-384"
echo ""
node bin/eckles.js fixtures/privkey-ec-p384.jwk.json sec1 | tee fixtures/privkey-ec-p384.sec1.pem.2
diff fixtures/privkey-ec-p384.sec1.pem fixtures/privkey-ec-p384.sec1.pem.2
node bin/eckles.js fixtures/privkey-ec-p384.jwk.json pkcs8 | tee fixtures/privkey-ec-p384.pkcs8.pem.2
diff fixtures/privkey-ec-p384.pkcs8.pem fixtures/privkey-ec-p384.pkcs8.pem.2
node bin/eckles.js fixtures/pub-ec-p384.jwk.json spki | tee fixtures/pub-ec-p384.spki.pem.2
diff fixtures/pub-ec-p384.spki.pem fixtures/pub-ec-p384.spki.pem.2
rm fixtures/*.2
echo ""
echo ""
echo "PASSED:"
echo "• All inputs produced valid outputs"
echo "• All outputs matched known-good values"
echo ""