advance to CSR
This commit is contained in:
		
							parent
							
								
									d646edf045
								
							
						
					
					
						commit
						6c0aed0491
					
				
							
								
								
									
										108
									
								
								js/app.js
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								js/app.js
									
									
									
									
									
								
							| @ -19,8 +19,9 @@ | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function submitForm(ev) { |   function submitForm(ev) { | ||||||
|     steps[i].submit(ev); |     var j = i; | ||||||
|     i += 1; |     i += 1; | ||||||
|  |     steps[j].submit(ev); | ||||||
|   } |   } | ||||||
|   $qsa('.js-acme-form').forEach(function ($el) { |   $qsa('.js-acme-form').forEach(function ($el) { | ||||||
|     $el.addEventListener('submit', function (ev) { |     $el.addEventListener('submit', function (ev) { | ||||||
| @ -51,7 +52,12 @@ | |||||||
|   }; |   }; | ||||||
|   steps[1].submit = function () { |   steps[1].submit = function () { | ||||||
|     info.identifiers = $qs('.js-acme-domains').value.split(/\s*,\s*/g).map(function (hostname) { |     info.identifiers = $qs('.js-acme-domains').value.split(/\s*,\s*/g).map(function (hostname) { | ||||||
|       return { type: 'dns', value: hostname.trim() }; |       return { type: 'dns', value: hostname.toLowerCase().trim() }; | ||||||
|  |     }); | ||||||
|  |     info.identifiers.sort(function (a, b) { | ||||||
|  |       if (a === b) { return 0; } | ||||||
|  |       if (a < b) { return 1; } | ||||||
|  |       if (a > b) { return -1; } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     return BACME.directory($qs('.js-acme-directory-url').value).then(function (directory) { |     return BACME.directory($qs('.js-acme-directory-url').value).then(function (directory) { | ||||||
| @ -59,6 +65,7 @@ | |||||||
|       return BACME.nonce().then(function (_nonce) { |       return BACME.nonce().then(function (_nonce) { | ||||||
|         nonce = _nonce; |         nonce = _nonce; | ||||||
| 
 | 
 | ||||||
|  |         console.log("MAGIC STEP NUMBER in 1 is:", i); | ||||||
|         steps[i](); |         steps[i](); | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
| @ -147,6 +154,7 @@ | |||||||
|             signedOrder: signedOrder |             signedOrder: signedOrder | ||||||
|           }).then(function (order) { |           }).then(function (order) { | ||||||
|             info.finalizeUrl = order.finalize; |             info.finalizeUrl = order.finalize; | ||||||
|  |             info.orderUrl = order.url; // from header Location ???
 | ||||||
|             return BACME.thumbprint({ jwk: jwk }).then(function (thumbprint) { |             return BACME.thumbprint({ jwk: jwk }).then(function (thumbprint) { | ||||||
|               return BACME.challenges.all().then(function (claims) { |               return BACME.challenges.all().then(function (claims) { | ||||||
|                 console.log('claims:'); |                 console.log('claims:'); | ||||||
| @ -176,7 +184,7 @@ | |||||||
|                     , challengeDomain: hostname |                     , challengeDomain: hostname | ||||||
|                     }); |                     }); | ||||||
|                     return BACME.challenges['dns-01']({ |                     return BACME.challenges['dns-01']({ | ||||||
|                       keyAuth: keyAuth |                       keyAuth: keyAuth.value | ||||||
|                     , challengeDomain: hostname |                     , challengeDomain: hostname | ||||||
|                     }).then(function (dnsAuth) { |                     }).then(function (dnsAuth) { | ||||||
|                       var data = { |                       var data = { | ||||||
| @ -230,6 +238,7 @@ | |||||||
| 
 | 
 | ||||||
|                   updateChallengeType(); |                   updateChallengeType(); | ||||||
| 
 | 
 | ||||||
|  |                   console.log("MAGIC STEP NUMBER in 2 is:", i); | ||||||
|                   steps[i](); |                   steps[i](); | ||||||
|                 }); |                 }); | ||||||
| 
 | 
 | ||||||
| @ -249,23 +258,44 @@ | |||||||
|     $qs('.js-acme-form-challenges').hidden = false; |     $qs('.js-acme-form-challenges').hidden = false; | ||||||
|   }; |   }; | ||||||
|   steps[3].submit = function () { |   steps[3].submit = function () { | ||||||
|     var chType = $qs('.js-acme-challenge-type').value; |     // for now just show the next page immediately (its a spinner)
 | ||||||
|     var ps = []; |     console.log("MAGIC STEP NUMBER is:", i); | ||||||
|  | 
 | ||||||
|  |     var chType; | ||||||
|  |     Array.prototype.some.call($qsa('.js-acme-challenge-type'), function ($el) { | ||||||
|  |       if ($el.checked) { | ||||||
|  |         chType = $el.value; | ||||||
|  |         return true; | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |     console.log('chType is:', chType); | ||||||
|  |     var chs = []; | ||||||
| 
 | 
 | ||||||
|     // do each wildcard, if any
 |     // do each wildcard, if any
 | ||||||
|     // do each challenge, by selected type only
 |     // do each challenge, by selected type only
 | ||||||
|     [ 'wildcard', chType].forEach(function (typ) { |     [ 'wildcard', chType].forEach(function (typ) { | ||||||
|       info.challenges[typ].forEach(function (ch) { |       info.challenges[typ].forEach(function (ch) { | ||||||
|         // { jwk, challengeUrl, accountId (kid) }
 |         // { jwk, challengeUrl, accountId (kid) }
 | ||||||
|         ps.push(BACME.challenges.accept({ |         chs.push({ | ||||||
|           jwk: info.jwk |           jwk: info.jwk | ||||||
|         , challengeUrl: ch.url |         , challengeUrl: ch.url | ||||||
|         , accountId: info.kid |         , accountId: info.kid | ||||||
|         })); |         }); | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     return Promise.all(ps).then(function (results) { |     var results = []; | ||||||
|  |     function nextChallenge() { | ||||||
|  |       var ch = chs.pop(); | ||||||
|  |       if (!ch) { return results; } | ||||||
|  |       return BACME.challenges.accept(ch).then(function (result) { | ||||||
|  |         results.push(result); | ||||||
|  |         return nextChallenge(); | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     steps[i](); | ||||||
|  |     return nextChallenge().then(function (results) { | ||||||
|       console.log('challenge status:', results); |       console.log('challenge status:', results); | ||||||
|       var polls = results.slice(0); |       var polls = results.slice(0); | ||||||
|       var allsWell = true; |       var allsWell = true; | ||||||
| @ -276,7 +306,9 @@ | |||||||
|         }).then(function () { |         }).then(function () { | ||||||
|           return Promise.all(polls.map(function (poll) { |           return Promise.all(polls.map(function (poll) { | ||||||
|             return BACME.challenges.check({ challengePollUrl: poll.url }); |             return BACME.challenges.check({ challengePollUrl: poll.url }); | ||||||
|           })).then(function () { |           })).then(function (polls) { | ||||||
|  |             console.log(polls); | ||||||
|  | 
 | ||||||
|             polls = polls.filter(function (poll) { |             polls = polls.filter(function (poll) { | ||||||
|               //return 'valid' !== poll.status && 'invalid' !== poll.status;
 |               //return 'valid' !== poll.status && 'invalid' !== poll.status;
 | ||||||
|               if ('pending' === poll.status) { |               if ('pending' === poll.status) { | ||||||
| @ -312,7 +344,63 @@ | |||||||
|   } |   } | ||||||
|   steps[4].submit = function () { |   steps[4].submit = function () { | ||||||
|     console.log('Congrats! Auto advancing...'); |     console.log('Congrats! Auto advancing...'); | ||||||
|     return BACME.order |     var key = info.identifiers.map(function (ident) { return ident.value; }).join(','); | ||||||
|  |     var serverJwk = JSON.parse(localStorage.getItem('server:' + key) || 'null'); | ||||||
|  |     var p; | ||||||
|  | 
 | ||||||
|  |     function createKeypair() { | ||||||
|  |       return BACME.accounts.generateKeypair({ | ||||||
|  |         type: 'ECDSA' | ||||||
|  |       , bitlength: '256' | ||||||
|  |       }).then(function (serverJwk) { | ||||||
|  |         localStorage.setItem('server:' + key, JSON.stringify(serverJwk)); | ||||||
|  |         return serverJwk; | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (serverJwk) { | ||||||
|  |       p = Promise.resolve(serverJwk); | ||||||
|  |     } else { | ||||||
|  |       p = createKeypair(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return p.then(function (_serverJwk) { | ||||||
|  |       serverJwk = _serverJwk; | ||||||
|  |       // { serverJwk, domains }
 | ||||||
|  |       return BACME.orders.generateCsr({ | ||||||
|  |         serverJwk: serverJwk | ||||||
|  |       , domains: info.identifiers.map(function (ident) { | ||||||
|  |           return ident.value; | ||||||
|  |         }) | ||||||
|  |       }).then(function (csrweb64) { | ||||||
|  |         return BACME.order.finalize({ | ||||||
|  |           csr: csrweb64 | ||||||
|  |         , jwk: info.jwk | ||||||
|  |         , finalizeUrl: info.finalizeUrl | ||||||
|  |         , accountId: info.kid | ||||||
|  |         }); | ||||||
|  |       }).then(function () { | ||||||
|  |         function checkCert() { | ||||||
|  |           return new Promise(function (resolve) { | ||||||
|  |             setTimeout(resolve, 1000); | ||||||
|  |           }).then(function () { | ||||||
|  |             return BACME.order.check({ orderUrl: info.orderUrl }); | ||||||
|  |           }).then(function (reply) { | ||||||
|  |             if ('processing' === reply) { | ||||||
|  |               return checkCert(); | ||||||
|  |             } | ||||||
|  |             return reply; | ||||||
|  |           }); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return checkCert(); | ||||||
|  |       }).then(function (reply) { | ||||||
|  |         return BACME.order.receive({ certificateUrl: reply.certificate }); | ||||||
|  |       }).then(function (certs) { | ||||||
|  |         console.log('WINNING!'); | ||||||
|  |         console.log(certs); | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   steps[5] = function () { |   steps[5] = function () { | ||||||
|  | |||||||
							
								
								
									
										68
									
								
								js/bacme.js
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								js/bacme.js
									
									
									
									
									
								
							| @ -102,6 +102,8 @@ BACME.accounts.generateKeypair = function (opts) { | |||||||
| 			console.log('private jwk:'); | 			console.log('private jwk:'); | ||||||
| 			console.log(JSON.stringify(privJwk, null, 2)); | 			console.log(JSON.stringify(privJwk, null, 2)); | ||||||
| 
 | 
 | ||||||
|  |       return privJwk; | ||||||
|  |       /* | ||||||
| 			return webCrypto.subtle.exportKey( | 			return webCrypto.subtle.exportKey( | ||||||
| 				"pkcs8" | 				"pkcs8" | ||||||
| 			, result.privateKey | 			, result.privateKey | ||||||
| @ -112,6 +114,7 @@ BACME.accounts.generateKeypair = function (opts) { | |||||||
|         return privJwk; |         return privJwk; | ||||||
|         //return accountKeypair;
 |         //return accountKeypair;
 | ||||||
| 			}); | 			}); | ||||||
|  |       */ | ||||||
| 		}) | 		}) | ||||||
| 	}); | 	}); | ||||||
| }; | }; | ||||||
| @ -335,6 +338,7 @@ BACME.orders.create = function (opts) { | |||||||
| 			finalizeUrl = result.finalize; | 			finalizeUrl = result.finalize; | ||||||
|       BACME._logBody(result); |       BACME._logBody(result); | ||||||
| 
 | 
 | ||||||
|  |       result.url = currentOrderUrl; | ||||||
|       return result; |       return result; | ||||||
| 		}); | 		}); | ||||||
| 	}); | 	}); | ||||||
| @ -404,9 +408,9 @@ BACME.thumbprint = function (opts) { | |||||||
|   var keys; |   var keys; | ||||||
| 
 | 
 | ||||||
|   if (/^EC/i.test(opts.jwk.kty)) { |   if (/^EC/i.test(opts.jwk.kty)) { | ||||||
|     keys = [ 'e', 'kty', 'n' ]; |  | ||||||
|   } else if (/^RS/i.test(opts.jwk.kty)) { |  | ||||||
|     keys = [ 'crv', 'kty', 'x', 'y' ]; |     keys = [ 'crv', 'kty', 'x', 'y' ]; | ||||||
|  |   } else if (/^RS/i.test(opts.jwk.kty)) { | ||||||
|  |     keys = [ 'e', 'kty', 'n' ]; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| 	var accountPublicStr = '{' + keys.map(function (key) { | 	var accountPublicStr = '{' + keys.map(function (key) { | ||||||
| @ -416,12 +420,14 @@ BACME.thumbprint = function (opts) { | |||||||
| 	return window.crypto.subtle.digest( | 	return window.crypto.subtle.digest( | ||||||
| 		{ name: "SHA-256" } // SHA-256 is spec'd, non-optional
 | 		{ name: "SHA-256" } // SHA-256 is spec'd, non-optional
 | ||||||
| 	, textEncoder.encode(accountPublicStr) | 	, textEncoder.encode(accountPublicStr) | ||||||
| 	).then(function(hash){ | 	).then(function (hash) { | ||||||
| 		thumbprint = btoa(Array.prototype.map.call(new Uint8Array(hash), function (ch) { | 		thumbprint = btoa(Array.prototype.map.call(new Uint8Array(hash), function (ch) { | ||||||
| 			return String.fromCharCode(ch); | 			return String.fromCharCode(ch); | ||||||
| 		}).join('')).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); | 		}).join('')).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); | ||||||
| 
 | 
 | ||||||
| 		console.log('Thumbprint:'); | 		console.log('Thumbprint:'); | ||||||
|  | 		console.log(opts); | ||||||
|  | 		console.log(accountPublicStr); | ||||||
| 		console.log(thumbprint); | 		console.log(thumbprint); | ||||||
| 
 | 
 | ||||||
|     return thumbprint; |     return thumbprint; | ||||||
| @ -446,10 +452,12 @@ BACME.challenges['http-01'] = function (opts) { | |||||||
| 
 | 
 | ||||||
| // { keyAuth }
 | // { keyAuth }
 | ||||||
| BACME.challenges['dns-01'] = function (opts) { | BACME.challenges['dns-01'] = function (opts) { | ||||||
|  |   console.log('opts.keyAuth for DNS:'); | ||||||
|  |   console.log(opts.keyAuth); | ||||||
| 	return window.crypto.subtle.digest( | 	return window.crypto.subtle.digest( | ||||||
| 		{ name: "SHA-256", } | 		{ name: "SHA-256", } | ||||||
| 	, textEncoder.encode(opts.keyAuth) | 	, textEncoder.encode(opts.keyAuth) | ||||||
| 	).then(function(hash){ | 	).then(function (hash) { | ||||||
| 		dnsAuth = btoa(Array.prototype.map.call(new Uint8Array(hash), function (ch) { | 		dnsAuth = btoa(Array.prototype.map.call(new Uint8Array(hash), function (ch) { | ||||||
| 			return String.fromCharCode(ch); | 			return String.fromCharCode(ch); | ||||||
| 		}).join('')).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); | 		}).join('')).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); | ||||||
| @ -478,8 +486,7 @@ BACME.challenges.accept = function (opts) { | |||||||
| 		{} | 		{} | ||||||
| 	); | 	); | ||||||
| 
 | 
 | ||||||
| 	nonce = null; |   return BACME._importKey(opts.jwk).then(function (abstractKey) { | ||||||
|   return BACME._import(opts.jwk).then(function (abstractKey) { |  | ||||||
|     var protected64 = BACME._jsto64( |     var protected64 = BACME._jsto64( | ||||||
|       { nonce: nonce, alg: abstractKey.meta.alg/*'ES256'*/, url: opts.challengeUrl, kid: opts.accountId } |       { nonce: nonce, alg: abstractKey.meta.alg/*'ES256'*/, url: opts.challengeUrl, kid: opts.accountId } | ||||||
|     ); |     ); | ||||||
| @ -490,6 +497,7 @@ BACME.challenges.accept = function (opts) { | |||||||
|     }); |     }); | ||||||
|   }).then(function (signedAccept) { |   }).then(function (signedAccept) { | ||||||
| 
 | 
 | ||||||
|  | 	  nonce = null; | ||||||
| 		return window.fetch( | 		return window.fetch( | ||||||
| 			opts.challengeUrl | 			opts.challengeUrl | ||||||
| 		, { mode: 'cors' | 		, { mode: 'cors' | ||||||
| @ -555,8 +563,11 @@ BACME.domains.generateKeypair = function () { | |||||||
| 	}); | 	}); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| BACME.orders.generateCsr = function (keypair, domains) { | // { serverJwk, domains }
 | ||||||
|   return Promise.resolve(CSR.generate(keypair, 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 })); | ||||||
|  |   }); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| var certificateUrl; | var certificateUrl; | ||||||
| @ -567,8 +578,7 @@ BACME.orders.finalize = function (opts) { | |||||||
| 		{ csr: opts.csr } | 		{ csr: opts.csr } | ||||||
| 	); | 	); | ||||||
| 
 | 
 | ||||||
| 	nonce = null; |   return BACME._importKey(opts.jwk).then(function (abstractKey) { | ||||||
|   return BACME._import(opts.jwk).then(function (abstractKey) { |  | ||||||
|     var protected64 = BACME._jsto64( |     var protected64 = BACME._jsto64( | ||||||
|       { nonce: nonce, alg: abstractKey.meta.alg/*'ES256'*/, url: opts.finalizeUrl, kid: opts.accountId } |       { nonce: nonce, alg: abstractKey.meta.alg/*'ES256'*/, url: opts.finalizeUrl, kid: opts.accountId } | ||||||
|     ); |     ); | ||||||
| @ -579,8 +589,9 @@ BACME.orders.finalize = function (opts) { | |||||||
|     }); |     }); | ||||||
|   }).then(function (signedFinal) { |   }).then(function (signedFinal) { | ||||||
| 
 | 
 | ||||||
|  | 	  nonce = null; | ||||||
| 		return window.fetch( | 		return window.fetch( | ||||||
| 			finalizeUrl | 			opts.finalizeUrl | ||||||
| 		, { mode: 'cors' | 		, { mode: 'cors' | ||||||
| 			, method: 'POST' | 			, method: 'POST' | ||||||
| 			, headers: { 'Content-Type': 'application/jose+json' } | 			, headers: { 'Content-Type': 'application/jose+json' } | ||||||
| @ -600,4 +611,39 @@ BACME.orders.finalize = function (opts) { | |||||||
| 	}); | 	}); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | BACME.orders.receive = function (opts) { | ||||||
|  |   return window.fetch( | ||||||
|  |     opts.certificateUrl | ||||||
|  |   , { mode: 'cors' | ||||||
|  |     , method: 'GET' | ||||||
|  |     } | ||||||
|  |   ).then(function (resp) { | ||||||
|  |     BACME._logHeaders(resp); | ||||||
|  |     nonce = resp.headers.get('replay-nonce'); | ||||||
|  | 
 | ||||||
|  |     return resp.json().then(function (reply) { | ||||||
|  |       BACME._logBody(reply); | ||||||
|  | 
 | ||||||
|  |       return reply; | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | BACME.orders.check = function (opts) { | ||||||
|  |   return window.fetch( | ||||||
|  |     opts.orderUrl | ||||||
|  |   , { mode: 'cors' | ||||||
|  |     , method: 'GET' | ||||||
|  |     } | ||||||
|  |   ).then(function (resp) { | ||||||
|  |     BACME._logHeaders(resp); | ||||||
|  | 
 | ||||||
|  |     return resp.json().then(function (reply) { | ||||||
|  |       BACME._logBody(reply); | ||||||
|  | 
 | ||||||
|  |       return reply; | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| }(window)); | }(window)); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user