protected async Task OneTimeSetUp() { // start GDS first clean, then restart server // to ensure the application cert is not 'fresh' _server = await TestUtils.StartGDS(true); _server.StopServer(); await Task.Delay(1000); _server = await TestUtils.StartGDS(false); _serverCapabilities = new ServerCapabilities(); _randomSource = new RandomSource(randomStart); _dataGenerator = new DataGenerator(_randomSource); // load clients _gdsClient = new GlobalDiscoveryTestClient(true); await _gdsClient.LoadClientConfiguration(_server.BasePort); _pushClient = new ServerConfigurationPushTestClient(true); await _pushClient.LoadClientConfiguration(_server.BasePort); // connect once await _gdsClient.GDSClient.Connect(_gdsClient.GDSClient.EndpointUrl); await _pushClient.PushClient.Connect(_pushClient.PushClient.EndpointUrl); ConnectGDSClient(true); RegisterPushServerApplication(_pushClient.PushClient.EndpointUrl); _selfSignedServerCert = new X509Certificate2(_pushClient.PushClient.Session.ConfiguredEndpoint.Description.ServerCertificate); _domainNames = X509Utils.GetDomainsFromCertficate(_selfSignedServerCert).ToArray(); await CreateCATestCerts(_pushClient.TempStorePath); }
/// <summary> /// Handles a domain validation error. /// </summary> /// <param name="caption">The caller's text is used as the caption of the <see cref="MessageBox"/> shown to provide details about the error.</param> public static bool HandleDomainCheckError(string caption, ServiceResult serviceResult, X509Certificate2 certificate = null) { StringBuilder buffer = new StringBuilder(); buffer.AppendFormat("Certificate could not be validated!\r\n"); buffer.AppendFormat("Validation error(s): \r\n"); buffer.AppendFormat("\t{0}\r\n", serviceResult.StatusCode); if (certificate != null) { buffer.AppendFormat("\r\nSubject: {0}\r\n", certificate.Subject); buffer.AppendFormat("Issuer: {0}\r\n", X509Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer) ? "Self-signed" : certificate.Issuer); buffer.AppendFormat("Valid From: {0}\r\n", certificate.NotBefore); buffer.AppendFormat("Valid To: {0}\r\n", certificate.NotAfter); buffer.AppendFormat("Thumbprint: {0}\r\n\r\n", certificate.Thumbprint); var domains = X509Utils.GetDomainsFromCertficate(certificate); if (domains.Count > 0) { bool comma = false; buffer.AppendFormat("Domains:"); foreach (var domain in domains) { if (comma) { buffer.Append(","); } buffer.AppendFormat(" {0}", domain); comma = true; } buffer.AppendLine(); } } buffer.Append("This certificate validation error indicates that the hostname used to connect"); buffer.Append(" is not listed as a valid hostname in the server certificate."); buffer.Append("\r\n\r\nIgnore error and disable the hostname verification?"); if (MessageBox.Show(buffer.ToString(), caption, MessageBoxButtons.YesNo) == DialogResult.Yes) { return(true); } return(false); }
private ServiceResult CreateSigningRequest( ISystemContext context, MethodState method, NodeId objectId, NodeId certificateGroupId, NodeId certificateTypeId, string subjectName, bool regeneratePrivateKey, byte[] nonce, ref byte[] certificateRequest) { HasApplicationSecureAdminAccess(context); ServerCertificateGroup certificateGroup = VerifyGroupAndTypeId(certificateGroupId, certificateTypeId); if (!String.IsNullOrEmpty(subjectName)) { throw new ArgumentNullException(nameof(subjectName)); } // TODO: implement regeneratePrivateKey // TODO: use nonce for generating the private key var passwordProvider = m_configuration.SecurityConfiguration.CertificatePasswordProvider; X509Certificate2 certWithPrivateKey = certificateGroup.ApplicationCertificate.LoadPrivateKeyEx(passwordProvider).Result; Utils.LogCertificate(Utils.TraceMasks.Security, "Create signing request: ", certWithPrivateKey); certificateRequest = CertificateFactory.CreateSigningRequest(certWithPrivateKey, X509Utils.GetDomainsFromCertficate(certWithPrivateKey)); return(ServiceResult.Good); }
/// <summary> /// Checks that the domains in the server addresses match the domains in the certificates. /// </summary> private static async Task <bool> CheckDomainsInCertificate( ApplicationConfiguration configuration, X509Certificate2 certificate, bool silent) { Utils.Trace(Utils.TraceMasks.Information, "Checking domains in certificate. {0}", certificate.Subject); bool valid = true; IList <string> serverDomainNames = configuration.GetServerDomainNames(); IList <string> certificateDomainNames = X509Utils.GetDomainsFromCertficate(certificate); // get computer name. string computerName = Utils.GetHostName(); // get IP addresses. IPAddress[] addresses = null; for (int ii = 0; ii < serverDomainNames.Count; ii++) { if (Utils.FindStringIgnoreCase(certificateDomainNames, serverDomainNames[ii])) { continue; } if (String.Compare(serverDomainNames[ii], "localhost", StringComparison.OrdinalIgnoreCase) == 0) { if (Utils.FindStringIgnoreCase(certificateDomainNames, computerName)) { continue; } // check for aliases. bool found = false; // get IP addresses only if necessary. if (addresses == null) { addresses = await Utils.GetHostAddressesAsync(computerName); } // check for ip addresses. for (int jj = 0; jj < addresses.Length; jj++) { if (Utils.FindStringIgnoreCase(certificateDomainNames, addresses[jj].ToString())) { found = true; break; } } if (found) { continue; } } string message = Utils.Format( "The server is configured to use domain '{0}' which does not appear in the certificate. Use certificate?", serverDomainNames[ii]); valid = false; if (await ApproveMessage(message, silent)) { valid = true; continue; } break; } return(valid); }
public static void VerifySignedApplicationCert(ApplicationTestData testApp, byte[] rawSignedCert, byte[][] rawIssuerCerts) { X509Certificate2 signedCert = new X509Certificate2(rawSignedCert); X509Certificate2 issuerCert = new X509Certificate2(rawIssuerCerts[0]); TestContext.Out.WriteLine($"Signed cert: {signedCert}"); TestContext.Out.WriteLine($"Issuer cert: {issuerCert}"); Assert.NotNull(signedCert); Assert.False(signedCert.HasPrivateKey); Assert.True(X509Utils.CompareDistinguishedName(testApp.Subject, signedCert.Subject)); Assert.False(X509Utils.CompareDistinguishedName(signedCert.Issuer, signedCert.Subject)); Assert.True(X509Utils.CompareDistinguishedName(signedCert.Issuer, issuerCert.Subject)); TestContext.Out.WriteLine($"Signed Subject: {signedCert.Subject}"); TestContext.Out.WriteLine($"Issuer Subject: {issuerCert.Subject}"); // test basic constraints X509BasicConstraintsExtension constraints = X509Extensions.FindExtension <X509BasicConstraintsExtension>(signedCert); Assert.NotNull(constraints); TestContext.Out.WriteLine($"Constraints: {constraints.Format(true)}"); Assert.True(constraints.Critical); Assert.False(constraints.CertificateAuthority); Assert.False(constraints.HasPathLengthConstraint); // key usage X509KeyUsageExtension keyUsage = X509Extensions.FindExtension <X509KeyUsageExtension>(signedCert); Assert.NotNull(keyUsage); TestContext.Out.WriteLine($"KeyUsage: {keyUsage.Format(true)}"); Assert.True(keyUsage.Critical); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.CrlSign) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DataEncipherment) == X509KeyUsageFlags.DataEncipherment); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DecipherOnly) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) == X509KeyUsageFlags.DigitalSignature); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.EncipherOnly) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyAgreement) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyCertSign) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyEncipherment) == X509KeyUsageFlags.KeyEncipherment); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == X509KeyUsageFlags.NonRepudiation); // enhanced key usage X509EnhancedKeyUsageExtension enhancedKeyUsage = X509Extensions.FindExtension <X509EnhancedKeyUsageExtension>(signedCert); Assert.NotNull(enhancedKeyUsage); TestContext.Out.WriteLine($"Enhanced Key Usage: {enhancedKeyUsage.Format(true)}"); Assert.True(enhancedKeyUsage.Critical); // test for authority key X509AuthorityKeyIdentifierExtension authority = X509Extensions.FindExtension <X509AuthorityKeyIdentifierExtension>(signedCert); Assert.NotNull(authority); TestContext.Out.WriteLine($"Authority Key Identifier: {authority.Format(true)}"); Assert.NotNull(authority.SerialNumber); Assert.NotNull(authority.KeyIdentifier); Assert.NotNull(authority.Issuer); Assert.AreEqual(issuerCert.SubjectName.RawData, authority.Issuer.RawData); Assert.AreEqual(issuerCert.SubjectName.RawData, authority.Issuer.RawData); // verify authority key in signed cert X509SubjectKeyIdentifierExtension subjectKeyId = X509Extensions.FindExtension <X509SubjectKeyIdentifierExtension>(issuerCert); TestContext.Out.WriteLine($"Issuer Subject Key Identifier: {subjectKeyId}"); Assert.AreEqual(subjectKeyId.SubjectKeyIdentifier, authority.KeyIdentifier); Assert.AreEqual(issuerCert.SerialNumber, authority.SerialNumber); X509SubjectAltNameExtension subjectAlternateName = X509Extensions.FindExtension <X509SubjectAltNameExtension>(signedCert); Assert.NotNull(subjectAlternateName); TestContext.Out.WriteLine($"Issuer Subject Alternate Name: {subjectAlternateName}"); Assert.False(subjectAlternateName.Critical); var domainNames = X509Utils.GetDomainsFromCertficate(signedCert); foreach (var domainName in testApp.DomainNames) { Assert.True(domainNames.Contains(domainName, StringComparer.OrdinalIgnoreCase)); } Assert.True(subjectAlternateName.Uris.Count == 1); var applicationUri = X509Utils.GetApplicationUriFromCertificate(signedCert); Assert.True(testApp.ApplicationRecord.ApplicationUri == applicationUri); }
public static void VerifyApplicationCert(ApplicationTestData testApp, X509Certificate2 cert, X509Certificate2 issuerCert = null) { bool signedCert = issuerCert != null; if (issuerCert == null) { issuerCert = cert; } TestContext.Out.WriteLine($"{nameof(VerifyApplicationCert)}:"); Assert.NotNull(cert); TestContext.Out.WriteLine(cert); Assert.False(cert.HasPrivateKey); Assert.True(X509Utils.CompareDistinguishedName(testApp.Subject, cert.Subject)); Assert.True(X509Utils.CompareDistinguishedName(issuerCert.Subject, cert.Issuer)); // test basic constraints X509BasicConstraintsExtension constraints = X509Extensions.FindExtension <X509BasicConstraintsExtension>(cert); Assert.NotNull(constraints); TestContext.Out.WriteLine(constraints.Format(true)); Assert.True(constraints.Critical); if (signedCert) { Assert.False(constraints.CertificateAuthority); Assert.False(constraints.HasPathLengthConstraint); } else { Assert.True(constraints.CertificateAuthority); Assert.True(constraints.HasPathLengthConstraint); Assert.AreEqual(0, constraints.PathLengthConstraint); } // key usage X509KeyUsageExtension keyUsage = X509Extensions.FindExtension <X509KeyUsageExtension>(cert); Assert.NotNull(keyUsage); TestContext.Out.WriteLine(keyUsage.Format(true)); Assert.True(keyUsage.Critical); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.CrlSign) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DataEncipherment) == X509KeyUsageFlags.DataEncipherment); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DecipherOnly) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) == X509KeyUsageFlags.DigitalSignature); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.EncipherOnly) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyAgreement) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyCertSign) == (signedCert ? 0 : X509KeyUsageFlags.KeyCertSign)); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyEncipherment) == X509KeyUsageFlags.KeyEncipherment); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == X509KeyUsageFlags.NonRepudiation); // enhanced key usage X509EnhancedKeyUsageExtension enhancedKeyUsage = X509Extensions.FindExtension <X509EnhancedKeyUsageExtension>(cert); Assert.NotNull(enhancedKeyUsage); TestContext.Out.WriteLine(enhancedKeyUsage.Format(true)); Assert.True(enhancedKeyUsage.Critical); // test for authority key X509AuthorityKeyIdentifierExtension authority = X509Extensions.FindExtension <X509AuthorityKeyIdentifierExtension>(cert); Assert.NotNull(authority); TestContext.Out.WriteLine(authority.Format(true)); Assert.NotNull(authority.SerialNumber); Assert.NotNull(authority.KeyIdentifier); Assert.NotNull(authority.Issuer); if (issuerCert == null) { Assert.AreEqual(cert.SubjectName.RawData, authority.Issuer.RawData); Assert.True(X509Utils.CompareDistinguishedName(cert.SubjectName.Name, authority.Issuer.Name), $"{cert.SubjectName.Name} != {authority.Issuer.Name}"); } else { Assert.AreEqual(issuerCert.SubjectName.RawData, authority.Issuer.RawData); Assert.True(X509Utils.CompareDistinguishedName(issuerCert.SubjectName.Name, authority.Issuer.Name), $"{cert.SubjectName.Name} != {authority.Issuer.Name}"); } // verify authority key in signed cert X509SubjectKeyIdentifierExtension subjectKeyId = X509Extensions.FindExtension <X509SubjectKeyIdentifierExtension>(cert); TestContext.Out.WriteLine(subjectKeyId.Format(true)); if (signedCert) { var caCertSubjectKeyId = X509Extensions.FindExtension <X509SubjectKeyIdentifierExtension>(issuerCert); Assert.NotNull(caCertSubjectKeyId); Assert.AreEqual(caCertSubjectKeyId.SubjectKeyIdentifier, authority.KeyIdentifier); } else { Assert.AreEqual(subjectKeyId.SubjectKeyIdentifier, authority.KeyIdentifier); } Assert.AreEqual(issuerCert.GetSerialNumber(), authority.GetSerialNumber()); Assert.AreEqual(issuerCert.SerialNumber, authority.SerialNumber); X509SubjectAltNameExtension subjectAlternateName = X509Extensions.FindExtension <X509SubjectAltNameExtension>(cert); Assert.NotNull(subjectAlternateName); TestContext.Out.WriteLine(subjectAlternateName.Format(true)); Assert.False(subjectAlternateName.Critical); var domainNames = X509Utils.GetDomainsFromCertficate(cert); foreach (var domainName in testApp.DomainNames) { Assert.True(domainNames.Contains(domainName, StringComparer.OrdinalIgnoreCase)); } Assert.True(subjectAlternateName.Uris.Count == 1); var applicationUri = X509Utils.GetApplicationUriFromCertificate(cert); TestContext.Out.WriteLine("ApplicationUri: "); TestContext.Out.WriteLine(applicationUri); Assert.AreEqual(testApp.ApplicationUri, applicationUri); }
/// <summary> /// Displays the dialog. /// </summary> public async Task<bool> ShowDialog(CertificateIdentifier certificate) { m_certificate = certificate; CertificateStoreCTRL.StoreType = null; CertificateStoreCTRL.StorePath = null; CertificateStoreCTRL.ReadOnly = true; ApplicationNameTB.Text = null; ApplicationUriTB.Text = null; OrganizationTB.Text = null; DomainsTB.Text = System.Net.Dns.GetHostName(); SubjectNameTB.Text = null; IssuerNameTB.Text = null; ValidFromTB.Text = null; ValidToTB.Text = null; ThumbprintTB.Text = null; if (certificate != null) { CertificateStoreCTRL.StoreType = certificate.StoreType; CertificateStoreCTRL.StorePath = certificate.StorePath; SubjectNameTB.Text = certificate.SubjectName; ThumbprintTB.Text = certificate.Thumbprint; X509Certificate2 data = await certificate.Find(); if (data != null) { // fill in subject name. StringBuilder buffer = new StringBuilder(); foreach (string element in X509Utils.ParseDistinguishedName(data.Subject)) { if (element.StartsWith("CN=")) { ApplicationNameTB.Text = element.Substring(3); } if (element.StartsWith("O=")) { OrganizationTB.Text = element.Substring(2); } if (buffer.Length > 0) { buffer.Append('/'); } buffer.Append(element); } if (buffer.Length > 0) { SubjectNameTB.Text = buffer.ToString(); } // fill in issuer name. buffer = new StringBuilder(); foreach (string element in X509Utils.ParseDistinguishedName(data.Issuer)) { if (buffer.Length > 0) { buffer.Append('/'); } buffer.Append(element); } if (buffer.Length > 0) { IssuerNameTB.Text = buffer.ToString(); } // fill in application uri. string applicationUri = X509Utils.GetApplicationUriFromCertificate(data); if (!String.IsNullOrEmpty(applicationUri)) { ApplicationUriTB.Text = applicationUri; } // fill in domains. buffer = new StringBuilder(); foreach (string domain in X509Utils.GetDomainsFromCertficate(data)) { if (buffer.Length > 0) { buffer.Append(", "); } buffer.Append(domain); } if (buffer.Length > 0) { DomainsTB.Text = buffer.ToString(); } ValidFromTB.Text = data.NotBefore.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"); ValidToTB.Text = data.NotAfter.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"); ThumbprintTB.Text = data.Thumbprint; } } if (ShowDialog() != DialogResult.OK) { return false; } return true; }
/// <summary> /// Checks if the certicate meets the filter criteria. /// </summary> /// <param name="certificate">The certificate.</param> /// <returns>True if it meets the criteria.</returns> public bool Match(X509Certificate2 certificate) { if (certificate == null) { return(false); } try { if (!String.IsNullOrEmpty(m_subjectName)) { if (!Utils.Match(certificate.Subject, "CN*" + m_subjectName + ",*", false)) { return(false); } } if (!String.IsNullOrEmpty(m_issuerName)) { if (!Utils.Match(certificate.Issuer, "CN*" + m_issuerName + ",*", false)) { return(false); } } if (!String.IsNullOrEmpty(m_domain)) { IList <string> domains = X509Utils.GetDomainsFromCertficate(certificate); bool found = false; for (int ii = 0; ii < domains.Count; ii++) { if (Utils.Match(domains[ii], m_domain, false)) { found = true; break; } } if (!found) { return(false); } } // check for private key. if (m_privateKey) { if (!certificate.HasPrivateKey) { return(false); } } if (m_certificateTypes != null) { // determine if a CA certificate. bool isCA = X509Utils.IsCertificateAuthority(certificate); // determine if self-signed. bool isSelfSigned = X509Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer); // match if one or more of the criteria match. bool found = false; for (int ii = 0; ii < m_certificateTypes.Length; ii++) { switch (m_certificateTypes[ii]) { case CertificateListFilterType.Application: { if (!isCA) { found = true; } break; } case CertificateListFilterType.CA: { if (isCA) { found = true; } break; } case CertificateListFilterType.SelfSigned: { if (isSelfSigned) { found = true; } break; } case CertificateListFilterType.Issued: { if (!isSelfSigned) { found = true; } break; } } } if (!found) { return(false); } } return(true); } catch (Exception) { return(false); } }
/// <summary> /// Updates an item in the view. /// </summary> protected override void UpdateItem(ListViewItem listItem, object item) { X509Certificate2 certificate = item as X509Certificate2; if (certificate == null) { base.UpdateItem(listItem, item); return; } listItem.SubItems[0].Text = null; listItem.SubItems[1].Text = null; listItem.SubItems[2].Text = null; listItem.SubItems[3].Text = null; listItem.SubItems[4].Text = null; listItem.SubItems[5].Text = null; if (certificate != null) { List <string> fields = X509Utils.ParseDistinguishedName(certificate.Subject); for (int ii = 0; ii < fields.Count; ii++) { if (fields[ii].StartsWith("CN=")) { listItem.SubItems[0].Text = fields[ii].Substring(3); } if (fields[ii].StartsWith("DC=")) { listItem.SubItems[1].Text = fields[ii].Substring(3); } } if (String.IsNullOrEmpty(listItem.SubItems[0].Text)) { listItem.SubItems[0].Text = String.Format("{0}", certificate.Subject); } // determine certificate type. foreach (X509Extension extension in certificate.Extensions) { X509BasicConstraintsExtension basicContraints = extension as X509BasicConstraintsExtension; if (basicContraints != null) { if (basicContraints.CertificateAuthority) { listItem.SubItems[1].Text = "CA"; } else { listItem.SubItems[1].Text = "End-Entity"; } break; } } // check if a private key is available. if (certificate.HasPrivateKey) { listItem.SubItems[2].Text = "Yes"; } else { listItem.SubItems[2].Text = "No"; } // look up domains. IList <string> domains = X509Utils.GetDomainsFromCertficate(certificate); StringBuilder buffer = new StringBuilder(); for (int ii = 0; ii < domains.Count; ii++) { if (buffer.Length > 0) { buffer.Append(";"); } buffer.Append(domains[ii]); } listItem.SubItems[3].Text = buffer.ToString(); listItem.SubItems[4].Text = X509Utils.GetApplicationUriFromCertificate(certificate); listItem.SubItems[5].Text = String.Format("{0:yyyy-MM-dd}", certificate.NotAfter); } listItem.ImageKey = GuiUtils.Icons.Certificate; listItem.Tag = item; }
public List <string> GetDomainNames(X509Certificate2 certificate) { List <string> domainNames = new List <string>(); if (!String.IsNullOrEmpty(Domains)) { var domains = Domains.Split(','); List <string> trimmedDomains = new List <string>(); foreach (var domain in domains) { var d = domain.Trim(); if (d.Length > 0) { trimmedDomains.Add(d); } } if (trimmedDomains.Count > 0) { return(trimmedDomains); } } if (DiscoveryUrl != null) { foreach (var discoveryUrl in DiscoveryUrl) { if (Uri.IsWellFormedUriString(discoveryUrl, UriKind.Absolute)) { string name = new Uri(discoveryUrl).DnsSafeHost; if (name == "localhost") { name = Utils.GetHostName(); } bool found = false; //domainNames.Any(n => String.Compare(n, name, StringComparison.OrdinalIgnoreCase) == 0); foreach (var domainName in domainNames) { if (String.Compare(domainName, name, StringComparison.OrdinalIgnoreCase) == 0) { found = true; break; } } if (!found) { domainNames.Add(name); } } } } if (domainNames != null && domainNames.Count > 0) { return(domainNames); } if (certificate != null) { var names = X509Utils.GetDomainsFromCertficate(certificate); if (names != null && names.Count > 0) { domainNames.AddRange(names); return(domainNames); } var fields = X509Utils.ParseDistinguishedName(certificate.Subject); string name = null; foreach (var field in fields) { if (field.StartsWith("DC=", StringComparison.Ordinal)) { if (name != null) { name += "."; } name += field.Substring(3); } } if (names != null) { domainNames.AddRange(names); return(domainNames); } } domainNames.Add(Utils.GetHostName()); return(domainNames); }