Example #1
0
            public async Task CanGenerateCertificateDns()
            {
                var dirUri = await GetAcmeUriV2();

                var hosts    = new[] { $"www-dns-{DomainSuffix}.es256.certes-ci.dymetis.com", $"mail-dns-{DomainSuffix}.es256.certes-ci.dymetis.com" };
                var ctx      = new AcmeContext(dirUri, GetKeyV2(), http: GetAcmeHttpClient(dirUri));
                var orderCtx = await AuthzDns(ctx, hosts);

                while (orderCtx == null)
                {
                    Output.WriteLine("DNS authz failed, retrying...");
                    orderCtx = await AuthzDns(ctx, hosts);
                }

                var csr = new CertificationRequestBuilder();

                csr.AddName($"C=CA, ST=Ontario, L=Toronto, O=Certes, OU=Dev, CN={hosts[0]}");
                foreach (var h in hosts)
                {
                    csr.SubjectAlternativeNames.Add(h);
                }

                var der = csr.Generate();

                var finalizedOrder = await orderCtx.Finalize(der);

                var certificate = await orderCtx.Download();

                await ClearAuthorizations(orderCtx);
            }
            public async Task CanGenerateWildcard()
            {
                var dirUri = await GetAcmeUriV2();

                var hosts = new[] { $"*.wildcard-{DomainSuffix}.es256.certes-ci.dymetis.com" };
                var ctx   = new AcmeContext(dirUri, GetKeyV2(), http: GetAcmeHttpClient(dirUri));

                var orderCtx = await AuthzDns(ctx, hosts);

                var certKey        = KeyFactory.NewKey(KeyAlgorithm.RS256);
                var finalizedOrder = await orderCtx.Finalize(new CsrInfo
                {
                    CountryName      = "CA",
                    State            = "Ontario",
                    Locality         = "Toronto",
                    Organization     = "Certes",
                    OrganizationUnit = "Dev",
                    CommonName       = hosts[0],
                }, certKey);

                var pem = await orderCtx.Download(null);

                var builder = new PfxBuilder(pem.Certificate.ToDer(), certKey);

                foreach (var issuer in pem.Issuers)
                {
                    builder.AddIssuer(issuer.ToDer());
                }

                builder.AddTestCerts();

                var pfx = builder.Build("ci", "abcd1234");

                Assert.NotNull(pfx);
            }
Example #3
0
        protected async Task CanGenerateCertificateWithEC(KeyAlgorithm algo)
        {
            var dirUri = await GetAcmeUriV2();

            var hosts    = new[] { $"www-ec-{DomainSuffix}.{algo}.certes-ci.dymetis.com".ToLower() };
            var ctx      = new AcmeContext(dirUri, GetKeyV2(algo), http: GetAcmeHttpClient(dirUri));
            var orderCtx = await AuthorizeHttp(ctx, hosts);

            var certKey        = KeyFactory.NewKey(algo);
            var finalizedOrder = await orderCtx.Finalize(new CsrInfo
            {
                CountryName      = "CA",
                State            = "Ontario",
                Locality         = "Toronto",
                Organization     = "Certes",
                OrganizationUnit = "Dev",
                CommonName       = hosts[0],
            }, certKey);

            var cert = await orderCtx.Download(null);

            var x509 = new X509Certificate2(cert.Certificate.ToDer());

            Assert.Contains(hosts[0], x509.Subject);

            // deactivate authz so the subsequence can trigger challenge validation
            await ClearAuthorizations(orderCtx);
        }
            public async Task CanDiscoverAccountByKey()
            {
                var dirUri = await GetAcmeUriV2();

                var ctx  = new AcmeContext(dirUri, GetKeyV2(), GetAcmeHttpClient(dirUri));
                var acct = await ctx.Account();

                Assert.NotNull(acct.Location);

                var res = await acct.Resource();
            }
Example #5
0
        private static async Task <IOrderContext> AuthorizeHttp(AcmeContext ctx, IList <string> hosts)
        {
            for (var i = 0; i < 10; ++i)
            {
                var orderCtx = await ctx.NewOrder(hosts);

                var order = await orderCtx.Resource();

                Assert.NotNull(order);
                Assert.Equal(hosts.Count, order.Authorizations?.Count);
                Assert.True(OrderStatus.Pending == order.Status || OrderStatus.Ready == order.Status || OrderStatus.Processing == order.Status);

                var authrizations = await orderCtx.Authorizations();

                foreach (var authz in authrizations)
                {
                    var httpChallenge = await authz.Http();

                    await httpChallenge.Validate();
                }

                while (true)
                {
                    await Task.Delay(100);

                    var statuses = new List <AuthorizationStatus>();
                    foreach (var authz in authrizations)
                    {
                        var a = await authz.Resource();

                        statuses.Add(a.Status ?? AuthorizationStatus.Pending);
                    }

                    if (statuses.All(s => s == AuthorizationStatus.Valid))
                    {
                        return(orderCtx);
                    }


                    if (statuses.Any(s => s == AuthorizationStatus.Invalid))
                    {
                        break;
                    }
                }
            }

            Assert.True(false, "Authorization failed.");
            return(null);
        }
Example #6
0
        public async Task Account()
        {
            var acmeDir = await IntegrationHelper.GetAcmeUriV2();

            var accountKey = Helper.GetKeyV2(KeyAlgorithm.RS256);
            var httpClient = IntegrationHelper.GetAcmeHttpClient(acmeDir);

            var acme    = new AcmeContext(acmeDir, accountKey, httpClient);
            var account = await acme.Account();

            var order = await acme.NewOrder(new[] { "www.certes-ci.dymetis.com" });

            var authz         = (await order.Authorizations()).First();
            var httpChallenge = await authz.Http();

            var token    = httpChallenge.Token;
            var keyAuthz = httpChallenge.KeyAuthz;

            var orderUri = order.Location;

            await httpChallenge.Validate();

            var res = await authz.Resource();

            while (res.Status != AuthorizationStatus.Valid && res.Status != AuthorizationStatus.Invalid)
            {
                res = await authz.Resource();
            }

            acme  = new AcmeContext(acmeDir, accountKey, httpClient);
            order = acme.Order(orderUri);
            var privateKey = KeyFactory.NewKey(KeyAlgorithm.ES256);
            var cert       = await order.Generate(new CsrInfo
            {
                CountryName      = "CA",
                State            = "Ontario",
                Locality         = "Toronto",
                Organization     = "Certes",
                OrganizationUnit = "Dev",
                CommonName       = "www.certes-ci.dymetis.com",
            }, privateKey, null);

            var pfxBuilder = cert.ToPfx(privateKey);

            pfxBuilder.AddTestCerts();
            var pfx = pfxBuilder.Build("my-cert", "abcd1234");
        }
            public async Task CanChangeAccountKey()
            {
                var dirUri = await GetAcmeUriV2();

                var ctx     = new AcmeContext(dirUri, http: GetAcmeHttpClient(dirUri));
                var account = await ctx.NewAccount(
                    new[] { $"mailto:certes-{DateTime.UtcNow.Ticks}@example.com" }, true);

                var location = await ctx.Account().Location();

                var newKey = KeyFactory.NewKey(KeyAlgorithm.ES256);
                await ctx.ChangeKey(newKey);

                var ctxWithNewKey      = new AcmeContext(dirUri, newKey, http: GetAcmeHttpClient(dirUri));
                var locationWithNewKey = await ctxWithNewKey.Account().Location();

                Assert.Equal(location, locationWithNewKey);
            }
Example #8
0
        public static async Task <Uri> GetAcmeUriV2()
        {
            if (stagingServerV2 != null)
            {
                return(stagingServerV2);
            }

            var servers = new[] {
                //new Uri("https://lo0.in:4431/directory"),
                new Uri("https://boulder-certes-ci.dymetis.com:4431/directory"),
                //WellKnownServers.LetsEncryptStagingV2,
            };

            var exceptions = new List <Exception>();

            foreach (var uri in servers)
            {
                try
                {
                    await http.Value.GetStringAsync(uri);

                    foreach (var algo in new[] { KeyAlgorithm.ES256, KeyAlgorithm.ES384, KeyAlgorithm.RS256 })
                    {
                        try
                        {
                            var ctx = new AcmeContext(uri, Helper.GetKeyV2(algo), GetAcmeHttpClient(uri));
                            await ctx.NewAccount(new[] { "mailto:[email protected]" }, true);
                        }
                        catch
                        {
                        }
                    }

                    return(stagingServerV2 = uri);
                }
                catch (Exception ex)
                {
                    exceptions.Add(ex);
                }
            }

            throw new AggregateException("No staging server available.", exceptions);
        }
Example #9
0
            public async Task CanGenerateWildcard()
            {
                var dirUri = await GetAcmeUriV2();

                var hosts = new[] { $"wildcard-{DomainSuffix}.es256.certes-ci.dymetis.com" };
                var ctx   = new AcmeContext(dirUri, GetKeyV2(), http: GetAcmeHttpClient(dirUri));

                var orderCtx = await AuthzDns(ctx, hosts);

                var certKey        = KeyFactory.NewKey(KeyAlgorithm.RS256);
                var finalizedOrder = await orderCtx.Finalize(new CsrInfo
                {
                    CountryName      = "CA",
                    State            = "Ontario",
                    Locality         = "Toronto",
                    Organization     = "Certes",
                    OrganizationUnit = "Dev",
                    CommonName       = hosts[0],
                }, certKey);

                var pem = await orderCtx.Download();
            }
            public async Task CanGenerateCertificateDns()
            {
                var dirUri = await GetAcmeUriV2();

                var hosts    = new[] { $"www-dns-{DomainSuffix}.es256.certes-ci.dymetis.com", $"mail-dns-{DomainSuffix}.es256.certes-ci.dymetis.com" };
                var ctx      = new AcmeContext(dirUri, GetKeyV2(), http: GetAcmeHttpClient(dirUri));
                var orderCtx = await AuthzDns(ctx, hosts);

                while (orderCtx == null)
                {
                    Output.WriteLine("DNS authz failed, retrying...");
                    orderCtx = await AuthzDns(ctx, hosts);
                }

                var csr = new CertificationRequestBuilder();

                csr.AddName($"C=CA, ST=Ontario, L=Toronto, O=Certes, OU=Dev, CN={hosts[0]}");
                foreach (var h in hosts)
                {
                    csr.SubjectAlternativeNames.Add(h);
                }

                var der = csr.Generate();

                var finalizedOrder = await orderCtx.Finalize(der);

                var certificate = await orderCtx.Download();

                // deactivate authz so the subsequence can trigger challenge validation
                var authrizations = await orderCtx.Authorizations();

                foreach (var authz in authrizations)
                {
                    var authzRes = await authz.Deactivate();

                    Assert.Equal(AuthorizationStatus.Deactivated, authzRes.Status);
                }
            }
            public async Task CanGenerateCertificateHttp()
            {
                var dirUri = await GetAcmeUriV2();

                var hosts    = new[] { $"www-http-{DomainSuffix}.es256.certes-ci.dymetis.com", $"mail-http-{DomainSuffix}.es256.certes-ci.dymetis.com" };
                var ctx      = new AcmeContext(dirUri, GetKeyV2(), http: GetAcmeHttpClient(dirUri));
                var orderCtx = await AuthorizeHttp(ctx, hosts);

                var certKey        = KeyFactory.NewKey(KeyAlgorithm.RS256);
                var finalizedOrder = await orderCtx.Finalize(new CsrInfo
                {
                    CountryName      = "CA",
                    State            = "Ontario",
                    Locality         = "Toronto",
                    Organization     = "Certes",
                    OrganizationUnit = "Dev",
                    CommonName       = hosts[0],
                }, certKey);

                var certChain = await orderCtx.Download(null);

                var pfxBuilder = certChain.ToPfx(certKey);

                pfxBuilder.AddIssuers(IntegrationHelper.TestCertificates);

                var pfx = pfxBuilder.Build("my-pfx", "abcd1234");

                // revoke certificate
                var certParser  = new X509CertificateParser();
                var certificate = certParser.ReadCertificate(certChain.Certificate.ToDer());
                var der         = certificate.GetEncoded();

                await ctx.RevokeCertificate(der, RevocationReason.Unspecified, null);

                // deactivate authz so the subsequence can trigger challenge validation
                await ClearAuthorizations(orderCtx);
            }
            public async Task CanRunAccountFlows()
            {
                var dirUri = await GetAcmeUriV2();

                var ctx        = new AcmeContext(dirUri, http: GetAcmeHttpClient(dirUri));
                var accountCtx = await ctx.NewAccount(
                    new[] { $"mailto:certes-{DateTime.UtcNow.Ticks}@example.com" }, true);

                var account = await accountCtx.Resource();

                var location = accountCtx.Location;

                Assert.NotNull(account);
                Assert.Equal(AccountStatus.Valid, account.Status);

                await accountCtx.Update(agreeTermsOfService : true);

                await accountCtx.Update(contact : new[] { $"mailto:certes-{DateTime.UtcNow.Ticks}@example.com" });

                account = await accountCtx.Deactivate();

                Assert.NotNull(account);
                Assert.Equal(AccountStatus.Deactivated, account.Status);
            }
Example #13
0
            public async Task CanGenerateCertificateTlsAlpn()
            {
                var dirUri = await GetAcmeUriV2();

                var hosts    = new[] { $"{DomainSuffix}.tls-alpn.certes-ci.dymetis.com" };
                var ctx      = new AcmeContext(dirUri, GetKeyV2(), http: GetAcmeHttpClient(dirUri));
                var orderCtx = await ctx.NewOrder(hosts);

                var order = await orderCtx.Resource();

                Assert.NotNull(order);
                Assert.Equal(hosts.Length, order.Authorizations?.Count);
                Assert.True(
                    OrderStatus.Ready == order.Status || OrderStatus.Pending == order.Status || OrderStatus.Processing == order.Status,
                    $"Invalid order status: {order.Status}");

                var authrizations = await orderCtx.Authorizations();

                foreach (var authzCtx in authrizations)
                {
                    var authz = await authzCtx.Resource();

                    var tlsAlpnChallenge = await authzCtx.TlsAlpn();

                    var alpnCertKey = KeyFactory.NewKey(KeyAlgorithm.ES256);
                    var alpnCert    = ctx.AccountKey.TlsAlpnCertificate(tlsAlpnChallenge.Token, authz.Identifier.Value, alpnCertKey);

                    await SetupValidationResponder(authz, alpnCert, alpnCertKey);

                    await tlsAlpnChallenge.Validate();
                }

                while (true)
                {
                    await Task.Delay(100);

                    var statuses = new List <AuthorizationStatus>();
                    foreach (var authz in authrizations)
                    {
                        var a = await authz.Resource();

                        statuses.Add(a.Status ?? AuthorizationStatus.Pending);
                    }

                    if (statuses.All(s => s == AuthorizationStatus.Valid || s == AuthorizationStatus.Invalid))
                    {
                        break;
                    }
                }

                var certKey        = KeyFactory.NewKey(KeyAlgorithm.RS256);
                var finalizedOrder = await orderCtx.Finalize(new CsrInfo
                {
                    CountryName      = "CA",
                    State            = "Ontario",
                    Locality         = "Toronto",
                    Organization     = "Certes",
                    OrganizationUnit = "Dev",
                    CommonName       = hosts[0],
                }, certKey);

                var certChain = await orderCtx.Download(null);

                var pfxBuilder = certChain.ToPfx(certKey);

                pfxBuilder.AddTestCerts();

                var pfx = pfxBuilder.Build("my-pfx", "abcd1234");

                // revoke certificate
                var certParser  = new X509CertificateParser();
                var certificate = certParser.ReadCertificate(certChain.Certificate.ToDer());
                var der         = certificate.GetEncoded();

                await ctx.RevokeCertificate(der, RevocationReason.Unspecified, null);

                // deactivate authz so the subsequence can trigger challenge validation
                foreach (var authz in authrizations)
                {
                    var authzRes = await authz.Deactivate();

                    Assert.Equal(AuthorizationStatus.Deactivated, authzRes.Status);
                }
            }
Example #14
0
        protected async Task CanGenerateCertificateWithEC(KeyAlgorithm algo)
        {
            var dirUri = await GetAcmeUriV2();

            var hosts    = new[] { $"www-ec-{DomainSuffix}.{algo}.certes-ci.dymetis.com".ToLower() };
            var ctx      = new AcmeContext(dirUri, GetKeyV2(algo), http: GetAcmeHttpClient(dirUri));
            var orderCtx = await ctx.NewOrder(hosts);

            var order = await orderCtx.Resource();

            Assert.NotNull(order);
            Assert.Equal(hosts.Length, order.Authorizations?.Count);
            Assert.True(OrderStatus.Pending == order.Status || OrderStatus.Processing == order.Status);

            var authrizations = await orderCtx.Authorizations();

            foreach (var authz in authrizations)
            {
                var httpChallenge = await authz.Http();

                await httpChallenge.Validate();
            }

            while (true)
            {
                await Task.Delay(100);

                var statuses = new List <AuthorizationStatus>();
                foreach (var authz in authrizations)
                {
                    var a = await authz.Resource();

                    statuses.Add(a.Status ?? AuthorizationStatus.Pending);
                }

                if (statuses.All(s => s == AuthorizationStatus.Valid || s == AuthorizationStatus.Invalid))
                {
                    break;
                }
            }

            var certKey        = KeyFactory.NewKey(algo);
            var finalizedOrder = await orderCtx.Finalize(new CsrInfo
            {
                CountryName      = "CA",
                State            = "Ontario",
                Locality         = "Toronto",
                Organization     = "Certes",
                OrganizationUnit = "Dev",
                CommonName       = hosts[0],
            }, certKey);

            var cert = await orderCtx.Download();

            var x509 = new X509Certificate2(cert.Certificate.ToDer());

            Assert.Contains(hosts[0], x509.Subject);

            // deactivate authz so the subsequence can trigger challenge validation
            foreach (var authz in authrizations)
            {
                var authzRes = await authz.Deactivate();

                Assert.Equal(AuthorizationStatus.Deactivated, authzRes.Status);
            }
        }
Example #15
0
        protected async Task <IOrderContext> AuthzDns(AcmeContext ctx, string[] hosts)
        {
            var orderCtx = await ctx.NewOrder(hosts);

            var order = await orderCtx.Resource();

            Assert.NotNull(order);
            Assert.Equal(hosts.Length, order.Authorizations?.Count);
            Assert.True(OrderStatus.Pending == order.Status || OrderStatus.Processing == order.Status);

            var authrizations = await orderCtx.Authorizations();

            var tokens = new Dictionary <string, string>();

            foreach (var authz in authrizations)
            {
                var res = await authz.Resource();

                var dnsChallenge = await authz.Dns();

                tokens.Add(res.Identifier.Value, dnsChallenge.Token);
            }

            await DeployDns01(KeyAlgorithm.ES256, tokens);

            await Task.Delay(1000);

            foreach (var authz in authrizations)
            {
                var res = await authz.Resource();

                var dnsChallenge = await authz.Dns();

                await dnsChallenge.Validate();
            }

            while (true)
            {
                await Task.Delay(100);

                var statuses = new List <AuthorizationStatus>();
                foreach (var authz in authrizations)
                {
                    var a = await authz.Resource();

                    if (AuthorizationStatus.Invalid == a.Status)
                    {
                        return(null);
                    }
                    else
                    {
                        statuses.Add(a.Status ?? AuthorizationStatus.Pending);
                    }
                }

                if (statuses.All(s => s == AuthorizationStatus.Valid))
                {
                    break;
                }
            }

            return(orderCtx);
        }