예제 #1
0
 protected virtual void HandleCertificate(TlsCertificate message)
 {
     if (CertificateManager.CheckClientCertificate(Config, message.Certificates))
     {
         PendingCrypto.ClientCertificates = message.Certificates;
     }
 }
예제 #2
0
            public CertInfo(string name, TlsCertificate cert)
            {
                this.Name = name;

                if (cert.ValidUntil.HasValue)
                {
                    this.ValidUntil = cert.ValidUntil.Value.ToString("MM/dd/yyy HH:mm:ss", CultureInfo.InvariantCulture) + " GMT";
                }
                else
                {
                    this.ValidUntil = "-";
                }

                if (cert.Hosts != null && cert.Hosts.Count > 0)
                {
                    var sb = new StringBuilder();

                    foreach (var host in cert.Hosts)
                    {
                        sb.AppendWithSeparator(host, ", ");
                    }

                    this.Hosts = sb.ToString();
                }
                else
                {
                    this.Hosts = "";
                }
            }
예제 #3
0
        public void X509_SelfSigned()
        {
            // $todo(jeff.lill):
            //
            // TlsCertificate.ToX509Certificate() is having trouble parsing the
            // private keys generated for self-signed certificates.  It's seeing
            // only three fields when nine are required.  I dumped a private generated
            // key by TlsCertificate.CreateSelfSigned() with OpenSSL and compared
            // it to a (presumably self-signed client key) generated by Kubernetes
            // and they both look like they have the same number of parameters; so
            // this is a bit weird.
            //
            // We don't need this functionality right now, so I'm putting this
            // on the backlog.  I hope to be able to address this when we
            // upgrade TlsCertificate to use the improved .NET Core 3.0
            // crypto APIs.
            //
            //      https://github.com/nforgeio/neonKUBE/issues/438

            var tlsCert = TlsCertificate.CreateSelfSigned("foo.com", wildcard: Wildcard.RootAndSubdomains);

            tlsCert.Parse();
            Assert.NotNull(tlsCert.Thumbprint);
            Assert.NotEmpty(tlsCert.Thumbprint);
            Assert.Equal(2, tlsCert.Hosts.Count);
            Assert.Contains("foo.com", tlsCert.Hosts);
            Assert.Contains("*.foo.com", tlsCert.Hosts);

            var x509Cert = tlsCert.ToX509();

            Assert.NotNull(x509Cert);
            Assert.Equal(tlsCert.Thumbprint, x509Cert.Thumbprint, ignoreCase: true);
        }
예제 #4
0
        public void X509_NoPrivateKey()
        {
            // Verify that we can load a certificate generated by
            // Kubernetes without a private key.

            var certPem =
                @"-----BEGIN CERTIFICATE-----
MIIC8jCCAdqgAwIBAgIIdaABVSybOjowDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
AxMKa3ViZXJuZXRlczAeFw0xOTAyMTQyMzQ2MDVaFw0yMDAyMTQyMzQ2MDdaMDQx
FzAVBgNVBAoTDnN5c3RlbTptYXN0ZXJzMRkwFwYDVQQDExBrdWJlcm5ldGVzLWFk
bWluMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzjgtmL1scH9zwMkF
syXmhuhchLDgkZ+CuEIwmACE6AwlHZ6XfEXaRnLUuwmv87S2epj9rwJ1Sp/EchYV
Q6YjOODYfkJXSxCTiiNwBCzGrTDqKa8JBj1Zy9jkC+ZoKoErJFRKlw5ePtxsdUZE
QozQpIFvjACrTcmJtJiaGnY2C/f6Csrf4OXT2ulSYq+AS3bY4cfrcXGdsUTG5ATS
DblHvntjqLi8loEEj2kjDbK82chAkcgPadQ28/P6cqwKnxHAgWeleCSxxNvHE8+O
vJiqrxh7TBUQiFWWSbgAVED8JiN++E779P/MgQCeGYPD3OgrW97T1U7ciQWZ38XB
KqZFKwIDAQABoycwJTAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUH
AwIwDQYJKoZIhvcNAQELBQADggEBAL9sKWHOj1cia9i+QZDg4UIFY3STEyH/FJXn
NknAH5u0ioW4y+OIjFMQDqNjTiIjVm2qnEf1K+MYgsb88OObUo84edVNvu8Fq2Fl
o/K3+OwMXjYjzlLIh+pUQp7KXiyt2TdCh06l/ApjPgAnVa2uIB+/SGndDB8VNXhb
i2YHnN60aOPJkq6ow00Y0s6ncjYtmeiUs8B6wZljGcbOEopXAiS9sDIYz1p4a0AB
5vbzZ8mh4fM+zQ5owUopVvBF4Mv8yJEHgJ/zoxwGT/7kmcmZ/27ix0v7kFvrhKaU
NOrsafukaeMnu7sKsM5jeCimps8GlBJUM6bVrlbAgUuPl5B0oWg=
-----END CERTIFICATE-----
";
            var x509 = TlsCertificate.FromPemParts(certPem).ToX509();

            Assert.Equal("CN=kubernetes", x509.Issuer);
            Assert.Equal("43EE9CFF1FBFBCCEA1A73C7F941F7921E2B688EF", x509.Thumbprint);
            Assert.Equal(new DateTime(2019, 2, 14, 15, 46, 05), x509.NotBefore);
            Assert.Equal(new DateTime(2020, 2, 14, 15, 46, 07), x509.NotAfter);

            Assert.False(x509.HasPrivateKey);
        }
예제 #5
0
        public void CheckArgs()
        {
            //-----------------------------------------------------------------
            // Verify that the module detects unknown top-level arguments.

            var name        = "cert-" + Guid.NewGuid().ToString("D");
            var certificate = TlsCertificate.CreateSelfSigned("test.com");
            var certPem     = GetIndentedPem(certificate);
            var playbook    =
                $@"
- name: test
  hosts: localhost
  tasks:
    - name: create cert
      neon_certificate:
        name: {name}
        value: |
{certPem}
        state: present
        UNKNOWN: argument
";
            var results    = AnsiblePlayer.PlayNoGather(playbook);
            var taskResult = results.GetTaskResult("create cert");

            Assert.False(taskResult.Success);
        }
예제 #6
0
        public void ErrorNoValue()
        {
            // Verify that the module ensures that the [value] argument is present.

            var name        = "cert-" + Guid.NewGuid().ToString("D");
            var certificate = TlsCertificate.CreateSelfSigned("test.com");
            var certPem     = GetIndentedPem(certificate);
            var playbook    =
                $@"
- name: test
  hosts: localhost
  tasks:
    - name: create cert
      neon_certificate:
        name: {name}
        value: |
{certPem}
        state: absent
";
            var results = AnsiblePlayer.PlayNoGather(playbook);

            Assert.NotNull(results);

            var taskResult = results.GetTaskResult("create cert");

            Assert.NotNull(taskResult);
            Assert.Equal("create cert", taskResult.TaskName);
            Assert.True(taskResult.Success);
            Assert.False(taskResult.Changed);
            Assert.Empty(hive.ListCertificates().Where(c => c == name));
        }
예제 #7
0
        /// <summary>
        /// Adds or updates a hive certificate.
        /// </summary>
        /// <param name="name">The certificate name.</param>
        /// <param name="certificate">The certificate.</param>
        /// <exception cref="ArgumentException">Thrown if the certificate is not valid.</exception>
        /// <remarks>
        /// <note>
        /// The <paramref name="certificate"/> must be fully parsed (it's
        /// <see cref="TlsCertificate.Parse()"/> method must have been called at
        /// some point to load the <see cref="TlsCertificate.Hosts"/>,
        /// <see cref="TlsCertificate.ValidFrom"/> and <see cref="TlsCertificate.ValidUntil"/>
        /// properties).
        /// </note>
        /// </remarks>
        public void Set(string name, TlsCertificate certificate)
        {
            Covenant.Requires <ArgumentException>(HiveDefinition.IsValidName(name));
            Covenant.Requires <ArgumentNullException>(certificate != null);

            hive.Vault.Client.WriteJsonAsync(HiveHelper.GetVaultCertificateKey(name), certificate).Wait();
            hive.SignalTrafficManagerUpdate();
        }
예제 #8
0
        public void SelfSigned_Host()
        {
            var cert = TlsCertificate.CreateSelfSigned("foo.com");

            cert.Parse();
            Assert.NotNull(cert.Thumbprint);
            Assert.NotEmpty(cert.Thumbprint);
            Assert.Single(cert.Hosts);
            Assert.Contains("foo.com", cert.Hosts);
        }
예제 #9
0
        public void SelfSigned_SubdomainsOnly()
        {
            var cert = TlsCertificate.CreateSelfSigned("foo.com", wildcard: Wildcard.SubdomainsOnly);

            cert.Parse();
            Assert.NotNull(cert.Thumbprint);
            Assert.NotEmpty(cert.Thumbprint);
            Assert.Single(cert.Hosts);
            Assert.Contains("*.foo.com", cert.Hosts);
        }
예제 #10
0
        public void SelfSigned_OtherFields()
        {
            var cert = TlsCertificate.CreateSelfSigned("foo.com", wildcard: Wildcard.RootAndSubdomains);

            cert.Parse();
            Assert.NotNull(cert.Thumbprint);
            Assert.NotEmpty(cert.Thumbprint);
            Assert.Equal(2, cert.Hosts.Count);
            Assert.Contains("foo.com", cert.Hosts);
            Assert.Contains("*.foo.com", cert.Hosts);
        }
예제 #11
0
        public void Load()
        {
            var path1 = Path.GetTempFileName();
            var path2 = Path.GetTempFileName();

            try
            {
                // Separate files with CRLF line endings.

                File.WriteAllText(path1, TestCertPart);
                File.WriteAllText(path2, TestKeyPart);

                var cert = TlsCertificate.Load(path1, path2);

                Assert.Equal(TlsCertificate.NormalizePem(TestCertPart), cert.CertPem);
                Assert.Equal(TlsCertificate.NormalizePem(TestKeyPart), cert.KeyPem);

                // Separate files with LF line endings.

                File.WriteAllText(path1, TlsCertificate.NormalizePem(TestCertPart));
                File.WriteAllText(path2, TlsCertificate.NormalizePem(TestKeyPart));

                cert = TlsCertificate.Load(path1, path2);

                Assert.Equal(TlsCertificate.NormalizePem(TestCertPart), cert.CertPem);
                Assert.Equal(TlsCertificate.NormalizePem(TestKeyPart), cert.KeyPem);

                // Combined file with CRLF line endings.

                File.WriteAllText(path1, TestCertPart + TestKeyPart);

                cert = TlsCertificate.Load(path1);

                File.WriteAllText(path1, TlsCertificate.NormalizePem(TestCertPart));
                File.WriteAllText(path2, TlsCertificate.NormalizePem(TestKeyPart));

                // Combined file with LF line endings.

                File.WriteAllText(path1, TlsCertificate.NormalizePem(TestCertPart) + TlsCertificate.NormalizePem(TestKeyPart));

                cert = TlsCertificate.Load(path1);

                File.WriteAllText(path1, TlsCertificate.NormalizePem(TestCertPart));
                File.WriteAllText(path2, TlsCertificate.NormalizePem(TestKeyPart));
            }
            finally
            {
                File.Delete(path1);
                File.Delete(path2);
            }
        }
예제 #12
0
        public void Constructor()
        {
            var cert = new TlsCertificate(TestCertPart + TestKeyPart);

            Assert.Equal(TlsCertificate.NormalizePem(TestCertPart), cert.CertPem);
            Assert.Equal(TlsCertificate.NormalizePem(TestKeyPart), cert.KeyPem);

            cert = new TlsCertificate(TestCertPart, TestKeyPart);

            Assert.Equal(TlsCertificate.NormalizePem(TestCertPart), cert.CertPem);
            Assert.Equal(TlsCertificate.NormalizePem(TestKeyPart), cert.KeyPem);

            Assert.Equal(TlsCertificate.NormalizePem(TestCertPart) + TlsCertificate.NormalizePem(TestKeyPart), cert.CombinedPem);
        }
예제 #13
0
        /// <summary>
        /// Loads the certificate files (if any).
        /// </summary>
        /// <returns>
        /// Returns a <see cref="TlsCertificate"/> instance with the loaded public certificate
        /// and private key or <c>null</c> if no certificate is defined.
        /// </returns>
        public TlsCertificate Load()
        {
            if (IsSecured)
            {
                var certificate = TlsCertificate.Load(Path);

                certificate.Parse();

                return(certificate);
            }
            else
            {
                return(null);
            }
        }
예제 #14
0
        /// <summary>
        /// Returns the certificate and private key as text indented
        /// by 10 spaces so that it can be included within a playbook
        /// beneath the <b>values:</b> argument.  This is sensitive
        /// to how the playbooks are formatted in the tests below.
        /// </summary>
        /// <param name="certificate">The certificate.</param>
        /// <returns>The indented PEM text.</returns>
        private string GetIndentedPem(TlsCertificate certificate)
        {
            var indent = new string(' ', 10);
            var sb     = new StringBuilder();

            using (var reader = new StringReader(certificate.CombinedPem))
            {
                foreach (var line in reader.Lines())
                {
                    sb.AppendLine($"{indent}{line}");
                }
            }

            return(sb.ToString());
        }
예제 #15
0
 internal static void ValidateTlsSenderCertificateRestrictions(TlsCertificate certificate, MultiValuedProperty <SmtpX509IdentifierEx> ffoFDSmtpCerts, MultiValuedProperty <ServiceProviderSettings> serviceProviders, Task task)
 {
     if (certificate == null)
     {
         return;
     }
     if (!MultiValuedPropertyBase.IsNullOrEmpty(ffoFDSmtpCerts) && ffoFDSmtpCerts.Any((SmtpX509IdentifierEx ffoFDSmtpCert) => ffoFDSmtpCert.Matches(certificate)))
     {
         task.WriteError(new TlsSenderCertificateNameMatchesFfoFDSmtpCertificateException(certificate.ToString()), ErrorCategory.InvalidArgument, null);
     }
     if (!MultiValuedPropertyBase.IsNullOrEmpty(serviceProviders) && serviceProviders.Any((ServiceProviderSettings serviceProvider) => serviceProvider.Certificates != null && serviceProvider.Certificates.Any((TlsCertificate providerCertificate) => providerCertificate != null && providerCertificate.Equals(certificate))))
     {
         task.WriteError(new TlsSenderCertificateNameMatchesServiceProviderCertificateException(certificate.ToString()), ErrorCategory.InvalidArgument, null);
     }
 }
예제 #16
0
        public void ToX509Certificate2()
        {
            var cert = TlsCertificate.CreateSelfSigned("foo.com", wildcard: Wildcard.RootAndSubdomains);

            cert.Parse();
            Assert.NotNull(cert.Thumbprint);
            Assert.NotEmpty(cert.Thumbprint);
            Assert.Equal(2, cert.Hosts.Count);
            Assert.Contains("foo.com", cert.Hosts);
            Assert.Contains("*.foo.com", cert.Hosts);

            var x509Cert = cert.ToX509Certificate2();

            Assert.NotNull(x509Cert);
            Assert.Equal(cert.Thumbprint, x509Cert.Thumbprint, ignoreCase: true);
        }
예제 #17
0
		protected virtual void HandleCertificate (TlsCertificate message)
		{
			if (message.Certificates == null || message.Certificates.Count < 1) {
				if (Context.SettingsProvider.RequireClientCertificate)
					throw new TlsException (AlertDescription.CertificateUnknown);
				return;
			}

			var certificate = message.Certificates [0];
			var exchangeAlgorithm = PendingCrypto.Cipher.ExchangeAlgorithmType;
			if (!CertificateManager.VerifyClientCertificate (Context, certificate, exchangeAlgorithm))
				throw new TlsException (AlertDescription.UnsupportedCertificate);

			CertificateManager.CheckClientCertificate (Context, message.Certificates);

			PendingCrypto.ClientCertificates = message.Certificates;
		}
예제 #18
0
        public void Load()
        {
            using (var tempFolder = new TempFolder())
            {
                var path1 = Path.Combine(tempFolder.Path, "test1");
                var path2 = Path.Combine(tempFolder.Path, "test2");

                // Separate files with CRLF line endings.

                File.WriteAllText(path1, TestCertPart);
                File.WriteAllText(path2, TestKeyPart);

                var cert = TlsCertificate.Load(path1, path2);

                Assert.Equal(TlsCertificate.NormalizePem(TestCertPart), cert.CertPem);
                Assert.Equal(TlsCertificate.NormalizePem(TestKeyPart), cert.KeyPem);

                // Separate files with LF line endings.

                File.WriteAllText(path1, TlsCertificate.NormalizePem(TestCertPart));
                File.WriteAllText(path2, TlsCertificate.NormalizePem(TestKeyPart));

                cert = TlsCertificate.Load(path1, path2);

                Assert.Equal(TlsCertificate.NormalizePem(TestCertPart), cert.CertPem);
                Assert.Equal(TlsCertificate.NormalizePem(TestKeyPart), cert.KeyPem);

                // Combined file with CRLF line endings.

                File.WriteAllText(path1, TestCertPart + TestKeyPart);

                cert = TlsCertificate.Load(path1);

                File.WriteAllText(path1, TlsCertificate.NormalizePem(TestCertPart));
                File.WriteAllText(path2, TlsCertificate.NormalizePem(TestKeyPart));

                // Combined file with LF line endings.

                File.WriteAllText(path1, TlsCertificate.NormalizePem(TestCertPart) + TlsCertificate.NormalizePem(TestKeyPart));

                cert = TlsCertificate.Load(path1);

                File.WriteAllText(path1, TlsCertificate.NormalizePem(TestCertPart));
                File.WriteAllText(path2, TlsCertificate.NormalizePem(TestKeyPart));
            }
        }
예제 #19
0
        protected override MessageStatus HandleMessage(Message message)
        {
            switch (message.Type)
            {
            case HandshakeType.Certificate:
                if (!Session.AskedForCertificate)
                {
                    throw new TlsException(AlertDescription.UnexpectedMessage);
                }
                certificate = (TlsCertificate)message;
                HandleCertificate(certificate);
                return(MessageStatus.ContinueNeeded);

            case HandshakeType.ClientKeyExchange:
                if (Settings.RequireClientCertificate && certificate == null)
                {
                    throw new TlsException(AlertDescription.UnexpectedMessage, "Peer did not respond with a certificate.");
                }
                keyExchange = (TlsClientKeyExchange)message;
                HandleClientKeyExchange(keyExchange);
                return(MessageStatus.ContinueNeeded);

            case HandshakeType.ChanceCipherSpec:
                if (Settings.RequireClientCertificate && certificateVerify == null)
                {
                    throw new TlsException(AlertDescription.UnexpectedMessage, "Missing CertificateVerify message.");
                }
                cipherSpec = (TlsChangeCipherSpec)message;
                HandleChangeCipherSpec(cipherSpec);
                return(MessageStatus.ContinueNeeded);

            case HandshakeType.Finished:
                finished = (TlsFinished)message;
                HandleFinished(finished);
                return(MessageStatus.Finished);

            case HandshakeType.CertificateVerify:
                certificateVerify = (TlsCertificateVerify)message;
                HandleCertificateVerify(certificateVerify);
                return(MessageStatus.ContinueNeeded);

            default:
                throw new InvalidOperationException();
            }
        }
예제 #20
0
        protected virtual void HandleCertificate(TlsCertificate message)
        {
            if (message.Certificates == null || message.Certificates.Count < 1)
            {
                throw new TlsException(AlertDescription.CertificateUnknown);
            }

            var exchangeAlgorithm = PendingCrypto.Cipher.ExchangeAlgorithmType;

            if (!CertificateManager.VerifyServerCertificate(Context, message.Certificates [0], exchangeAlgorithm))
            {
                throw new TlsException(AlertDescription.UnsupportedCertificate);
            }

            CertificateManager.CheckRemoteCertificate(Config, message.Certificates);
            PendingCrypto.ServerCertificates        = message.Certificates;
            PendingCrypto.RemoteCertificateVerified = true;
        }
예제 #21
0
        protected override MessageStatus HandleMessage(Message message)
        {
            switch (message.Type)
            {
            case HandshakeType.ServerHello:
                hello = (TlsServerHello)message;
                HandleExtensions(hello);
                CheckSecureRenegotiation();
                HandleServerHello(hello);
                return(MessageStatus.ContinueNeeded);

            case HandshakeType.Certificate:
                certificate = (TlsCertificate)message;
                HandleCertificate(certificate);
                return(MessageStatus.ContinueNeeded);

            case HandshakeType.ServerKeyExchange:
                serverKeyExchange = (TlsServerKeyExchange)message;
                HandleServerKeyExchange(serverKeyExchange);
                return(MessageStatus.ContinueNeeded);

            case HandshakeType.CertificateRequest:
                if (!Config.HasCredentials)
                {
                    if (!askedForCertificate)
                    {
                        askedForCertificate = true;
                        return(MessageStatus.CredentialsNeeded);
                    }
                }

                certificateRequest = (TlsCertificateRequest)message;
                HandleCertificateRequest(certificateRequest);
                return(MessageStatus.ContinueNeeded);

            case HandshakeType.ServerHelloDone:
                done = (TlsServerHelloDone)message;
                HandleServerHelloDone(done);
                return(MessageStatus.GenerateOutput);

            default:
                throw new InvalidOperationException();
            }
        }
예제 #22
0
        public void SelfSigned_MultiHosts()
        {
            var cert = TlsCertificate.CreateSelfSigned(
                new List <string>()
            {
                "foo.com",
                "bar.com",
                "foobar.com",
                "*.root.com"
            });

            cert.Parse();
            Assert.NotNull(cert.Thumbprint);
            Assert.NotEmpty(cert.Thumbprint);
            Assert.Equal(4, cert.Hosts.Count);
            Assert.Contains("foo.com", cert.Hosts);
            Assert.Contains("bar.com", cert.Hosts);
            Assert.Contains("foobar.com", cert.Hosts);
            Assert.Contains("*.root.com", cert.Hosts);
        }
예제 #23
0
		protected override MessageStatus HandleMessage (Message message)
		{
			switch (message.Type) {
			case HandshakeType.ServerHello:
				hello = (TlsServerHello)message;
				HandleExtensions (hello);
				CheckSecureRenegotiation ();
				HandleServerHello (hello);
				return MessageStatus.ContinueNeeded;

			case HandshakeType.Certificate:
				certificate = (TlsCertificate)message;
				HandleCertificate (certificate);
				return MessageStatus.ContinueNeeded;

			case HandshakeType.ServerKeyExchange:
				serverKeyExchange = (TlsServerKeyExchange)message;
				HandleServerKeyExchange (serverKeyExchange);
				return MessageStatus.ContinueNeeded;

			case HandshakeType.CertificateRequest:
				if (!Config.HasCredentials) {
					if (!askedForCertificate) {
						askedForCertificate = true;
						return MessageStatus.CredentialsNeeded;
					}
				}

				certificateRequest = (TlsCertificateRequest)message;
				HandleCertificateRequest (certificateRequest);
				return MessageStatus.ContinueNeeded;

			case HandshakeType.ServerHelloDone:
				done = (TlsServerHelloDone)message;
				HandleServerHelloDone (done);
				return MessageStatus.GenerateOutput;

			default:
				throw new InvalidOperationException ();
			}
		}
예제 #24
0
        public void Verify()
        {
            // Verify basic fields.

            var cert = new TlsCertificate();

            cert.Hosts.Add("foo.com");
            cert.ValidFrom  = DateTime.UtcNow - TimeSpan.FromMinutes(5);
            cert.ValidUntil = DateTime.UtcNow + TimeSpan.FromMinutes(5);

            Assert.True(cert.IsValidDate());
            Assert.True(cert.IsValidDate(DateTime.UtcNow));
            Assert.True(cert.IsValidDate(cert.ValidFrom));
            Assert.True(cert.IsValidDate(cert.ValidUntil));

            Assert.True(cert.IsValidHost("foo.com"));
            Assert.False(cert.IsValidHost("bar.com"));

            // Verify wildcard certs.

            cert.Hosts.Add("*.foo.com");

            Assert.True(cert.IsValidHost("foo.com"));
            Assert.False(cert.IsValidHost("bar.com"));
            Assert.True(cert.IsValidHost("test.foo.com"));
            Assert.True(cert.IsValidHost("bar.foo.com"));
            Assert.False(cert.IsValidHost("foobar.test.foo.com"));

            // Verify SAN certs with different hosts.

            cert.Hosts.Clear();
            cert.Hosts.Add("foo.com");
            cert.Hosts.Add("bar.com");
            cert.Hosts.Add("foobar.com");

            Assert.True(cert.IsValidHost("foo.com"));
            Assert.True(cert.IsValidHost("bar.com"));
            Assert.True(cert.IsValidHost("foobar.com"));
            Assert.False(cert.IsValidHost("test.foo.com"));
        }
예제 #25
0
		protected override MessageStatus HandleMessage (Message message)
		{
			switch (message.Type) {
			case HandshakeType.Certificate:
				if (!Session.AskedForCertificate)
					throw new TlsException (AlertDescription.UnexpectedMessage);
				certificate = (TlsCertificate)message;
				HandleCertificate (certificate);
				return MessageStatus.ContinueNeeded;

			case HandshakeType.ClientKeyExchange:
				if (Settings.RequireClientCertificate && certificate == null)
					throw new TlsException (AlertDescription.UnexpectedMessage, "Peer did not respond with a certificate.");
				keyExchange = (TlsClientKeyExchange)message;
				HandleClientKeyExchange (keyExchange);
				return MessageStatus.ContinueNeeded;

			case HandshakeType.ChanceCipherSpec:
				if (Settings.RequireClientCertificate && certificateVerify == null)
					throw new TlsException (AlertDescription.UnexpectedMessage, "Missing CertificateVerify message.");
				cipherSpec = (TlsChangeCipherSpec)message;
				HandleChangeCipherSpec (cipherSpec);
				return MessageStatus.ContinueNeeded;

			case HandshakeType.Finished:
				finished = (TlsFinished)message;
				HandleFinished (finished);
				return MessageStatus.Finished;

			case HandshakeType.CertificateVerify:
				certificateVerify = (TlsCertificateVerify)message;
				HandleCertificateVerify (certificateVerify);
				return MessageStatus.ContinueNeeded;

			default:
				throw new InvalidOperationException ();
			}
		}
예제 #26
0
        protected virtual void HandleCertificate(TlsCertificate message)
        {
            if (message.Certificates == null || message.Certificates.Count < 1)
            {
                if (Context.SettingsProvider.RequireClientCertificate)
                {
                    throw new TlsException(AlertDescription.CertificateUnknown);
                }
                return;
            }

            var certificate       = message.Certificates [0];
            var exchangeAlgorithm = PendingCrypto.Cipher.ExchangeAlgorithmType;

            if (!CertificateManager.VerifyClientCertificate(Context, certificate, exchangeAlgorithm))
            {
                throw new TlsException(AlertDescription.UnsupportedCertificate);
            }

            CertificateManager.CheckClientCertificate(Context, message.Certificates);

            PendingCrypto.ClientCertificates = message.Certificates;
        }
예제 #27
0
        public Test_HiveTrafficManager(HiveFixture fixture)
        {
            if (!fixture.LoginAndInitialize())
            {
                fixture.Reset();
            }

            this.hiveFixture = fixture;
            this.hive        = fixture.Hive;

            // Generate a self-signed wildcard certificate we can reuse across tests if
            // we haven't already created one.

            if (certificate == null)
            {
                var hosts = new string[]
                {
                    testHostname,
                    $"*.{testHostname}"
                };

                certificate = TlsCertificate.CreateSelfSigned(hosts);
            }
        }
예제 #28
0
        public void X509_WithPrivateKey()
        {
            // $todo(jeff.lill):
            //
            // Enable this when we upgrade to .NET Standard 2.1
            //
            //      https://github.com/nforgeio/neonKUBE/issues/new

            // Verify that we can load a certificate generated by
            // Kubernetes without a private key.

            var certPem =
                @"-----BEGIN CERTIFICATE-----
MIIC8jCCAdqgAwIBAgIIdaABVSybOjowDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
AxMKa3ViZXJuZXRlczAeFw0xOTAyMTQyMzQ2MDVaFw0yMDAyMTQyMzQ2MDdaMDQx
FzAVBgNVBAoTDnN5c3RlbTptYXN0ZXJzMRkwFwYDVQQDExBrdWJlcm5ldGVzLWFk
bWluMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzjgtmL1scH9zwMkF
syXmhuhchLDgkZ+CuEIwmACE6AwlHZ6XfEXaRnLUuwmv87S2epj9rwJ1Sp/EchYV
Q6YjOODYfkJXSxCTiiNwBCzGrTDqKa8JBj1Zy9jkC+ZoKoErJFRKlw5ePtxsdUZE
QozQpIFvjACrTcmJtJiaGnY2C/f6Csrf4OXT2ulSYq+AS3bY4cfrcXGdsUTG5ATS
DblHvntjqLi8loEEj2kjDbK82chAkcgPadQ28/P6cqwKnxHAgWeleCSxxNvHE8+O
vJiqrxh7TBUQiFWWSbgAVED8JiN++E779P/MgQCeGYPD3OgrW97T1U7ciQWZ38XB
KqZFKwIDAQABoycwJTAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUH
AwIwDQYJKoZIhvcNAQELBQADggEBAL9sKWHOj1cia9i+QZDg4UIFY3STEyH/FJXn
NknAH5u0ioW4y+OIjFMQDqNjTiIjVm2qnEf1K+MYgsb88OObUo84edVNvu8Fq2Fl
o/K3+OwMXjYjzlLIh+pUQp7KXiyt2TdCh06l/ApjPgAnVa2uIB+/SGndDB8VNXhb
i2YHnN60aOPJkq6ow00Y0s6ncjYtmeiUs8B6wZljGcbOEopXAiS9sDIYz1p4a0AB
5vbzZ8mh4fM+zQ5owUopVvBF4Mv8yJEHgJ/zoxwGT/7kmcmZ/27ix0v7kFvrhKaU
NOrsafukaeMnu7sKsM5jeCimps8GlBJUM6bVrlbAgUuPl5B0oWg=
-----END CERTIFICATE-----
";
            var keyPem =
                @"-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAzjgtmL1scH9zwMkFsyXmhuhchLDgkZ+CuEIwmACE6AwlHZ6X
fEXaRnLUuwmv87S2epj9rwJ1Sp/EchYVQ6YjOODYfkJXSxCTiiNwBCzGrTDqKa8J
Bj1Zy9jkC+ZoKoErJFRKlw5ePtxsdUZEQozQpIFvjACrTcmJtJiaGnY2C/f6Csrf
4OXT2ulSYq+AS3bY4cfrcXGdsUTG5ATSDblHvntjqLi8loEEj2kjDbK82chAkcgP
adQ28/P6cqwKnxHAgWeleCSxxNvHE8+OvJiqrxh7TBUQiFWWSbgAVED8JiN++E77
9P/MgQCeGYPD3OgrW97T1U7ciQWZ38XBKqZFKwIDAQABAoIBAErAOmb/Yut0h7T+
KT7DIkkMuVyv8PdYZr374Dl5FrQ2ks2lyyuU9oZK4ana3RjuDKdsBakGrxWZzE++
iX64HlRjzJYX3iSroY+VQOmCgZIOBROPCypj2sT1ndRidKfTopvMoi0XXDpVFEt+
aQfmm0rGUHTjWTUdNPltx46IAxda6Yd378hXAUmTQSQ2FoVcmHuQn4Sr/0Qehf8W
ZeyEzhD1s6w2KhAWZKtadvmeBV/rBpaK/iH+B9bKH+7afSJU6otSuNidE+u6m8gY
6Q4JSHa7v+vR3hLBlbIMoBd21vXNCpoTpgt7+kbE1j224aZ/TAYww5E4nHC16KBZ
c/HE/+ECgYEA47c5WhRq8B+yh/Bqj2AzGxYqSBtPmzIpFktpyDbRkxrVBELOb/Es
52D0KLoAc0rs4XtcxU94ayCUGBQbW7ITiIb19wqGhS+9ATifPyjB/1N9E4beEutO
y2sbsuTqjDsnGx+s1XDZqbx6K/cvGGSAEbNxEXJ0GSOLUMUaTQFwX2cCgYEA59Vt
froASB3KAgOroXCC6c3CVIbYu2pP9Am1aGFUITOUZB54elsY1is7wKbVxgYqvmAn
kHuO8SVLuZTk9BmrtNnBxLh4aJNpb5L7BVGwwNLrSxEwgSmudzT3v31QrZgYXFsA
YF9QymqIHbUMN6HzFht3nITGs5sTKgtYWCazRZ0CgYBL5kJDeBK8vpPvI38hEtt1
58loB1JdVDbFq5UymrL36TWfGfVc8nIZHQPEn1qPEyYpccjWK0rjyhQSgoEr6wr/
spxBH0z/D45b3deWYatnwxgpbgaPH8c/ng+5bPuQihbav5AIBHlITf4asWUNKFJX
lAvX2OJBjstcvJWrnRMreQKBgGDJwSH0Q6PYE/tNTv1ifLVh+uzRM3DjTKgE2aDP
aZFG+H/oHMJwf+kCObsPrBY1gujiOgJfI2lX+cpr+D5U7VPeyb/4iASY7p7vTS+G
UHXgWO2JKqfyH+2SxpBCoEkpQ5pjP7/8az1mxpcofAZJ7bPgGcrVwCNB7flSrTp4
RcYdAoGAM713rdsR/0NsbN16e8hnaDphmtwAeG2PuRhIeG4VfXG/bjZ8sUEu8Jwb
v/diFRFasFCXhaZGcKluXqYGb4V3CRwDQRBTTbdmnIiUFuP1rY6o02vcZcW7wy5T
UUHWzDpotXDXwAwuIxh71LVCBnQRPryVc6Ynx3YF8HD8in600zw=
-----END RSA PRIVATE KEY-----
";
            var x509 = TlsCertificate.FromPemParts(certPem, keyPem).ToX509();

            Assert.Equal("CN=kubernetes", x509.Issuer);
            Assert.Equal("43EE9CFF1FBFBCCEA1A73C7F941F7921E2B688EF", x509.Thumbprint);
            Assert.Equal(new DateTime(2019, 2, 14, 15, 46, 05), x509.NotBefore);
            Assert.Equal(new DateTime(2020, 2, 14, 15, 46, 07), x509.NotAfter);
            Assert.True(x509.HasPrivateKey);
        }
예제 #29
0
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="name">The certificate name.</param>
 /// <param name="certificate">The certificate.</param>
 public CertInfo(string name, TlsCertificate certificate)
 {
     this.Name        = name;
     this.Certificate = certificate;
     this.Hash        = MD5.Create().ComputeHashBase64(NeonHelper.JsonSerialize(certificate, Formatting.None));
 }
예제 #30
0
		protected virtual void HandleCertificate (TlsCertificate message)
		{
			if (message.Certificates == null || message.Certificates.Count < 1)
				throw new TlsException (AlertDescription.CertificateUnknown);

			var exchangeAlgorithm = PendingCrypto.Cipher.ExchangeAlgorithmType;
			if (!CertificateManager.VerifyServerCertificate (Context, message.Certificates [0], exchangeAlgorithm))
				throw new TlsException (AlertDescription.UnsupportedCertificate);

			CertificateManager.CheckRemoteCertificate (Config, message.Certificates);
			PendingCrypto.ServerCertificates = message.Certificates;
			PendingCrypto.RemoteCertificateVerified = true;
		}
예제 #31
0
		protected virtual void HandleCertificate (TlsCertificate message)
		{
			if (CertificateManager.CheckClientCertificate (Context, message.Certificates))
				PendingCrypto.ClientCertificates = message.Certificates;
		}
예제 #32
0
		protected virtual void HandleCertificate (TlsCertificate message)
		{
			CertificateManager.CheckRemoteCertificate (Config, message.Certificates);
			PendingCrypto.ServerCertificates = message.Certificates;
			PendingCrypto.RemoteCertificateVerified = true;
		}
예제 #33
0
        /// <summary>
        /// Deploys the local Docker registry to the hive.
        /// </summary>
        /// <param name="hostname">The registry hostname.</param>
        /// <param name="username">The registry username.</param>
        /// <param name="password">The registry password.</param>
        /// <param name="secret">The registry secret.</param>
        /// <param name="certificate">The certificate used to secure the registry.</param>
        /// <param name="image">Optionally specifies the Docker image to be deployed (defaults to <b>nhive/neon-registry</b>).</param>
        /// <param name="progress">Optional action that will be called with a progress message.</param>
        /// <exception cref="HiveException">Thrown if a registry is already deployed or deployment failed.</exception>
        /// <exception cref="NotSupportedException">Thrown if the hive does not support local registries.</exception>
        public void CreateLocalRegistry(
            string hostname,
            string username,
            string password,
            string secret,
            TlsCertificate certificate,
            string image             = HiveConst.NeonProdRegistry + "/neon-registry",
            Action <string> progress = null)
        {
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(hostname));
            Covenant.Requires <ArgumentException>(HiveDefinition.DnsHostRegex.IsMatch(hostname));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(username));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(password));
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(secret));
            Covenant.Requires <ArgumentNullException>(certificate != null);

            if (!hive.Definition.HiveFS.Enabled)
            {
                throw new NotSupportedException("Cannot deploy a local Docker registry to the hive because the hive's Cepf file system is not enabled.");
            }

            if (HasLocalRegistry)
            {
                throw new HiveException("The [neon-registry] service is already deployed.");
            }

            progress?.Invoke($"Setting certificate.");
            hive.Certificate.Set("neon-registry", certificate);

            progress?.Invoke($"Updating Consul settings.");
            hive.Registry.SetLocalHostname(hostname);
            hive.Registry.SetLocalSecret(secret);

            progress?.Invoke($"Adding hive DNS host entry for [{hostname}] (60 seconds).");
            hive.Dns.Set(GetRegistryDnsEntry(hostname), waitUntilPropagated: true);

            progress?.Invoke($"Writing traffic manager rule.");
            hive.PublicTraffic.SetRule(GetRegistryTrafficManagerRule(hostname));

            progress?.Invoke($"Creating [neon-registry] service.");

            var manager = hive.GetReachableManager();

            var createResponse = manager.DockerCommand(RunOptions.None,
                                                       "docker service create",
                                                       "--name", "neon-registry",
                                                       "--mode", "global",
                                                       "--constraint", "node.role==manager",
                                                       "--env", $"USERNAME={username}",
                                                       "--env", $"PASSWORD={password}",
                                                       "--env", $"SECRET={secret}",
                                                       "--env", $"LOG_LEVEL=info",
                                                       "--env", $"READ_ONLY=false",
                                                       "--mount", "type=volume,src=neon-registry,volume-driver=neon,dst=/var/lib/neon-registry",
                                                       "--network", "neon-public",
                                                       "--restart-delay", "10s",
                                                       image);

            if (createResponse.ExitCode != 0)
            {
                throw new HiveException($"[neon-registry] service create failed: {createResponse.ErrorText}");
            }

            progress?.Invoke($"Service created.");
            progress?.Invoke($"Logging the hive into the [{hostname}] registry.");
            hive.Registry.Login(hostname, username, password);
        }
예제 #34
0
 public void NormalizePem()
 {
     Assert.Equal("abcde\n", TlsCertificate.NormalizePem("abcde"));
     Assert.Equal("abcde\n", TlsCertificate.NormalizePem("abcde\n"));
     Assert.Equal("abcde\n", TlsCertificate.NormalizePem("abcde\r\n"));
 }
예제 #35
0
        public void ParseCertUtil()
        {
            // Verify a [CertUtil] dump of a non-SAN certificate.

            // $todo(jeff.lill):
            //
            // I just manually edited a SAN certificate to remove the [Subject Alternative Name]
            // part.  I should redo this at somepoint to use a legitimate non-SAN cert dump.

            const string dump =
                @"X509 Certificate:
Version: 3
Serial Number: f7c33b6eed61a3695c1a61e77e7d349f
Signature Algorithm:
    Algorithm ObjectId: 1.2.840.113549.1.1.11 sha256RSA
    Algorithm Parameters:
    05 00
Issuer:
    CN=COMODO RSA Domain Validation Secure Server CA
    O=COMODO CA Limited
    L=Salford
    S=Greater Manchester
    C=GB
  Name Hash(sha1): 7ae13ee8a0c42a2cb428cbe7a605461940e2a1e9
  Name Hash(md5): 737301010f9ec759d54329bbb1553aa2

 NotBefore: 10/15/2016 4:00 PM
 NotAfter: 10/16/2017 3:59 PM

Subject:
    CN=*.neontest.com
    OU=PositiveSSL Wildcard
    OU=Domain Control Validated
  Name Hash(sha1): 21a9a243dec2654cc845de819db21f9828960a44
  Name Hash(md5): b663f495938586143c2e4ab879f89fae

Public Key Algorithm:
    Algorithm ObjectId: 1.2.840.113549.1.1.1 RSA
    Algorithm Parameters:
    05 00
Public Key Length: 2048 bits
Public Key: UnusedBits = 0
    0000  30 82 01 0a 02 82 01 01  00 e3 40 b1 8a 4f ce 50
    0010  71 5d 00 8f e7 b2 f0 52  22 2d 7b f4 97 01 e6 d5
    0020  cf 37 2f 62 a8 1b af 87  ca 26 d6 9a 83 f9 21 25
    0030  2d 4e f8 f7 85 7b 65 06  1b 17 de 53 e7 4f 77 b1
    0040  ac 71 d5 49 7e 9b f8 42  48 3a 83 af 3b 03 87 c8
    0050  c6 d1 2e f8 cb fa 5b d5  9f f3 68 b6 c4 87 82 9f
    0060  9c e3 b7 c3 7b 71 cb bc  f9 00 1b 0d 7e b2 ae 7a
    0070  50 8f cb 0c 01 e5 6b 72  a3 dc 08 a1 f3 53 88 84
    0080  92 5c 3b 88 28 20 de 39  22 ac 6e 53 99 cf 43 dd
    0090  20 ee 2e 1c 02 f4 42 13  84 75 03 17 0c bf 46 59
    00a0  44 70 ac fa 3e 2d d9 ca  47 6e a8 a2 13 72 5e d5
    00b0  fd 4b 60 99 27 01 35 a3  1a 70 9a 9d 48 bb 89 14
    00c0  0b ed a7 de 90 90 25 db  31 81 33 96 c5 7f 7a b6
    00d0  61 db 22 8e 93 5d a0 e9  02 a9 f3 05 72 3f 79 ed
    00e0  fa 69 c3 a9 e5 ef 5c 7f  db 36 aa df b6 76 16 fc
    00f0  b6 f2 0b b8 cb 21 8e e6  00 85 35 d8 7e 01 c1 fb
    0100  78 b5 ba 4e 91 4e dd 9f  4f 02 03 01 00 01
Certificate Extensions: 9
    2.5.29.35: Flags = 0, Length = 18
    Authority Key Identifier
        KeyID=90 af 6a 3a 94 5a 0b d8 90 ea 12 56 73 df 43 b4 3a 28 da e7

    2.5.29.14: Flags = 0, Length = 16
    Subject Key Identifier
        70 ac 36 1f 8e 34 33 4a 41 95 7b d5 ef 3d d8 98 6c d4 c8 d9

    2.5.29.15: Flags = 1(Critical), Length = 4
    Key Usage
        Digital Signature, Key Encipherment (a0)

    2.5.29.19: Flags = 1(Critical), Length = 2
    Basic Constraints
        Subject Type=End Entity
        Path Length Constraint=None

    2.5.29.37: Flags = 0, Length = 16
    Enhanced Key Usage
        Server Authentication (1.3.6.1.5.5.7.3.1)
        Client Authentication (1.3.6.1.5.5.7.3.2)

    2.5.29.32: Flags = 0, Length = 48
    Certificate Policies
        [1]Certificate Policy:
             Policy Identifier=1.3.6.1.4.1.6449.1.2.2.7
             [1,1]Policy Qualifier Info:
                  Policy Qualifier Id=CPS
                  Qualifier:
                       https://secure.comodo.com/CPS
        [2]Certificate Policy:
             Policy Identifier=2.23.140.1.2.1

    2.5.29.31: Flags = 0, Length = 4d
    CRL Distribution Points
        [1]CRL Distribution Point
             Distribution Point Name:
                  Full Name:
                       URL=http://crl.comodoca.com/COMODORSADomainValidationSecureServerCA.crl

    1.3.6.1.5.5.7.1.1: Flags = 0, Length = 79
    Authority Information Access
        [1]Authority Info Access
             Access Method=Certification Authority Issuer (1.3.6.1.5.5.7.48.2)
             Alternative Name:
                  URL=http://crt.comodoca.com/COMODORSADomainValidationSecureServerCA.crt
        [2]Authority Info Access
             Access Method=On-line Certificate Status Protocol (1.3.6.1.5.5.7.48.1)
             Alternative Name:
                  URL=http://ocsp.comodoca.com

Signature Algorithm:
    Algorithm ObjectId: 1.2.840.113549.1.1.11 sha256RSA
    Algorithm Parameters:
    05 00
Signature: UnusedBits=0
    0000  1b 85 72 a2 5e 38 c7 3c  be 48 59 c5 b5 9c 87 03
    0010  c6 4e 9c 52 b0 20 6a 14  4a 85 75 3f 59 af 57 92
    0020  14 1c 0c 69 c6 7a 42 3d  cd c8 a7 95 a9 b8 47 7e
    0030  ed f2 63 25 10 8b bf 0c  d8 0f 46 29 b5 78 9f 13
    0040  d9 0f 34 84 c9 83 c3 1a  97 07 57 dd 66 22 c5 19
    0050  77 4c ea 04 97 79 cd 3b  f2 02 44 f1 89 ee 6b 0a
    0060  e3 d5 df 86 c6 8a 3b 98  7d 21 20 2d 10 09 54 c3
    0070  9c a9 6b 94 70 5b 8a ed  97 54 b4 d9 74 22 f5 1e
    0080  78 d7 7e a8 cf ef 21 57  ee 3c d5 45 45 25 74 ac
    0090  56 c6 0f 56 b4 42 51 0a  86 e9 02 bb 93 1d 06 0c
    00a0  4b ad 4b 27 63 29 11 f0  d2 2f 97 4b b8 04 54 d2
    00b0  d6 dd 20 ee f2 a8 bf d0  20 f0 0f e0 45 92 60 ad
    00c0  50 82 cd 4a a2 63 bb f7  a5 83 68 ec 4a 1d 05 ae
    00d0  78 57 e0 15 f8 b0 bd 4f  67 14 25 9c d8 96 bf 2b
    00e0  7c b4 fc b6 3b 90 ca 77  3e 67 e4 9d 88 a6 08 d5
    00f0  52 bc 1e a0 91 6f 6b c4  45 2d e2 4b 66 35 a5 49
Non-root Certificate
Key Id Hash(rfc-sha1): 70 ac 36 1f 8e 34 33 4a 41 95 7b d5 ef 3d d8 98 6c d4 c8 d9
Key Id Hash(sha1): 6a cd 98 59 03 c9 4d 39 5d fa 68 2d e9 ed 2d f5 78 b7 49 2a
Key Id Hash(md5): 95be85460316d2476c909c824ec6108b
Key Id Hash(sha256): f5ad0d32302d410daad3f39ddbb2e1a52e79fcd8bff1c4d77e028830844bb363
Cert Hash(md5): 99 d4 81 bc 75 c7 fb 36 e3 ba ec e4 b5 a6 21 6d
Cert Hash(sha1): 83 db 76 4a 8f a2 cd c9 a0 12 d5 ff 6f 0d 46 1c 82 3c ac ac
Cert Hash(sha256): 87b1a786fe76f7498831ea654a567ebe293763a396d43ecf039ea7041ed6ee63
Signature Hash: 90c9102b85154435565bfa90928858d5b9eafd9a714d320efa0da0c9c5062ad1
CertUtil: -dump command completed successfully.
";

            var cert = new TlsCertificate();

            cert.ParseCertUtil(dump);

            Assert.Equal(new DateTime(2016, 10, 15, 16, 00, 00, DateTimeKind.Utc), cert.ValidFrom);
            Assert.Equal(new DateTime(2017, 10, 16, 15, 59, 00, DateTimeKind.Utc), cert.ValidUntil);
            Assert.Equal(new string[] { "*.neontest.com" }, cert.Hosts);
        }
예제 #36
0
        public void ParseOpenSSL_SAN()
        {
            // Verify an [OpenSSL] dump of a SAN certificate.

            const string dump =
                @"Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            f7:c3:3b:6e:ed:61:a3:69:5c:1a:61:e7:7e:7d:34:9f
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Domain Validation Secure Server CA
        Validity
            Not Before: Oct 16 00:00:00 2016 GMT
            Not After : Oct 16 23:59:59 2017 GMT
        Subject: OU=Domain Control Validated, OU=PositiveSSL Wildcard, CN=*.neontest.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:e3:40:b1:8a:4f:ce:50:71:5d:00:8f:e7:b2:f0:
                    52:22:2d:7b:f4:97:01:e6:d5:cf:37:2f:62:a8:1b:
                    af:87:ca:26:d6:9a:83:f9:21:25:2d:4e:f8:f7:85:
                    7b:65:06:1b:17:de:53:e7:4f:77:b1:ac:71:d5:49:
                    7e:9b:f8:42:48:3a:83:af:3b:03:87:c8:c6:d1:2e:
                    f8:cb:fa:5b:d5:9f:f3:68:b6:c4:87:82:9f:9c:e3:
                    b7:c3:7b:71:cb:bc:f9:00:1b:0d:7e:b2:ae:7a:50:
                    8f:cb:0c:01:e5:6b:72:a3:dc:08:a1:f3:53:88:84:
                    92:5c:3b:88:28:20:de:39:22:ac:6e:53:99:cf:43:
                    dd:20:ee:2e:1c:02:f4:42:13:84:75:03:17:0c:bf:
                    46:59:44:70:ac:fa:3e:2d:d9:ca:47:6e:a8:a2:13:
                    72:5e:d5:fd:4b:60:99:27:01:35:a3:1a:70:9a:9d:
                    48:bb:89:14:0b:ed:a7:de:90:90:25:db:31:81:33:
                    96:c5:7f:7a:b6:61:db:22:8e:93:5d:a0:e9:02:a9:
                    f3:05:72:3f:79:ed:fa:69:c3:a9:e5:ef:5c:7f:db:
                    36:aa:df:b6:76:16:fc:b6:f2:0b:b8:cb:21:8e:e6:
                    00:85:35:d8:7e:01:c1:fb:78:b5:ba:4e:91:4e:dd:
                    9f:4f
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Authority Key Identifier: 
                keyid:90:AF:6A:3A:94:5A:0B:D8:90:EA:12:56:73:DF:43:B4:3A:28:DA:E7

            X509v3 Subject Key Identifier: 
                70:AC:36:1F:8E:34:33:4A:41:95:7B:D5:EF:3D:D8:98:6C:D4:C8:D9
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Certificate Policies: 
                Policy: 1.3.6.1.4.1.6449.1.2.2.7
                  CPS: https://secure.comodo.com/CPS
                Policy: 2.23.140.1.2.1

            X509v3 CRL Distribution Points: 

                Full Name:
                  URI:http://crl.comodoca.com/COMODORSADomainValidationSecureServerCA.crl

            Authority Information Access: 
                CA Issuers - URI:http://crt.comodoca.com/COMODORSADomainValidationSecureServerCA.crt
                OCSP - URI:http://ocsp.comodoca.com

            X509v3 Subject Alternative Name: 
                DNS:*.neontest.com, DNS:neontest.com
    Signature Algorithm: sha256WithRSAEncryption
         49:a5:35:66:4b:e2:2d:45:c4:6b:6f:91:a0:1e:bc:52:d5:08:
         a6:88:9d:e4:67:3e:77:ca:90:3b:b6:fc:b4:7c:2b:bf:96:d8:
         9c:25:14:67:4f:bd:b0:f8:15:e0:57:78:ae:05:1d:4a:ec:68:
         83:a5:f7:bb:63:a2:4a:cd:82:50:ad:60:92:45:e0:0f:f0:20:
         d0:bf:a8:f2:ee:20:dd:d6:d2:54:04:b8:4b:97:2f:d2:f0:11:
         29:63:27:4b:ad:4b:0c:06:1d:93:bb:02:e9:86:0a:51:42:b4:
         56:0f:c6:56:ac:74:25:45:45:d5:3c:ee:57:21:ef:cf:a8:7e:
         d7:78:1e:f5:22:74:d9:b4:54:97:ed:8a:5b:70:94:6b:a9:9c:
         c3:54:09:10:2d:20:21:7d:98:3b:8a:c6:86:df:d5:e3:0a:6b:
         ee:89:f1:44:02:f2:3b:cd:79:97:04:ea:4c:77:19:c5:22:66:
         dd:57:07:97:1a:c3:83:c9:84:34:0f:d9:13:9f:78:b5:29:46:
         0f:d8:0c:bf:8b:10:25:63:f2:ed:7e:47:b8:a9:95:a7:c8:cd:
         3d:42:7a:c6:69:0c:1c:14:92:57:af:59:3f:75:85:4a:14:6a:
         20:b0:52:9c:4e:c6:03:87:9c:b5:c5:59:48:be:3c:c7:38:5e:
         a2:72:85:1b
-----BEGIN CERTIFICATE-----
MIIFUjCCBDqgAwIBAgIRAPfDO27tYaNpXBph5359NJ8wDQYJKoZIhvcNAQELBQAw
gZAxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTYwNAYD
VQQDEy1DT01PRE8gUlNBIERvbWFpbiBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIg
Q0EwHhcNMTYxMDE2MDAwMDAwWhcNMTcxMDE2MjM1OTU5WjBbMSEwHwYDVQQLExhE
b21haW4gQ29udHJvbCBWYWxpZGF0ZWQxHTAbBgNVBAsTFFBvc2l0aXZlU1NMIFdp
bGRjYXJkMRcwFQYDVQQDDA4qLm5lb250ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAONAsYpPzlBxXQCP57LwUiIte/SXAebVzzcvYqgbr4fK
Jtaag/khJS1O+PeFe2UGGxfeU+dPd7GscdVJfpv4Qkg6g687A4fIxtEu+Mv6W9Wf
82i2xIeCn5zjt8N7ccu8+QAbDX6yrnpQj8sMAeVrcqPcCKHzU4iEklw7iCgg3jki
rG5Tmc9D3SDuLhwC9EIThHUDFwy/RllEcKz6Pi3ZykduqKITcl7V/UtgmScBNaMa
cJqdSLuJFAvtp96QkCXbMYEzlsV/erZh2yKOk12g6QKp8wVyP3nt+mnDqeXvXH/b
NqrftnYW/LbyC7jLIY7mAIU12H4Bwft4tbpOkU7dn08CAwEAAaOCAdkwggHVMB8G
A1UdIwQYMBaAFJCvajqUWgvYkOoSVnPfQ7Q6KNrnMB0GA1UdDgQWBBRwrDYfjjQz
SkGVe9XvPdiYbNTI2TAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNV
HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTwYDVR0gBEgwRjA6BgsrBgEEAbIx
AQICBzArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQ
UzAIBgZngQwBAgEwVAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL2NybC5jb21vZG9j
YS5jb20vQ09NT0RPUlNBRG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNy
bDCBhQYIKwYBBQUHAQEEeTB3ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LmNvbW9k
b2NhLmNvbS9DT01PRE9SU0FEb21haW5WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0Eu
Y3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wJwYDVR0R
BCAwHoIOKi5uZW9udGVzdC5jb22CDG5lb250ZXN0LmNvbTANBgkqhkiG9w0BAQsF
AAOCAQEASaU1ZkviLUXEa2+RoB68UtUIpoid5Gc+d8qQO7b8tHwrv5bYnCUUZ0+9
sPgV4Fd4rgUdSuxog6X3u2OiSs2CUK1gkkXgD/Ag0L+o8u4g3dbSVAS4S5cv0vAR
KWMnS61LDAYdk7sC6YYKUUK0Vg/GVqx0JUVF1TzuVyHvz6h+13ge9SJ02bRUl+2K
W3CUa6mcw1QJEC0gIX2YO4rGht/V4wpr7onxRALyO815lwTqTHcZxSJm3VcHlxrD
g8mENA/ZE594tSlGD9gMv4sQJWPy7X5HuKmVp8jNPUJ6xmkMHBSSV69ZP3WFShRq
ILBSnE7GA4ectcVZSL48xzheonKFGw==
-----END CERTIFICATE-----
";

            var cert = new TlsCertificate();

            cert.ParseOpenSsl(dump);

            Assert.Equal(new DateTime(2016, 10, 16, 00, 00, 00, DateTimeKind.Utc), cert.ValidFrom);
            Assert.Equal(new DateTime(2017, 10, 16, 23, 59, 59, DateTimeKind.Utc), cert.ValidUntil);
            Assert.Equal(new string[] { "*.neontest.com", "neontest.com" }, cert.Hosts);
        }