/// <summary> /// Retrieves the certificate from the ACME service. This method also generates the key and the CSR. /// </summary> /// <param name="commonName">the CN of the certificate to be requested</param> /// <param name="pathForPfx">Path where the resulting PFX/PKCS#12 file will be generated</param> /// <param name="pfxFriendlyName">Friendly name for the resulting PFX/PKCS#12</param> /// <returns>The name of the generated PFX/PKCS#12 file, or null in case of error</returns> public async Task <AuthenticatedPFX> RetrieveCertificate(IList <string> domains, string pathForPfx, string pfxFriendlyName) { try { if (_orderCtx == null) { throw new Exception("Do not call RetrieveCertificate before RegisterNewOrderAndVerify"); } if (!System.IO.Directory.Exists(pathForPfx)) { throw new Exception("Directory for PFX writing do not exists"); } InitCertes(); // Let's generate a new key (RSA is good enough IMHO) IKey certKey = KeyFactory.FromPem(Utils.GenerateRSAKeyAsPEM(_keySize)); // Then let's generate the CSR var csr = await _orderCtx.CreateCsr(certKey); csr.AddName("CN", domains[0]); csr.SubjectAlternativeNames = domains; // and finalize the ACME order var finalOrder = await _orderCtx.Finalize(csr.Generate()); // Now we can fetch the certificate CertificateChain cert = await _orderCtx.Download(); // We build the PFX/PKCS#12 and the cert/key as PEM var pfx = cert.ToPfx(certKey); var cer = cert.ToPem(); var key = certKey.ToPem(); pfx.AddIssuers(GetCACertChainFromStore()); var pfxBytes = pfx.Build(pfxFriendlyName, PfxPassword); var fileName = pathForPfx + "\\" + Guid.NewGuid().ToString(); var pfxName = fileName + ".pfx"; var cerPath = fileName + ".cer"; var keyPath = fileName + ".key"; // We write the PFX/PKCS#12 to file System.IO.File.WriteAllBytes(pfxName, pfxBytes); logger.Info($"Retrieved certificate from the CA. The certificate is in {pfxName}"); // We write the PEMs to corresponding files System.IO.File.WriteAllText(cerPath, cer); System.IO.File.WriteAllText(keyPath, key); AuthenticatedPFX authPFX = new AuthenticatedPFX(pfxName, PfxPassword, cerPath, keyPath); return(authPFX); } catch (Exception exp) { logger.Error($"Failed to retrieve certificate from CA: {ProcessCertesException(exp)}"); return(null); } }
/// <summary> /// Finalizes the certificate order. /// </summary> /// <param name="context">The order context.</param> /// <param name="csr">The CSR.</param> /// <param name="key">The private key for the certificate.</param> /// <returns> /// The order finalized. /// </returns> public static async Task <Order> Finalize(this IOrderContext context, CsrInfo csr, IKey key) { var builder = await context.CreateCsr(key); foreach (var(name, value) in csr.Fields) { builder.AddName(name, value); } if (string.IsNullOrWhiteSpace(csr.CommonName)) { builder.AddName("CN", builder.SubjectAlternativeNames[0]); } return(await context.Finalize(builder.Generate())); }
/// <summary> /// Retrieves the certificate from the ACME service. This method also generates the key and the CSR. /// </summary> /// <param name="commonName">the CN of the certificate to be requested</param> /// <param name="pathForPfx">Path where the resulting PFX/PKCS#12 file will be generated</param> /// <param name="pfxFriendlyName">Friendly name for the resulting PFX/PKCS#12</param> /// <returns>The name of the generated PFX/PKCS#12 file, or null in case of error</returns> public async Task <string> RetrieveCertificate(IList <string> domains, string pathForPfx, string pfxFriendlyName) { try { if (_orderCtx == null) { throw new Exception("Do not call RetrieveCertificate before RegisterNewOrderAndVerify"); } if (!System.IO.Directory.Exists(pathForPfx)) { throw new Exception("Directory for PFX writing do not exists"); } InitCertes(); // Let's generate a new key (RSA is good enough IMHO) IKey certKey = KeyFactory.NewKey(KeyAlgorithm.RS256); // Then let's generate the CSR var csr = await _orderCtx.CreateCsr(certKey); csr.AddName("CN", domains[0]); csr.SubjectAlternativeNames = domains; // and finalize the ACME order var finalOrder = await _orderCtx.Finalize(csr.Generate()); // Now we can fetch the certificate CertificateChain cert = await _orderCtx.Download(); // We build the PFX/PKCS#12 var pfx = cert.ToPfx(certKey); pfx.AddIssuers(GetCACertChainFromStore()); var pfxBytes = pfx.Build(pfxFriendlyName, PfxPassword); var pfxName = Guid.NewGuid().ToString() + ".pfx"; // We write the PFX/PKCS#12 to file System.IO.File.WriteAllBytes(pathForPfx + "\\" + pfxName, pfxBytes); logger.Info($"Retrieved certificate from the CA. The certificate is in {pfxName}"); return(pfxName); } catch (Exception exp) { logger.Error($"Failed to retrieve certificate from CA: {ProcessCertesException(exp)}"); return(null); } }