Example #1
0
        /// <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;
            }
        }
Example #3
0
        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);
        }
Example #4
0
 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);
         }
 }
Example #5
0
        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);
            }
        }
Example #6
0
 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();
                 }
             }
         }
     }
 }
Example #7
0
        /// <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);
                                }
                            }
                        }
                    }
            }
        }
Example #9
0
 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);
     }
 }
Example #10
0
            /// <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;
                    }
Example #11
0
        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);
        }
Example #12
0
        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);
            }
        }
Example #16
0
        /// <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);
        }
Example #19
0
        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);
        }