Пример #1
6
        public void TestSignFlagJson()
        {
            Func <byte[], byte[]> sigFunc = (x) =>
            {
                using (var rsa = new System.Security.Cryptography.RSACryptoServiceProvider())
                {
                    rsa.ImportParameters(JwsTests.GetRsaParamsForRfc7515Example_A_2_1());
                    using (var sha256 = new System.Security.Cryptography.SHA256CryptoServiceProvider())
                    {
                        return(rsa.SignData(x, sha256));
                    }
                }
            };

            object protectedSample = new // From the RFC example
            {
                alg = "RS256"
            };
            object headerSample = new // From the RFC example
            {
                kid = "2010-12-29"
            };
            string payloadSample = // From the RFC example
                                   "{\"iss\":\"joe\",\r\n" +
                                   " \"exp\":1300819380,\r\n" +
                                   " \"http://example.com/is_root\":true}";

            var wsRegex     = new Regex("\\s+");
            var sigExpected = // Derived from the RFC example in A.6.4
                              wsRegex.Replace(@"{
                        ""header"":{""kid"":""2010-12-29""},
                        ""protected"":""eyJhbGciOiJSUzI1NiJ9"",
                        ""payload"":""eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"",
                        ""signature"":
                            ""cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZ
                            mh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjb
                            KBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHl
                            b1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZES
                            c6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AX
                            LIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw""
                    }", "");
            var sigActual = wsRegex.Replace(JwsHelper.SignFlatJson(
                                                sigFunc, payloadSample, protectedSample, headerSample), "");

            Assert.AreEqual(sigExpected, sigActual);
        }
        public static IssuedCertificate RequestCertificate(AcmeClient client, CertificateProvider certProvider, string hostName, List <string> alternativeNames = null)
        {
            if (alternativeNames == null)
            {
                alternativeNames = new List <string>();
            }

            PrivateKey pk;
            var        csr = GenerateCSR(certProvider, hostName, alternativeNames, out pk);

            var certRequest = client.RequestCertificate(JwsHelper.Base64UrlEncode(csr));

            if (certRequest.StatusCode != HttpStatusCode.Created)
            {
                throw new CertificateApplicationException(certRequest, hostName, alternativeNames.ToArray());
            }

            Crt crt;

            using (var ms = new MemoryStream())
            {
                certRequest.SaveCertificate(ms);

                ms.Seek(0, SeekOrigin.Begin);
                crt = certProvider.ImportCertificate(EncodingFormat.DER, ms);
            }
            var caCrt = GetCACertificate(certProvider, certRequest);

            return(new IssuedCertificate {
                PublicKey = crt, PrivateKey = pk, CAPublicKey = caCrt
            });
        }
Пример #3
0
        static void RetrieveCertificates(AcmeClient client, string api, string domain, string certificatesFolder, int certBits)
        {
            var cp     = CertificateProvider.GetProvider();
            var rsaPkp = new RsaPrivateKeyParams()
            {
                NumBits = certBits
            };

            var rsaKeys   = cp.GeneratePrivateKey(rsaPkp);
            var csrParams = new CsrParams
            {
                Details = new CsrDetails {
                    CommonName = domain
                }
            };

            var derRaw = default(byte[]);
            var csr    = cp.GenerateCsr(csrParams, rsaKeys, Crt.MessageDigest.SHA256);

            using (var bs = new MemoryStream())
            {
                cp.ExportCsr(csr, EncodingFormat.DER, bs);
                derRaw = bs.ToArray();
            }

            var derB64U  = JwsHelper.Base64UrlEncode(derRaw);
            var certRequ = client.RequestCertificate(derB64U);

            if (certRequ.StatusCode == HttpStatusCode.Created)
            {
                GenerateCertFiles(cp, rsaKeys, csr, certRequ, certificatesFolder, domain);
            }
        }
Пример #4
0
        public Challenge Decode(IdentifierPart ip, ChallengePart cp, ISigner signer)
        {
            if (cp.Type != AcmeProtocol.CHALLENGE_TYPE_DNS)
            {
                throw new InvalidDataException("unsupported Challenge type")
                      .With("challengeType", cp.Type)
                      .With("supportedChallengeTypes", AcmeProtocol.CHALLENGE_TYPE_DNS);
            }

            //var token = (string)cp["token"];
            var token = cp.Token;

            // This response calculation is described in:
            //    https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-7.5

            var keyAuthz    = JwsHelper.ComputeKeyAuthorization(signer, token);
            var keyAuthzDig = JwsHelper.ComputeKeyAuthorizationDigest(signer, token);

            var ca = new DnsChallengeAnswer
            {
                KeyAuthorization = keyAuthz,
            };

            var c = new DnsChallenge(cp.Type, ca)
            {
                Token       = token,
                RecordName  = $"{AcmeProtocol.DNS_CHALLENGE_NAMEPREFIX}{ip.Value}",
                RecordValue = keyAuthzDig,
            };

            return(c);
        }
Пример #5
0
        /// <summary>
        /// Computes the JWS-signed ACME request body for the given message object
        /// and signer instance.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="signer"></param>
        /// <returns></returns>
        private string ComputeAcmeSigned(object message, ISigner signer)
        {
            var protectedHeader = new
            {
                nonce = NextNonce
            };
            var unprotectedHeader = new
            {
                alg = Signer.JwsAlg,
                jwk = Signer.ExportJwk()
            };

            var payload = string.Empty;

            if (message is JObject)
            {
                payload = ((JObject)message).ToString(Formatting.None);
            }
            else
            {
                payload = JsonConvert.SerializeObject(message, Formatting.None);
            }

            var acmeSigned = JwsHelper.SignFlatJson(Signer.Sign, payload,
                                                    protectedHeader, unprotectedHeader);

            return(acmeSigned);
        }
Пример #6
0
        public Challenge Decode(IdentifierPart ip, ChallengePart cp, ISigner signer)
        {
            if (cp.Type != AcmeProtocol.CHALLENGE_TYPE_SNI)
            {
                throw new InvalidDataException("unsupported Challenge type")
                      .With("challengeType", cp.Type)
                      .With("supportedChallengeTypes", AcmeProtocol.CHALLENGE_TYPE_SNI);
            }

            var token = cp.Token;

            // This response calculation is described in:
            //    https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-7.3

            var keyAuthz    = JwsHelper.ComputeKeyAuthorization(signer, token);
            var keyAuthzDig = JwsHelper.ComputeKeyAuthorizationDigest(signer, token);

            LOG.Debug("Computed key authorization {0} and digest {1}", keyAuthz, keyAuthzDig);

            var ca = new TlsSniChallengeAnswer
            {
                KeyAuthorization = keyAuthz,
            };

            var c = new TlsSniChallenge(cp.Type, ca)
            {
                Token          = token,
                IterationCount = 1 // see: https://github.com/ietf-wg-acme/acme/pull/22 for reason n=1
            };

            return(c);
        }
Пример #7
0
        public Challenge Decode(IdentifierPart ip, ChallengePart cp, ISigner signer)
        {
            if (cp.Type != AcmeProtocol.CHALLENGE_TYPE_HTTP)
            {
                throw new InvalidDataException("unsupported Challenge type")
                      .With("challengeType", cp.Type)
                      .With("supportedChallengeTypes", AcmeProtocol.CHALLENGE_TYPE_HTTP);
            }

            //var token = (string)cp["token"];
            var token = cp.Token;

            // This response calculation is described in:
            //    https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-7.2

            var keyAuthz = JwsHelper.ComputeKeyAuthorization(signer, token);
            var path     = $"{AcmeProtocol.HTTP_CHALLENGE_PATHPREFIX}{token}";
            var url      = $"http://{ip.Value}/{path}";


            var ca = new HttpChallengeAnswer
            {
                KeyAuthorization = keyAuthz,
            };

            var c = new HttpChallenge(cp.Type, ca)
            {
                Token       = token,
                FileUrl     = url,
                FilePath    = path,
                FileContent = keyAuthz,
            };

            return(c);
        }
Пример #8
0
        /// <summary>
        /// Returns a key-value pair that represents the HTTP resource path that
        /// needs to be configured (the key) and the resource content that should be returned
        /// for an HTTP request for this path on a server that the target DNS resolve to.
        /// </summary>
        /// <param name="dnsId"></param>
        /// <param name="signer"></param>
        /// <returns></returns>
        public KeyValuePair <string, string> GenerateHttpChallengeAnswer(string dnsId, ISigner signer)
        {
            var keyAuthz = JwsHelper.ComputeKeyAuthorization(signer, Token);

            return(new KeyValuePair <string, string>(
                       $"{AcmeProtocol.HTTP_CHALLENGE_PATHPREFIX}{Token}", keyAuthz));
        }
Пример #9
0
 public byte[] GetCertificateContent()
 {
     if (string.IsNullOrEmpty(CertificateContent))
     {
         return(null);
     }
     return(JwsHelper.Base64UrlDecode(CertificateContent));
 }
Пример #10
0
        /// <summary>
        /// </summary>
        /// <remarks>
        /// https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05
        /// </remarks>
        public static TlsAlpn01ChallengeValidationDetails ResolveChallengeForTlsAlpn01(
            Authorization authz, Challenge challenge, IJwsTool signer)
        {
            var keyAuthz = JwsHelper.ComputeKeyAuthorization(signer, challenge.Token);

            return(new TlsAlpn01ChallengeValidationDetails
            {
                TokenValue = keyAuthz,
            });
        }
Пример #11
0
        public void SaveCertificate(Stream s)
        {
            if (string.IsNullOrEmpty(CertificateContent))
            {
                throw new InvalidOperationException("Certificate content is missing or empty");
            }

            var raw = JwsHelper.Base64UrlDecode(CertificateContent);

            s.Write(raw, 0, raw.Length);
        }
Пример #12
0
 public void SetCertificateContent(byte[] raw)
 {
     if (raw != null && raw.Length > 0)
     {
         CertificateContent = JwsHelper.Base64UrlEncode(raw);
     }
     else
     {
         CertificateContent = null;
     }
 }
Пример #13
0
        public static void GetCertificateUseCSR(CertificateGeneratorParam param)
        {
            if (param == null)
            {
                log.Info($" {nameof(param)} is null");
                return;
            }
            var dnsIdentifier = DateTime.Now.ToString("yyyyMMddHHmmss");
            var cp            = CertificateProvider.GetProvider();

            MemoryStream ms  = new MemoryStream(Encoding.UTF8.GetBytes(param.csr));
            var          csr = cp.ImportCsr(EncodingFormat.PEM, ms);

            ms.Dispose();
            byte[] derRaw;
            using (var bs = new MemoryStream())
            {
                cp.ExportCsr(csr, EncodingFormat.DER, bs);
                derRaw = bs.ToArray();
            }

            var derB64u = JwsHelper.Base64UrlEncode(derRaw);

            log.Info($"\nRequesting Certificate");
            var certRequ = param.client.RequestCertificate(derB64u);

            log.Info($" Request Status: {certRequ.StatusCode}");

            if (certRequ.StatusCode == System.Net.HttpStatusCode.Created)
            {
                var csrPemFile = Path.Combine(param.path, $"{dnsIdentifier}-csr.pem");
                var crtDerFile = Path.Combine(param.path, $"{dnsIdentifier}-crt.der");
                var crtPemFile = Path.Combine(param.path, $"{dnsIdentifier}-crt.pem");
                using (var fs = new FileStream(csrPemFile, FileMode.Create))
                    cp.ExportCsr(csr, EncodingFormat.PEM, fs);

                log.Info($" 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);
                }
                cp.Dispose();

                return;
            }

            throw new Exception($"Request status = {certRequ.StatusCode}");
        }
Пример #14
0
        public JwsSignedPayload Payload()
        {
            var protectedHeader = new Dictionary <string, object>
            {
                ["alg"] = Algorithm,
                ["kid"] = KeyIdentifier,
                ["url"] = Url
            };

            return(JwsHelper.SignFlatJsonAsObject(Sign, AccountKey, protectedHeader, null));
        }
Пример #15
0
        [Ignore] // *Normally*, we skip this test because it depends on a local Boulder setup to accessible
        public void TestNewRegRequest()
        {
            var requ = WebRequest.Create(_rootUrl);
            var resp = requ.GetResponse();

            Assert.IsNotNull(resp);

            var nonceKey = resp.Headers.AllKeys.FirstOrDefault(
                x => x.Equals("Replay-nonce", StringComparison.OrdinalIgnoreCase));

            Assert.IsFalse(string.IsNullOrEmpty(nonceKey));
            var nonceValue = resp.Headers[nonceKey];

            var newReg = new
            {
                resource = "new-reg",
                contact  = new string[]
                {
                    "mailto:[email protected]",
                    // Tel contact method is no longer supported by Boulder
                    //"tel:+12025551212"
                },
            };
            var newRegSer = JsonConvert.SerializeObject(newReg);

            var algSigner = new RS256Signer();

            algSigner.Init();

            var unprotectedHeader = new
            {
                alg = "RS256",
                jwk = algSigner.ExportJwk()
            };
            var protectedHeader = new
            {
                nonce = nonceValue,
            };

            var acmeJson = JwsHelper.SignFlatJson(algSigner.Sign, newRegSer,
                                                  protectedHeader, unprotectedHeader);
            var acmeJsonBytes = Encoding.ASCII.GetBytes(acmeJson);

            requ               = WebRequest.Create(new Uri(_rootUrl, "/acme/new-reg"));
            requ.Method        = "POST";
            requ.ContentType   = "application/json";
            requ.ContentLength = acmeJsonBytes.Length;
            using (var s = requ.GetRequestStream())
            {
                s.Write(acmeJsonBytes, 0, acmeJsonBytes.Length);
            }
            resp = requ.GetResponse();
        }
        /// <summary>
        /// </summary>
        /// <remarks>
        /// https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-8.4
        /// </remarks>
        public static Dns01ChallengeValidationDetails ResolveChallengeForDns01(
            Authorization authz, Challenge challenge, IJwsTool signer)
        {
            var keyAuthzDigested = JwsHelper.ComputeKeyAuthorizationDigest(
                signer, challenge.Token);

            return(new Dns01ChallengeValidationDetails
            {
                DnsRecordName = $@"{Dns01ChallengeValidationDetails.DnsRecordNamePrefix}.{
                        authz.Identifier.Value}",
                DnsRecordType = Dns01ChallengeValidationDetails.DnsRecordTypeDefault,
                DnsRecordValue = keyAuthzDigested,
            });
        }
Пример #17
0
        public AuthorizeChallenge GenerateAuthorizeChallengeAnswer(AuthorizationState authzState, string type)
        {
            AssertInit();
            AssertRegistration();

            var c = authzState.Challenges.FirstOrDefault(x => x.Type == type);

            if (c == null)
            {
                throw new ArgumentOutOfRangeException("no challenge found matching requested type");
            }

            switch (type)
            {
            case AcmeProtocol.CHALLENGE_TYPE_DNS:
                c.ChallengeAnswer        = c.GenerateDnsChallengeAnswer(authzState.Identifier, Signer);
                c.ChallengeAnswerMessage = new AnswerDnsChallengeRequest
                {
                    ClientPublicKey = Signer.ExportJwk(),
                    Validation      = new
                    {
                        header  = new { alg = Signer.JwsAlg },
                        payload = JwsHelper.Base64UrlEncode(JsonConvert.SerializeObject(new
                        {
                            type  = type,
                            token = c.Token
                        })),
                        signature = c.ChallengeAnswer.Value,
                    }
                };
                break;

            case AcmeProtocol.CHALLENGE_TYPE_HTTP:
                c.ChallengeAnswer        = c.GenerateHttpChallengeAnswer(authzState.Identifier, Signer);
                c.ChallengeAnswerMessage = new AnswerHttpChallengeRequest
                {
                    KeyAuthorization = c.ChallengeAnswer.Value,
                };
                break;

            case AcmeProtocol.CHALLENGE_TYPE_SNI:
            case AcmeProtocol.CHALLENGE_TYPE_PRIORKEY:
                throw new ArgumentException("unimplemented or unsupported challenge type", nameof(type));

            default:
                throw new ArgumentException("unknown challenge type", nameof(type));
            }

            return(c);
        }
        /// <summary>
        /// Revoke previously issued certificate
        /// </summary>
        /// <param name="binding"></param>
        public void RevokeCertificate(Target binding)
        {
            var fi = new FileInfo(GetPath(binding, "-crt.der"));

            if (!fi.Exists)
            {
                _log.Warning("Unable to find file {fi}", fi.FullName);
                return;
            }
            var der    = File.ReadAllBytes(fi.FullName);
            var base64 = JwsHelper.Base64UrlEncode(der);

            _client.Acme.RevokeCertificate(base64);
            _log.Warning("Certificate for {target} revoked, you should renew immediately", binding);
        }
Пример #19
0
        public AuthorizeChallenge GenerateAuthorizeChallengeAnswer(AuthorizationState authzState, string type)
        {
            AssertInit();
            AssertRegistration();

            var c = authzState.Challenges.FirstOrDefault(x => x.Type == type);

            if (c == null)
            {
                throw new ArgumentOutOfRangeException("no challenge found matching requested type");
            }

            switch (type)
            {
            case "dns":
                c.ChallengeAnswer        = c.GenerateDnsChallengeAnswer(authzState.Identifier, Signer);
                c.ChallengeAnswerMessage = new AnswerDnsChallengeRequest
                {
                    ClientPublicKey = Signer.ExportJwk(),
                    Validation      = new
                    {
                        header  = new { alg = Signer.JwsAlg },
                        payload = JwsHelper.Base64UrlEncode(JsonConvert.SerializeObject(new
                        {
                            type  = "dns",
                            token = c.Token
                        })),
                        signature = c.ChallengeAnswer.Value
                    }
                };
                break;

            case "simpleHttp":
                var tls = c.Tls.GetValueOrDefault(true);
                c.ChallengeAnswer        = c.GenerateHttpChallengeAnswer(authzState.Identifier, Signer, tls);
                c.ChallengeAnswerMessage = new AnswerHttpChallengeRequest
                {
                    Tls = tls
                };
                break;

            default:
                throw new ArgumentException("unsupported challenge type", nameof(type));
            }

            return(c);
        }
        /// <summary>
        /// </summary>
        /// <remarks>
        /// https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-8.3
        /// </remarks>
        public static Http01ChallengeValidationDetails ResolveChallengeForHttp01(
            Authorization authz, Challenge challenge, IJwsTool signer)
        {
            var keyAuthz = JwsHelper.ComputeKeyAuthorization(
                signer, challenge.Token);

            return(new Http01ChallengeValidationDetails
            {
                HttpResourceUrl = $@"http://{authz.Identifier.Value}/{
                        Http01ChallengeValidationDetails.HttpPathPrefix}/{
                        challenge.Token}",
                HttpResourcePath = $@"{Http01ChallengeValidationDetails.HttpPathPrefix}/{
                        challenge.Token}",
                HttpResourceContentType = Http01ChallengeValidationDetails.HttpResourceContentTypeDefault,
                HttpResourceValue = keyAuthz,
            });
        }
Пример #21
0
        /// <summary>
        /// Returns a key-value pair that represents the Simple HTTP resource path that
        /// needs to be configured (the key) and the resource content that should be returned
        /// for an HTTP request for this path on a server that the target DNS resolve to.
        /// </summary>
        /// <param name="dnsId"></param>
        /// <param name="signer"></param>
        /// <param name="tls"></param>
        /// <returns></returns>
        public KeyValuePair<string, string> GenerateHttpChallengeAnswer(string dnsId, ISigner signer, bool tls)
        {
            var resp = new
            {
                type = "simpleHttp",
                token = Token,
                tls = tls
            };
            var json = JsonConvert.SerializeObject(resp);
            var hdrs = new { alg = signer.JwsAlg, jwk = signer.ExportJwk() };
            var signed = JwsHelper.SignFlatJsonAsObject(
                    signer.Sign, json, unprotectedHeaders: hdrs);

            return new KeyValuePair<string, string>(
                    $"{HTTP_CHALLENGE_PATHPREFIX}{Token}",
                    JsonConvert.SerializeObject(signed, Formatting.Indented));
        }
Пример #22
0
        /// <summary>
        /// Returns a key-value pair that represents the DNS domain name that needs
        /// to be configured (the key) and the value that should be returned (the value)
        /// for a query against that domain name for a record of type TXT.
        /// </summary>
        /// <param name="dnsId"></param>
        /// <param name="signer"></param>
        /// <returns></returns>
        public KeyValuePair<string, string> GenerateDnsChallengeAnswer(string dnsId, ISigner signer)
        {
            var resp = new
            {
                type = "dns",
                token = Token
            };
            var json = JsonConvert.SerializeObject(resp);
            var hdrs = new { alg = signer.JwsAlg, jwk = signer.ExportJwk() };
            var signed = JwsHelper.SignFlatJsonAsObject(
                    signer.Sign, json, unprotectedHeaders: hdrs);

            /*
            // We format it as a set of lines broken on 100-character boundaries to make it
            // easier to copy and put into a DNS TXT RR which normally have a 255-char limit
            // so this result may need to be broken up into multiple smaller TXT RR entries
            var sigFormatted = Regex.Replace(signed.signature,
                    "(.{100,100})", "$1\r\n");
            */

            return new KeyValuePair<string, string>(
                    $"{DNS_CHALLENGE_NAMEPREFIX}{dnsId}",
                    signed.signature); /*sigFormatted);*/
        }
        public string RequestCertificateAndConvertToPfx(List <Binding> bindings)
        {
            var keyGenFile   = Path.Combine(Config.Path, $"{bindings[0].IPAddress}-gen-key.json");
            var keyPemFile   = Path.Combine(Config.Path, $"{bindings[0].IPAddress}-key.pem");
            var csrGenFile   = Path.Combine(Config.Path, $"{bindings[0].IPAddress}-gen-csr.json");
            var csrPemFile   = Path.Combine(Config.Path, $"{bindings[0].IPAddress}-csr.pem");
            var crtDerFile   = Path.Combine(Config.Path, $"{bindings[0].IPAddress}-crt.der");
            var crtPemFile   = Path.Combine(Config.Path, $"{bindings[0].IPAddress}-crt.pem");
            var chainPemFile = Path.Combine(Config.Path, $"{bindings[0].IPAddress}-chain.pem");
            var crtPfxFile   = Path.Combine(Config.Path, $"{bindings[0].IPAddress}-all.pfx");

            if (Globals.ShouldCreateCertificate())
            {
                // TODOX Should check if the requested certificate (lowercase and sort hostnames) was issued in previous 10 days

                var cp     = CertificateProvider.GetProvider();
                var rsaPkp = new RsaPrivateKeyParams();
                try {
                    if (Properties.Settings.Default.RSAKeyBits >= 2048)
                    {
                        rsaPkp.NumBits = Properties.Settings.Default.RSAKeyBits;
                    }
                    else
                    {
                        Globals.Log($"Requested key size of {Properties.Settings.Default.RSAKeyBits} is not secure.  Using 2048.");
                        rsaPkp.NumBits = 2048;
                    }
                } catch (Exception ex) {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Globals.Log($"Unable to set RSA key size, letting ACMESharp select default. Error: {ex}");
                    Console.ResetColor();
                }

                var rsaKeys    = cp.GeneratePrivateKey(rsaPkp);
                var csrDetails = new CsrDetails {
                    CommonName       = bindings[0].Hostname,
                    AlternativeNames = bindings.Select(x => x.Hostname).ToList(),
                };
                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);

                Globals.Log();
                Globals.Log("Requesting Certificate");
                var certRequ = _Client.RequestCertificate(derB64U);

                Globals.Log($" - Request Status: {certRequ.StatusCode}");

                if (certRequ.StatusCode == System.Net.HttpStatusCode.Created)
                {
                    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);

                    Globals.Log($" - Saving DER 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);

                    using (FileStream intermediate = new FileStream(isuPemFile, FileMode.Open),
                           certificate = new FileStream(crtPemFile, FileMode.Open),
                           chain = new FileStream(chainPemFile, FileMode.Create)) {
                        certificate.CopyTo(chain);
                        intermediate.CopyTo(chain);
                    }

                    Globals.Log($" - Saving PFX certificate to {crtPfxFile}");
                    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();

                    // TODOX Should store that the requested certificate (lowercase and sort hostnames) was issued

                    return(crtPfxFile);
                }
                else
                {
                    throw new Exception($"Certificate request status = {certRequ.StatusCode}, uri = {certRequ.Uri}");
                }
            }
            else
            {
                // Don't want to request a new cert, so return the filename to the last requested cert
                return(crtPfxFile);
            }
        }
Пример #24
0
        public static void GetCertificateAutoGen(CertificateGeneratorParam param)
        {
            if (param == null)
            {
                log.Info($" {nameof(param)} is null");
                return;
            }
            param.domains = param.domains.Where(o => o.valid).ToList();
            if (param.domains.Count == 0)
            {
                log.Info($" can't find a valid domain name.");
                return;
            }
            var dnsIdentifier = string.IsNullOrWhiteSpace(param.common_name) ? param.domains.FirstOrDefault().domain : param.common_name.Trim();
            var cp            = CertificateProvider.GetProvider();
            var rsaPkp        = new RsaPrivateKeyParams();

            var rsaKeys    = cp.GeneratePrivateKey(rsaPkp);
            var csrDetails = new CsrDetails
            {
                CommonName       = dnsIdentifier,
                AlternativeNames = param.domains.Select(o => o.domain).ToList(),
            };
            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);

            log.Info($"\nRequesting Certificate");
            var certRequ = param.client.RequestCertificate(derB64u);

            log.Info($" Request Status: {certRequ.StatusCode}");

            //log.Info($"Refreshing Cert Request");
            //client.RefreshCertificateRequest(certRequ);

            if (certRequ.StatusCode == System.Net.HttpStatusCode.Created)
            {
                var    keyGenFile = Path.Combine(param.path, $"{dnsIdentifier}-gen-key.json");
                var    keyPemFile = Path.Combine(param.path, $"{dnsIdentifier}-key.pem");
                var    csrGenFile = Path.Combine(param.path, $"{dnsIdentifier}-gen-csr.json");
                var    csrPemFile = Path.Combine(param.path, $"{dnsIdentifier}-csr.pem");
                var    crtDerFile = Path.Combine(param.path, $"{dnsIdentifier}-crt.der");
                var    crtPemFile = Path.Combine(param.path, $"{dnsIdentifier}-crt.pem");
                string crtPfxFile = null;

                crtPfxFile = Path.Combine(param.path, $"{dnsIdentifier}-all.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);

                log.Info($" 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, param.account);

                log.Info($" 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;
            }

            throw new Exception($"Request status = {certRequ.StatusCode}");
        }
        private void GetCertificate()
        {
            Log.Information("Requesting Certificate");

            using (CertificateProvider cp = CertificateProvider.GetProvider())
            {
                RsaPrivateKeyParams rsaPkp = new RsaPrivateKeyParams();

                PrivateKey rsaKeys   = cp.GeneratePrivateKey(rsaPkp);
                CsrParams  csrParams = new CsrParams
                {
                    Details = new CsrDetails
                    {
                        CommonName = _options.HostName,
                    },
                };

                Csr csr = cp.GenerateCsr(csrParams, rsaKeys, Crt.MessageDigest.SHA256);

                byte[] derRaw;
                using (MemoryStream bs = new MemoryStream())
                {
                    cp.ExportCsr(csr, EncodingFormat.DER, bs);
                    derRaw = bs.ToArray();
                }
                string derB64U = JwsHelper.Base64UrlEncode(derRaw);

                CertificateRequest certReq = _acmeClient.RequestCertificate(derB64U);

                if (certReq.StatusCode != HttpStatusCode.Created)
                {
                    throw new Exception($"Request status = {certReq.StatusCode}");
                }

                using (FileStream fs = new FileStream(_options.WellKnownFilePaths[WellKnownFile.KeyGen], FileMode.Create))
                    cp.SavePrivateKey(rsaKeys, fs);
                using (FileStream fs = new FileStream(_options.WellKnownFilePaths[WellKnownFile.KeyPem], FileMode.Create))
                    cp.ExportPrivateKey(rsaKeys, EncodingFormat.PEM, fs);
                using (FileStream fs = new FileStream(_options.WellKnownFilePaths[WellKnownFile.CsrGen], FileMode.Create))
                    cp.SaveCsr(csr, fs);
                using (FileStream fs = new FileStream(_options.WellKnownFilePaths[WellKnownFile.CsrPem], FileMode.Create))
                    cp.ExportCsr(csr, EncodingFormat.PEM, fs);

                Log.Information($"Saving Certificate to {_options.WellKnownFilePaths[WellKnownFile.CrtDer]}");
                using (FileStream file = File.Create(_options.WellKnownFilePaths[WellKnownFile.CrtDer]))
                    certReq.SaveCertificate(file);

                Crt crt;
                using (FileStream source = new FileStream(_options.WellKnownFilePaths[WellKnownFile.CrtDer], FileMode.Open),
                       target = new FileStream(_options.WellKnownFilePaths[WellKnownFile.CrtPem], 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
                string isuPemFile = GetIssuerCertificate(certReq, cp);

                using (FileStream intermediate = new FileStream(isuPemFile, FileMode.Open),
                       certificate = new FileStream(_options.WellKnownFilePaths[WellKnownFile.CrtPem], FileMode.Open),
                       chain = new FileStream(_options.WellKnownFilePaths[WellKnownFile.ChainPem], FileMode.Create))
                {
                    certificate.CopyTo(chain);
                    intermediate.CopyTo(chain);
                }

                Log.Information($"Saving Certificate to {_options.WellKnownFilePaths[WellKnownFile.CrtPfx]}");
                using (FileStream source = new FileStream(isuPemFile, FileMode.Open),
                       target = new FileStream(_options.WellKnownFilePaths[WellKnownFile.CrtPfx], FileMode.Create))
                {
                    Crt isuCrt = cp.ImportCertificate(EncodingFormat.PEM, source);
                    cp.ExportArchive(rsaKeys, new[] { crt, isuCrt }, ArchiveFormat.PKCS12, target, _options.PfxPassword);
                }
            }
        }
Пример #26
0
        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.Certificates == null || v.Certificates.Count < 1)
                {
                    throw new InvalidOperationException("No certificates found");
                }

                var ci = v.Certificates.GetByRef(CertificateRef);
                if (ci == null)
                {
                    throw new Exception("Unable to find a Certificate for the given reference");
                }

                using (var cp = CertificateProvider.GetProvider())
                {
                    if (!string.IsNullOrEmpty(ci.GenerateDetailsFile))
                    {
                        // Generate a private key and CSR:
                        //    Key:  RSA 2048-bit
                        //    MD:   SHA 256
                        //    CSR:  Details pulled from CSR Details JSON file

                        CsrDetails csrDetails;
                        var        csrDetailsAsset = vlt.GetAsset(VaultAssetType.CsrDetails, ci.GenerateDetailsFile);
                        using (var s = vlt.LoadAsset(csrDetailsAsset))
                        {
                            csrDetails = JsonHelper.Load <CsrDetails>(s);
                        }

                        var keyGenFile = $"{ci.Id}-gen-key.json";
                        var keyPemFile = $"{ci.Id}-key.pem";
                        var csrGenFile = $"{ci.Id}-gen-csr.json";
                        var csrPemFile = $"{ci.Id}-csr.pem";

                        var keyGenAsset = vlt.CreateAsset(VaultAssetType.KeyGen, keyGenFile, getOrCreate: Force);
                        var keyPemAsset = vlt.CreateAsset(VaultAssetType.KeyPem, keyPemFile, isSensitive: true, getOrCreate: Force);
                        var csrGenAsset = vlt.CreateAsset(VaultAssetType.CsrGen, csrGenFile, getOrCreate: Force);
                        var csrPemAsset = vlt.CreateAsset(VaultAssetType.CsrPem, csrPemFile, getOrCreate: Force);

                        var genKeyParams = new RsaPrivateKeyParams();

                        var genKey = cp.GeneratePrivateKey(genKeyParams);
                        using (var s = vlt.SaveAsset(keyGenAsset))
                        {
                            cp.SavePrivateKey(genKey, s);
                        }
                        using (var s = vlt.SaveAsset(keyPemAsset))
                        {
                            cp.ExportPrivateKey(genKey, EncodingFormat.PEM, s);
                        }

                        // TODO: need to surface details of the CSR params up higher
                        var csrParams = new CsrParams
                        {
                            Details = csrDetails
                        };
                        var genCsr = cp.GenerateCsr(csrParams, genKey, Crt.MessageDigest.SHA256);
                        using (var s = vlt.SaveAsset(csrGenAsset))
                        {
                            cp.SaveCsr(genCsr, s);
                        }
                        using (var s = vlt.SaveAsset(csrPemAsset))
                        {
                            cp.ExportCsr(genCsr, EncodingFormat.PEM, s);
                        }

                        ci.KeyPemFile = keyPemFile;
                        ci.CsrPemFile = csrPemFile;
                    }



                    byte[] derRaw;

                    var asset = vlt.GetAsset(VaultAssetType.CsrPem, ci.CsrPemFile);
                    // Convert the stored CSR in PEM format to DER
                    using (var source = vlt.LoadAsset(asset))
                    {
                        var csr = cp.ImportCsr(EncodingFormat.PEM, source);
                        using (var target = new MemoryStream())
                        {
                            cp.ExportCsr(csr, EncodingFormat.DER, target);
                            derRaw = target.ToArray();
                        }
                    }

                    var derB64u = JwsHelper.Base64UrlEncode(derRaw);

                    try
                    {
                        using (var c = ClientHelper.GetClient(v, ri))
                        {
                            c.Init();
                            c.GetDirectory(true);

                            ci.CertificateRequest = c.RequestCertificate(derB64u);
                        }
                    }
                    catch (AcmeClient.AcmeWebException ex)
                    {
                        ThrowTerminatingError(PoshHelper.CreateErrorRecord(ex, ci));
                        return;
                    }

                    if (!string.IsNullOrEmpty(ci.CertificateRequest.CertificateContent))
                    {
                        var crtDerFile = $"{ci.Id}-crt.der";
                        var crtPemFile = $"{ci.Id}-crt.pem";

                        var crtDerBytes = ci.CertificateRequest.GetCertificateContent();

                        var crtDerAsset = vlt.CreateAsset(VaultAssetType.CrtDer, crtDerFile);
                        var crtPemAsset = vlt.CreateAsset(VaultAssetType.CrtPem, crtPemFile);

                        using (Stream source = new MemoryStream(crtDerBytes),
                               derTarget = vlt.SaveAsset(crtDerAsset),
                               pemTarget = vlt.SaveAsset(crtPemAsset))
                        {
                            var crt = cp.ImportCertificate(EncodingFormat.DER, source);

                            cp.ExportCertificate(crt, EncodingFormat.DER, derTarget);
                            ci.CrtDerFile = crtDerFile;

                            cp.ExportCertificate(crt, EncodingFormat.PEM, pemTarget);
                            ci.CrtPemFile = crtPemFile;
                        }

                        // Extract a few pieces of info from the issued
                        // cert that we like to have quick access to
                        var x509 = new X509Certificate2(ci.CertificateRequest.GetCertificateContent());
                        ci.SerialNumber       = x509.SerialNumber;
                        ci.Thumbprint         = x509.Thumbprint;
                        ci.SignatureAlgorithm = x509.SignatureAlgorithm?.FriendlyName;
                        ci.Signature          = x509.GetCertHashString();
                    }
                }

                vlt.SaveVault(v);

                WriteObject(ci);
            }
        }
Пример #27
0
        /// <summary>
        /// Request certificate from the ACME server
        /// </summary>
        /// <param name="binding"></param>
        /// <returns></returns>
        public CertificateInfo RequestCertificate(Target binding)
        {
            // What are we going to get?
            var identifiers  = binding.GetHosts(false);
            var friendlyName = FriendlyName(binding);
            var pfxPassword  = Properties.Settings.Default.PFXPassword;
            var pfxFileInfo  = new FileInfo(PfxFilePath(binding));

            // 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, pfxPassword),
                        PfxFile     = pfxFileInfo
                    };
                    var idn = new IdnMapping();
                    if (cached.SubjectName == identifiers.First() &&
                        cached.HostNames.Count == identifiers.Count &&
                        cached.HostNames.All(h => identifiers.Contains(idn.GetAscii(h))))
                    {
                        if (_options.ForceRenewal)
                        {
                            _log.Warning("Cached certificate available but not used with --forcerenewal. Use 'Renew specific' or 'Renew all' in the main menu to run unscheduled renewals without hitting rate limits.");
                        }
                        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 --forcerenewal switch. Be ware that you might run into rate limits doing so.", friendlyName);
                            return(cached);
                        }
                    }
                }
                catch
                {
                    // File corrupt or invalid password?
                    _log.Warning("Unable to read from certificate cache");
                }
            }

            using (var cp = CertificateProvider.GetProvider("BouncyCastle"))
            {
                // Generate the private key and CSR
                var    rsaPkp  = GetRsaKeyParameters();
                var    rsaKeys = cp.GeneratePrivateKey(rsaPkp);
                var    csr     = GetCsr(cp, identifiers, rsaKeys, binding.CommonName);
                byte[] derRaw;
                using (var bs = new MemoryStream())
                {
                    cp.ExportCsr(csr, EncodingFormat.DER, bs);
                    derRaw = bs.ToArray();
                }
                var derB64U = JwsHelper.Base64UrlEncode(derRaw);

                // Save request parameters to disk
                using (var fs = new FileStream(GetPath(binding, "-gen-key.json"), FileMode.Create))
                    cp.SavePrivateKey(rsaKeys, fs);

                using (var fs = new FileStream(GetPath(binding, "-key.pem"), FileMode.Create))
                    cp.ExportPrivateKey(rsaKeys, EncodingFormat.PEM, fs);

                using (var fs = new FileStream(GetPath(binding, "-gen-csr.json"), FileMode.Create))
                    cp.SaveCsr(csr, fs);

                using (var fs = new FileStream(GetPath(binding, "-csr.pem"), FileMode.Create))
                    cp.ExportCsr(csr, EncodingFormat.PEM, fs);

                // Request the certificate from the ACME server
                _log.Information("Requesting certificate {friendlyName}", friendlyName);
                var certificateRequest = _client.Acme.RequestCertificate(derB64U);
                if (certificateRequest.StatusCode != HttpStatusCode.Created)
                {
                    throw new Exception($"Request status {certificateRequest.StatusCode}");
                }

                // Main certicate and issuer certificate
                Crt certificate;
                Crt issuerCertificate;

                // Certificate request was successful, save the certificate itself
                var crtDerFile = GetPath(binding, $"-crt.der");
                _log.Information("Saving certificate to {crtDerFile}", _certificatePath);
                using (var file = File.Create(crtDerFile))
                    certificateRequest.SaveCertificate(file);

                // Save certificate in PEM format too
                var crtPemFile = GetPath(binding, $"-crt.pem");
                using (FileStream source = new FileStream(crtDerFile, FileMode.Open),
                       target = new FileStream(crtPemFile, FileMode.Create))
                {
                    certificate = cp.ImportCertificate(EncodingFormat.DER, source);
                    cp.ExportCertificate(certificate, EncodingFormat.PEM, target);
                }

                // Get issuer certificate and save in DER and PEM formats
                issuerCertificate = GetIssuerCertificate(certificateRequest, cp);
                using (var target = new FileStream(GetPath(binding, "-crt.der", "ca-"), FileMode.Create))
                    cp.ExportCertificate(issuerCertificate, EncodingFormat.DER, target);

                var issuerPemFile = GetPath(binding, "-crt.pem", "ca-");
                using (var target = new FileStream(issuerPemFile, FileMode.Create))
                    cp.ExportCertificate(issuerCertificate, EncodingFormat.PEM, target);

                // Save chain in PEM format
                using (FileStream intermediate = new FileStream(issuerPemFile, FileMode.Open),
                       certificateStrean = new FileStream(crtPemFile, FileMode.Open),
                       chain = new FileStream(GetPath(binding, "-chain.pem"), FileMode.Create))
                {
                    certificateStrean.CopyTo(chain);
                    intermediate.CopyTo(chain);
                }

                // All raw data has been saved, now generate the PFX file
                using (var target = new FileStream(pfxFileInfo.FullName, FileMode.Create))
                {
                    try
                    {
                        cp.ExportArchive(rsaKeys,
                                         new[] { certificate, issuerCertificate },
                                         ArchiveFormat.PKCS12,
                                         target,
                                         pfxPassword);
                    }
                    catch (Exception ex)
                    {
                        _log.Error("Error exporting archive {@ex}", ex);
                    }
                }

                // Flags used for the internally cached certificate
                var internalFlags =
                    X509KeyStorageFlags.MachineKeySet |
                    X509KeyStorageFlags.PersistKeySet |
                    X509KeyStorageFlags.Exportable;

                // See http://paulstovell.com/blog/x509certificate2
                try
                {
                    // Convert Private Key to different CryptoProvider
                    _log.Verbose("Converting private key...");
                    var res        = new X509Certificate2(pfxFileInfo.FullName, pfxPassword, internalFlags);
                    var privateKey = (RSACryptoServiceProvider)res.PrivateKey;
                    res.PrivateKey   = Convert(privateKey);
                    res.FriendlyName = friendlyName;
                    File.WriteAllBytes(pfxFileInfo.FullName, res.Export(X509ContentType.Pfx, pfxPassword));
                    pfxFileInfo.Refresh();
                }
                catch (Exception ex)
                {
                    // If we couldn't convert the private key that
                    // means we're left with a pfx generated with the
                    // 'wrong' Crypto provider therefor delete it to
                    // make sure it's retried on the next run.
                    _log.Warning("Error converting private key to Microsoft RSA SChannel Cryptographic Provider, which means it might not be usable for Exchange.");
                    _log.Verbose("{ex}", ex);
                }

                // Recreate X509Certificate2 with correct flags for Store/Install
                return(new CertificateInfo()
                {
                    Certificate = ReadForUse(pfxFileInfo, pfxPassword),
                    PfxFile = pfxFileInfo
                });
            }
        }
Пример #28
0
        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.Certificates == null || v.Certificates.Count < 1)
                {
                    throw new InvalidOperationException("No certificates found");
                }

                var ci = v.Certificates.GetByRef(Ref);
                if (ci == null)
                {
                    throw new Exception("Unable to find a Certificate for the given reference");
                }

                if (!string.IsNullOrEmpty(ci.GenerateDetailsFile))
                {
                    // Generate a private key and CSR:
                    //    Key:  RSA 2048-bit
                    //    MD:   SHA 256
                    //    CSR:  Details pulled from CSR Details JSON file

                    CsrHelper.CsrDetails csrDetails;
                    var csrDetailsAsset = vp.GetAsset(VaultAssetType.CsrDetails, ci.GenerateDetailsFile);
                    using (var s = vp.LoadAsset(csrDetailsAsset))
                    {
                        csrDetails = JsonHelper.Load <CsrHelper.CsrDetails>(s);
                    }

                    var keyGenFile = $"{ci.Id}-gen-key.json";
                    var keyPemFile = $"{ci.Id}-key.pem";
                    var csrGenFile = $"{ci.Id}-gen-csr.json";
                    var csrPemFile = $"{ci.Id}-csr.pem";

                    var keyGenAsset = vp.CreateAsset(VaultAssetType.KeyGen, keyGenFile);
                    var keyPemAsset = vp.CreateAsset(VaultAssetType.KeyPem, keyPemFile);
                    var csrGenAsset = vp.CreateAsset(VaultAssetType.CsrGen, csrGenFile);
                    var csrPemAsset = vp.CreateAsset(VaultAssetType.CsrPem, csrPemFile);

                    var genKey = CsrHelper.GenerateRsaPrivateKey();
                    using (var s = vp.SaveAsset(keyGenAsset))
                    {
                        genKey.Save(s);
                    }
                    using (var w = new StreamWriter(vp.SaveAsset(keyPemAsset)))
                    {
                        w.Write(genKey.Pem);
                    }

                    var genCsr = CsrHelper.GenerateCsr(csrDetails, genKey);
                    using (var s = vp.SaveAsset(csrGenAsset))
                    {
                        genCsr.Save(s);
                    }
                    using (var w = new StreamWriter(vp.SaveAsset(csrPemAsset)))
                    {
                        w.Write(genCsr.Pem);
                    }

                    ci.KeyPemFile = keyPemFile;
                    ci.CsrPemFile = csrPemFile;
                }

                var asset = vp.GetAsset(VaultAssetType.CsrPem, ci.CsrPemFile);

                byte[] derRaw;
                using (var s = vp.LoadAsset(asset))
                {
                    using (var ms = new MemoryStream())
                    {
                        CsrHelper.Csr.ConvertPemToDer(s, ms);
                        derRaw = ms.ToArray();
                    }
                }

                var derB64u = JwsHelper.Base64UrlEncode(derRaw);

                using (var c = ClientHelper.GetClient(v, ri))
                {
                    c.Init();
                    c.GetDirectory(true);

                    ci.CertificateRequest = c.RequestCertificate(derB64u);
                }

                if (!string.IsNullOrEmpty(ci.CertificateRequest.CertificateContent))
                {
                    var crtDerFile = $"{ci.Id}-crt.der";
                    var crtPemFile = $"{ci.Id}-crt.pem";

                    var crtDerAsset = vp.CreateAsset(VaultAssetType.CrtDer, crtDerFile);
                    var crtPemAsset = vp.CreateAsset(VaultAssetType.CrtPem, crtPemFile);

                    using (var s = vp.SaveAsset(crtDerAsset))
                    {
                        ci.CertificateRequest.SaveCertificate(s);
                        ci.CrtDerFile = crtDerFile;
                    }

                    using (Stream source = vp.LoadAsset(crtDerAsset), target = vp.SaveAsset(crtPemAsset))
                    {
                        CsrHelper.Crt.ConvertDerToPem(source, target);
                        ci.CrtPemFile = crtPemFile;
                    }

                    var crt = new X509Certificate2(ci.CertificateRequest.GetCertificateContent());
                    ci.SerialNumber       = crt.SerialNumber;
                    ci.Thumbprint         = crt.Thumbprint;
                    ci.SignatureAlgorithm = crt.SignatureAlgorithm?.FriendlyName;
                    ci.Signature          = crt.GetCertHashString();
                }

                vp.SaveVault(v);

                WriteObject(ci);
            }
        }
Пример #29
0
        public string GetCertificate(AcmeClient client)
        {
            IdnMapping idn           = new IdnMapping();
            var        dnsIdentifier = idn.GetAscii(config.Host);

            CertificateProvider.RegisterProvider <BouncyCastleProvider>(BouncyCastleProvider.PROVIDER_NAME);
            var cp     = CertificateProvider.GetProvider(BouncyCastleProvider.PROVIDER_NAME);
            var rsaPkp = new RsaPrivateKeyParams();

            try
            {
                if (config.RSAKeyLength >= 1024)
                {
                    rsaPkp.NumBits = config.RSAKeyLength;
                    Trace.TraceInformation("RSAKeyBits: {0}", config.RSAKeyLength);
                }
                else
                {
                    Trace.TraceWarning("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)
            {
                Trace.TraceWarning("Unable to set RSA Key Bits, Letting ACMESharp default key bits, Error: {0}", ex);
                Console.WriteLine($"Unable to set RSA Key Bits, Letting ACMESharp default key bits, Error: {ex.Message.ToString()}");
            }

            var rsaKeys    = cp.GeneratePrivateKey(rsaPkp);
            var csrDetails = new CsrDetails
            {
                CommonName = dnsIdentifier,
            };

            if (config.AlternateNames != null)
            {
                if (config.AlternateNames.Count > 0)
                {
                    csrDetails.AlternativeNames = config.AlternateNames.Select(s => idn.GetAscii(s));
                }
            }
            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");
            Trace.TraceInformation("Requesting Certificate");
            CertificateRequest certRequ = client.RequestCertificate(derB64u);

            Trace.TraceInformation("certRequ {0}", JsonConvert.SerializeObject(certRequ));

            Console.WriteLine($" Request Status: {certRequ.StatusCode}");
            Trace.TraceInformation("Request Status: {0}", certRequ.StatusCode);

            if (certRequ.StatusCode == System.Net.HttpStatusCode.Created)
            {
                var    keyGenFile = Path.Combine(this.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;

                crtPfxFile = Path.Combine(configPath, $"{dnsIdentifier}-all.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}");
                Trace.TraceInformation("Saving Certificate to {0}", 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}");
                Trace.TraceInformation("Saving Certificate to {0}", 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, config.PFXPassword);
                    }
                    catch (Exception ex)
                    {
                        Trace.TraceError("Error exporting archive {0}", ex);
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine($"Error exporting archive: {ex.Message.ToString()}");
                        Console.ResetColor();
                    }
                }


                cp.Dispose();

                return(crtPfxFile);
            }
            if ((int)certRequ.StatusCode == 429)
            {
                Trace.TraceError("Unable to request certificate, too many certificate requests to Let's Encrypt certificate servers for the domain within the last 7 days. Please try again later. (If you are testing, please use the staging enviroment where you can request unlimited number of certificates. During the beta period only 5 certificate requests per domain per week are allowed to the production environment.)");
                throw new Exception("Unable to request certificate, too many certificate requests to Let's Encrypt certificate servers for the domain within the last 7 days. Please try again later. (If you are testing, please use the staging enviroment where you can request unlimited number of certificates. During the beta period only 5 certificate requests per domain per week are allowed to the production environment.)");
            }

            Trace.TraceError("Request status = {0}", certRequ.StatusCode);
            throw new Exception($"Request status = {certRequ.StatusCode}");
        }
Пример #30
0
        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}");
        }