public static string GetCertificate(Target binding) { var dnsIdentifier = binding.Host; var SANList = binding.AlternativeNames; List<string> allDnsIdentifiers = new List<string>(); if (!Options.SAN) { allDnsIdentifiers.Add(binding.Host); } if (binding.AlternativeNames != null) { allDnsIdentifiers.AddRange(binding.AlternativeNames); } var cp = CertificateProvider.GetProvider(); var rsaPkp = new RsaPrivateKeyParams(); try { if (Properties.Settings.Default.RSAKeyBits >= 1024) { rsaPkp.NumBits = Properties.Settings.Default.RSAKeyBits; Log.Debug("RSAKeyBits: {RSAKeyBits}", Properties.Settings.Default.RSAKeyBits); } else { Log.Warning("RSA Key Bits less than 1024 is not secure. Letting ACMESharp default key bits. http://openssl.org/docs/manmaster/crypto/RSA_generate_key_ex.html"); } } catch (Exception ex) { Log.Warning("Unable to set RSA Key Bits, Letting ACMESharp default key bits, Error: {@ex}", ex); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"Unable to set RSA Key Bits, Letting ACMESharp default key bits, Error: {ex.Message.ToString()}"); Console.ResetColor(); } var rsaKeys = cp.GeneratePrivateKey(rsaPkp); var csrDetails = new CsrDetails { CommonName = dnsIdentifier, }; if(SANList != null) { if (SANList.Count > 0) { csrDetails.AlternativeNames = SANList; } } var csrParams = new CsrParams { Details = csrDetails, }; var csr = cp.GenerateCsr(csrParams, rsaKeys, Crt.MessageDigest.SHA256); byte[] derRaw; using (var bs = new MemoryStream()) { cp.ExportCsr(csr, EncodingFormat.DER, bs); derRaw = bs.ToArray(); } var derB64u = JwsHelper.Base64UrlEncode(derRaw); Console.WriteLine($"\nRequesting Certificate"); Log.Information("Requesting Certificate"); var certRequ = client.RequestCertificate(derB64u); Log.Debug("certRequ {@certRequ}", certRequ); Console.WriteLine($" Request Status: {certRequ.StatusCode}"); Log.Information("Request Status: {StatusCode}", certRequ.StatusCode); if (certRequ.StatusCode == System.Net.HttpStatusCode.Created) { var keyGenFile = Path.Combine(certificatePath, $"{dnsIdentifier}-gen-key.json"); var keyPemFile = Path.Combine(certificatePath, $"{dnsIdentifier}-key.pem"); var csrGenFile = Path.Combine(certificatePath, $"{dnsIdentifier}-gen-csr.json"); var csrPemFile = Path.Combine(certificatePath, $"{dnsIdentifier}-csr.pem"); var crtDerFile = Path.Combine(certificatePath, $"{dnsIdentifier}-crt.der"); var crtPemFile = Path.Combine(certificatePath, $"{dnsIdentifier}-crt.pem"); string crtPfxFile = null; if (!CentralSSL) { crtPfxFile = Path.Combine(certificatePath, $"{dnsIdentifier}-all.pfx"); } else { crtPfxFile = Path.Combine(Options.CentralSSLStore, $"{dnsIdentifier}.pfx"); } using (var fs = new FileStream(keyGenFile, FileMode.Create)) cp.SavePrivateKey(rsaKeys, fs); using (var fs = new FileStream(keyPemFile, FileMode.Create)) cp.ExportPrivateKey(rsaKeys, EncodingFormat.PEM, fs); using (var fs = new FileStream(csrGenFile, FileMode.Create)) cp.SaveCsr(csr, fs); using (var fs = new FileStream(csrPemFile, FileMode.Create)) cp.ExportCsr(csr, EncodingFormat.PEM, fs); Console.WriteLine($" Saving Certificate to {crtDerFile}"); Log.Information("Saving Certificate to {crtDerFile}", crtDerFile); using (var file = File.Create(crtDerFile)) certRequ.SaveCertificate(file); Crt crt; using (FileStream source = new FileStream(crtDerFile, FileMode.Open), target = new FileStream(crtPemFile, FileMode.Create)) { crt = cp.ImportCertificate(EncodingFormat.DER, source); cp.ExportCertificate(crt, EncodingFormat.PEM, target); } // To generate a PKCS#12 (.PFX) file, we need the issuer's public certificate var isuPemFile = GetIssuerCertificate(certRequ, cp); Log.Debug("CentralSSL {CentralSSL} SAN {SAN}", CentralSSL.ToString(), Options.SAN.ToString()); if(CentralSSL && Options.SAN) { foreach (var host in allDnsIdentifiers) { Console.WriteLine($"Host: {host}"); crtPfxFile = Path.Combine(Options.CentralSSLStore, $"{host}.pfx"); Console.WriteLine($" Saving Certificate to {crtPfxFile}"); Log.Information("Saving Certificate to {crtPfxFile}", crtPfxFile); using (FileStream source = new FileStream(isuPemFile, FileMode.Open), target = new FileStream(crtPfxFile, FileMode.Create)) { try { var isuCrt = cp.ImportCertificate(EncodingFormat.PEM, source); cp.ExportArchive(rsaKeys, new[] { crt, isuCrt }, ArchiveFormat.PKCS12, target, Properties.Settings.Default.PFXPassword); } catch (Exception ex) { Log.Error("Error exporting archive {@ex}", ex); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"Error exporting archive: {ex.Message.ToString()}"); Console.ResetColor(); } } } } else //Central SSL and SAN need to save the cert for each hostname { Console.WriteLine($" Saving Certificate to {crtPfxFile}"); Log.Information("Saving Certificate to {crtPfxFile}", crtPfxFile); using (FileStream source = new FileStream(isuPemFile, FileMode.Open), target = new FileStream(crtPfxFile, FileMode.Create)) { try { var isuCrt = cp.ImportCertificate(EncodingFormat.PEM, source); cp.ExportArchive(rsaKeys, new[] { crt, isuCrt }, ArchiveFormat.PKCS12, target, Properties.Settings.Default.PFXPassword); } catch (Exception ex) { Log.Error("Error exporting archive {@ex}", ex); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"Error exporting archive: {ex.Message.ToString()}"); Console.ResetColor(); } } } cp.Dispose(); return crtPfxFile; } Log.Error("Request status = {StatusCode}", certRequ.StatusCode); throw new Exception($"Request status = {certRequ.StatusCode}"); }
public static string GetCertificate(Target binding) { var dnsIdentifier = binding.Host; var cp = CertificateProvider.GetProvider(); var rsaPkp = new RsaPrivateKeyParams(); var rsaKeys = cp.GeneratePrivateKey(rsaPkp); var csrDetails = new CsrDetails { CommonName = dnsIdentifier, }; var csrParams = new CsrParams { Details = csrDetails, }; var csr = cp.GenerateCsr(csrParams, rsaKeys, Crt.MessageDigest.SHA256); byte[] derRaw; using (var bs = new MemoryStream()) { cp.ExportCsr(csr, EncodingFormat.DER, bs); derRaw = bs.ToArray(); } var derB64u = JwsHelper.Base64UrlEncode(derRaw); Console.WriteLine($"\nRequesting Certificate"); var certRequ = client.RequestCertificate(derB64u); Console.WriteLine($" Request Status: {certRequ.StatusCode}"); //Console.WriteLine($"Refreshing Cert Request"); //client.RefreshCertificateRequest(certRequ); if (certRequ.StatusCode == System.Net.HttpStatusCode.Created) { var keyGenFile = Path.Combine(configPath, $"{dnsIdentifier}-gen-key.json"); var keyPemFile = Path.Combine(configPath, $"{dnsIdentifier}-key.pem"); var csrGenFile = Path.Combine(configPath, $"{dnsIdentifier}-gen-csr.json"); var csrPemFile = Path.Combine(configPath, $"{dnsIdentifier}-csr.pem"); var crtDerFile = Path.Combine(configPath, $"{dnsIdentifier}-crt.der"); var crtPemFile = Path.Combine(configPath, $"{dnsIdentifier}-crt.pem"); string crtPfxFile = null; if (!CentralSSL) { crtPfxFile = Path.Combine(configPath, $"{dnsIdentifier}-all.pfx"); } else { crtPfxFile = Path.Combine(Options.CentralSSLStore, $"{dnsIdentifier}.pfx"); } using (var fs = new FileStream(keyGenFile, FileMode.Create)) cp.SavePrivateKey(rsaKeys, fs); using (var fs = new FileStream(keyPemFile, FileMode.Create)) cp.ExportPrivateKey(rsaKeys, EncodingFormat.PEM, fs); using (var fs = new FileStream(csrGenFile, FileMode.Create)) cp.SaveCsr(csr, fs); using (var fs = new FileStream(csrPemFile, FileMode.Create)) cp.ExportCsr(csr, EncodingFormat.PEM, fs); Console.WriteLine($" Saving Certificate to {crtDerFile}"); using (var file = File.Create(crtDerFile)) certRequ.SaveCertificate(file); Crt crt; using (FileStream source = new FileStream(crtDerFile, FileMode.Open), target = new FileStream(crtPemFile, FileMode.Create)) { crt = cp.ImportCertificate(EncodingFormat.DER, source); cp.ExportCertificate(crt, EncodingFormat.PEM, target); } // To generate a PKCS#12 (.PFX) file, we need the issuer's public certificate var isuPemFile = GetIssuerCertificate(certRequ, cp); Console.WriteLine($" Saving Certificate to {crtPfxFile} (with no password set)"); using (FileStream source = new FileStream(isuPemFile, FileMode.Open), target = new FileStream(crtPfxFile, FileMode.Create)) { var isuCrt = cp.ImportCertificate(EncodingFormat.PEM, source); cp.ExportArchive(rsaKeys, new[] { crt, isuCrt }, ArchiveFormat.PKCS12, target); } cp.Dispose(); return crtPfxFile; } throw new Exception($"Request status = {certRequ.StatusCode}"); }
protected override void ProcessRecord() { using (var vlt = Util.VaultHelper.GetVault(VaultProfile)) { vlt.OpenStorage(); var v = vlt.LoadVault(); if (v.Registrations == null || v.Registrations.Count < 1) throw new InvalidOperationException("No registrations found"); var ri = v.Registrations[0]; var r = ri.Registration; if (v.Identifiers == null || v.Identifiers.Count < 1) throw new InvalidOperationException("No identifiers found"); var ii = v.Identifiers.GetByRef(IdentifierRef); if (ii == null) throw new Exception("Unable to find an Identifier for the given reference"); var ci = new CertificateInfo { Id = EntityHelper.NewId(), Alias = Alias, Label = Label, Memo = Memo, IdentifierRef = ii.Id, IdentifierDns = ii.Dns, }; if (Generate) { Func<string, string> csrDtlValue = x => null; Func<string, IEnumerable<string>> csrDtlValues = x => null; if (CsrDetails != null) { csrDtlValue = x => CsrDetails.ContainsKey(x) ? CsrDetails[x] as string : null; csrDtlValues = x => !string.IsNullOrEmpty(csrDtlValue(x)) ? Regex.Split(csrDtlValue(x).Trim(), "[\\s,;]+") : null; } var csrDetails = new CsrDetails { // Common Name is always pulled from associated Identifier CommonName = ii.Dns, // Remaining elements will be used if defined AlternativeNames /**/ = csrDtlValues(nameof(PKI.CsrDetails.AlternativeNames)), Country /**/ = csrDtlValue(nameof(PKI.CsrDetails.Country )), Description /**/ = csrDtlValue(nameof(PKI.CsrDetails.Description )), Email /**/ = csrDtlValue(nameof(PKI.CsrDetails.Email )), GivenName /**/ = csrDtlValue(nameof(PKI.CsrDetails.GivenName )), Initials /**/ = csrDtlValue(nameof(PKI.CsrDetails.Initials )), Locality /**/ = csrDtlValue(nameof(PKI.CsrDetails.Locality )), Organization /**/ = csrDtlValue(nameof(PKI.CsrDetails.Organization )), OrganizationUnit /**/ = csrDtlValue(nameof(PKI.CsrDetails.OrganizationUnit )), SerialNumber /**/ = csrDtlValue(nameof(PKI.CsrDetails.SerialNumber )), StateOrProvince /**/ = csrDtlValue(nameof(PKI.CsrDetails.StateOrProvince )), Surname /**/ = csrDtlValue(nameof(PKI.CsrDetails.Surname )), Title /**/ = csrDtlValue(nameof(PKI.CsrDetails.Title )), UniqueIdentifier /**/ = csrDtlValue(nameof(PKI.CsrDetails.UniqueIdentifier )), }; if (AlternativeIdentifierRefs != null) { if (csrDetails.AlternativeNames != null) throw new Exception("Alternative names already specified manually") .With(nameof(csrDetails.AlternativeNames), string.Join(",", csrDetails.AlternativeNames)); csrDetails.AlternativeNames = AlternativeIdentifierRefs.Select(alternativeIdentifierRef => { var altId = v.Identifiers.GetByRef($"{alternativeIdentifierRef}"); if (altId == null) throw new Exception("Unable to find an Identifier for the given Alternative Identifier reference") .With(nameof(alternativeIdentifierRef), alternativeIdentifierRef) .With(nameof(AlternativeIdentifierRefs), string.Join(",", AlternativeIdentifierRefs)); return altId.Dns; }); ci.AlternativeIdentifierDns = csrDetails.AlternativeNames.ToArray(); } ci.GenerateDetailsFile = $"{ci.Id}-gen.json"; var asset = vlt.CreateAsset(VaultAssetType.CsrDetails, ci.GenerateDetailsFile); using (var s = vlt.SaveAsset(asset)) { JsonHelper.Save(s, csrDetails); } } else { if (!File.Exists(KeyPemFile)) throw new FileNotFoundException("Missing specified RSA Key file path"); if (!File.Exists(CsrPemFile)) throw new FileNotFoundException("Missing specified CSR details file path"); var keyPemFile = $"{ci.Id}-key.pem"; var csrPemFile = $"{ci.Id}-csr.pem"; var keyAsset = vlt.CreateAsset(VaultAssetType.KeyPem, keyPemFile, true); var csrAsset = vlt.CreateAsset(VaultAssetType.CsrPem, csrPemFile); using (Stream fs = new FileStream(KeyPemFile, FileMode.Open), s = vlt.SaveAsset(keyAsset)) { fs.CopyTo(s); } using (Stream fs = new FileStream(KeyPemFile, FileMode.Open), s = vlt.SaveAsset(csrAsset)) { fs.CopyTo(s); } ci.KeyPemFile = keyPemFile; ci.CsrPemFile = csrPemFile; } if (v.Certificates == null) v.Certificates = new EntityDictionary<CertificateInfo>(); v.Certificates.Add(ci); vlt.SaveVault(v); WriteObject(ci); } }
protected override void ProcessRecord() { using (var vp = InitializeVault.GetVaultProvider(VaultProfile)) { vp.OpenStorage(); var v = vp.LoadVault(); if (v.Registrations == null || v.Registrations.Count < 1) throw new InvalidOperationException("No registrations found"); var ri = v.Registrations[0]; var r = ri.Registration; if (v.Identifiers == null || v.Identifiers.Count < 1) throw new InvalidOperationException("No identifiers found"); var ii = v.Identifiers.GetByRef(Identifier); if (ii == null) throw new Exception("Unable to find an Identifier for the given reference"); var ci = new CertificateInfo { Id = EntityHelper.NewId(), Alias = Alias, Label = Label, Memo = Memo, IdentifierRef = ii.Id, }; if (Generate) { var csrDetails = new CsrDetails { CommonName = ii.Dns, }; ci.GenerateDetailsFile = $"{ci.Id}-gen.json"; var asset = vp.CreateAsset(VaultAssetType.CsrDetails, ci.GenerateDetailsFile); using (var s = vp.SaveAsset(asset)) { JsonHelper.Save(s, csrDetails); } } else { if (!File.Exists(KeyPemFile)) throw new FileNotFoundException("Missing specified RSA Key file path"); if (!File.Exists(CsrPemFile)) throw new FileNotFoundException("Missing specified CSR details file path"); var keyPemFile = $"{ci.Id}-key.pem"; var csrPemFile = $"{ci.Id}-csr.pem"; var keyAsset = vp.CreateAsset(VaultAssetType.KeyPem, keyPemFile, true); var csrAsset = vp.CreateAsset(VaultAssetType.CsrPem, csrPemFile); using (Stream fs = new FileStream(KeyPemFile, FileMode.Open), s = vp.SaveAsset(keyAsset)) { fs.CopyTo(s); } using (Stream fs = new FileStream(KeyPemFile, FileMode.Open), s = vp.SaveAsset(csrAsset)) { fs.CopyTo(s); } ci.KeyPemFile = keyPemFile; ci.CsrPemFile = csrPemFile; } if (v.Certificates == null) v.Certificates = new EntityDictionary<CertificateInfo>(); v.Certificates.Add(ci); vp.SaveVault(v); WriteObject(ci); } }