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