protected async Task <byte[]> GenerateCertificateAsync(CertificateInfo certificateInfo, IOrderContext orderCtx)
        {
            //Создаем CSR-builder и добавляем туда все домены и CN
            var csrBuilder = new CertificationRequestBuilder();

            csrBuilder.AddName("CN", certificateInfo.CommonName);

            foreach (var domain in certificateInfo.Domains)
            {
                csrBuilder.SubjectAlternativeNames.Add(domain);
            }

            //Отправляем запрос на завершение Order'а (генерацию сертификата)
            var order = await orderCtx.Finalize(csrBuilder.Generate());

            if (order.Status != OrderStatus.Valid)
            {
                throw  new InvalidOperationException("Order finalization error!");
            }

            //Получаем цепочку сертификатов и возвращаем ее виде PFX-файла
            var certChain = await orderCtx.Download();

            LogNewCertificateInfo(certChain);

            return(certChain.ToPfx(csrBuilder.Key).Build(certificateInfo.CommonName, certificateInfo.PfxPassword));
        }
Example #2
0
        /// <summary>
        /// Finalizes and download the certifcate for the 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>
        /// <param name="retryCount">Number of retries when the Order is in 'processing' state. (default = 1)</param>
        /// <param name="preferredChain">The preferred Root Certificate.</param>
        /// <returns>
        /// The certificate generated.
        /// </returns>
        public static async Task <CertificateChain> Generate(this IOrderContext context, CsrInfo csr, IKey key, string preferredChain = null, int retryCount = 1)
        {
            var order = await context.Resource();

            if (order.Status != OrderStatus.Ready && // draft-11
                order.Status != OrderStatus.Pending) // pre draft-11
            {
                throw new AcmeException(string.Format(Strings.ErrorInvalidOrderStatusForFinalize, order.Status));
            }

            order = await context.Finalize(csr, key);

            while (order.Status == OrderStatus.Processing && retryCount-- > 0)
            {
                await Task.Delay(TimeSpan.FromSeconds(Math.Max(context.RetryAfter, 1)));

                order = await context.Resource();
            }

            if (order.Status != OrderStatus.Valid)
            {
                throw new AcmeException(Strings.ErrorFinalizeFailed);
            }

            return(await context.Download(preferredChain));
        }
Example #3
0
        /// <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()));
        }
Example #5
0
        /// <summary>
        /// Finalizes and download the certifcate for the 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 certificate generated.
        /// </returns>
        public static async Task <CertificateChain> Generate(this IOrderContext context, CsrInfo csr, IKey key)
        {
            var order = await context.Resource();

            if (order.Status != OrderStatus.Pending)
            {
                throw new Exception($"Can not finalize order with status {order.Status}.");
            }

            order = await context.Finalize(csr, key);

            if (order.Status != OrderStatus.Valid)
            {
                throw new Exception("Failto finalize order.");
            }

            return(await context.Download());
        }
        /// <summary>
        /// Finalizes and download the certifcate for the 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 certificate generated.
        /// </returns>
        public static async Task <CertificateChain> Generate(this IOrderContext context, CsrInfo csr, IKey key)
        {
            var order = await context.Resource();

            if (order.Status != OrderStatus.Ready && // draft-11
                order.Status != OrderStatus.Pending) // pre draft-11
            {
                throw new AcmeException(string.Format(Strings.ErrorInvalidOrderStatusForFinalize, order.Status));
            }

            order = await context.Finalize(csr, key);

            if (order.Status != OrderStatus.Valid)
            {
                throw new AcmeException(Strings.ErrorFinalizeFailed);
            }

            return(await context.Download());
        }
Example #7
0
        /// <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);
            }
        }
        public async Task <(byte[] pfxBytes, string password)> BuildCertificateAsync(
            IOrderContext order,
            CertificateRenewalOptions cfg,
            CancellationToken cancellationToken)
        {
            var key = KeyFactory.NewKey(KeyAlgorithm.RS256);
            await order.Finalize(new CsrInfo(), key);

            var certChain = await order.Download();

            var builder = certChain.ToPfx(key);

            builder.FullChain = true;

            var bytes = new byte[32];

            _randomGenerator.GetNonZeroBytes(bytes);
            var password = Convert.ToBase64String(bytes);
            var pfxBytes = builder.Build(string.Join(";", cfg.HostNames), password);

            return(pfxBytes, password);
        }