/// <summary> /// Handles a certificate validation error. /// </summary> /// <param name="caller">The caller's text is used as the caption of the <see cref="MessageBox"/> shown to provide details about the error.</param> /// <param name="validator">The validator (not used).</param> /// <param name="e">The <see cref="Opc.Ua.CertificateValidationEventArgs"/> instance event arguments provided when a certificate validation error occurs.</param> public static void HandleCertificateValidationError(Form caller, CertificateValidator validator, CertificateValidationEventArgs e) { 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", e.Error.StatusCode); if (e.Error.InnerResult != null) { buffer.AppendFormat("\t{0}\r\n", e.Error.InnerResult.StatusCode); } buffer.AppendFormat("\r\nSubject: {0}\r\n", e.Certificate.Subject); buffer.AppendFormat("Issuer: {0}\r\n", X509Utils.CompareDistinguishedName(e.Certificate.Subject, e.Certificate.Issuer) ? "Self-signed" : e.Certificate.Issuer); buffer.AppendFormat("Valid From: {0}\r\n", e.Certificate.NotBefore); buffer.AppendFormat("Valid To: {0}\r\n", e.Certificate.NotAfter); buffer.AppendFormat("Thumbprint: {0}\r\n\r\n", e.Certificate.Thumbprint); buffer.AppendFormat("The security certificate was not issued by a trusted certificate authority. "); buffer.AppendFormat("Security certificate problems may indicate an attempt to intercept any data you send "); buffer.AppendFormat("to a server or to allow an untrusted client to connect to your server."); buffer.AppendFormat("\r\n\r\nAccept anyway?"); if (MessageBox.Show(buffer.ToString(), caller.Text, MessageBoxButtons.YesNo) == DialogResult.Yes) { e.Accept = true; } }
/// <summary> /// Handles a certificate validation error. /// </summary> /// <param name="caller">The caller's text is used as the caption of the <see cref="MessageBox"/> shown to provide details about the error.</param> /// <param name="validator">The validator (not used).</param> /// <param name="e">The <see cref="Opc.Ua.CertificateValidationEventArgs"/> instance event arguments provided when a certificate validation error occurs.</param> public static void HandleCertificateValidationError(Form caller, CertificateValidator validator, CertificateValidationEventArgs e) { StringBuilder buffer = new StringBuilder(); buffer.AppendLine("Certificate could not be validated!"); buffer.AppendLine("Validation error(s):"); ServiceResult error = e.Error; while (error != null) { buffer.AppendFormat("- {0}\r\n", error.ToString().Split('\r', '\n').FirstOrDefault()); error = error.InnerResult; } buffer.AppendFormat("\r\nSubject: {0}\r\n", e.Certificate.Subject); buffer.AppendFormat("Issuer: {0}\r\n", X509Utils.CompareDistinguishedName(e.Certificate.Subject, e.Certificate.Issuer) ? "Self-signed" : e.Certificate.Issuer); buffer.AppendFormat("Valid From: {0}\r\n", e.Certificate.NotBefore); buffer.AppendFormat("Valid To: {0}\r\n", e.Certificate.NotAfter); buffer.AppendFormat("Thumbprint: {0}\r\n\r\n", e.Certificate.Thumbprint); buffer.Append("Security certificate problems may indicate an attempt to intercept any data you send "); buffer.Append("to a server or to allow an untrusted client to connect to your server."); buffer.Append("\r\n\r\nAccept anyway?"); if (MessageBox.Show(buffer.ToString(), caller.Text, MessageBoxButtons.YesNo) == DialogResult.Yes) { e.AcceptAll = true; } }
public async Task VerifyNotAfterInvalid(bool trusted) { var cert = CertificateFactory.CreateCertificate( null, null, "CN=App Test Cert", null, CertificateFactory.DefaultKeySize, new DateTime(2010, 1, 1), 12, CertificateFactory.DefaultHashSize); TestContext.Out.WriteLine($"{cert}:"); Assert.NotNull(cert); cert = new X509Certificate2(cert); Assert.NotNull(cert); Assert.True(X509Utils.CompareDistinguishedName("CN=App Test Cert", cert.Subject)); CleanupValidatorAndStores(); if (trusted) { await m_issuerStore.Add(cert); } else { await m_trustedStore.Add(cert); } var certValidator = InitValidatorWithStores(); var serviceResultException = Assert.Throws <ServiceResultException>(() => { certValidator.Validate(cert); }); Assert.AreEqual(StatusCodes.BadCertificateTimeInvalid, serviceResultException.StatusCode, serviceResultException.Message); }
public void UpdateCertificateSelfSignedNoPrivateKeyAsserts() { ConnectPushClient(true); using (X509Certificate2 invalidCert = CertificateFactory.CreateCertificate("uri:x:y:z", "TestApp", "CN=Push Server Test", null).CreateForRSA()) using (X509Certificate2 serverCert = new X509Certificate2(m_pushClient.PushClient.Session.ConfiguredEndpoint.Description.ServerCertificate)) { if (!X509Utils.CompareDistinguishedName(serverCert.Subject, serverCert.Issuer)) { Assert.Ignore("Server has no self signed cert in use."); } byte[] invalidRawCert = { 0xba, 0xd0, 0xbe, 0xef, 3 }; // negative test all parameter combinations NodeId invalidCertGroup = new NodeId(333); NodeId invalidCertType = new NodeId(Guid.NewGuid()); Assert.That(() => { m_pushClient.PushClient.UpdateCertificate(null, null, null, null, null, null); }, Throws.Exception); Assert.That(() => { m_pushClient.PushClient.UpdateCertificate(invalidCertGroup, null, serverCert.RawData, null, null, null); }, Throws.Exception); Assert.That(() => { m_pushClient.PushClient.UpdateCertificate(null, invalidCertType, serverCert.RawData, null, null, null); }, Throws.Exception); Assert.That(() => { m_pushClient.PushClient.UpdateCertificate(invalidCertGroup, invalidCertType, serverCert.RawData, null, null, null); }, Throws.Exception); Assert.That(() => { m_pushClient.PushClient.UpdateCertificate(null, null, invalidRawCert, null, null, null); }, Throws.Exception); Assert.That(() => { m_pushClient.PushClient.UpdateCertificate(null, null, invalidCert.RawData, null, null, null); }, Throws.Exception); Assert.That(() => { m_pushClient.PushClient.UpdateCertificate(null, null, serverCert.RawData, "XYZ", null, null); }, Throws.Exception); Assert.That(() => { m_pushClient.PushClient.UpdateCertificate(null, null, serverCert.RawData, "XYZ", invalidCert.RawData, null); }, Throws.Exception); Assert.That(() => { m_pushClient.PushClient.UpdateCertificate(null, null, invalidCert.RawData, null, null, new byte[][] { serverCert.RawData, invalidCert.RawData }); }, Throws.Exception); Assert.That(() => { m_pushClient.PushClient.UpdateCertificate(null, null, null, null, null, new byte[][] { serverCert.RawData, invalidCert.RawData }); }, Throws.Exception); Assert.That(() => { m_pushClient.PushClient.UpdateCertificate(null, null, invalidRawCert, null, null, new byte[][] { serverCert.RawData, invalidCert.RawData }); }, Throws.Exception); Assert.That(() => { m_pushClient.PushClient.UpdateCertificate(null, null, serverCert.RawData, null, null, new byte[][] { serverCert.RawData, invalidRawCert }); }, Throws.Exception); Assert.That(() => { m_pushClient.PushClient.UpdateCertificate(null, null, serverCert.RawData, null, null, null); }, Throws.Exception); } }
public virtual async Task Init() { Utils.LogInfo("InitializeCertificateGroup: {0}", SubjectName); using (ICertificateStore store = CertificateStoreIdentifier.OpenStore(AuthoritiesStorePath)) { X509Certificate2Collection certificates = await store.Enumerate().ConfigureAwait(false); foreach (var certificate in certificates) { if (X509Utils.CompareDistinguishedName(certificate.Subject, SubjectName)) { if (X509Utils.GetRSAPublicKeySize(certificate) != Configuration.CACertificateKeySize) { continue; } // TODO check hash size if (Certificate != null) { // always use latest issued cert in store if (certificate.NotBefore > DateTime.UtcNow || Certificate.NotBefore > certificate.NotBefore) { continue; } } Certificate = certificate; } } } if (Certificate == null) { Utils.LogInfo(Utils.TraceMasks.Security, "Create new CA Certificate: {0}, KeySize: {1}, HashSize: {2}, LifeTime: {3} months", SubjectName, Configuration.CACertificateKeySize, Configuration.CACertificateHashSize, Configuration.CACertificateLifetime ); X509Certificate2 newCertificate = await CreateCACertificateAsync(SubjectName).ConfigureAwait(false); Certificate = new X509Certificate2(newCertificate.RawData); Utils.LogCertificate(Utils.TraceMasks.Security, "Created CA certificate: ", Certificate); } }
protected void OneTimeTearDown() { foreach (var certStore in CertStores) { using (var x509Store = new X509CertificateStore()) { x509Store.Open(certStore); var collection = x509Store.Enumerate().Result; foreach (var cert in collection) { if (X509Utils.CompareDistinguishedName(X509StoreSubject, cert.Subject)) { x509Store.Delete(cert.Thumbprint).Wait(); } } } } }
/// <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); }
/// <summary> /// Updates the certificate authority certificate and CRL in the trusted list. /// </summary> protected async Task UpdateAuthorityCertInTrustedList() { string trustedListStorePath = Configuration.TrustedListPath; if (!String.IsNullOrEmpty(Configuration.TrustedListPath)) { using (ICertificateStore authorityStore = CertificateStoreIdentifier.OpenStore(m_authoritiesStorePath)) using (ICertificateStore trustedStore = CertificateStoreIdentifier.OpenStore(trustedListStorePath)) { X509Certificate2Collection certificates = await authorityStore.Enumerate().ConfigureAwait(false); foreach (var certificate in certificates) { if (X509Utils.CompareDistinguishedName(certificate.Subject, m_subjectName)) { X509Certificate2Collection certs = await trustedStore.FindByThumbprint(certificate.Thumbprint).ConfigureAwait(false); if (certs.Count == 0) { await trustedStore.Add(new X509Certificate2(certificate.RawData)).ConfigureAwait(false); } // delete existing CRL in trusted list foreach (var crl in trustedStore.EnumerateCRLs(certificate, false)) { if (crl.VerifySignature(certificate, false)) { trustedStore.DeleteCRL(crl); } } // copy latest CRL to trusted list foreach (var crl in authorityStore.EnumerateCRLs(certificate, true)) { trustedStore.AddCRL(crl); } } } } } }
public void UpdateCertificateSelfSignedNoPrivateKey() { ConnectPushClient(true); using (X509Certificate2 serverCert = new X509Certificate2(m_pushClient.PushClient.Session.ConfiguredEndpoint.Description.ServerCertificate)) { if (!X509Utils.CompareDistinguishedName(serverCert.Subject, serverCert.Issuer)) { Assert.Ignore("Server has no self signed cert in use."); } var success = m_pushClient.PushClient.UpdateCertificate( null, m_pushClient.PushClient.ApplicationCertificateType, serverCert.RawData, null, null, null); if (success) { m_pushClient.PushClient.ApplyChanges(); } VerifyNewPushServerCert(serverCert.RawData); } }
/// <summary> /// Verifies that a certificate user token is trusted. /// </summary> private bool VerifyCertificate(X509Certificate2 certificate) { try { if (_certificateValidator != null) { _certificateValidator.Validate(certificate); } else { CertificateValidator.Validate(certificate); } // determine if self-signed. var isSelfSigned = X509Utils.CompareDistinguishedName( certificate.Subject, certificate.Issuer); // do not allow self signed application certs as user token if (isSelfSigned && X509Utils.HasApplicationURN(certificate)) { throw new ServiceResultException(StatusCodes.BadCertificateUseNotAllowed); } return(false); } catch (Exception e) { TranslationInfo info; StatusCode result = StatusCodes.BadIdentityTokenRejected; if (e is ServiceResultException se && se.StatusCode == StatusCodes.BadCertificateUseNotAllowed) { info = new TranslationInfo( "InvalidCertificate", "en-US", "'{0}' is an invalid user certificate.", certificate.Subject); result = StatusCodes.BadIdentityTokenInvalid; }
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); }
private ServiceResult UpdateCertificate( ISystemContext context, MethodState method, NodeId objectId, NodeId certificateGroupId, NodeId certificateTypeId, byte[] certificate, byte[][] issuerCertificates, string privateKeyFormat, byte[] privateKey, ref bool applyChangesRequired) { HasApplicationSecureAdminAccess(context); if (certificate == null) { throw new ArgumentNullException(nameof(certificate)); } privateKeyFormat = privateKeyFormat?.ToUpper(); if (!(String.IsNullOrEmpty(privateKeyFormat) || privateKeyFormat == "PEM" || privateKeyFormat == "PFX")) { throw new ServiceResultException(StatusCodes.BadNotSupported, "The private key format is not supported."); } ServerCertificateGroup certificateGroup = VerifyGroupAndTypeId(certificateGroupId, certificateTypeId); certificateGroup.UpdateCertificate = null; X509Certificate2Collection newIssuerCollection = new X509Certificate2Collection(); X509Certificate2 newCert; try { // build issuer chain if (issuerCertificates != null) { foreach (byte[] issuerRawCert in issuerCertificates) { var newIssuerCert = new X509Certificate2(issuerRawCert); newIssuerCollection.Add(newIssuerCert); } } newCert = new X509Certificate2(certificate); } catch { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Certificate data is invalid."); } // validate new subject matches the previous subject if (!X509Utils.CompareDistinguishedName(certificateGroup.ApplicationCertificate.SubjectName, newCert.SubjectName.Name)) { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Subject Name of new certificate doesn't match the application."); } // self signed bool selfSigned = X509Utils.CompareDistinguishedName(newCert.Subject, newCert.Issuer); if (selfSigned && newIssuerCollection.Count != 0) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Issuer list not empty for self signed certificate."); } if (!selfSigned) { try { // verify cert with issuer chain CertificateValidator certValidator = new CertificateValidator(); CertificateTrustList issuerStore = new CertificateTrustList(); CertificateIdentifierCollection issuerCollection = new CertificateIdentifierCollection(); foreach (var issuerCert in newIssuerCollection) { issuerCollection.Add(new CertificateIdentifier(issuerCert)); } issuerStore.TrustedCertificates = issuerCollection; certValidator.Update(issuerStore, issuerStore, null); certValidator.Validate(newCert); } catch { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to verify integrity of the new certificate and the issuer list."); } } var updateCertificate = new UpdateCertificateData(); try { var passwordProvider = m_configuration.SecurityConfiguration.CertificatePasswordProvider; switch (privateKeyFormat) { case null: case "": { X509Certificate2 certWithPrivateKey = certificateGroup.ApplicationCertificate.LoadPrivateKeyEx(passwordProvider).Result; updateCertificate.CertificateWithPrivateKey = CertificateFactory.CreateCertificateWithPrivateKey(newCert, certWithPrivateKey); break; } case "PFX": { X509Certificate2 certWithPrivateKey = X509Utils.CreateCertificateFromPKCS12(privateKey, passwordProvider?.GetPassword(certificateGroup.ApplicationCertificate)); updateCertificate.CertificateWithPrivateKey = CertificateFactory.CreateCertificateWithPrivateKey(newCert, certWithPrivateKey); break; } case "PEM": { updateCertificate.CertificateWithPrivateKey = CertificateFactory.CreateCertificateWithPEMPrivateKey(newCert, privateKey, passwordProvider?.GetPassword(certificateGroup.ApplicationCertificate)); break; } } updateCertificate.IssuerCollection = newIssuerCollection; updateCertificate.SessionId = context.SessionId; } catch { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to verify integrity of the new certificate and the private key."); } certificateGroup.UpdateCertificate = updateCertificate; applyChangesRequired = true; if (updateCertificate != null) { try { using (ICertificateStore appStore = certificateGroup.ApplicationCertificate.OpenStore()) { Utils.LogCertificate(Utils.TraceMasks.Security, "Delete application certificate: ", certificateGroup.ApplicationCertificate.Certificate); appStore.Delete(certificateGroup.ApplicationCertificate.Thumbprint).Wait(); Utils.LogCertificate(Utils.TraceMasks.Security, "Add new application certificate: ", updateCertificate.CertificateWithPrivateKey); var passwordProvider = m_configuration.SecurityConfiguration.CertificatePasswordProvider; appStore.Add(updateCertificate.CertificateWithPrivateKey, passwordProvider?.GetPassword(certificateGroup.ApplicationCertificate)).Wait(); // keep only track of cert without private key var certOnly = new X509Certificate2(updateCertificate.CertificateWithPrivateKey.RawData); updateCertificate.CertificateWithPrivateKey.Dispose(); updateCertificate.CertificateWithPrivateKey = certOnly; } using (ICertificateStore issuerStore = CertificateStoreIdentifier.OpenStore(certificateGroup.IssuerStorePath)) { foreach (var issuer in updateCertificate.IssuerCollection) { try { Utils.LogCertificate(Utils.TraceMasks.Security, "Add new issuer certificate: ", issuer); issuerStore.Add(issuer).Wait(); } catch (ArgumentException) { // ignore error if issuer cert already exists } } } } catch (Exception ex) { Utils.LogError(Utils.TraceMasks.Security, ServiceResult.BuildExceptionTrace(ex)); throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to update certificate.", ex); } } return(ServiceResult.Good); }
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); }
public void Initialize(TrustListDataType trustList, X509Certificate2Collection rejectedList, bool deleteBeforeAdd) { if (deleteBeforeAdd) { CertificatesTable.Rows.Clear(); } if (trustList != null) { if ((trustList.SpecifiedLists & (uint)TrustListMasks.TrustedCertificates) != 0 && trustList.TrustedCertificates != null) { foreach (var certificateBytes in trustList.TrustedCertificates) { var certificate = new X509Certificate2(certificateBytes); List <X509CRL> crls = new List <X509CRL>(); if ((trustList.SpecifiedLists & (uint)TrustListMasks.TrustedCrls) != 0 && trustList.TrustedCrls != null) { foreach (var crlBytes in trustList.TrustedCrls) { X509CRL crl = new X509CRL(crlBytes); if (X509Utils.CompareDistinguishedName(crl.Issuer, certificate.Subject) && crl.VerifySignature(certificate, false)) { crls.Add(crl); } } } AddCertificate(certificate, Status.Trusted, crls); } } if ((trustList.SpecifiedLists & (uint)TrustListMasks.IssuerCertificates) != 0 && trustList.IssuerCertificates != null) { foreach (var certificateBytes in trustList.IssuerCertificates) { var certificate = new X509Certificate2(certificateBytes); List <X509CRL> crls = new List <X509CRL>(); if ((trustList.SpecifiedLists & (uint)TrustListMasks.IssuerCrls) != 0 && trustList.IssuerCrls != null) { foreach (var crlBytes in trustList.IssuerCrls) { X509CRL crl = new X509CRL(crlBytes); if (X509Utils.CompareDistinguishedName(crl.Issuer, certificate.Subject) && crl.VerifySignature(certificate, false)) { crls.Add(crl); } } } AddCertificate(certificate, Status.Issuer, crls); } } } if (rejectedList != null) { foreach (X509Certificate2 certificate in rejectedList) { AddCertificate(certificate, Status.Rejected, null); } } m_dataset.AcceptChanges(); NoDataWarningLabel.Visible = CertificatesTable.Rows.Count == 0; }
/// <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> /// Adds the certificate to the Trusted Certificate Store /// </summary> /// <param name="configuration">The application's configuration which specifies the location of the TrustedStore.</param> /// <param name="certificate">The certificate to register.</param> private static async Task AddToTrustedStore(ApplicationConfiguration configuration, X509Certificate2 certificate) { if (certificate == null) { throw new ArgumentNullException(nameof(certificate)); } string storePath = null; if (configuration != null && configuration.SecurityConfiguration != null && configuration.SecurityConfiguration.TrustedPeerCertificates != null) { storePath = configuration.SecurityConfiguration.TrustedPeerCertificates.StorePath; } if (String.IsNullOrEmpty(storePath)) { Utils.Trace(Utils.TraceMasks.Information, "WARNING: Trusted peer store not specified."); return; } try { ICertificateStore store = configuration.SecurityConfiguration.TrustedPeerCertificates.OpenStore(); if (store == null) { Utils.Trace("Could not open trusted peer store. StorePath={0}", storePath); return; } try { // check if it already exists. X509Certificate2Collection existingCertificates = await store.FindByThumbprint(certificate.Thumbprint); if (existingCertificates.Count > 0) { return; } Utils.Trace(Utils.TraceMasks.Information, "Adding certificate to trusted peer store. StorePath={0}", storePath); List <string> subjectName = X509Utils.ParseDistinguishedName(certificate.Subject); // check for old certificate. X509Certificate2Collection certificates = await store.Enumerate(); for (int ii = 0; ii < certificates.Count; ii++) { if (X509Utils.CompareDistinguishedName(certificates[ii], subjectName)) { if (certificates[ii].Thumbprint == certificate.Thumbprint) { return; } await store.Delete(certificates[ii].Thumbprint); break; } } // add new certificate. X509Certificate2 publicKey = new X509Certificate2(certificate.RawData); await store.Add(publicKey); } finally { store.Close(); } } catch (Exception e) { Utils.Trace(e, "Could not add certificate to trusted peer store. StorePath={0}", storePath); } }
public static void VerifyCACert(X509Certificate2 cert, string subject, int pathLengthConstraint) { TestContext.Out.WriteLine($"{nameof(VerifyCACert)}:"); Assert.NotNull(cert); TestContext.Out.WriteLine(cert); Assert.False(cert.HasPrivateKey); Assert.True(X509Utils.CompareDistinguishedName(subject, cert.Subject)); Assert.True(X509Utils.CompareDistinguishedName(subject, cert.Issuer)); // test basic constraints var constraints = X509Extensions.FindExtension <X509BasicConstraintsExtension>(cert); Assert.NotNull(constraints); TestContext.Out.WriteLine(constraints.Format(true)); Assert.True(constraints.Critical); Assert.True(constraints.CertificateAuthority); if (pathLengthConstraint < 0) { Assert.False(constraints.HasPathLengthConstraint); } else { Assert.True(constraints.HasPathLengthConstraint); Assert.AreEqual(pathLengthConstraint, constraints.PathLengthConstraint); } // key usage var keyUsage = X509Extensions.FindExtension <X509KeyUsageExtension>(cert); Assert.NotNull(keyUsage); TestContext.Out.WriteLine(keyUsage.Format(true)); Assert.True(keyUsage.Critical); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.CrlSign) == X509KeyUsageFlags.CrlSign); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.DataEncipherment) == 0); 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) == X509KeyUsageFlags.KeyCertSign); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.KeyEncipherment) == 0); Assert.True((keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) == 0); // enhanced key usage X509EnhancedKeyUsageExtension enhancedKeyUsage = X509Extensions.FindExtension <X509EnhancedKeyUsageExtension>(cert); Assert.Null(enhancedKeyUsage); // 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.GetSerialNumber()); Assert.NotNull(authority.KeyIdentifier); Assert.NotNull(authority.Issuer); Assert.NotNull(authority.ToString()); Assert.AreEqual(authority.SerialNumber, Utils.ToHexString(authority.GetSerialNumber(), true)); // verify authority key in signed cert X509SubjectKeyIdentifierExtension subjectKeyId = X509Extensions.FindExtension <X509SubjectKeyIdentifierExtension>(cert); TestContext.Out.WriteLine(subjectKeyId.Format(true)); Assert.AreEqual(subjectKeyId.SubjectKeyIdentifier, authority.KeyIdentifier); Assert.AreEqual(cert.SerialNumber, authority.SerialNumber); Assert.AreEqual(cert.GetSerialNumber(), authority.GetSerialNumber()); X509SubjectAltNameExtension subjectAlternateName = X509Extensions.FindExtension <X509SubjectAltNameExtension>(cert); Assert.Null(subjectAlternateName); }
/// <summary> /// Revoke the CA signed certificate. /// The issuer CA public key, the private key and the crl reside in the storepath. /// The CRL number is increased by one and existing CRL for the issuer are deleted from the store. /// </summary> public static async Task <X509CRL> RevokeCertificateAsync( string storePath, X509Certificate2 certificate, string issuerKeyFilePassword = null ) { X509CRL updatedCRL = null; string subjectName = certificate.IssuerName.Name; string keyId = null; string serialNumber = null; // caller may want to create empty CRL using the CA cert itself bool isCACert = X509Utils.IsCertificateAuthority(certificate); // find the authority key identifier. X509AuthorityKeyIdentifierExtension authority = X509Extensions.FindExtension <X509AuthorityKeyIdentifierExtension>(certificate); if (authority != null) { keyId = authority.KeyIdentifier; serialNumber = authority.SerialNumber; } else { throw new ArgumentException("Certificate does not contain an Authority Key"); } if (!isCACert) { if (serialNumber == certificate.SerialNumber || X509Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer)) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Cannot revoke self signed certificates"); } } X509Certificate2 certCA = null; using (ICertificateStore store = CertificateStoreIdentifier.OpenStore(storePath)) { if (store == null) { throw new ArgumentException("Invalid store path/type"); } certCA = await X509Utils.FindIssuerCABySerialNumberAsync(store, certificate.Issuer, serialNumber).ConfigureAwait(false); if (certCA == null) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Cannot find issuer certificate in store."); } if (!certCA.HasPrivateKey) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Issuer certificate has no private key, cannot revoke certificate."); } CertificateIdentifier certCAIdentifier = new CertificateIdentifier(certCA) { StorePath = storePath, StoreType = CertificateStoreIdentifier.DetermineStoreType(storePath) }; X509Certificate2 certCAWithPrivateKey = await certCAIdentifier.LoadPrivateKey(issuerKeyFilePassword).ConfigureAwait(false); if (certCAWithPrivateKey == null) { throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Failed to load issuer private key. Is the password correct?"); } List <X509CRL> certCACrl = store.EnumerateCRLs(certCA, false); var certificateCollection = new X509Certificate2Collection() { }; if (!isCACert) { certificateCollection.Add(certificate); } updatedCRL = CertificateFactory.RevokeCertificate(certCAWithPrivateKey, certCACrl, certificateCollection); store.AddCRL(updatedCRL); // delete outdated CRLs from store foreach (X509CRL caCrl in certCACrl) { store.DeleteCRL(caCrl); } store.Close(); } return(updatedCRL); }
private ServiceResult RemoveCertificate( ISystemContext context, MethodState method, NodeId objectId, string thumbprint, bool isTrustedCertificate) { HasSecureWriteAccess(context); lock (m_lock) { if (m_sessionId != null) { return(StatusCodes.BadInvalidState); } if (String.IsNullOrEmpty(thumbprint)) { return(StatusCodes.BadInvalidArgument); } using (ICertificateStore store = CertificateStoreIdentifier.OpenStore(isTrustedCertificate ? m_trustedStorePath : m_issuerStorePath)) { var certCollection = store.FindByThumbprint(thumbprint).Result; if (certCollection.Count == 0) { return(StatusCodes.BadInvalidArgument); } // delete all CRLs signed by cert var crlsToDelete = new List <X509CRL>(); foreach (var crl in store.EnumerateCRLs()) { foreach (var cert in certCollection) { if (X509Utils.CompareDistinguishedName(cert.Subject, crl.Issuer) && crl.VerifySignature(cert, false)) { crlsToDelete.Add(crl); break; } } } if (!store.Delete(thumbprint).Result) { return(StatusCodes.BadInvalidArgument); } foreach (var crl in crlsToDelete) { if (!store.DeleteCRL(crl)) { // intentionally ignore errors, try best effort Utils.Trace("RemoveCertificate: Failed to delete CRL {0}.", crl.ToString()); } } } m_node.LastUpdateTime.Value = DateTime.UtcNow; } return(ServiceResult.Good); }
private ServiceResult RemoveCertificate( ISystemContext context, MethodState method, NodeId objectId, string thumbprint, bool isTrustedCertificate) { HasSecureWriteAccess(context); ServiceResult result = StatusCodes.Good; lock (m_lock) { if (m_sessionId != null) { result = StatusCodes.BadInvalidState; } else if (String.IsNullOrEmpty(thumbprint)) { result = StatusCodes.BadInvalidArgument; } else { using (ICertificateStore store = CertificateStoreIdentifier.OpenStore(isTrustedCertificate ? m_trustedStorePath : m_issuerStorePath)) { var certCollection = store.FindByThumbprint(thumbprint).GetAwaiter().GetResult(); if (certCollection.Count == 0) { result = StatusCodes.BadInvalidArgument; } else { // delete all CRLs signed by cert var crlsToDelete = new X509CRLCollection(); foreach (var crl in store.EnumerateCRLs().GetAwaiter().GetResult()) { foreach (var cert in certCollection) { if (X509Utils.CompareDistinguishedName(cert.SubjectName, crl.IssuerName) && crl.VerifySignature(cert, false)) { crlsToDelete.Add(crl); break; } } } if (!store.Delete(thumbprint).GetAwaiter().GetResult()) { result = StatusCodes.BadInvalidArgument; } else { foreach (var crl in crlsToDelete) { if (!store.DeleteCRL(crl).GetAwaiter().GetResult()) { // intentionally ignore errors, try best effort Utils.LogError("RemoveCertificate: Failed to delete CRL {0}.", crl.ToString()); } } } } } m_node.LastUpdateTime.Value = DateTime.UtcNow; } } // report the TrustListUpdatedAuditEvent object[] inputParameters = new object[] { thumbprint }; m_node.ReportTrustListUpdatedAuditEvent(context, objectId, "Method/RemoveCertificate", method.NodeId, inputParameters, result.StatusCode); return(result); }