v1.0.0: full PEM-to-JWK support
This commit is contained in:
parent
ea13bda056
commit
130a98677c
44
README.md
44
README.md
@ -1,19 +1,19 @@
|
|||||||
eckles.js
|
eckles.js
|
||||||
=========
|
=========
|
||||||
|
|
||||||
ECDSA tools. Lightweight. Zero Dependencies. Universal compatibility.
|
ECDSA (elliptic curve) tools. Lightweight. Zero Dependencies. Universal compatibility.
|
||||||
|
|
||||||
* [x] PEM-to-JWK
|
* [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] SEC1/X9.62, PKCS#8, SPKI/PKIX
|
||||||
* [x] P-256 (prime256v1, secp256r1), P-384 (secp384r1)
|
* [x] P-256 (prime256v1, secp256r1), P-384 (secp384r1)
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var eckles = require('eckles');
|
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) {
|
eckles.import({ pem: pem }).then(function (jwk) {
|
||||||
console.log(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)
|
* [x] P-256 (prime256v1, secp256r1), P-384 (secp384r1)
|
||||||
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
var eckles = require('eckles');
|
||||||
|
var jwk = require('eckles/fixtures/privkey-ec-p256.jwk.json');
|
||||||
|
|
||||||
eckles.export({ jwk: jwk }).then(function (pem) {
|
eckles.export({ jwk: jwk }).then(function (pem) {
|
||||||
// PEM in sec1 (x9.62) format
|
// PEM in SEC1 (x9.62) format
|
||||||
console.log(pem);
|
console.log(pem);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
@ -51,14 +53,32 @@ yZe7CnFsqeDcpnPbubP6cpYiVcnevNIYyg==
|
|||||||
-----END EC PRIVATE KEY-----
|
-----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
|
```js
|
||||||
eckles.exportSEC1(jwk).then(function (pem) {
|
eckles.export({ jwk: jwk, format: 'pkcs8' }).then(function (pem) {
|
||||||
// PEM in sec1 (x9.62) format
|
// 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);
|
console.log(pem);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
-->
|
|
||||||
|
|
||||||
Goals
|
Goals
|
||||||
-----
|
-----
|
||||||
|
@ -14,7 +14,7 @@ var OBJ_ID_EC_384 = '06 05 2B81040022'.replace(/\s+/g, '').toLowerCase();
|
|||||||
|
|
||||||
// 1.2.840.10045.2.1
|
// 1.2.840.10045.2.1
|
||||||
// ecPublicKey (ANSI X9.62 public key type)
|
// 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
|
// 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) {
|
if ('sec1' === format) {
|
||||||
return PEM.packBlock({ type: "EC PRIVATE KEY", bytes: EC.packSec1(jwk) });
|
return PEM.packBlock({ type: "EC PRIVATE KEY", bytes: EC.packSec1(jwk) });
|
||||||
} else if ('pkcs8' === format) {
|
} else if ('pkcs8' === format) {
|
||||||
throw new Error("pkcs8 output not implemented");
|
return PEM.packBlock({ type: "EC PRIVATE KEY", bytes: EC.packPkcs8(jwk) });
|
||||||
} else {
|
} 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 x = toHex(base64ToUint8(urlBase64ToBase64(jwk.x)));
|
||||||
var y = toHex(base64ToUint8(urlBase64ToBase64(jwk.y)));
|
var y = toHex(base64ToUint8(urlBase64ToBase64(jwk.y)));
|
||||||
var objId = ('P-256' === jwk.crv) ? OBJ_ID_EC : OBJ_ID_EC_384;
|
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) {
|
EC.packSpki = function (jwk) {
|
||||||
var x = toHex(base64ToUint8(urlBase64ToBase64(jwk.x)));
|
var x = toHex(base64ToUint8(urlBase64ToBase64(jwk.x)));
|
||||||
var y = toHex(base64ToUint8(urlBase64ToBase64(jwk.y)));
|
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;
|
EC.packPkix = EC.packSpki;
|
||||||
|
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "eckles",
|
"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.",
|
"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",
|
"homepage": "https://git.coolaj86.com/coolaj86/eckles.js",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
"eckles": "bin/eckles.js"
|
"eckles": "bin/eckles.js"
|
||||||
},
|
},
|
||||||
|
"files": [
|
||||||
|
"bin",
|
||||||
|
"fixtures",
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
"directories": {
|
"directories": {
|
||||||
"lib": "lib"
|
"lib": "lib"
|
||||||
},
|
},
|
||||||
|
51
test.sh
51
test.sh
@ -3,26 +3,53 @@ set -e
|
|||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo ""
|
echo ""
|
||||||
node bin/eckles.js fixtures/privkey-ec-p256.sec1.pem
|
echo "Testing PEM-to-JWK P-256"
|
||||||
node bin/eckles.js fixtures/privkey-ec-p256.pkcs8.pem
|
echo ""
|
||||||
node bin/eckles.js fixtures/pub-ec-p256.spki.pem
|
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 ""
|
||||||
echo ""
|
echo ""
|
||||||
node bin/eckles.js fixtures/privkey-ec-p384.sec1.pem
|
echo "Testing PEM-to-JWK P-384"
|
||||||
node bin/eckles.js fixtures/privkey-ec-p384.pkcs8.pem
|
echo ""
|
||||||
node bin/eckles.js fixtures/pub-ec-p384.spki.pem
|
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 ""
|
||||||
echo ""
|
echo ""
|
||||||
node bin/eckles.js fixtures/privkey-ec-p256.jwk sec1
|
echo "Testing JWK-to-PEM P-256"
|
||||||
node bin/eckles.js fixtures/privkey-ec-p256.jwk pkcs8
|
echo ""
|
||||||
node bin/eckles.js fixtures/pub-ec-p256.jwk spki
|
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 ""
|
||||||
echo ""
|
echo ""
|
||||||
node bin/eckles.js fixtures/privkey-ec-p384.jwk sec1
|
echo "Testing JWK-to-PEM P-384"
|
||||||
node bin/eckles.js fixtures/privkey-ec-p384.jwk pkcs8
|
echo ""
|
||||||
node bin/eckles.js fixtures/pub-ec-p384.jwk spki
|
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 ""
|
||||||
|
echo "PASSED:"
|
||||||
|
echo "• All inputs produced valid outputs"
|
||||||
|
echo "• All outputs matched known-good values"
|
||||||
|
echo ""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user