private Func <bool> PrepareChallengeResponse_TlsSni01(ILog log, ICertifiedServer iisManager, string domain, ManagedCertificate managedCertificate, PendingAuthorization pendingAuth) { var requestConfig = managedCertificate.RequestConfig; var tlsSniChallenge = pendingAuth.Challenges.FirstOrDefault(c => c.ChallengeType == SupportedChallengeTypes.CHALLENGE_TYPE_SNI); if (tlsSniChallenge == null) { log.Warning($"No tls-sni-01 challenge to complete for {managedCertificate.Name}. Request cannot continue."); return(() => false); } var sha256 = System.Security.Cryptography.SHA256.Create(); var z = new byte[tlsSniChallenge.HashIterationCount][]; // compute n sha256 hashes, where n=challengedata.iterationcount z[0] = sha256.ComputeHash(Encoding.UTF8.GetBytes(tlsSniChallenge.Value)); for (var i = 1; i < z.Length; i++) { z[i] = sha256.ComputeHash(z[i - 1]); } // generate certs and install iis bindings var cleanupQueue = new List <Action>(); var checkQueue = new List <Func <bool> >(); foreach (var hex in z.Select(b => BitConverter.ToString(b).Replace("-", "").ToLower())) { var sni = $"{hex.Substring(0, 32)}.{hex.Substring(32)}.acme.invalid"; log.Information($"Preparing binding at: https://{domain}, sni: {sni}"); var x509 = CertificateManager.GenerateSelfSignedCertificate(sni); CertificateManager.StoreCertificate(x509); var certStoreName = CertificateManager.GetStore().Name; // iisManager.InstallCertificateforBinding(certStoreName, x509.GetCertHash(), // managedCertificate.ServerSiteId, sni); // add check to the queue checkQueue.Add(() => _netUtil.CheckSNI(domain, sni).Result); // add cleanup actions to queue cleanupQueue.Add(() => iisManager.RemoveHttpsBinding(managedCertificate.ServerSiteId, sni)); cleanupQueue.Add(() => CertificateManager.RemoveCertificate(x509)); } // configure cleanup to execute the cleanup queue pendingAuth.Cleanup = () => cleanupQueue.ForEach(a => a()); // perform our own config checks return(() => checkQueue.All(check => check())); }
/// <summary> /// Prepares IIS to respond to a tls-sni-01 challenge /// </summary> /// <returns> /// A Boolean-returning Func. Invoke the Func to test the challenge response locally. /// </returns> private Func <bool> PrepareChallengeResponse_TlsSni01(IISManager iisManager, string domain, ManagedSite managedSite, PendingAuthorization pendingAuth) { var requestConfig = managedSite.RequestConfig; var tlsSniChallenge = (ACMESharp.ACME.TlsSniChallenge)pendingAuth.Challenge.ChallengeData; var tlsSniAnswer = (ACMESharp.ACME.TlsSniChallengeAnswer)tlsSniChallenge.Answer; var sha256 = System.Security.Cryptography.SHA256.Create(); var z = new byte[tlsSniChallenge.IterationCount][]; // compute n sha256 hashes, where n=challengedata.iterationcount z[0] = sha256.ComputeHash(Encoding.UTF8.GetBytes(tlsSniAnswer.KeyAuthorization)); for (int i = 1; i < z.Length; i++) { z[i] = sha256.ComputeHash(z[i - 1]); } // generate certs and install iis bindings var cleanupQueue = new List <Action>(); var checkQueue = new List <Func <bool> >(); foreach (string hex in z.Select(b => BitConverter.ToString(b).Replace("-", "").ToLower())) { string sni = $"{hex.Substring(0, 32)}.{hex.Substring(32)}.acme.invalid"; this.LogAction($"Preparing binding at: https://{domain}, sni: {sni}"); var x509 = CertificateManager.GenerateTlsSni01Certificate(sni); CertificateManager.StoreCertificate(x509); iisManager.InstallCertificateforBinding(managedSite, x509, sni); // add check to the queue checkQueue.Add(() => NetUtil.CheckSNI(domain, sni)); // add cleanup actions to queue cleanupQueue.Add(() => iisManager.RemoveHttpsBinding(managedSite, sni)); cleanupQueue.Add(() => CertificateManager.RemoveCertificate(x509)); } // configure cleanup to execute the cleanup queue pendingAuth.Cleanup = () => cleanupQueue.ForEach(a => a()); // perform our own config checks pendingAuth.TlsSniConfigCheckedOK = true; return(() => checkQueue.All(check => check())); }