working der and pem generation #2
							
								
								
									
										142
									
								
								app.js
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								app.js
									
									
									
									
									
								
							| @ -1,68 +1,98 @@ | |||||||
| (function () { | (function () { | ||||||
| 'use strict'; |   'use strict'; | ||||||
| 
 | 
 | ||||||
| var Keypairs = window.Keypairs; |   var Keypairs = window.Keypairs; | ||||||
| 
 | 
 | ||||||
| function $(sel) { |   function $(sel) { | ||||||
|   return document.querySelector(sel); |     return document.querySelector(sel); | ||||||
| } |   } | ||||||
| function $$(sel) { |   function $$(sel) { | ||||||
|   return Array.prototype.slice.call(document.querySelectorAll(sel)); |     return Array.prototype.slice.call(document.querySelectorAll(sel)); | ||||||
| } |   } | ||||||
| 
 | 
 | ||||||
| function run() { |   function run() { | ||||||
|   console.log('hello'); |     console.log('hello'); | ||||||
| 
 | 
 | ||||||
|   // Show different options for ECDSA vs RSA
 |     // Show different options for ECDSA vs RSA
 | ||||||
|   $$('input[name="kty"]').forEach(function ($el) { |     $$('input[name="kty"]').forEach(function ($el) { | ||||||
|     $el.addEventListener('change', function (ev) { |       $el.addEventListener('change', function (ev) { | ||||||
|       console.log(this); |         console.log(this); | ||||||
|       console.log(ev); |         console.log(ev); | ||||||
|       if ("RSA" === ev.target.value) { |         if ("RSA" === ev.target.value) { | ||||||
|         $('.js-rsa-opts').hidden = false; |           $('.js-rsa-opts').hidden = false; | ||||||
|         $('.js-ec-opts').hidden = true; |           $('.js-ec-opts').hidden = true; | ||||||
|       } else { |         } else { | ||||||
|         $('.js-rsa-opts').hidden = true; |           $('.js-rsa-opts').hidden = true; | ||||||
|         $('.js-ec-opts').hidden = false; |           $('.js-ec-opts').hidden = false; | ||||||
|       } |         } | ||||||
|  |       }); | ||||||
|     }); |     }); | ||||||
|   }); |  | ||||||
| 
 | 
 | ||||||
|   // Generate a key on submit
 |     // Generate a key on submit
 | ||||||
|   $('form.js-keygen').addEventListener('submit', function (ev) { |     $('form.js-keygen').addEventListener('submit', function (ev) { | ||||||
|     ev.preventDefault(); |       ev.preventDefault(); | ||||||
|     ev.stopPropagation(); |       ev.stopPropagation(); | ||||||
|     $('.js-loading').hidden = false; |       $('.js-loading').hidden = false; | ||||||
|     $('.js-jwk').hidden = true; |       $('.js-jwk').hidden = true; | ||||||
|     $$('input').map(function ($el) { $el.disabled = true; }); |       $('.js-toc-der-public').hidden = true; | ||||||
|     $$('button').map(function ($el) { $el.disabled = true; }); |       $('.js-toc-pem-public').hidden = true; | ||||||
|     var opts = { |       $('.js-toc-der-private').hidden = true; | ||||||
|       kty: $('input[name="kty"]:checked').value |       $('.js-toc-pem-private').hidden = true; | ||||||
|     , namedCurve: $('input[name="ec-crv"]:checked').value |       $$('input').map(function ($el) { $el.disabled = true; }); | ||||||
|     , modulusLength: $('input[name="rsa-len"]:checked').value |       $$('button').map(function ($el) { $el.disabled = true; }); | ||||||
|     }; |       var opts = { | ||||||
|     console.log('opts', opts); |         kty: $('input[name="kty"]:checked').value | ||||||
|     Keypairs.generate(opts).then(function (results) { |         , namedCurve: $('input[name="ec-crv"]:checked').value | ||||||
|       $('.js-jwk').innerText = JSON.stringify(results, null, 2); |         , modulusLength: $('input[name="rsa-len"]:checked').value | ||||||
|       //
 |       }; | ||||||
|       $('.js-loading').hidden = true; |       console.log('opts', opts); | ||||||
|       $('.js-jwk').hidden = false; |       Keypairs.generate(opts).then(function (results) { | ||||||
|       $$('input').map(function ($el) { $el.disabled = false; }); |         var der_public, der_private; | ||||||
|       $$('button').map(function ($el) { $el.disabled = false; }); |         if (opts.kty == 'EC') { | ||||||
|       $('.js-toc-jwk').hidden = false; |           der_public = x509.packSpki(results.public); | ||||||
|  |           der_private = x509.packPkcs8(results.private); | ||||||
|  |           var pem_private = Eckles.export({ jwk: results.private }) | ||||||
|  |           var pem_public = Eckles.export({ jwk: results.public, public: true }) | ||||||
|  |           $('.js-input-pem-public').innerText = pem_public; | ||||||
|  |           $('.js-toc-pem-public').hidden = false; | ||||||
|  |           $('.js-input-pem-private').innerText = pem_private; | ||||||
|  |           $('.js-toc-pem-private').hidden = false; | ||||||
|  |         } else { | ||||||
|  |           der_private = x509.packPkcs8(results.private); | ||||||
|  |           der_public = x509.packPkcs8(results.public); | ||||||
|  |           Rasha.pack({ jwk: results.private }).then(function (pem) { | ||||||
|  |             $('.js-input-pem-private').innerText = pem; | ||||||
|  |             $('.js-toc-pem-private').hidden = false; | ||||||
|  |           }) | ||||||
|  |           Rasha.pack({ jwk: results.public }).then(function (pem) { | ||||||
|  |             $('.js-input-pem-public').innerText = pem; | ||||||
|  |             $('.js-toc-pem-public').hidden = false; | ||||||
|  |           }) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         $('.js-der-public').innerText = der_public; | ||||||
|  |         $('.js-toc-der-public').hidden = false; | ||||||
|  |         $('.js-der-private').innerText = der_private; | ||||||
|  |         $('.js-toc-der-private').hidden = false; | ||||||
|  |         $('.js-jwk').innerText = JSON.stringify(results, null, 2); | ||||||
|  |         $('.js-loading').hidden = true; | ||||||
|  |         $('.js-jwk').hidden = false; | ||||||
|  |         $$('input').map(function ($el) { $el.disabled = false; }); | ||||||
|  |         $$('button').map(function ($el) { $el.disabled = false; }); | ||||||
|  |         $('.js-toc-jwk').hidden = false; | ||||||
|  |       }); | ||||||
|     }); |     }); | ||||||
|   }); |  | ||||||
| 
 | 
 | ||||||
|   $('form.js-acme-account').addEventListener('submit', function (ev) { |     $('form.js-acme-account').addEventListener('submit', function (ev) { | ||||||
|     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; | ||||||
|   $('.js-create-account').hidden = false; |     $('.js-create-account').hidden = false; | ||||||
| } |   } | ||||||
| 
 | 
 | ||||||
| window.addEventListener('load', run); |   window.addEventListener('load', run); | ||||||
| }()); | }()); | ||||||
|  | |||||||
							
								
								
									
										34
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								index.html
									
									
									
									
									
								
							| @ -1,6 +1,20 @@ | |||||||
| <html> | <html> | ||||||
|   <head> |   <head> | ||||||
|     <title>BlueCrypt</title> |     <title>BlueCrypt</title> | ||||||
|  |     <style> | ||||||
|  |       textarea { | ||||||
|  |         width: 42em; | ||||||
|  |         height: 10em; | ||||||
|  |       } | ||||||
|  |       /* need to word wrap the binary no space der */ | ||||||
|  |       .js-der-public, .js-der-private{ | ||||||
|  |         white-space: pre-wrap;      /* CSS3 */    | ||||||
|  |         white-space: -moz-pre-wrap; /* Firefox */     | ||||||
|  |         white-space: -pre-wrap;     /* Opera <7 */    | ||||||
|  |         white-space: -o-pre-wrap;   /* Opera 7 */     | ||||||
|  |         word-wrap: break-word;      /* IE */ | ||||||
|  |       } | ||||||
|  |     </style> | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
|     <h1>BlueCrypt for the Browser</h1> |     <h1>BlueCrypt for the Browser</h1> | ||||||
| @ -58,6 +72,22 @@ | |||||||
|       <summary>JWK Keypair</summary> |       <summary>JWK Keypair</summary> | ||||||
|       <pre><code class="js-jwk"> </code></pre> |       <pre><code class="js-jwk"> </code></pre> | ||||||
|     </details> |     </details> | ||||||
|  |     <details class="js-toc-der-private" hidden> | ||||||
|  |       <summary>DER Private Binary</summary> | ||||||
|  |       <pre><code class="js-der-private"> </code></pre> | ||||||
|  |     </details> | ||||||
|  |     <details class="js-toc-der-public" hidden> | ||||||
|  |       <summary>DER Public Binary</summary> | ||||||
|  |       <pre><code class="js-der-public"> </code></pre> | ||||||
|  |     </details> | ||||||
|  |     <details class="js-toc-pem-private" hidden> | ||||||
|  |       <summary>PEM Private (base64-encoded DER)</summary> | ||||||
|  |       <pre><code  class="js-input-pem-private" ></code></pre> | ||||||
|  |     </details> | ||||||
|  |     <details class="js-toc-pem-public" hidden> | ||||||
|  |       <summary>PEM Public (base64-encoded DER)</summary> | ||||||
|  |       <pre><code  class="js-input-pem-public" ></code></pre> | ||||||
|  |     </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> | ||||||
|       <pre><code class="js-acme-account-request"> </code></pre> |       <pre><code class="js-acme-account-request"> </code></pre> | ||||||
| @ -66,8 +96,10 @@ | |||||||
|       <summary>ACME Account Response</summary> |       <summary>ACME Account Response</summary> | ||||||
|       <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/ecdsa.js"></script> |     <script src="./lib/ecdsa.js"></script> | ||||||
|  |     <script src="./lib/asn1-packer.js"></script> | ||||||
|  |     <script src="./lib/x509.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> | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| (function (exports) { | (function (exports) { | ||||||
| 
 | 
 | ||||||
| var Enc = exports.BluecryptEncoding = {}; | var Enc = exports.Enc = {}; | ||||||
| 
 | 
 | ||||||
| Enc.bufToBin = function (buf) { | Enc.bufToBin = function (buf) { | ||||||
|   var bin = ''; |   var bin = ''; | ||||||
|  | |||||||
							
								
								
									
										53
									
								
								lib/ecdsa.js
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								lib/ecdsa.js
									
									
									
									
									
								
							| @ -51,6 +51,59 @@ EC.generate = function (opts) { | |||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | EC.export = function (opts) { | ||||||
|  |   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; | ||||||
|  |   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 (!jwk.d) { | ||||||
|  |     if (!format || -1 !== [ 'spki', 'pkix' ].indexOf(format)) { | ||||||
|  |       format = 'spki'; | ||||||
|  |     } 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 { | ||||||
|  |     if (!format || 'sec1' === format) { | ||||||
|  |       format = 'sec1'; | ||||||
|  |     } else if ('pkcs8' !== format) { | ||||||
|  |       throw new Error("options.format must be 'sec1' or 'pkcs8' for private EC keys, not '" + format + "'"); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   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) { | ||||||
|  |     return PEM.packBlock({ type: "EC PRIVATE KEY", bytes: x509.packSec1(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.packSsh(jwk); | ||||||
|  |   } else { | ||||||
|  |     throw new Error("Sanity Error: reached unreachable code block with format: " + format); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | EC.pack = function (opts) { | ||||||
|  |   return Promise.resolve().then(function () { | ||||||
|  |     return EC.exportSync(opts); | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| // Chopping off the private parts is now part of the public API.
 | // Chopping off the private parts is now part of the public API.
 | ||||||
| // I thought it sounded a little too crude at first, but it really is the best name in every possible way.
 | // I thought it sounded a little too crude at first, but it really is the best name in every possible way.
 | ||||||
| EC.neuter = function (opts) { | EC.neuter = function (opts) { | ||||||
|  | |||||||
| @ -3,8 +3,8 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| var Keypairs = exports.Keypairs = {}; | var Keypairs = exports.Keypairs = {}; | ||||||
| var Rasha = exports.Rasha || require('rasha'); | var Rasha = exports.Rasha; | ||||||
| var Eckles = exports.Eckles || require('eckles'); | var Eckles = exports.Eckles; | ||||||
| var Enc = exports.Enc || {}; | var Enc = exports.Enc || {}; | ||||||
| 
 | 
 | ||||||
| Keypairs._stance = "We take the stance that if you're knowledgeable enough to" | Keypairs._stance = "We take the stance that if you're knowledgeable enough to" | ||||||
| @ -34,10 +34,12 @@ Keypairs.generate = function (opts) { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // Chopping off the private parts is now part of the public API.
 | /** | ||||||
| // I thought it sounded a little too crude at first, but it really is the best name in every possible way.
 |  * Chopping off the private parts is now part of the public API. | ||||||
|  |  * I thought it sounded a little too crude at first, but it really is the best name in every possible way. | ||||||
|  |  */ | ||||||
| Keypairs.neuter = Keypairs._neuter = function (opts) { | Keypairs.neuter = Keypairs._neuter = function (opts) { | ||||||
|   // trying to find the best balance of an immutable copy with custom attributes
 |   /** trying to find the best balance of an immutable copy with custom attributes */ | ||||||
|   var jwk = {}; |   var jwk = {}; | ||||||
|   Object.keys(opts.jwk).forEach(function (k) { |   Object.keys(opts.jwk).forEach(function (k) { | ||||||
|     if ('undefined' === typeof opts.jwk[k]) { return; } |     if ('undefined' === typeof opts.jwk[k]) { return; } | ||||||
| @ -61,7 +63,7 @@ Keypairs.thumbprint = function (opts) { | |||||||
| Keypairs.publish = function (opts) { | Keypairs.publish = function (opts) { | ||||||
|   if ('object' !== typeof opts.jwk || !opts.jwk.kty) { throw new Error("invalid jwk: " + JSON.stringify(opts.jwk)); } |   if ('object' !== typeof opts.jwk || !opts.jwk.kty) { throw new Error("invalid jwk: " + JSON.stringify(opts.jwk)); } | ||||||
| 
 | 
 | ||||||
|   // returns a copy
 |   /** returns a copy */  | ||||||
|   var jwk = Keypairs.neuter(opts); |   var jwk = Keypairs.neuter(opts); | ||||||
| 
 | 
 | ||||||
|   if (jwk.exp) { |   if (jwk.exp) { | ||||||
|  | |||||||
							
								
								
									
										61
									
								
								lib/rsa.js
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								lib/rsa.js
									
									
									
									
									
								
							| @ -3,6 +3,7 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| var RSA = exports.Rasha = {}; | var RSA = exports.Rasha = {}; | ||||||
|  | var x509 = exports.x509; | ||||||
| if ('undefined' !== typeof module) { module.exports = RSA; } | if ('undefined' !== typeof module) { module.exports = RSA; } | ||||||
| var Enc = {}; | var Enc = {}; | ||||||
| var textEncoder = new TextEncoder(); | var textEncoder = new TextEncoder(); | ||||||
| @ -106,6 +107,66 @@ RSA.thumbprint = function (opts) { | |||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | RSA.export = function (opts) { | ||||||
|  |   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 pub = opts.public; | ||||||
|  |   if (pub || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) { | ||||||
|  |     jwk = RSA.nueter(jwk); | ||||||
|  |   } | ||||||
|  |   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
 | ||||||
|  |     pub = true; | ||||||
|  |     if (!format || 'pkcs1' === format) { | ||||||
|  |       format = 'pkcs1'; | ||||||
|  |     } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) { | ||||||
|  |       format = 'spki'; | ||||||
|  |     } 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 { | ||||||
|  |     // 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 (jwk.d) { | ||||||
|  |       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 { | ||||||
|  |     throw new Error("Sanity Error: reached unreachable code block with format: " + format); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | RSA.pack = function (opts) { | ||||||
|  |   // wrapped in a promise for API compatibility
 | ||||||
|  |   // with the forthcoming browser version
 | ||||||
|  |   // (and potential future native node capability)
 | ||||||
|  |   return Promise.resolve().then(function () { | ||||||
|  |     return RSA.export(opts); | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| Enc.bufToUrlBase64 = function (u8) { | Enc.bufToUrlBase64 = function (u8) { | ||||||
|   return Enc.bufToBase64(u8) |   return Enc.bufToBase64(u8) | ||||||
|     .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); |     .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); | ||||||
|  | |||||||
							
								
								
									
										69
									
								
								lib/x509.js
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								lib/x509.js
									
									
									
									
									
								
							| @ -55,6 +55,27 @@ | |||||||
|     }; |     }; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  |   x509.packPkcs1 = function (jwk) { | ||||||
|  |     var n = ASN1.UInt(Enc.base64ToHex(jwk.n)); | ||||||
|  |     var e = ASN1.UInt(Enc.base64ToHex(jwk.e)); | ||||||
|  |    | ||||||
|  |     if (!jwk.d) { | ||||||
|  |       return Enc.hexToBuf(ASN1('30', n, e)); | ||||||
|  |     } | ||||||
|  |    | ||||||
|  |     return Enc.hexToBuf(ASN1('30' | ||||||
|  |     , ASN1.UInt('00') | ||||||
|  |     , n | ||||||
|  |     , 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.parsePkcs8 = function parseEcPkcs8(u8, jwk) { |   x509.parsePkcs8 = function parseEcPkcs8(u8, jwk) { | ||||||
|     var index = 24 + (OBJ_ID_EC.length / 2); |     var index = 24 + (OBJ_ID_EC.length / 2); | ||||||
|     var len = 32; |     var len = 32; | ||||||
| @ -128,7 +149,7 @@ | |||||||
|     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; | ||||||
|     return Enc.hexToUint8( |     return Enc.hexToBuf( | ||||||
|       ASN1('30' |       ASN1('30' | ||||||
|         , ASN1.UInt('01') |         , ASN1.UInt('01') | ||||||
|         , ASN1('04', d) |         , ASN1('04', d) | ||||||
| @ -136,12 +157,54 @@ | |||||||
|         , ASN1('A1', ASN1.BitStr('04' + x + y))) |         , ASN1('A1', ASN1.BitStr('04' + x + y))) | ||||||
|     ); |     ); | ||||||
|   }; |   }; | ||||||
|  |   /** | ||||||
|  |    * take a private jwk and creates a der from it | ||||||
|  |    * @param {*} jwk  | ||||||
|  |    */ | ||||||
|   x509.packPkcs8 = function (jwk) { |   x509.packPkcs8 = function (jwk) { | ||||||
|  |     if (jwk.kty == 'RSA') { | ||||||
|  |       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)) | ||||||
|  |           ) | ||||||
|  |         ) | ||||||
|  |       )); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     var d = Enc.base64ToHex(jwk.d); |     var d = Enc.base64ToHex(jwk.d); | ||||||
|     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; | ||||||
|     return Enc.hexToUint8( |     return Enc.hexToBuf( | ||||||
|       ASN1('30' |       ASN1('30' | ||||||
|         , ASN1.UInt('00') |         , ASN1.UInt('00') | ||||||
|         , ASN1('30' |         , ASN1('30' | ||||||
| @ -159,7 +222,7 @@ | |||||||
|     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; | ||||||
|     return Enc.hexToUint8( |     return Enc.hexToBuf( | ||||||
|       ASN1('30' |       ASN1('30' | ||||||
|         , ASN1('30' |         , ASN1('30' | ||||||
|           , OBJ_ID_EC_PUB |           , OBJ_ID_EC_PUB | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user