private (RsaPrivateCrtKeyParameters rsaPrivateKey, X509Certificate certificate) Extract(Stream stream, string password) { Org.BouncyCastle.Pkcs.Pkcs12Store p12Store = new Org.BouncyCastle.Pkcs.Pkcs12Store(stream, password.ToCharArray()); string keyEntryAlias = p12Store.Aliases.Cast <string>().FirstOrDefault(t => p12Store.IsKeyEntry(t)); Org.BouncyCastle.Pkcs.X509CertificateEntry x509CertEntry = p12Store.GetCertificate(keyEntryAlias); Org.BouncyCastle.Pkcs.AsymmetricKeyEntry keyEntry = p12Store.GetKey(keyEntryAlias); return(keyEntry.Key as RsaPrivateCrtKeyParameters, x509CertEntry.Certificate); }
public static void Test() { string pfxLocation = @"D:\lol\certificate.pfx"; pfxLocation = @"D:\username\Desktop\DesktopArchiv\20180329_Desktop\CORMailService\CORMailService\CORMailService\CORMailService_TemporaryKey.pfx"; Org.BouncyCastle.Pkcs.Pkcs12Store store = null; using (System.IO.Stream pfxStream = System.IO.File.OpenRead(pfxLocation)) { store = new Org.BouncyCastle.Pkcs.Pkcs12Store(pfxStream, "".ToCharArray()); } System.Console.WriteLine(store); foreach (string alias in store.Aliases) { System.Console.WriteLine(alias); // https://7thzero.com/blog/bouncy-castle-convert-a-bouncycastle-asymmetrickeyentry-to-a-.ne if (store.IsKeyEntry((string)alias)) { Org.BouncyCastle.Pkcs.AsymmetricKeyEntry keyEntry = store.GetKey(alias); System.Console.WriteLine(keyEntry); AsymmetricKeyParameter privateKey = keyEntry.Key; System.Console.WriteLine(privateKey.IsPrivate); } // End if (store.IsKeyEntry((string)alias)) Org.BouncyCastle.Pkcs.X509CertificateEntry certEntry = store.GetCertificate(alias); Org.BouncyCastle.X509.X509Certificate cert = certEntry.Certificate; System.Console.WriteLine(cert); AsymmetricKeyParameter publicKey = cert.GetPublicKey(); System.Console.WriteLine(publicKey); // Org.BouncyCastle.Pkcs.X509CertificateEntry[] chain = store.GetCertificateChain(alias); // System.Security.Cryptography.X509Certificates.X509Certificate2 cert2 = new System.Security.Cryptography.X509Certificates.X509Certificate2(cert.GetEncoded()); // Org.BouncyCastle.Security.DotNetUtilities.ToX509Certificate(cert); System.Security.Cryptography.X509Certificates.X509Certificate2 cert2 = new System.Security.Cryptography.X509Certificates.X509Certificate2(pfxLocation); // cert2.PrivateKey = null; if (cert2.HasPrivateKey) { System.Console.WriteLine(cert2.PrivateKey); } } }
} // End Sub GenerateRootCertificate public static void BouncyCert() { string pemOrDerFile = ""; Org.BouncyCastle.X509.X509CertificateParser kpp = new Org.BouncyCastle.X509.X509CertificateParser(); Org.BouncyCastle.X509.X509Certificate cert = kpp.ReadCertificate(System.IO.File.OpenRead(pemOrDerFile)); Org.BouncyCastle.Security.DotNetUtilities.ToX509Certificate(cert); System.Security.Cryptography.X509Certificates.X509Certificate msCert = Org.BouncyCastle.Security.DotNetUtilities.ToX509Certificate(cert); System.Security.Cryptography.X509Certificates.X509Certificate2 ms2 = new System.Security.Cryptography.X509Certificates.X509Certificate2(msCert); Org.BouncyCastle.Pkcs.AsymmetricKeyEntry keyEntry = null; //store.GetKey(alias); Org.BouncyCastle.Crypto.AsymmetricKeyParameter privateKey = keyEntry.Key; ms2.PrivateKey = Org.BouncyCastle.Security.DotNetUtilities.ToRSA((Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters)keyEntry.Key); }
/// <summary> /// Imports certificates and private keys from the specified stream. /// </summary> /// <remarks> /// <para>Imports certificates and private keys from the specified pkcs12 stream.</para> /// </remarks> /// <param name="stream">The stream to import.</param> /// <param name="password">The password to unlock the stream.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="stream"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="password"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.IO.IOException"> /// An error occurred reading the stream. /// </exception> public void Import(System.IO.Stream stream, string password) { if (stream == null) { throw new System.ArgumentNullException(nameof(stream)); } if (password == null) { throw new System.ArgumentNullException(nameof(password)); } Org.BouncyCastle.Pkcs.Pkcs12Store pkcs12 = new Org.BouncyCastle.Pkcs.Pkcs12Store(stream, password.ToCharArray()); foreach (string alias in pkcs12.Aliases) { if (pkcs12.IsKeyEntry(alias)) { Org.BouncyCastle.Pkcs.X509CertificateEntry[] chain = pkcs12.GetCertificateChain(alias); Org.BouncyCastle.Pkcs.AsymmetricKeyEntry entry = pkcs12.GetKey(alias); for (int i = 0; i < chain.Length; i++) { if (unique.Add(chain[i].Certificate)) { certs.Add(chain[i].Certificate); } } if (entry.Key.IsPrivate) { keys.Add(chain[0].Certificate, entry.Key); } } else if (pkcs12.IsCertificateEntry(alias)) { Org.BouncyCastle.Pkcs.X509CertificateEntry entry = pkcs12.GetCertificate(alias); if (unique.Add(entry.Certificate)) { certs.Add(entry.Certificate); } } } }
} // End Sub WithMsPfx public static PfxData Read(string pfxFilePath, string password = "") { Org.BouncyCastle.Pkcs.Pkcs12Store store = null; using (System.IO.Stream pfxStream = System.IO.File.OpenRead(pfxFilePath)) { store = new Org.BouncyCastle.Pkcs.Pkcs12Store(pfxStream, password.ToCharArray()); } // System.Console.WriteLine(store); foreach (string alias in store.Aliases) { Org.BouncyCastle.Pkcs.X509CertificateEntry certEntry = store.GetCertificate(alias); Org.BouncyCastle.X509.X509Certificate cert = certEntry.Certificate; // Org.BouncyCastle.Crypto.AsymmetricKeyParameter publicKey = cert.GetPublicKey(); // System.Console.WriteLine(publicKey); // https://7thzero.com/blog/bouncy-castle-convert-a-bouncycastle-asymmetrickeyentry-to-a-.ne if (store.IsKeyEntry(alias)) { Org.BouncyCastle.Pkcs.AsymmetricKeyEntry keyEntry = store.GetKey(alias); Org.BouncyCastle.Crypto.AsymmetricKeyParameter privateKey = keyEntry.Key; if (privateKey.IsPrivate) { return new PfxData() { Certificate = cert, PrivateKey = privateKey } } ; } // End if (store.IsKeyEntry((string)alias)) } // Next alias return(null); } // End Sub Read
/// <summary> /// Request certificate from the ACME server /// </summary> /// <param name="binding"></param> /// <returns></returns> public CertificateInfo RequestCertificate(ICsrPlugin csrPlugin, RunLevel runLevel, Renewal renewal, Target target, OrderDetails order) { // What are we going to get? var pfxFileInfo = new FileInfo(PfxFilePath(renewal)); // Determine/check the common name var identifiers = target.GetHosts(false); var commonNameUni = target.CommonName; var commonNameAscii = string.Empty; if (!string.IsNullOrWhiteSpace(commonNameUni)) { var idn = new IdnMapping(); commonNameAscii = idn.GetAscii(commonNameUni); if (!identifiers.Contains(commonNameAscii, StringComparer.InvariantCultureIgnoreCase)) { _log.Warning($"Common name {commonNameUni} provided is invalid."); commonNameAscii = identifiers.First(); commonNameUni = idn.GetUnicode(commonNameAscii); } } // Determine the friendly name var friendlyName = renewal.FriendlyName; if (string.IsNullOrEmpty(friendlyName)) { friendlyName = target.FriendlyName; } if (string.IsNullOrEmpty(friendlyName)) { friendlyName = commonNameUni; } // Try using cached certificate first to avoid rate limiting during // (initial?) deployment troubleshooting. Real certificate requests // will only be done once per day maximum unless the --force parameter // is used. var cache = CachedInfo(renewal); if (cache != null && cache.CacheFile.LastWriteTime > DateTime.Now.AddDays(Settings.Default.CertificateCacheDays * -1) && cache.Match(target)) { if (runLevel.HasFlag(RunLevel.IgnoreCache)) { _log.Warning("Cached certificate available but not used with --{switch}. Use 'Renew specific' or " + "'Renew all' in the main menu to run unscheduled renewals without hitting rate limits.", nameof(MainArguments.Force).ToLower()); } else { _log.Warning("Using cached certificate for {friendlyName}. To force issue of a new certificate within " + "24 hours, delete the .pfx file from the CertificatePath or run with the --{switch} switch. " + "Be ware that you might run into rate limits doing so.", friendlyName, nameof(MainArguments.Force).ToLower()); return(cache); } } var csr = csrPlugin.GenerateCsr(commonNameAscii, identifiers); var csrBytes = csr.CreateSigningRequest(); order = _client.SubmitCsr(order, csrBytes); File.WriteAllText(GetPath(renewal, "-csr.pem"), _pemService.GetPem("CERTIFICATE REQUEST", csrBytes)); _log.Information("Requesting certificate {friendlyName}", friendlyName); var rawCertificate = _client.GetCertificate(order); if (rawCertificate == null) { throw new Exception($"Unable to get certificate"); } var certificate = new X509Certificate2(rawCertificate); var certificateExport = certificate.Export(X509ContentType.Cert); var crtPem = _pemService.GetPem("CERTIFICATE", certificateExport); // Get issuer certificate var issuerCertificate = new X509Certificate2(rawCertificate.Skip(certificateExport.Length).ToArray()); var issuerCertificateExport = issuerCertificate.Export(X509ContentType.Cert); var issuerPem = _pemService.GetPem("CERTIFICATE", issuerCertificateExport); // Build pfx archive var pfx = new bc.Pkcs.Pkcs12Store(); var bcCertificate = _pemService.ParsePem <bc.X509.X509Certificate>(crtPem); var bcCertificateEntry = new bc.Pkcs.X509CertificateEntry(bcCertificate); var bcCertificateAlias = bcCertificate.SubjectDN.ToString(); var bcPrivateKeyEntry = new bc.Pkcs.AsymmetricKeyEntry(csrPlugin.GetPrivateKey()); pfx.SetCertificateEntry(bcCertificateAlias, bcCertificateEntry); pfx.SetKeyEntry(bcCertificateAlias, bcPrivateKeyEntry, new[] { bcCertificateEntry }); var bcIssuer = _pemService.ParsePem <bc.X509.X509Certificate>(issuerPem); var bcIssuerEntry = new bc.Pkcs.X509CertificateEntry(bcIssuer); var bcIssuerAlias = bcIssuer.SubjectDN.ToString(); pfx.SetCertificateEntry(bcIssuerAlias, bcIssuerEntry); var pfxStream = new MemoryStream(); pfx.Save(pfxStream, null, new bc.Security.SecureRandom()); pfxStream.Position = 0; using (var pfxStreamReader = new BinaryReader(pfxStream)) { var tempPfx = new X509Certificate2( pfxStreamReader.ReadBytes((int)pfxStream.Length), (string)null, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); if (csrPlugin.CanConvert()) { try { var converted = csrPlugin.Convert(tempPfx.PrivateKey); if (converted != null) { tempPfx.PrivateKey = converted; } } catch { _log.Warning("Private key conversion error."); } } tempPfx.FriendlyName = $"{friendlyName} {DateTime.Now.ToUserString()}"; File.WriteAllBytes(pfxFileInfo.FullName, tempPfx.Export(X509ContentType.Pfx, renewal.PfxPassword?.Value)); pfxFileInfo.Refresh(); } // Update LastFriendlyName so that the user sees // the most recently issued friendlyName in // the WACS GUI renewal.LastFriendlyName = friendlyName; // Recreate X509Certificate2 with correct flags for Store/Install return(new CertificateInfo() { Certificate = ReadForUse(pfxFileInfo, renewal.PfxPassword?.Value), CacheFile = pfxFileInfo, CacheFilePassword = renewal.PfxPassword?.Value }); }
/// <summary> /// Request certificate from the ACME server /// </summary> /// <param name="binding"></param> /// <returns></returns> public CertificateInfo RequestCertificate(ICsrPlugin csrPlugin, Renewal renewal, Target target, OrderDetails order) { // What are we going to get? var pfxFileInfo = new FileInfo(PfxFilePath(renewal)); // Determine/check the common name var identifiers = target.GetHosts(false); var commonName = target.CommonName; if (!string.IsNullOrWhiteSpace(commonName)) { var idn = new IdnMapping(); commonName = idn.GetAscii(commonName); if (!identifiers.Contains(commonName, StringComparer.InvariantCultureIgnoreCase)) { _log.Warning($"Common name {commonName} provided is invalid."); commonName = identifiers.First(); } } // Try using cached certificate first to avoid rate limiting during // (initial?) deployment troubleshooting. Real certificate requests // will only be done once per day maximum. if (pfxFileInfo.Exists && pfxFileInfo.LastWriteTime > DateTime.Now.AddDays(-1)) { try { var cached = new CertificateInfo() { Certificate = ReadForUse(pfxFileInfo, renewal.PfxPassword), PfxFile = pfxFileInfo }; var idn = new IdnMapping(); if (cached.SubjectName == commonName && cached.HostNames.Count == identifiers.Count() && cached.HostNames.All(h => identifiers.Contains(idn.GetAscii(h)))) { if (_options.Force) { _log.Warning("Cached certificate available but not used with --{switch}. Use 'Renew specific' or 'Renew all' in the main menu to run unscheduled renewals without hitting rate limits.", nameof(MainArguments.Force).ToLower()); } else { _log.Warning("Using cached certificate for {friendlyName}. To force issue of a new certificate within 24 hours, delete the .pfx file from the CertificatePath or run with the --{switch} switch. Be ware that you might run into rate limits doing so.", renewal.FriendlyName, nameof(MainArguments.Force).ToLower()); return(cached); } } } catch { // File corrupt or invalid password? _log.Warning("Unable to read from certificate cache"); } } var csr = csrPlugin.GenerateCsr(commonName, identifiers); var csrBytes = csr.CreateSigningRequest(); order = _client.SubmitCsr(order, csrBytes); if (Settings.Default.SavePrivateKeyPem) { File.WriteAllText(GetPath(renewal, "-key.pem"), GetPem(csrPlugin.GeneratePrivateKey())); } File.WriteAllText(GetPath(renewal, "-csr.pem"), GetPem("CERTIFICATE REQUEST", csrBytes)); _log.Information("Requesting certificate {friendlyName}", renewal.FriendlyName); var rawCertificate = _client.GetCertificate(order); if (rawCertificate == null) { throw new Exception($"Unable to get certificate"); } var certificate = new X509Certificate2(rawCertificate); var certificateExport = certificate.Export(X509ContentType.Cert); var crtDerFile = GetPath(renewal, $"-crt.der"); var crtPemFile = GetPath(renewal, $"-crt.pem"); var crtPem = GetPem("CERTIFICATE", certificateExport); _log.Information("Saving certificate to {crtDerFile}", _certificatePath); File.WriteAllBytes(crtDerFile, certificateExport); File.WriteAllText(crtPemFile, crtPem); // Get issuer certificate and save in DER and PEM formats var chain = new X509Chain(); chain.Build(certificate); X509Certificate2 issuerCertificate = chain.ChainElements[1].Certificate; var issuerCertificateExport = issuerCertificate.Export(X509ContentType.Cert); var issuerPem = GetPem("CERTIFICATE", issuerCertificateExport); File.WriteAllBytes(GetPath(renewal, "-crt.der", "ca-"), issuerCertificateExport); File.WriteAllText(GetPath(renewal, "-crt.pem", "ca-"), issuerPem); // Generate combined files File.WriteAllText(GetPath(renewal, "-chain.pem", "ca-"), crtPem + issuerPem); // Build pfx archive var pfx = new bc.Pkcs.Pkcs12Store(); var bcCertificate = ParsePem <bc.X509.X509Certificate>(crtPem); var bcCertificateEntry = new bc.Pkcs.X509CertificateEntry(bcCertificate); var bcCertificateAlias = bcCertificate.SubjectDN.ToString(); var bcPrivateKeyEntry = new bc.Pkcs.AsymmetricKeyEntry(csrPlugin.GeneratePrivateKey()); pfx.SetCertificateEntry(bcCertificateAlias, bcCertificateEntry); pfx.SetKeyEntry(bcCertificateAlias, bcPrivateKeyEntry, new[] { bcCertificateEntry }); var bcIssuer = ParsePem <bc.X509.X509Certificate>(issuerPem); var bcIssuerEntry = new bc.Pkcs.X509CertificateEntry(bcIssuer); var bcIssuerAlias = bcIssuer.SubjectDN.ToString(); pfx.SetCertificateEntry(bcIssuerAlias, bcIssuerEntry); using (var pfxStream = new MemoryStream()) { pfx.Save(pfxStream, null, new bc.Security.SecureRandom()); pfxStream.Position = 0; using (var pfxStreamReader = new BinaryReader(pfxStream)) { var tempPfx = new X509Certificate2( pfxStreamReader.ReadBytes((int)pfxStream.Length), (string)null, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); if (csrPlugin.CanConvert()) { try { var converted = csrPlugin.Convert(tempPfx.PrivateKey); if (converted != null) { tempPfx.PrivateKey = converted; } } catch { _log.Warning("Private key conversion error."); } } tempPfx.FriendlyName = FriendlyName(renewal); File.WriteAllBytes(pfxFileInfo.FullName, tempPfx.Export(X509ContentType.Pfx, renewal.PfxPassword)); pfxFileInfo.Refresh(); } } // Recreate X509Certificate2 with correct flags for Store/Install return(new CertificateInfo() { Certificate = ReadForUse(pfxFileInfo, renewal.PfxPassword), PfxFile = pfxFileInfo }); }
/// <summary> /// Exports the specified stream and password to a pkcs12 encrypted file. /// </summary> /// <remarks> /// Exports the specified stream and password to a pkcs12 encrypted file. /// </remarks> /// <param name="stream">The output stream.</param> /// <param name="password">The password to use to lock the private keys.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="stream"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="password"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.IO.IOException"> /// An error occurred while writing to the stream. /// </exception> public void Export(System.IO.Stream stream, string password) { if (stream == null) { throw new System.ArgumentNullException(nameof(stream)); } if (password == null) { throw new System.ArgumentNullException(nameof(password)); } Org.BouncyCastle.Pkcs.Pkcs12Store store = new Org.BouncyCastle.Pkcs.Pkcs12Store(); foreach (Org.BouncyCastle.X509.X509Certificate certificate in certs) { if (keys.ContainsKey(certificate)) { continue; } string alias = GetCommonName(certificate); if (alias == null) { continue; } Org.BouncyCastle.Pkcs.X509CertificateEntry entry = new Org.BouncyCastle.Pkcs.X509CertificateEntry(certificate); store.SetCertificateEntry(alias, entry); } foreach ( System.Collections.Generic.KeyValuePair < Org.BouncyCastle.X509.X509Certificate, Org.BouncyCastle.Crypto.AsymmetricKeyParameter > kvp in keys) { string alias = GetCommonName(kvp.Key); if (alias == null) { continue; } Org.BouncyCastle.Pkcs.AsymmetricKeyEntry entry = new Org.BouncyCastle.Pkcs.AsymmetricKeyEntry(kvp.Value); Org.BouncyCastle.Pkcs.X509CertificateEntry cert = new Org.BouncyCastle.Pkcs.X509CertificateEntry(kvp.Key); System.Collections.Generic.List <Org.BouncyCastle.Pkcs.X509CertificateEntry> chain = new System.Collections.Generic.List <Org.BouncyCastle.Pkcs.X509CertificateEntry>(); chain.Add(cert); store.SetKeyEntry(alias, entry, chain.ToArray()); } store.Save(stream, password.ToCharArray(), new Org.BouncyCastle.Security.SecureRandom()); }