Compare commits
	
		
			No commits in common. "14c24e3aeab5249d977ce7a0d540c3f47536aca2" and "f1e11f1be778df9f7a088bb1fa6de10b873c8418" have entirely different histories.
		
	
	
		
			14c24e3aea
			...
			f1e11f1be7
		
	
		
							
								
								
									
										13
									
								
								app.js
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								app.js
									
									
									
									
									
								
							| @ -1,4 +1,3 @@ | |||||||
| /*global Promise*/ |  | ||||||
| (function () { | (function () { | ||||||
|   'use strict'; |   'use strict'; | ||||||
| 
 | 
 | ||||||
| @ -6,9 +5,6 @@ | |||||||
|   var Rasha = window.Rasha; |   var Rasha = window.Rasha; | ||||||
|   var Eckles = window.Eckles; |   var Eckles = window.Eckles; | ||||||
|   var x509 = window.x509; |   var x509 = window.x509; | ||||||
|   var CSR = window.CSR; |  | ||||||
|   var ACME = window.ACME; |  | ||||||
|   var accountStuff = {}; |  | ||||||
| 
 | 
 | ||||||
|   function $(sel) { |   function $(sel) { | ||||||
|     return document.querySelector(sel); |     return document.querySelector(sel); | ||||||
| @ -53,10 +49,8 @@ | |||||||
|       , namedCurve: $('input[name="ec-crv"]:checked').value |       , namedCurve: $('input[name="ec-crv"]:checked').value | ||||||
|       , modulusLength: $('input[name="rsa-len"]:checked').value |       , modulusLength: $('input[name="rsa-len"]:checked').value | ||||||
|       }; |       }; | ||||||
|       var then = Date.now(); |  | ||||||
|       console.log('opts', opts); |       console.log('opts', opts); | ||||||
|       Keypairs.generate(opts).then(function (results) { |       Keypairs.generate(opts).then(function (results) { | ||||||
|         console.log("Key generation time:", (Date.now() - then) + "ms"); |  | ||||||
|         var pubDer; |         var pubDer; | ||||||
|         var privDer; |         var privDer; | ||||||
|         if (/EC/i.test(opts.kty)) { |         if (/EC/i.test(opts.kty)) { | ||||||
| @ -105,13 +99,12 @@ | |||||||
|         $$('input').map(function ($el) { $el.disabled = false; }); |         $$('input').map(function ($el) { $el.disabled = false; }); | ||||||
|         $$('button').map(function ($el) { $el.disabled = false; }); |         $$('button').map(function ($el) { $el.disabled = false; }); | ||||||
|         $('.js-toc-jwk').hidden = false; |         $('.js-toc-jwk').hidden = false; | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
| 
 | 
 | ||||||
|         $('.js-create-account').hidden = false; |  | ||||||
|         $('.js-create-csr').hidden = false; |  | ||||||
|       }); |  | ||||||
|     }); |  | ||||||
| 
 | 
 | ||||||
|     $('.js-generate').hidden = false; |     $('.js-generate').hidden = false; | ||||||
|  |     $('.js-create-account').hidden = false; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   window.addEventListener('load', run); |   window.addEventListener('load', run); | ||||||
|  | |||||||
							
								
								
									
										31
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								index.html
									
									
									
									
									
								
							| @ -34,21 +34,27 @@ | |||||||
|       </div> |       </div> | ||||||
|       <div class="js-ec-opts"> |       <div class="js-ec-opts"> | ||||||
|         <p>EC Options:</p> |         <p>EC Options:</p> | ||||||
|         <label for="-crv2"><input type="radio" id="-crv2" |         <input type="radio" id="-crv2" | ||||||
|          name="ec-crv" value="P-256" checked>P-256</label> |          name="ec-crv" value="P-256" checked> | ||||||
|         <label for="-crv3"><input type="radio" id="-crv3" |         <label for="-crv2">P-256</label> | ||||||
|          name="ec-crv" value="P-384">P-384</label> |         <input type="radio" id="-crv3" | ||||||
|         <!-- label for="-crv5"><input type="radio" id="-crv5" |          name="ec-crv" value="P-384"> | ||||||
|          name="ec-crv" value="P-521">P-521</label --> |         <label for="-crv3">P-384</label> | ||||||
|  |         <!-- input type="radio" id="-crv5" | ||||||
|  |          name="ec-crv" value="P-521"> | ||||||
|  |         <label for="-crv5">P-521</label --> | ||||||
|       </div> |       </div> | ||||||
|       <div class="js-rsa-opts" hidden> |       <div class="js-rsa-opts" hidden> | ||||||
|         <p>RSA Options:</p> |         <p>RSA Options:</p> | ||||||
|         <label for="-modlen2"><input type="radio" id="-modlen2" |         <input type="radio" id="-modlen2" | ||||||
|          name="rsa-len" value="2048" checked>2048</label> |          name="rsa-len" value="2048" checked> | ||||||
|         <label for="-modlen3"><input type="radio" id="-modlen3" |         <label for="-modlen2">2048</label> | ||||||
|          name="rsa-len" value="3072">3072</label> |         <input type="radio" id="-modlen3" | ||||||
|         <label for="-modlen5"><input type="radio" id="-modlen5" |          name="rsa-len" value="3072"> | ||||||
|          name="rsa-len" value="4096">4096</label> |         <label for="-modlen3">3072</label> | ||||||
|  |         <input type="radio" id="-modlen5" | ||||||
|  |          name="rsa-len" value="4096"> | ||||||
|  |         <label for="-modlen5">4096</label> | ||||||
|       </div> |       </div> | ||||||
|       <button class="js-generate" hidden>Generate</button> |       <button class="js-generate" hidden>Generate</button> | ||||||
|     </form> |     </form> | ||||||
| @ -94,6 +100,7 @@ | |||||||
|     <script src="./lib/ecdsa.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="./app.js"></script> |     <script src="./app.js"></script> | ||||||
|   </body> |   </body> | ||||||
| </html> | </html> | ||||||
|  | |||||||
| @ -125,7 +125,7 @@ PEM.parseBlock = PEM.parseBlock || function (str) { | |||||||
|   var der = str.split(/\n/).filter(function (line) { |   var der = str.split(/\n/).filter(function (line) { | ||||||
|     return !/-----/.test(line); |     return !/-----/.test(line); | ||||||
|   }).join(''); |   }).join(''); | ||||||
|   return { bytes: Enc.base64ToBuf(der) }; |   return { der: Enc.base64ToBuf(der) }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Enc.base64ToBuf = function (b64) { | Enc.base64ToBuf = function (b64) { | ||||||
|  | |||||||
| @ -66,11 +66,8 @@ Enc.numToHex = function (d) { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Enc.bufToUrlBase64 = function (u8) { | Enc.bufToUrlBase64 = function (u8) { | ||||||
|   return Enc.base64ToUrlBase64(Enc.bufToBase64(u8)); |   return Enc.bufToBase64(u8) | ||||||
| }; |     .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); | ||||||
| 
 |  | ||||||
| Enc.base64ToUrlBase64 = function (str) { |  | ||||||
|   return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Enc.bufToBase64 = function (u8) { | Enc.bufToBase64 = function (u8) { | ||||||
| @ -113,8 +110,6 @@ Enc.binToHex = function (bin) { | |||||||
|     return h; |     return h; | ||||||
|   }).join(''); |   }).join(''); | ||||||
| }; | }; | ||||||
| // TODO are there any nuance differences here?
 |  | ||||||
| Enc.utf8ToHex = Enc.binToHex; |  | ||||||
| 
 | 
 | ||||||
| Enc.hexToBase64 = function (hex) { | Enc.hexToBase64 = function (hex) { | ||||||
|   return btoa(Enc.hexToBin(hex)); |   return btoa(Enc.hexToBin(hex)); | ||||||
|  | |||||||
| @ -180,12 +180,24 @@ Keypairs.signJws = function (opts) { | |||||||
|       var msg = protected64 + '.' + payload64; |       var msg = protected64 + '.' + payload64; | ||||||
| 
 | 
 | ||||||
|       return Keypairs._sign(opts, msg).then(function (buf) { |       return Keypairs._sign(opts, msg).then(function (buf) { | ||||||
|  |         /* | ||||||
|  |          * This will come back into play for CSRs, but not for JOSE | ||||||
|  |         if ('EC' === opts.jwk.kty) { | ||||||
|  |           // ECDSA JWT signatures differ from "normal" ECDSA signatures
 | ||||||
|  |           // https://tools.ietf.org/html/rfc7518#section-3.4
 | ||||||
|  |           binsig = convertIfEcdsa(binsig); | ||||||
|  |         } | ||||||
|  |         */ | ||||||
|         var signedMsg = { |         var signedMsg = { | ||||||
|           protected: protected64 |           protected: protected64 | ||||||
|         , payload: payload64 |         , payload: payload64 | ||||||
|         , signature: Enc.bufToUrlBase64(buf) |         , signature: Enc.bufToUrlBase64(buf) | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|  |         console.log('Signed Base64 Msg:'); | ||||||
|  |         console.log(JSON.stringify(signedMsg, null, 2)); | ||||||
|  | 
 | ||||||
|  |         console.log('msg:', msg); | ||||||
|         return signedMsg; |         return signedMsg; | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
| @ -200,6 +212,40 @@ Keypairs.signJws = function (opts) { | |||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
|  | Keypairs._convertIfEcdsa = function (binsig) { | ||||||
|  |   // should have asn1 sequence header of 0x30
 | ||||||
|  |   if (0x30 !== binsig[0]) { throw new Error("Impossible EC SHA head marker"); } | ||||||
|  |   var index = 2; // first ecdsa "R" header byte
 | ||||||
|  |   var len = binsig[1]; | ||||||
|  |   var lenlen = 0; | ||||||
|  |   // Seek length of length if length is greater than 127 (i.e. two 512-bit / 64-byte R and S values)
 | ||||||
|  |   if (0x80 & len) { | ||||||
|  |     lenlen = len - 0x80; // should be exactly 1
 | ||||||
|  |     len = binsig[2]; // should be <= 130 (two 64-bit SHA-512s, plus padding)
 | ||||||
|  |     index += lenlen; | ||||||
|  |   } | ||||||
|  |   // should be of BigInt type
 | ||||||
|  |   if (0x02 !== binsig[index]) { throw new Error("Impossible EC SHA R marker"); } | ||||||
|  |   index += 1; | ||||||
|  | 
 | ||||||
|  |   var rlen = binsig[index]; | ||||||
|  |   var bits = 32; | ||||||
|  |   if (rlen > 49) { | ||||||
|  |     bits = 64; | ||||||
|  |   } else if (rlen > 33) { | ||||||
|  |     bits = 48; | ||||||
|  |   } | ||||||
|  |   var r = binsig.slice(index + 1, index + 1 + rlen).toString('hex'); | ||||||
|  |   var slen = binsig[index + 1 + rlen + 1]; // skip header and read length
 | ||||||
|  |   var s = binsig.slice(index + 1 + rlen + 1 + 1).toString('hex'); | ||||||
|  |   if (2 *slen !== s.length) { throw new Error("Impossible EC SHA S length"); } | ||||||
|  |   // There may be one byte of padding on either
 | ||||||
|  |   while (r.length < 2*bits) { r = '00' + r; } | ||||||
|  |   while (s.length < 2*bits) { s = '00' + s; } | ||||||
|  |   if (2*(bits+1) === r.length) { r = r.slice(2); } | ||||||
|  |   if (2*(bits+1) === s.length) { s = s.slice(2); } | ||||||
|  |   return Enc.hexToBuf(r + s); | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| Keypairs._sign = function (opts, payload) { | Keypairs._sign = function (opts, payload) { | ||||||
|   return Keypairs._import(opts).then(function (privkey) { |   return Keypairs._import(opts).then(function (privkey) { | ||||||
| @ -213,14 +259,9 @@ Keypairs._sign = function (opts, payload) { | |||||||
|     , privkey |     , privkey | ||||||
|     , payload |     , payload | ||||||
|     ).then(function (signature) { |     ).then(function (signature) { | ||||||
|       signature = new Uint8Array(signature); // ArrayBuffer -> u8
 |       // convert buffer to urlsafe base64
 | ||||||
|       // This will come back into play for CSRs, but not for JOSE
 |       //return Enc.bufToUrlBase64(new Uint8Array(signature));
 | ||||||
|       if ('EC' === opts.jwk.kty && /x509|asn1/i.test(opts.format)) { |       return new Uint8Array(signature); | ||||||
|         return Keypairs._ecdsaJoseSigToAsn1Sig(signature); |  | ||||||
|       } else { |  | ||||||
|         // jose/jws/jwt
 |  | ||||||
|         return signature; |  | ||||||
|       } |  | ||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| @ -246,6 +287,7 @@ Keypairs._getName = function (opts) { | |||||||
|     return 'RSASSA-PKCS1-v1_5'; |     return 'RSASSA-PKCS1-v1_5'; | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  | 
 | ||||||
| Keypairs._import = function (opts) { | Keypairs._import = function (opts) { | ||||||
|   return Promise.resolve().then(function () { |   return Promise.resolve().then(function () { | ||||||
|     var ops; |     var ops; | ||||||
| @ -259,6 +301,7 @@ Keypairs._import = function (opts) { | |||||||
|     opts.jwk.ext = true; |     opts.jwk.ext = true; | ||||||
|     opts.jwk.key_ops = ops; |     opts.jwk.key_ops = ops; | ||||||
| 
 | 
 | ||||||
|  |     console.log('jwk', opts.jwk); | ||||||
|     return window.crypto.subtle.importKey( |     return window.crypto.subtle.importKey( | ||||||
|       "jwk" |       "jwk" | ||||||
|     , opts.jwk |     , opts.jwk | ||||||
| @ -273,30 +316,6 @@ Keypairs._import = function (opts) { | |||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| // ECDSA JOSE / JWS / JWT signatures differ from "normal" ASN1/X509 ECDSA signatures
 |  | ||||||
| // https://tools.ietf.org/html/rfc7518#section-3.4
 |  | ||||||
| Keypairs._ecdsaJoseSigToAsn1Sig = function (bufsig) { |  | ||||||
|   // it's easier to do the manipulation in the browser with an array
 |  | ||||||
|   bufsig = Array.from(bufsig); |  | ||||||
|   var hlen = bufsig.length / 2; // should be even
 |  | ||||||
|   var r = bufsig.slice(0, hlen); |  | ||||||
|   var s = bufsig.slice(hlen); |  | ||||||
|   // unpad positive ints less than 32 bytes wide
 |  | ||||||
|   while (!r[0]) { r = r.slice(1); } |  | ||||||
|   while (!s[0]) { s = s.slice(1); } |  | ||||||
|   // pad (or re-pad) ambiguously non-negative BigInts, up to 33 bytes wide
 |  | ||||||
|   if (0x80 & r[0]) { r.unshift(0); } |  | ||||||
|   if (0x80 & s[0]) { s.unshift(0); } |  | ||||||
| 
 |  | ||||||
|   var len = 2 + r.length + 2 + s.length; |  | ||||||
|   var head = [0x30]; |  | ||||||
|   // hard code 0x80 + 1 because it won't be longer than
 |  | ||||||
|   // two SHA512 plus two pad bytes (130 bytes <= 256)
 |  | ||||||
|   if (len >= 0x80) { head.push(0x81); } |  | ||||||
|   head.push(len); |  | ||||||
| 
 |  | ||||||
|   return Uint8Array.from(head.concat([0x02, r.length], r, [0x02, s.length], s)); |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| function setTime(time) { | function setTime(time) { | ||||||
|   if ('number' === typeof time) { return time; } |   if ('number' === typeof time) { return time; } | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
|  | 'use strict'; | ||||||
| (function (exports) { | (function (exports) { | ||||||
|   'use strict'; |   'use strict'; | ||||||
| 
 |  | ||||||
|   var x509 = exports.x509 = {}; |   var x509 = exports.x509 = {}; | ||||||
|   var ASN1 = exports.ASN1; |   var ASN1 = exports.ASN1; | ||||||
|   var Enc = exports.Enc; |   var Enc = exports.Enc; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user