public StatusMessage SubmitCertificate(string certAlias) { try { var result = ACMESharpUtils.SubmitCertificate(certAlias, protectSensitiveFileStorage: UseEFSForSensitiveFiles); return(new StatusMessage { IsOK = true, Result = result }); } catch (Exception exp) { if (exp is ACMESharp.AcmeClient.AcmeWebException) { var aex = (ACMESharp.AcmeClient.AcmeWebException)exp; return(new StatusMessage { IsOK = false, Message = aex.Message, Result = aex }); } else { return(new StatusMessage { IsOK = false, Message = exp.Message, Result = exp }); } } }
public APIResult SubmitCertificate(string certAlias) { try { var result = ACMESharpUtils.SubmitCertificate(certAlias); return(new APIResult { IsOK = true, Result = result }); } catch (Exception exp) { if (exp is ACMESharp.AcmeClient.AcmeWebException) { var aex = (ACMESharp.AcmeClient.AcmeWebException)exp; return(new APIResult { IsOK = false, Message = aex.Message, Result = aex }); } else { return(new APIResult { IsOK = false, Message = exp.Message, Result = exp }); } } }
public async Task <StatusMessage> RevokeCertificate(string pfxPath) { var fi = new FileInfo(pfxPath); string certAlias = fi.Name.Replace("-all.pfx", ""); return(await Task <StatusMessage> .Run(() => { try { return new StatusMessage() { IsOK = true, Result = ACMESharpUtils.RevokeCertificate(certAlias) }; } catch (Exception ex) { return new StatusMessage() { IsOK = false, FailedItemSummary = new List <string>() { $"Certificate revocation error: {ex.Message}" }, Message = ex.Message }; } })); }
/// <summary> /// 生成证书 /// </summary> /// <returns></returns> private static bool GenericCertificate() { string savePathPrefix = Config.CertificateSaveDir; if (!savePathPrefix.EndsWith("\\") && !savePathPrefix.EndsWith("/")) { savePathPrefix += Path.DirectorySeparatorChar + Config.Domain + "_"; } try { ACMESharpUtils.GetCertificate("cert1", savePathPrefix + "key.pem", savePathPrefix + "csr.pem", savePathPrefix + "certificate.pem", savePathPrefix + "certificate.der", savePathPrefix + "issuer.pem", savePathPrefix + "issuer.der", savePathPrefix + "pkcs12.pfx", Config.PFXPassword, overwrite: true); string chinapem = savePathPrefix + "chain.pem"; if (File.Exists(chinapem)) { File.Delete(chinapem); } string content = string.Empty; content = File.ReadAllText(savePathPrefix + "certificate.pem") + "\r\n"; content += File.ReadAllText(savePathPrefix + "issuer.pem"); File.WriteAllText(chinapem, content); } catch (Exception ex) { Trace.Error("生成证书失败!~", ex); return(false); } return(true); }
public string GetVaultPath() { using (var vlt = (LocalDiskVault)ACMESharpUtils.GetVault(this.vaultProfile)) { this.vaultFolderPath = vlt.RootPath; } return(this.vaultFolderPath); }
public VaultInfo LoadVaultFromFile() { lock (VAULT_LOCK) { using (var vlt = ACMESharpUtils.GetVault(this.vaultProfile)) { OpenVaultStorage(vlt, true); var v = vlt.LoadVault(); return(v); } } }
public PendingAuthorization BeginRegistrationAndValidation(CertRequestConfig requestConfig, string identifierAlias, string challengeType = ACMESharpCompat.ACMESharpUtils.CHALLENGE_TYPE_HTTP, string domain = null) { //if no alternative domain specified, use the primary domains as the subject if (domain == null) { domain = requestConfig.PrimaryDomain; } // if (GetIdentifier(identifierAlias) == null) //if an identifier exists for the same dns in vault, remove it to avoid confusion this.DeleteIdentifierByDNS(domain); // ACME service requires international domain names in ascii mode, register the new // identifier with Lets Encrypt var authState = ACMESharpUtils.NewIdentifier(identifierAlias, idnMapping.GetAscii(domain)); var identifier = this.GetIdentifier(identifierAlias, reloadVaultConfig: true); //FIXME: when validating subsequent SAN names in parallel request mode, the identifier is null? if (identifier != null && identifier.Authorization != null && identifier.Authorization.IsPending()) { ACMESharpUtils.CompleteChallenge(identifier.Alias, challengeType, Handler: "manual", Regenerate: true, Repeat: true); //get challenge info ReloadVaultConfig(); identifier = GetIdentifier(identifierAlias); try { //identifier challenge specification is now ready for use to prepare and answer for LetsEncrypt to check var challengeInfo = identifier.Challenges.FirstOrDefault(c => c.Value.Type == challengeType).Value; return(new PendingAuthorization() { Challenge = GetAuthorizeChallengeItemFromAuthChallenge(challengeInfo), Identifier = GetDomainIdentifierItemFromIdentifierInfo(identifier), TempFilePath = "", ExtensionlessConfigCheckedOK = false, LogItems = this.GetActionLogSummary() }); } catch (Exception exp) { LogAction("GetIdentifier", exp.ToString()); //identifier challenge could not be requested this time (FIXME: did we discard it when reloading vault?) return(null); } } else { //identifier is null or already valid (previously authorized) return(new PendingAuthorization() { Challenge = null, Identifier = GetDomainIdentifierItemFromIdentifierInfo(identifier), TempFilePath = "", ExtensionlessConfigCheckedOK = false, LogItems = this.GetActionLogSummary() }); } }
public bool AddNewRegistrationAndAcceptTOS(string contact) { try { ACMESharpUtils.NewRegistration(null, new string[] { contact }, acceptTOS: true); return(true); } catch (Exception exp) { System.Diagnostics.Debug.WriteLine(exp.ToString()); return(false); } }
public PendingAuthorization BeginRegistrationAndValidation(CertRequestConfig requestConfig, string identifierAlias, string challengeType = "http-01", string domain = null) { //if no alternative domain specified, use the primary domains as the subject if (domain == null) { domain = requestConfig.PrimaryDomain; } // if (GetIdentifier(identifierAlias) == null) //if an identifier exists for the same dns in vault, remove it to avoid confusion this.DeleteIdentifierByDNS(domain); // ACME service requires international domain names in ascii mode, regiser the new identifier with Lets Encrypt var authState = ACMESharpUtils.NewIdentifier(identifierAlias, idnMapping.GetAscii(domain)); var identifier = this.GetIdentifier(identifierAlias, reloadVaultConfig: true); //FIXME: when validating subsequent SAN names in parallel request mode, the identifier is null? if (identifier != null && identifier.Authorization != null && identifier.Authorization.IsPending()) { ACMESharpUtils.CompleteChallenge(identifier.Alias, challengeType, Handler: "manual", Regenerate: true, Repeat: true); //get challenge info ReloadVaultConfig(); identifier = GetIdentifier(identifierAlias); var challengeInfo = identifier.Challenges.FirstOrDefault(c => c.Value.Type == challengeType).Value; //identifier challenege specification is now ready for use to prepare and answer for LetsEncrypt to check return(new PendingAuthorization() { Challenge = challengeInfo, Identifier = identifier, TempFilePath = "", ExtensionlessConfigCheckedOK = false }); } else { //identifier is null or already valid (previously authorized) return(new PendingAuthorization() { Challenge = null, Identifier = identifier, TempFilePath = "", ExtensionlessConfigCheckedOK = false }); } }
/// <summary> /// 初始化vault /// </summary> public static void InitializeVault() { string baseuri = ACMESharpUtils.WELL_KNOWN_BASE_SERVICES[ACMESharpUtils.WELL_KNOWN_LE]; using (var vlt = ACMESharpUtils.GetVault()) { vlt.InitStorage(true); var v = new VaultInfo { Id = ACMESharp.Vault.Util.EntityHelper.NewId(), Alias = "ztimage", Label = string.Empty, Memo = string.Empty, BaseService = string.Empty, BaseUri = baseuri, ServerDirectory = new ACMESharp.AcmeServerDirectory() }; vlt.SaveVault(v); } }
public StatusMessage NewCertificate(string domainIdentifierAlias, string certAlias, string[] subjectAlternativeNameIdentifiers) { //if (subjectAlternativeNameIdentifiers != null) cmd.AlternativeIdentifierRefs = subjectAlternativeNameIdentifiers; // cmd.Generate = new System.Management.Automation.SwitchParameter(true); try { var result = ACMESharpUtils.NewCertificate(certAlias, domainIdentifierAlias, subjectAlternativeNameIdentifiers); return(new StatusMessage { IsOK = true, Result = result }); } catch (Exception exp) { return(new StatusMessage { IsOK = false, Message = exp.ToString(), Result = exp }); } }
public bool DeleteRegistrationInfo(Guid id) { using (var vlt = ACMESharpUtils.GetVault(this.vaultProfile)) { lock (VAULT_LOCK) { try { OpenVaultStorage(vlt, true); vaultConfig.Registrations.Remove(id); vlt.SaveVault(vaultConfig); return(true); } catch (Exception e) { // TODO: Logging of errors. System.Diagnostics.Debug.WriteLine(e.Message); return(false); } } } }
public void ExportCertificate(string certRef, bool pfxOnly = false) { GetVaultPath(); if (!Directory.Exists(VaultFolderPath + "\\" + LocalDiskVault.ASSET)) { Directory.CreateDirectory(VaultFolderPath + "\\" + LocalDiskVault.ASSET); } if (certRef.StartsWith("=")) { certRef = certRef.Replace("=", ""); } if (pfxOnly) { var ExportPkcs12 = vaultFolderPath + "\\" + LocalDiskVault.ASSET + "\\" + certRef + "-all.pfx"; ACMESharpUtils.GetCertificate(certRef, ExportPkcs12: ExportPkcs12, overwrite: true); } else { var ExportKeyPEM = vaultFolderPath + "\\" + LocalDiskVault.KEYPM + "\\" + certRef + "-key.pem"; var ExportCsrPEM = vaultFolderPath + "\\" + LocalDiskVault.CSRPM + "\\" + certRef + "-csr.pem"; var ExportCertificatePEM = vaultFolderPath + "\\" + LocalDiskVault.CRTPM + "\\" + certRef + "-crt.pem"; var ExportCertificateDER = vaultFolderPath + "\\" + LocalDiskVault.CRTDR + "\\" + certRef + "-crt.der"; var ExportPkcs12 = vaultFolderPath + "\\" + LocalDiskVault.ASSET + "\\" + certRef + "-all.pfx"; ACMESharpUtils.GetCertificate( certRef, ExportKeyPEM: ExportKeyPEM, ExportCsrPEM: ExportCsrPEM, ExportCertificatePEM: ExportCertificatePEM, ExportCertificateDER: ExportCertificateDER, ExportPkcs12: ExportPkcs12, overwrite: true ); } }
internal bool DeleteIdentifierByDNS(string dns) { using (var vlt = ACMESharpUtils.GetVault(this.vaultProfile)) { try { lock (VAULT_LOCK) { OpenVaultStorage(vlt, true); if (vaultConfig.Identifiers != null) { var idsToRemove = vaultConfig.Identifiers.Values.Where(i => i.Dns == dns); List <Guid> removing = new List <Guid>(); foreach (var identifier in idsToRemove) { removing.Add(identifier.Id); } foreach (var identifier in removing) { vaultConfig.Identifiers.Remove(identifier); } vlt.SaveVault(vaultConfig); } } return(true); } catch (Exception e) { // TODO: Logging of errors. System.Diagnostics.Debug.WriteLine(e.Message); return(false); } } }
public void CleanupVault(Guid?identifierToRemove = null, bool includeDupeIdentifierRemoval = false) { //remove duplicate identifiers etc lock (VAULT_LOCK) { using (var vlt = ACMESharpUtils.GetVault(this.vaultProfile)) { OpenVaultStorage(vlt, true); var v = vlt.LoadVault(); List <Guid> toBeRemoved = new List <Guid>(); if (identifierToRemove != null) { if (v.Identifiers.Keys.Any(i => i == (Guid)identifierToRemove)) { toBeRemoved.Add((Guid)identifierToRemove); } } else { //find all orphaned identified or identifiers with no certificate if (v.Identifiers != null) { foreach (var k in v.Identifiers.Keys) { var identifier = v.Identifiers[k]; var certs = v.Certificates.Values.Where(c => c.IdentifierRef == identifier.Id); if (!certs.Any()) { toBeRemoved.Add(identifier.Id); } } } } foreach (var i in toBeRemoved) { v.Identifiers.Remove(i); } // //find and remove certificates with no valid identifier in vault or with empty settings toBeRemoved = new List <Guid>(); if (v.Certificates != null) { foreach (var c in v.Certificates) { if ( String.IsNullOrEmpty(c.IssuerSerialNumber) //no valid issuer serial || !v.Identifiers.ContainsKey(c.IdentifierRef) //no existing Identifier ) { toBeRemoved.Add(c.Id); } } foreach (var i in toBeRemoved) { v.Certificates.Remove(i); } } /*if (includeDupeIdentifierRemoval) * { * //remove identifiers where the dns occurs more than once * foreach (var i in v.Identifiers) * { * var count = v.Identifiers.Values.Where(l => l.Dns == i.Dns).Count(); * if (count > 1) * { * //identify most recent Identifier (based on assigned, non-expired cert), delete all the others * * toBeRemoved.Add(i.Id); * } * } * }*/ // Remove VaultInfo.ServerDirectory.* where * value contains // "adding-random-entries-to-the-directory" v.ServerDirectory. vlt.SaveVault(v); } } }
public void UpdateIdentifier(string domainIdentifierAlias) { ACMESharpUtils.UpdateIdentifier(domainIdentifierAlias); }
static void Main(string[] args) { Trace.EnableConsole(); Trace.EnableFile(); if (!CheckParmeter()) { return; } Trace.Info("check config ok!~"); InitializeVault(); Trace.Info("init vault ok!~"); try { ACMESharpUtils.NewRegistration("", new string[] { "mailto:" + Config.Mail }, true); } catch (Exception ex) { Trace.Error("registration error", ex); return; } Trace.Info("registration ok!~"); try { ACMESharpUtils.NewIdentifier("dns1", Config.Domain); } catch (Exception ex) { Trace.Error("newidentityfier error", ex); return; } Trace.Info("newidentityfier ok!~"); try { AuthorizationState state = ACMESharpUtils.CompleteChallenge("dns1", "http-01", "manual"); if (!CreateChallengeFile(state)) { Trace.Error("create challenge file erro"); return; } } catch (Exception ex) { Trace.Error("complete challenge error", ex); return; } Trace.Info("challege ok"); try { ACMESharpUtils.SubmitChallenge("dns1", "http-01"); } catch (Exception ex) { Trace.Error("submit challenge error", ex); return; } Trace.Info("submit challage ok!~"); Trace.Info("wait LE identifier"); DateTime startT = DateTime.Now; bool result = false; while ((DateTime.Now - startT).TotalSeconds < 300) { AuthorizationState state = null; try { state = ACMESharpUtils.UpdateIdentifier("dns1", "http-01"); } catch (Exception ex) { Trace.Error("update identifier error"); return; } if (state == null) { Trace.Error("update identifier state is null"); return; } var subResultState = state.Challenges.First <ACMESharp.AuthorizeChallenge>(item => item.Type == "http-01"); if (subResultState == null) { SaveState(state); Trace.Error("state is null"); return; } if (subResultState.Status.Equals("valid", StringComparison.CurrentCultureIgnoreCase)) { result = true; break; } else if (subResultState.Status.Equals("invalid", StringComparison.CurrentCultureIgnoreCase)) { SaveState(state); Trace.Error("state is invalid"); return; } else { Trace.Info(DateTime.Now.ToString("HH:mm:ss") + ",status is:" + subResultState.Status); } System.Threading.Thread.Sleep(5000); } if (!result) { Trace.Error("update identifer timeout"); return; } Trace.Info("update identifier ok!~"); try { ACMESharpUtils.NewCertificate("cert1", "dns1", null); } catch (Exception ex) { Trace.Error("new certificate erro", ex); return; } Trace.Info("new certificate is ok!~"); try { ACMESharpUtils.SubmitCertificate("cert1"); } catch (Exception ex) { Trace.Error("submit certificateerro", ex); return; } Trace.Info("submit certificate is ok!~"); try { CertificateInfo info = ACMESharpUtils.UpdateCertificate("cert1"); } catch (Exception ex) { Trace.Error("update certificate erro", ex); return; } Trace.Info("update certificate is ok!~"); if (!GenericCertificate()) { return; } Trace.Info("success!~"); if (Environment.UserInteractive) { Trace.Info("Enter press any key exit!~"); Console.ReadKey(); } }
public bool InitVault(bool staging = true) { string apiURI = ACMESharpUtils.WELL_KNOWN_BASE_SERVICES[ACMESharpUtils.WELL_KNOWN_LESTAGE]; if (!staging) { //live api apiURI = ACMESharpUtils.WELL_KNOWN_BASE_SERVICES[ACMESharpUtils.WELL_KNOWN_LE]; } bool vaultExists = false; lock (VAULT_LOCK) { using (var vlt = ACMESharpUtils.GetVault(this.vaultProfile)) { OpenVaultStorage(vlt, true); var v = vlt.LoadVault(false); if (v != null) { vaultExists = true; } } } if (!vaultExists) { var baseUri = apiURI; if (string.IsNullOrEmpty(baseUri)) { throw new InvalidOperationException("either a base service or URI is required"); } lock (VAULT_LOCK) { using (var vlt = ACMESharpUtils.GetVault(this.vaultProfile)) { this.LogAction("InitVault", "Creating Vault"); OpenVaultStorage(vlt, true); var v = new VaultInfo { Id = EntityHelper.NewId(), BaseUri = baseUri, ServerDirectory = new AcmeServerDirectory() }; vlt.SaveVault(v); } } } else { this.LogAction("InitVault", "Vault exists."); } this.vaultFolderPath = GetVaultPath(); return(true); }
public PendingAuthorization BeginRegistrationAndValidation(CertRequestConfig requestConfig, string identifierAlias, string challengeType = ACMESharpCompat.ACMESharpUtils.CHALLENGE_TYPE_HTTP, string domain = null) { //if no alternative domain specified, use the primary domains as the subject if (domain == null) { domain = requestConfig.PrimaryDomain; } // if (GetIdentifier(identifierAlias) == null) //if an identifier exists for the same dns in vault, remove it to avoid confusion this.DeleteIdentifierByDNS(domain); // ACME service requires international domain names in ascii mode, create new identifier // in vault try { var authState = ACMESharpUtils.NewIdentifier(identifierAlias, idnMapping.GetAscii(domain)); } catch (ACMESharp.AcmeClient.AcmeWebException exp) { //if we don't know the problem details, report the whole exception if (exp.Response?.ProblemDetail == null) { throw exp; } // failed to register the domain identifier with LE (invalid, rate limit or CAA fail?) LogAction("NewIdentifier [" + domain + "]", exp.Response.ProblemDetail.OrignalContent); return(new PendingAuthorization { AuthorizationError = $"{exp.Response.ProblemDetail.Detail} : {exp.Response.ProblemDetail.Type}" }); } catch (Exception exp) { // failed to register the domain identifier with LE (rate limit or CAA fail?) LogAction("NewIdentifier [" + domain + "]", exp.ToString()); return(new PendingAuthorization { AuthorizationError = exp.ToString() }); } Thread.Sleep(200); var identifier = this.GetIdentifier(identifierAlias, reloadVaultConfig: true); //FIXME: when validating subsequent SAN names in parallel request mode, the identifier is null? if (identifier != null && identifier.Authorization != null && identifier.Authorization.IsPending()) { var authState = ACMESharpUtils.CompleteChallenge(identifier.Alias, challengeType, Handler: "manual", Regenerate: true, Repeat: true); LogAction("CompleteChallenge", authState.Status); //get challenge info for this identifier identifier = GetIdentifier(identifierAlias, reloadVaultConfig: true); try { //identifier challenge specification is now ready for use to prepare and answer for LetsEncrypt to check var challenges = new List <AuthorizationChallengeItem>(); foreach (var c in identifier.Challenges) { if (c.Value.Type == SupportedChallengeTypes.CHALLENGE_TYPE_HTTP) { var httpChallenge = (ACMESharp.ACME.HttpChallenge)c.Value.Challenge; challenges.Add(new AuthorizationChallengeItem { ChallengeType = SupportedChallengeTypes.CHALLENGE_TYPE_HTTP, ChallengeData = c.Value, ResourcePath = httpChallenge.FilePath, ResourceUri = httpChallenge.FileUrl, Key = c.Value.Token, Value = httpChallenge.FileContent }); } if (c.Value.Type == SupportedChallengeTypes.CHALLENGE_TYPE_SNI) { var tlsSniChallenge = (ACMESharp.ACME.TlsSniChallenge)c.Value.Challenge; var tlsSniAnswer = (ACMESharp.ACME.TlsSniChallengeAnswer)tlsSniChallenge.Answer; challenges.Add(new AuthorizationChallengeItem { ChallengeType = SupportedChallengeTypes.CHALLENGE_TYPE_SNI, ChallengeData = tlsSniChallenge, Key = tlsSniChallenge.Token, Value = tlsSniAnswer.KeyAuthorization, HashIterationCount = tlsSniChallenge.IterationCount }); } //TODO: dns if (c.Value.Type == SupportedChallengeTypes.CHALLENGE_TYPE_DNS) { var dnsChallenge = (ACMESharp.ACME.DnsChallenge)c.Value.Challenge; challenges.Add(new AuthorizationChallengeItem { ChallengeType = SupportedChallengeTypes.CHALLENGE_TYPE_DNS, ChallengeData = dnsChallenge, Key = dnsChallenge.RecordName, Value = dnsChallenge.RecordValue }); } } return(new PendingAuthorization() { Challenges = challenges, Identifier = GetDomainIdentifierItemFromIdentifierInfo(identifier) }); } catch (Exception exp) { //identifier challenge could not be requested this time LogAction("GetIdentifier", exp.ToString()); return(null); } } else { //identifier is null or already valid (previously authorized) return(new PendingAuthorization() { Challenges = null, Identifier = GetDomainIdentifierItemFromIdentifierInfo(identifier), LogItems = this.GetActionLogSummary() }); } }
public AuthorizationState SubmitChallenge(string alias, string challengeType = ACMESharpCompat.ACMESharpUtils.CHALLENGE_TYPE_HTTP) { //well known challenge all ready to be read by server return(ACMESharpUtils.SubmitChallenge(alias, challengeType)); }
public AuthorizationState UpdateIdentifier(string domainIdentifierAlias) { return(ACMESharpUtils.UpdateIdentifier(domainIdentifierAlias)); }
public void SubmitChallenge(string alias, string challengeType = "http-01") { //well known challenge all ready to be read by server ACMESharpUtils.SubmitChallenge(alias, challengeType); }
public void UpdateCertificate(string certRef) { ACMESharpUtils.UpdateCertificate(certRef); }
public void AddNewRegistrationAndAcceptTOS(string contact) { ACMESharpUtils.NewRegistration(null, new string[] { contact }, acceptTOS: true); }