Example #1
0
        public KeyInfoX509Data(X509Certificate cert, X509IncludeOption includeOption)
        {
            if (cert == null)
            {
                throw new ArgumentNullException("cert");
            }

            X509Certificate2           certificate = new X509Certificate2(cert);
            X509ChainElementCollection elements    = null;
            X509Chain chain = null;

            switch (includeOption)
            {
            case X509IncludeOption.ExcludeRoot:
                // Build the certificate chain
                chain = new X509Chain();
                chain.Build(certificate);

                // Can't honor the option if we only have a partial chain.
                if ((chain.ChainStatus.Length > 0) &&
                    ((chain.ChainStatus[0].Status & X509ChainStatusFlags.PartialChain) == X509ChainStatusFlags.PartialChain))
                {
                    throw new CryptographicException(CAPI.CERT_E_CHAINING);
                }

                elements = (X509ChainElementCollection)chain.ChainElements;
                for (int index = 0; index < (X509Utils.IsSelfSigned(chain) ? 1 : elements.Count - 1); index++)
                {
                    AddCertificate(elements[index].Certificate);
                }
                break;

            case X509IncludeOption.EndCertOnly:
                AddCertificate(certificate);
                break;

            case X509IncludeOption.WholeChain:
                // Build the certificate chain
                chain = new X509Chain();
                chain.Build(certificate);

                // Can't honor the option if we only have a partial chain.
                if ((chain.ChainStatus.Length > 0) &&
                    ((chain.ChainStatus[0].Status & X509ChainStatusFlags.PartialChain) == X509ChainStatusFlags.PartialChain))
                {
                    throw new CryptographicException(CAPI.CERT_E_CHAINING);
                }

                elements = (X509ChainElementCollection)chain.ChainElements;
                foreach (X509ChainElement element in elements)
                {
                    AddCertificate(element.Certificate);
                }
                break;
            }
        }
Example #2
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);

            object[]         inputArguments = new object[] { certificateGroupId, certificateTypeId, certificate, issuerCertificates, privateKeyFormat, privateKey };
            X509Certificate2 newCert        = null;

            try
            {
                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();

                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.Certificate.SubjectName, newCert.SubjectName))
                {
                    throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Subject Name of new certificate doesn't match the application.");
                }

                // self signed
                bool selfSigned = X509Utils.IsSelfSigned(newCert);
                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 (Exception ex)
                    {
                        throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to verify integrity of the new certificate and the issuer list.", ex);
                    }
                }

                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
                                }
                            }
                        }

                        Server.ReportCertificateUpdatedAuditEvent(context, objectId, method, inputArguments, certificateGroupId, certificateTypeId);
                    }
                    catch (Exception ex)
                    {
                        Utils.LogError(Utils.TraceMasks.Security, ServiceResult.BuildExceptionTrace(ex));
                        throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Failed to update certificate.", ex);
                    }
                }
            }
            catch (Exception e)
            {
                // report the failure of UpdateCertificate via an audit event
                Server.ReportCertificateUpdatedAuditEvent(context, objectId, method, inputArguments, certificateGroupId, certificateTypeId, e);
                // Raise audit certificate event
                Server.ReportAuditCertificateEvent(newCert, e);
                throw;
            }

            return(ServiceResult.Good);
        }
Example #3
0
        /// <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;
            X500DistinguishedName subjectName = certificate.IssuerName;
            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.IsSelfSigned(certificate))
                {
                    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.IssuerName, serialNumber).ConfigureAwait(false);

                if (certCA == null)
                {
                    throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Cannot find issuer certificate in store.");
                }

                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?");
                }

                if (!certCAWithPrivateKey.HasPrivateKey)
                {
                    throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Issuer certificate has no private key, cannot revoke certificate.");
                }

                var certCACrl = await store.EnumerateCRLs(certCA, false).ConfigureAwait(false);

                var certificateCollection = new X509Certificate2Collection();
                if (!isCACert)
                {
                    certificateCollection.Add(certificate);
                }
                updatedCRL = CertificateFactory.RevokeCertificate(certCAWithPrivateKey, certCACrl, certificateCollection);

                await store.AddCRL(updatedCRL).ConfigureAwait(false);

                // delete outdated CRLs from store
                foreach (X509CRL caCrl in certCACrl)
                {
                    await store.DeleteCRL(caCrl).ConfigureAwait(false);
                }
                store.Close();
            }
            return(updatedCRL);
        }