display all ASN.1/x509 formats #3
							
								
								
									
										69
									
								
								app.js
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								app.js
									
									
									
									
									
								
							| @ -2,6 +2,9 @@ | |||||||
|   'use strict'; |   'use strict'; | ||||||
| 
 | 
 | ||||||
|   var Keypairs = window.Keypairs; |   var Keypairs = window.Keypairs; | ||||||
|  |   var Rasha = window.Rasha; | ||||||
|  |   var Eckles = window.Eckles; | ||||||
|  |   var x509 = window.x509; | ||||||
| 
 | 
 | ||||||
|   function $(sel) { |   function $(sel) { | ||||||
|     return document.querySelector(sel); |     return document.querySelector(sel); | ||||||
| @ -35,9 +38,10 @@ | |||||||
|       $('.js-loading').hidden = false; |       $('.js-loading').hidden = false; | ||||||
|       $('.js-jwk').hidden = true; |       $('.js-jwk').hidden = true; | ||||||
|       $('.js-toc-der-public').hidden = true; |       $('.js-toc-der-public').hidden = true; | ||||||
|       $('.js-toc-pem-public').hidden = true; |  | ||||||
|       $('.js-toc-der-private').hidden = true; |       $('.js-toc-der-private').hidden = true; | ||||||
|       $('.js-toc-pem-private').hidden = true; |       $$('.js-toc-pem').forEach(function ($el) { | ||||||
|  |         $el.hidden = true; | ||||||
|  |       }); | ||||||
|       $$('input').map(function ($el) { $el.disabled = true; }); |       $$('input').map(function ($el) { $el.disabled = true; }); | ||||||
|       $$('button').map(function ($el) { $el.disabled = true; }); |       $$('button').map(function ($el) { $el.disabled = true; }); | ||||||
|       var opts = { |       var opts = { | ||||||
| @ -47,32 +51,47 @@ | |||||||
|       }; |       }; | ||||||
|       console.log('opts', opts); |       console.log('opts', opts); | ||||||
|       Keypairs.generate(opts).then(function (results) { |       Keypairs.generate(opts).then(function (results) { | ||||||
|         var der_public, der_private; |         var pubDer; | ||||||
|         if (opts.kty == 'EC') { |         var privDer; | ||||||
|           der_public = x509.packSpki(results.public); |         if (/EC/i.test(opts.kty)) { | ||||||
|           der_private = x509.packPkcs8(results.private); |           privDer = x509.packPkcs8(results.private); | ||||||
|           var pem_private = Eckles.export({ jwk: results.private }) |           pubDer = x509.packSpki(results.public); | ||||||
|           var pem_public = Eckles.export({ jwk: results.public, public: true }) |           Eckles.export({ jwk: results.private, format: 'sec1' }).then(function (pem) { | ||||||
|           $('.js-input-pem-public').innerText = pem_public; |             $('.js-input-pem-sec1-private').innerText = pem; | ||||||
|           $('.js-toc-pem-public').hidden = false; |             $('.js-toc-pem-sec1-private').hidden = false; | ||||||
|           $('.js-input-pem-private').innerText = pem_private; |           }); | ||||||
|           $('.js-toc-pem-private').hidden = false; |           Eckles.export({ jwk: results.private, format: 'pkcs8' }).then(function (pem) { | ||||||
|  |             $('.js-input-pem-pkcs8-private').innerText = pem; | ||||||
|  |             $('.js-toc-pem-pkcs8-private').hidden = false; | ||||||
|  |           }); | ||||||
|  |           Eckles.export({ jwk: results.public, public: true }).then(function (pem) { | ||||||
|  |             $('.js-input-pem-spki-public').innerText = pem; | ||||||
|  |             $('.js-toc-pem-spki-public').hidden = false; | ||||||
|  |           }); | ||||||
|         } else { |         } else { | ||||||
|           der_private = x509.packPkcs8(results.private); |           privDer = x509.packPkcs8(results.private); | ||||||
|           der_public = x509.packPkcs8(results.public); |           pubDer = x509.packSpki(results.public); | ||||||
|           Rasha.pack({ jwk: results.private }).then(function (pem) { |           Rasha.export({ jwk: results.private, format: 'pkcs1' }).then(function (pem) { | ||||||
|             $('.js-input-pem-private').innerText = pem; |             $('.js-input-pem-pkcs1-private').innerText = pem; | ||||||
|             $('.js-toc-pem-private').hidden = false; |             $('.js-toc-pem-pkcs1-private').hidden = false; | ||||||
|           }) |           }); | ||||||
|           Rasha.pack({ jwk: results.public }).then(function (pem) { |           Rasha.export({ jwk: results.private, format: 'pkcs8' }).then(function (pem) { | ||||||
|             $('.js-input-pem-public').innerText = pem; |             $('.js-input-pem-pkcs8-private').innerText = pem; | ||||||
|             $('.js-toc-pem-public').hidden = false; |             $('.js-toc-pem-pkcs8-private').hidden = false; | ||||||
|           }) |           }); | ||||||
|  |           Rasha.export({ jwk: results.public, format: 'pkcs1' }).then(function (pem) { | ||||||
|  |             $('.js-input-pem-pkcs1-public').innerText = pem; | ||||||
|  |             $('.js-toc-pem-pkcs1-public').hidden = false; | ||||||
|  |           }); | ||||||
|  |           Rasha.export({ jwk: results.public, format: 'spki' }).then(function (pem) { | ||||||
|  |             $('.js-input-pem-spki-public').innerText = pem; | ||||||
|  |             $('.js-toc-pem-spki-public').hidden = false; | ||||||
|  |           }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         $('.js-der-public').innerText = der_public; |         $('.js-der-public').innerText = pubDer; | ||||||
|         $('.js-toc-der-public').hidden = false; |         $('.js-toc-der-public').hidden = false; | ||||||
|         $('.js-der-private').innerText = der_private; |         $('.js-der-private').innerText = privDer; | ||||||
|         $('.js-toc-der-private').hidden = false; |         $('.js-toc-der-private').hidden = false; | ||||||
|         $('.js-jwk').innerText = JSON.stringify(results, null, 2); |         $('.js-jwk').innerText = JSON.stringify(results, null, 2); | ||||||
|         $('.js-loading').hidden = true; |         $('.js-loading').hidden = true; | ||||||
| @ -87,7 +106,7 @@ | |||||||
|       ev.preventDefault(); |       ev.preventDefault(); | ||||||
|       ev.stopPropagation(); |       ev.stopPropagation(); | ||||||
|       $('.js-loading').hidden = false; |       $('.js-loading').hidden = false; | ||||||
|       ACME.accounts.create |       //ACME.accounts.create
 | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     $('.js-generate').hidden = false; |     $('.js-generate').hidden = false; | ||||||
|  | |||||||
							
								
								
									
										26
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								index.html
									
									
									
									
									
								
							| @ -80,13 +80,25 @@ | |||||||
|       <summary>DER Public Binary</summary> |       <summary>DER Public Binary</summary> | ||||||
|       <pre><code class="js-der-public"> </code></pre> |       <pre><code class="js-der-public"> </code></pre> | ||||||
|     </details> |     </details> | ||||||
|     <details class="js-toc-pem-private" hidden> |     <details class="js-toc-pem js-toc-pem-pkcs1-private" hidden> | ||||||
|       <summary>PEM Private (base64-encoded DER)</summary> |       <summary>PEM Private (base64-encoded PKCS1 DER)</summary> | ||||||
|       <pre><code  class="js-input-pem-private" ></code></pre> |       <pre><code  class="js-input-pem-pkcs1-private" ></code></pre> | ||||||
|     </details> |     </details> | ||||||
|     <details class="js-toc-pem-public" hidden> |     <details class="js-toc-pem js-toc-pem-sec1-private" hidden> | ||||||
|       <summary>PEM Public (base64-encoded DER)</summary> |       <summary>PEM Private (base64-encoded SEC1 DER)</summary> | ||||||
|       <pre><code  class="js-input-pem-public" ></code></pre> |       <pre><code  class="js-input-pem-sec1-private" ></code></pre> | ||||||
|  |     </details> | ||||||
|  |     <details class="js-toc-pem js-toc-pem-pkcs8-private" hidden> | ||||||
|  |       <summary>PEM Private (base64-encoded PKCS8 DER)</summary> | ||||||
|  |       <pre><code  class="js-input-pem-pkcs8-private" ></code></pre> | ||||||
|  |     </details> | ||||||
|  |     <details class="js-toc-pem js-toc-pem-pkcs1-public" hidden> | ||||||
|  |       <summary>PEM Public (base64-encoded PKCS1 DER)</summary> | ||||||
|  |       <pre><code  class="js-input-pem-pkcs1-public" ></code></pre> | ||||||
|  |     </details> | ||||||
|  |     <details class="js-toc-pem js-toc-pem-spki-public" hidden> | ||||||
|  |       <summary>PEM Public (base64-encoded SPKI/PKIX DER)</summary> | ||||||
|  |       <pre><code  class="js-input-pem-spki-public" ></code></pre> | ||||||
|     </details> |     </details> | ||||||
|     <details class="js-toc-acme-account-request" hidden> |     <details class="js-toc-acme-account-request" hidden> | ||||||
|       <summary>ACME Account Request</summary> |       <summary>ACME Account Request</summary> | ||||||
| @ -97,9 +109,9 @@ | |||||||
|       <pre><code class="js-acme-account-response"> </code></pre> |       <pre><code class="js-acme-account-response"> </code></pre> | ||||||
|     </details> |     </details> | ||||||
|     <script src="./lib/bluecrypt-encoding.js"></script> |     <script src="./lib/bluecrypt-encoding.js"></script> | ||||||
|     <script src="./lib/ecdsa.js"></script> |  | ||||||
|     <script src="./lib/asn1-packer.js"></script> |     <script src="./lib/asn1-packer.js"></script> | ||||||
|     <script src="./lib/x509.js"></script> |     <script src="./lib/x509.js"></script> | ||||||
|  |     <script src="./lib/ecdsa.js"></script> | ||||||
|     <script src="./lib/rsa.js"></script> |     <script src="./lib/rsa.js"></script> | ||||||
|     <script src="./lib/keypairs.js"></script> |     <script src="./lib/keypairs.js"></script> | ||||||
|     <script src="./lib/acme.js"></script> |     <script src="./lib/acme.js"></script> | ||||||
|  | |||||||
							
								
								
									
										87
									
								
								lib/ecdsa.js
									
									
									
									
									
								
							
							
						
						
									
										87
									
								
								lib/ecdsa.js
									
									
									
									
									
								
							| @ -3,7 +3,10 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| var EC = exports.Eckles = {}; | var EC = exports.Eckles = {}; | ||||||
|  | var x509 = exports.x509; | ||||||
| if ('undefined' !== typeof module) { module.exports = EC; } | if ('undefined' !== typeof module) { module.exports = EC; } | ||||||
|  | var PEM = exports.PEM; | ||||||
|  | var SSH = exports.SSH; | ||||||
| var Enc = {}; | var Enc = {}; | ||||||
| var textEncoder = new TextEncoder(); | var textEncoder = new TextEncoder(); | ||||||
| 
 | 
 | ||||||
| @ -52,51 +55,53 @@ EC.generate = function (opts) { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| EC.export = function (opts) { | EC.export = function (opts) { | ||||||
|   if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) { |   return Promise.resolve().then(function () { | ||||||
|     throw new Error("must pass { jwk: jwk } as a JSON object"); |     if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) { | ||||||
|   } |       throw new Error("must pass { jwk: jwk } as a JSON object"); | ||||||
|   var jwk = JSON.parse(JSON.stringify(opts.jwk)); |     } | ||||||
|   var format = opts.format; |     var jwk = JSON.parse(JSON.stringify(opts.jwk)); | ||||||
|   if (opts.public || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) { |     var format = opts.format; | ||||||
|     jwk.d = null; |     if (opts.public || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) { | ||||||
|   } |       jwk.d = null; | ||||||
|   if ('EC' !== jwk.kty) { |     } | ||||||
|     throw new Error("options.jwk.kty must be 'EC' for EC keys"); |     if ('EC' !== jwk.kty) { | ||||||
|   } |       throw new Error("options.jwk.kty must be 'EC' for EC keys"); | ||||||
|   if (!jwk.d) { |     } | ||||||
|     if (!format || -1 !== [ 'spki', 'pkix' ].indexOf(format)) { |     if (!jwk.d) { | ||||||
|       format = 'spki'; |       if (!format || -1 !== [ 'spki', 'pkix' ].indexOf(format)) { | ||||||
|     } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) { |         format = 'spki'; | ||||||
|       format = 'ssh'; |       } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) { | ||||||
|  |         format = 'ssh'; | ||||||
|  |       } else { | ||||||
|  |         throw new Error("options.format must be 'spki' or 'ssh' for public EC keys, not (" | ||||||
|  |           + typeof format + ") " + format); | ||||||
|  |       } | ||||||
|     } else { |     } else { | ||||||
|       throw new Error("options.format must be 'spki' or 'ssh' for public EC keys, not (" |       if (!format || 'sec1' === format) { | ||||||
|         + typeof format + ") " + format); |         format = 'sec1'; | ||||||
|  |       } else if ('pkcs8' !== format) { | ||||||
|  |         throw new Error("options.format must be 'sec1' or 'pkcs8' for private EC keys, not '" + format + "'"); | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } else { |     if (-1 === [ 'P-256', 'P-384' ].indexOf(jwk.crv)) { | ||||||
|     if (!format || 'sec1' === format) { |       throw new Error("options.jwk.crv must be either P-256 or P-384 for EC keys, not '" + jwk.crv + "'"); | ||||||
|       format = 'sec1'; |     } | ||||||
|     } else if ('pkcs8' !== format) { |     if (!jwk.y) { | ||||||
|       throw new Error("options.format must be 'sec1' or 'pkcs8' for private EC keys, not '" + format + "'"); |       throw new Error("options.jwk.y must be a urlsafe base64-encoded either P-256 or P-384"); | ||||||
|     } |     } | ||||||
|   } |  | ||||||
|   if (-1 === [ 'P-256', 'P-384' ].indexOf(jwk.crv)) { |  | ||||||
|     throw new Error("options.jwk.crv must be either P-256 or P-384 for EC keys, not '" + jwk.crv + "'"); |  | ||||||
|   } |  | ||||||
|   if (!jwk.y) { |  | ||||||
|     throw new Error("options.jwk.y must be a urlsafe base64-encoded either P-256 or P-384"); |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   if ('sec1' === format) { |     if ('sec1' === format) { | ||||||
|     return PEM.packBlock({ type: "EC PRIVATE KEY", bytes: x509.packSec1(jwk) }); |       return PEM.packBlock({ type: "EC PRIVATE KEY", bytes: x509.packSec1(jwk) }); | ||||||
|   } else if ('pkcs8' === format) { |     } else if ('pkcs8' === format) { | ||||||
|     return PEM.packBlock({ type: "PRIVATE KEY", bytes: x509.packPkcs8(jwk) }); |       return PEM.packBlock({ type: "PRIVATE KEY", bytes: x509.packPkcs8(jwk) }); | ||||||
|   } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) { |     } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) { | ||||||
|     return PEM.packBlock({ type: "PUBLIC KEY", bytes: x509.packSpki(jwk) }); |       return PEM.packBlock({ type: "PUBLIC KEY", bytes: x509.packSpki(jwk) }); | ||||||
|   } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) { |     } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) { | ||||||
|     return SSH.packSsh(jwk); |       return SSH.packSsh(jwk); | ||||||
|   } else { |     } else { | ||||||
|     throw new Error("Sanity Error: reached unreachable code block with format: " + format); |       throw new Error("Sanity Error: reached unreachable code block with format: " + format); | ||||||
|   } |     } | ||||||
|  |   }); | ||||||
| }; | }; | ||||||
| EC.pack = function (opts) { | EC.pack = function (opts) { | ||||||
|   return Promise.resolve().then(function () { |   return Promise.resolve().then(function () { | ||||||
|  | |||||||
							
								
								
									
										92
									
								
								lib/rsa.js
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								lib/rsa.js
									
									
									
									
									
								
							| @ -5,6 +5,8 @@ | |||||||
| var RSA = exports.Rasha = {}; | var RSA = exports.Rasha = {}; | ||||||
| var x509 = exports.x509; | var x509 = exports.x509; | ||||||
| if ('undefined' !== typeof module) { module.exports = RSA; } | if ('undefined' !== typeof module) { module.exports = RSA; } | ||||||
|  | var PEM = exports.PEM; | ||||||
|  | var SSH = exports.SSH; | ||||||
| var Enc = {}; | var Enc = {}; | ||||||
| var textEncoder = new TextEncoder(); | var textEncoder = new TextEncoder(); | ||||||
| 
 | 
 | ||||||
| @ -108,55 +110,57 @@ RSA.thumbprint = function (opts) { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| RSA.export = function (opts) { | RSA.export = function (opts) { | ||||||
|   if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) { |   return Promise.resolve().then(function () { | ||||||
|     throw new Error("must pass { jwk: jwk }"); |     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 jwk = JSON.parse(JSON.stringify(opts.jwk)); | ||||||
|   var pub = opts.public; |     var format = opts.format; | ||||||
|   if (pub || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) { |     var pub = opts.public; | ||||||
|     jwk = RSA.nueter(jwk); |     if (pub || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) { | ||||||
|   } |       jwk = RSA.neuter({ jwk: jwk }); | ||||||
|   if ('RSA' !== jwk.kty) { |     } | ||||||
|     throw new Error("options.jwk.kty must be 'RSA' for RSA keys"); |     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
 |     if (!jwk.p) { | ||||||
|     pub = true; |       // TODO test for n and e
 | ||||||
|     if (!format || 'pkcs1' === format) { |       pub = true; | ||||||
|       format = 'pkcs1'; |       if (!format || 'pkcs1' === format) { | ||||||
|     } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) { |         format = 'pkcs1'; | ||||||
|       format = 'spki'; |       } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) { | ||||||
|     } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) { |         format = 'spki'; | ||||||
|       format = 'ssh'; |       } 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 { |     } else { | ||||||
|       throw new Error("options.format must be 'spki', 'pkcs1', or 'ssh' for public RSA keys, not (" |       // TODO test for all necessary keys (d, p, q ...)
 | ||||||
|         + typeof format + ") " + format); |       if (!format || 'pkcs1' === format) { | ||||||
|  |         format = 'pkcs1'; | ||||||
|  |       } else if ('pkcs8' !== format) { | ||||||
|  |         throw new Error("options.format must be 'pkcs1' or 'pkcs8' for private RSA keys"); | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } 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 ('pkcs1' === format) { | ||||||
|     if (jwk.d) { |       if (jwk.d) { | ||||||
|       return PEM.packBlock({ type: "RSA PRIVATE KEY", bytes: x509.packPkcs1(jwk) }); |         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 { |     } else { | ||||||
|       return PEM.packBlock({ type: "RSA PUBLIC KEY", bytes: x509.packPkcs1(jwk) }); |       throw new Error("Sanity Error: reached unreachable code block with format: " + format); | ||||||
|     } |     } | ||||||
|   } 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) { | RSA.pack = function (opts) { | ||||||
|   // wrapped in a promise for API compatibility
 |   // wrapped in a promise for API compatibility
 | ||||||
|  | |||||||
							
								
								
									
										45
									
								
								lib/x509.js
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								lib/x509.js
									
									
									
									
									
								
							| @ -162,7 +162,7 @@ | |||||||
|    * @param {*} jwk |    * @param {*} jwk | ||||||
|    */ |    */ | ||||||
|   x509.packPkcs8 = function (jwk) { |   x509.packPkcs8 = function (jwk) { | ||||||
|     if (jwk.kty == 'RSA') { |     if ('RSA' === jwk.kty) { | ||||||
|       if (!jwk.d) { |       if (!jwk.d) { | ||||||
|         // Public RSA
 |         // Public RSA
 | ||||||
|         return Enc.hexToBuf(ASN1('30' |         return Enc.hexToBuf(ASN1('30' | ||||||
| @ -219,6 +219,49 @@ | |||||||
|     ); |     ); | ||||||
|   }; |   }; | ||||||
|   x509.packSpki = function (jwk) { |   x509.packSpki = function (jwk) { | ||||||
|  |     if (/EC/i.test(jwk.kty)) { | ||||||
|  |       return x509.packSpkiEc(jwk); | ||||||
|  |     } | ||||||
|  |     return x509.packSpkiRsa(jwk); | ||||||
|  |   }; | ||||||
|  |   x509.packSpkiRsa = function (jwk) { | ||||||
|  |   if (!jwk.d) { | ||||||
|  |     // Public RSA
 | ||||||
|  |     return Enc.hexToBuf(ASN1('30' | ||||||
|  |       , ASN1('30' | ||||||
|  |         , ASN1('06', '2a864886f70d010101') | ||||||
|  |         , ASN1('05') | ||||||
|  |       ) | ||||||
|  |       , ASN1.BitStr(ASN1('30' | ||||||
|  |         , ASN1.UInt(Enc.base64ToHex(jwk.n)) | ||||||
|  |         , ASN1.UInt(Enc.base64ToHex(jwk.e)) | ||||||
|  |       )) | ||||||
|  |     )); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Private RSA
 | ||||||
|  |   return Enc.hexToBuf(ASN1('30' | ||||||
|  |     , ASN1.UInt('00') | ||||||
|  |     , ASN1('30' | ||||||
|  |       , ASN1('06', '2a864886f70d010101') | ||||||
|  |       , ASN1('05') | ||||||
|  |     ) | ||||||
|  |     , ASN1('04' | ||||||
|  |       , ASN1('30' | ||||||
|  |         , ASN1.UInt('00') | ||||||
|  |         , ASN1.UInt(Enc.base64ToHex(jwk.n)) | ||||||
|  |         , ASN1.UInt(Enc.base64ToHex(jwk.e)) | ||||||
|  |         , ASN1.UInt(Enc.base64ToHex(jwk.d)) | ||||||
|  |         , ASN1.UInt(Enc.base64ToHex(jwk.p)) | ||||||
|  |         , ASN1.UInt(Enc.base64ToHex(jwk.q)) | ||||||
|  |         , ASN1.UInt(Enc.base64ToHex(jwk.dp)) | ||||||
|  |         , ASN1.UInt(Enc.base64ToHex(jwk.dq)) | ||||||
|  |         , ASN1.UInt(Enc.base64ToHex(jwk.qi)) | ||||||
|  |       ) | ||||||
|  |     ) | ||||||
|  |   )); | ||||||
|  | }; | ||||||
|  |   x509.packSpkiEc = function (jwk) { | ||||||
|     var x = Enc.base64ToHex(jwk.x); |     var x = Enc.base64ToHex(jwk.x); | ||||||
|     var y = Enc.base64ToHex(jwk.y); |     var y = Enc.base64ToHex(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; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user