appears to work
This commit is contained in:
		
							parent
							
								
									6c0aed0491
								
							
						
					
					
						commit
						510a367135
					
				
							
								
								
									
										13
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								index.html
									
									
									
									
									
								
							| @ -120,19 +120,22 @@ | ||||
|       <button type="submit">Next</button> | ||||
|     </form> | ||||
| 
 | ||||
|     <!-- Step 4 Process Challanges --> | ||||
|     <!-- Step 5 Get Certs --> | ||||
|     <form class="js-acme-form js-acme-form-download"> | ||||
|       <label>privkey.pem</label> | ||||
|       <textarea>-</textarea> | ||||
|       <textarea class="js-privkey">-</textarea> | ||||
| 
 | ||||
|       <label>fullchain.pem</label> | ||||
|       <textarea>-</textarea> | ||||
|       <textarea class="js-fullchain">-</textarea> | ||||
| 
 | ||||
|       <!-- | ||||
|         TODO | ||||
|       <label>cert.pem</label> | ||||
|       <textarea>-</textarea> | ||||
|       <textarea class="js-cert">-</textarea> | ||||
| 
 | ||||
|       <label>chain.pem</label> | ||||
|       <textarea>-</textarea> | ||||
|       <textarea class="js-chain">-</textarea> | ||||
|       --> | ||||
| 
 | ||||
|       <button type="button">Download SSL Certificates</button> | ||||
| 
 | ||||
|  | ||||
| @ -10,5 +10,5 @@ popd | ||||
| 
 | ||||
| mkdir -p js/browser-csr/v1.0.0-alpha/ | ||||
| pushd js/browser-csr/v1.0.0-alpha/ | ||||
|   wget -c https://git.coolaj86.com/coolaj86/browser-csr.js/raw/commit/c513a862a4e016794da800f0c2eec858b80837ab/csr.js | ||||
|   wget -c https://git.coolaj86.com/coolaj86/browser-csr.js/raw/commit/01cdc0e91b5bf03f12e1b25b4129e3cde927987c/csr.js | ||||
| popd | ||||
|  | ||||
							
								
								
									
										81
									
								
								js/app.js
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								js/app.js
									
									
									
									
									
								
							| @ -30,7 +30,9 @@ | ||||
|     }); | ||||
|   }); | ||||
|   function updateChallengeType() { | ||||
|     var input = this || $qs('.js-acme-challenge-type'); | ||||
|     var input = this || Array.prototype.filter.call( | ||||
|       $qsa('.js-acme-challenge-type'), function ($el) { return $el.checked; } | ||||
|     )[0]; | ||||
|     console.log('ch type radio:', input.value); | ||||
|     $qs('.js-acme-table-wildcard').hidden = true; | ||||
|     $qs('.js-acme-table-http-01').hidden = true; | ||||
| @ -200,7 +202,6 @@ | ||||
|                       , dnsAnswer: dnsAuth.answer | ||||
|                       }; | ||||
| 
 | ||||
|                       obj[c.type].push(data); | ||||
|                       console.log(''); | ||||
|                       console.log('CHALLENGE'); | ||||
|                       console.log(claim); | ||||
| @ -258,9 +259,6 @@ | ||||
|     $qs('.js-acme-form-challenges').hidden = false; | ||||
|   }; | ||||
|   steps[3].submit = function () { | ||||
|     // for now just show the next page immediately (its a spinner)
 | ||||
|     console.log("MAGIC STEP NUMBER is:", i); | ||||
| 
 | ||||
|     var chType; | ||||
|     Array.prototype.some.call($qsa('.js-acme-challenge-type'), function ($el) { | ||||
|       if ($el.checked) { | ||||
| @ -283,6 +281,7 @@ | ||||
|         }); | ||||
|       }); | ||||
|     }); | ||||
|     console.log("INFO.challenges !!!!!", info.challenges); | ||||
| 
 | ||||
|     var results = []; | ||||
|     function nextChallenge() { | ||||
| @ -294,6 +293,7 @@ | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     // for now just show the next page immediately (its a spinner)
 | ||||
|     steps[i](); | ||||
|     return nextChallenge().then(function (results) { | ||||
|       console.log('challenge status:', results); | ||||
| @ -366,6 +366,7 @@ | ||||
| 
 | ||||
|     return p.then(function (_serverJwk) { | ||||
|       serverJwk = _serverJwk; | ||||
|       info.serverJwk = serverJwk; | ||||
|       // { serverJwk, domains }
 | ||||
|       return BACME.orders.generateCsr({ | ||||
|         serverJwk: serverJwk | ||||
| @ -373,7 +374,7 @@ | ||||
|           return ident.value; | ||||
|         }) | ||||
|       }).then(function (csrweb64) { | ||||
|         return BACME.order.finalize({ | ||||
|         return BACME.orders.finalize({ | ||||
|           csr: csrweb64 | ||||
|         , jwk: info.jwk | ||||
|         , finalizeUrl: info.finalizeUrl | ||||
| @ -384,7 +385,7 @@ | ||||
|           return new Promise(function (resolve) { | ||||
|             setTimeout(resolve, 1000); | ||||
|           }).then(function () { | ||||
|             return BACME.order.check({ orderUrl: info.orderUrl }); | ||||
|             return BACME.orders.check({ orderUrl: info.orderUrl }); | ||||
|           }).then(function (reply) { | ||||
|             if ('processing' === reply) { | ||||
|               return checkCert(); | ||||
| @ -395,10 +396,74 @@ | ||||
| 
 | ||||
|         return checkCert(); | ||||
|       }).then(function (reply) { | ||||
|         return BACME.order.receive({ certificateUrl: reply.certificate }); | ||||
|         return BACME.orders.receive({ certificateUrl: reply.certificate }); | ||||
|       }).then(function (certs) { | ||||
|         console.log('WINNING!'); | ||||
|         console.log(certs); | ||||
|         $qs('.js-fullchain').value = certs; | ||||
| 
 | ||||
|         // https://stackoverflow.com/questions/40314257/export-webcrypto-key-to-pem-format
 | ||||
| 				function spkiToPEM(keydata){ | ||||
| 						var keydataS = arrayBufferToString(keydata); | ||||
| 						var keydataB64 = window.btoa(keydataS); | ||||
| 						var keydataB64Pem = formatAsPem(keydataB64); | ||||
| 						return keydataB64Pem; | ||||
| 				} | ||||
| 
 | ||||
| 				function arrayBufferToString( buffer ) { | ||||
| 						var binary = ''; | ||||
| 						var bytes = new Uint8Array( buffer ); | ||||
| 						var len = bytes.byteLength; | ||||
| 						for (var i = 0; i < len; i++) { | ||||
| 								binary += String.fromCharCode( bytes[ i ] ); | ||||
| 						} | ||||
| 						return binary; | ||||
| 				} | ||||
| 
 | ||||
| 
 | ||||
| 				function formatAsPem(str) { | ||||
| 						var finalString = '-----BEGIN ' + pemName + ' PRIVATE KEY-----\n'; | ||||
| 
 | ||||
| 						while(str.length > 0) { | ||||
| 								finalString += str.substring(0, 64) + '\n'; | ||||
| 								str = str.substring(64); | ||||
| 						} | ||||
| 
 | ||||
| 						finalString = finalString + '-----END ' + pemName + ' PRIVATE KEY-----'; | ||||
| 
 | ||||
| 						return finalString; | ||||
| 				} | ||||
| 
 | ||||
|         var wcOpts; | ||||
|         var pemName; | ||||
|         if (/^R/.test(info.serverJwk.kty)) { | ||||
|           pemName = 'RSA'; | ||||
|           wcOpts = { | ||||
|             name: "RSASSA-PKCS1-v1_5" | ||||
|           , hash: { name: "SHA-256" } | ||||
|           }; | ||||
|         } else { | ||||
|           pemName = 'EC'; | ||||
|           wcOpts = { | ||||
|             name: "ECDSA" | ||||
|           , namedCurve: "P-256" | ||||
|           } | ||||
|         } | ||||
| 				return crypto.subtle.importKey( | ||||
|           "jwk" | ||||
|         , info.serverJwk | ||||
|         , wcOpts | ||||
|         , true | ||||
|         , ["sign"] | ||||
| 				).then(function (privateKey) { | ||||
| 				  return window.crypto.subtle.exportKey("pkcs8", privateKey); | ||||
| 				}).then (function (keydata) { | ||||
| 					var pem = spkiToPEM(keydata); | ||||
| 					$qs('.js-privkey').value = pem; | ||||
|           steps[i](); | ||||
| 				}).catch(function(err){ | ||||
| 					console.error(err); | ||||
| 				}); | ||||
|       }); | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
							
								
								
									
										51
									
								
								js/bacme.js
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								js/bacme.js
									
									
									
									
									
								
							| @ -129,13 +129,24 @@ var textEncoder = new TextEncoder(); | ||||
| BACME._importKey = function (jwk) { | ||||
|   var alg; // I think the 256 refers to the hash
 | ||||
|   var wcOpts = {}; | ||||
|   var extractable = false; | ||||
|   var extractable = true; // TODO make optionally false?
 | ||||
|   var priv = jwk; | ||||
|   var pub; | ||||
| 
 | ||||
|   // ECDSA
 | ||||
|   if (/^EC/i.test(jwk.kty)) { | ||||
|     wcOpts.name = 'ECDSA'; | ||||
|     wcOpts.namedCurve = jwk.crv; | ||||
|     alg = 'ES256'; | ||||
|     pub = { | ||||
|       crv: priv.crv | ||||
|     , kty: priv.kty | ||||
|     , x: priv.x | ||||
|     , y: priv.y | ||||
|     }; | ||||
|     if (!priv.d) { | ||||
|       priv = null; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // RSA
 | ||||
| @ -143,17 +154,28 @@ BACME._importKey = function (jwk) { | ||||
|     wcOpts.name = 'RSASSA-PKCS1-v1_5'; | ||||
|     wcOpts.hash = { name: "SHA-256" }; | ||||
|     alg = 'RS256'; | ||||
|     pub = { | ||||
|       e: priv.e | ||||
|     , kty: priv.kty | ||||
|     , n: priv.n | ||||
|     } | ||||
|     if (!priv.p) { | ||||
|       priv = null; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return window.crypto.subtle.importKey( | ||||
|     "jwk" | ||||
|   , jwk | ||||
|   , pub | ||||
| 	, wcOpts | ||||
|   , extractable | ||||
|   , [ "sign"/*, "verify"*/ ] | ||||
|   ).then(function (keypair) { | ||||
|   , [ "verify" ] | ||||
|   ).then(function (publicKey) { | ||||
|     function give(privateKey) { | ||||
|       return { | ||||
|       wcKey: keypair | ||||
|         wcPub: publicKey | ||||
|       , wcKey: privateKey | ||||
|       , wcKeypair: { publicKey: publicKey, privateKey: privateKey } | ||||
|       , meta: { | ||||
|           alg: alg | ||||
|         , name: wcOpts.name | ||||
| @ -161,10 +183,21 @@ BACME._importKey = function (jwk) { | ||||
|         } | ||||
|       , jwk: jwk | ||||
|       }; | ||||
|     } | ||||
|     if (!priv) { | ||||
|       return give(); | ||||
|     } | ||||
|     return window.crypto.subtle.importKey( | ||||
|       "jwk" | ||||
|     , priv | ||||
|     , wcOpts | ||||
|     , extractable | ||||
|     , [ "sign"/*, "verify"*/ ] | ||||
|     ).then(give); | ||||
|   }); | ||||
| }; | ||||
| BACME._sign = function (opts) { | ||||
|   var wcPrivKey = opts.abstractKey.wcKey; | ||||
|   var wcPrivKey = opts.abstractKey.wcKeypair.privateKey; | ||||
|   var wcOpts = opts.abstractKey.meta; | ||||
|   var alg = opts.abstractKey.meta.alg; // I think the 256 refers to the hash
 | ||||
|   var signHash; | ||||
| @ -508,6 +541,7 @@ BACME.challenges.accept = function (opts) { | ||||
| 		).then(function (resp) { | ||||
|       BACME._logHeaders(resp); | ||||
| 			nonce = resp.headers.get('replay-nonce'); | ||||
|       console.log("ACCEPT NONCE:", nonce); | ||||
| 
 | ||||
| 			return resp.json().then(function (reply) { | ||||
|         challengePollUrl = reply.url; | ||||
| @ -523,7 +557,6 @@ BACME.challenges.accept = function (opts) { | ||||
| BACME.challenges.check = function (opts) { | ||||
| 	return window.fetch(opts.challengePollUrl, { mode: 'cors' }).then(function (resp) { | ||||
|     BACME._logHeaders(resp); | ||||
| 		nonce = resp.headers.get('replay-nonce'); | ||||
| 
 | ||||
| 		return resp.json().then(function (reply) { | ||||
| 			challengePollUrl = reply.url; | ||||
| @ -566,7 +599,7 @@ BACME.domains.generateKeypair = function () { | ||||
| // { serverJwk, domains }
 | ||||
| BACME.orders.generateCsr = function (opts) { | ||||
|   return BACME._importKey(opts.serverJwk).then(function (abstractKey) { | ||||
|     return Promise.resolve(CSR.generate({ keypair: abstractKey.wcKey, domains: opts.domains })); | ||||
|     return Promise.resolve(CSR.generate({ keypair: abstractKey.wcKeypair, domains: opts.domains })); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| @ -621,7 +654,7 @@ BACME.orders.receive = function (opts) { | ||||
|     BACME._logHeaders(resp); | ||||
|     nonce = resp.headers.get('replay-nonce'); | ||||
| 
 | ||||
|     return resp.json().then(function (reply) { | ||||
|     return resp.text().then(function (reply) { | ||||
|       BACME._logBody(reply); | ||||
| 
 | ||||
|       return reply; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user