/// <summary>
        /// Returns the CRLs for the issuer.
        /// </summary>
        public List <X509CRL> EnumerateCRLs(X509Certificate2 issuer, bool validateUpdateTime = true)
        {
            if (issuer == null)
            {
                throw new ArgumentNullException(nameof(issuer));
            }

            List <X509CRL> crls = new List <X509CRL>();

            foreach (X509CRL crl in EnumerateCRLs())
            {
                if (!Utils.CompareDistinguishedName(crl.Issuer, issuer.Subject))
                {
                    continue;
                }

                if (!crl.VerifySignature(issuer, false))
                {
                    continue;
                }

                if (!validateUpdateTime ||
                    crl.UpdateTime <= DateTime.UtcNow && (crl.NextUpdateTime == DateTime.MinValue || crl.NextUpdateTime >= DateTime.UtcNow))
                {
                    crls.Add(crl);
                }
            }

            return(crls);
        }
Example #2
0
        /// <summary>
        /// Finds a certificate in a collection.
        /// </summary>
        /// <param name="collection">The collection of the <see cref="X509Certificate2"/> certificates objects.</param>
        /// <param name="needPrivateKey">If set to <c>true</c> the certificate must have private key.</param>
        /// <returns>An <see cref="X509Certificate2"/> certificate with matching subject name.</returns>
        public static X509Certificate2 Find(X509Certificate2Collection collection, string thumbprint, string subjectName, bool needPrivateKey)
        {
            #if !SILVERLIGHT
            // find by thumbprint.
            if (!String.IsNullOrEmpty(thumbprint))
            {
                collection = collection.Find(X509FindType.FindByThumbprint, thumbprint, false);

                foreach (X509Certificate2 certificate in collection)
                {
                    if (!needPrivateKey || certificate.HasPrivateKey)
                    {
                        if (String.IsNullOrEmpty(subjectName))
                        {
                            return(certificate);
                        }

                        List <string> subjectName2 = Utils.ParseDistinguishedName(subjectName);

                        if (Utils.CompareDistinguishedName(certificate, subjectName2))
                        {
                            return(certificate);
                        }
                    }
                }

                return(null);
            }

            // find by subject name.
            if (!String.IsNullOrEmpty(subjectName))
            {
                List <string> subjectName2 = Utils.ParseDistinguishedName(subjectName);

                foreach (X509Certificate2 certificate in collection)
                {
                    if (Utils.CompareDistinguishedName(certificate, subjectName2))
                    {
                        if (!needPrivateKey || certificate.HasPrivateKey)
                        {
                            return(certificate);
                        }
                    }
                }

                collection = collection.Find(X509FindType.FindBySubjectName, subjectName, false);

                foreach (X509Certificate2 certificate in collection)
                {
                    if (!needPrivateKey || certificate.HasPrivateKey)
                    {
                        return(certificate);
                    }
                }
            }
            #endif

            // certificate not found.
            return(null);
        }
Example #3
0
        /// <summary>
        /// Returns the issuers for the certificate.
        /// </summary>
        /// <param name="certificate">The certificate.</param>
        /// <param name="issuers">The issuers.</param>
        /// <returns></returns>
        public async Task <bool> GetIssuers(X509Certificate2 certificate, List <CertificateIdentifier> issuers)
        {
            bool isTrusted = false;
            CertificateIdentifier issuer = null;

            do
            {
                issuer = await GetIssuer(certificate, m_trustedCertificateList, m_trustedCertificateStore, true);

                if (issuer == null)
                {
                    issuer = await GetIssuer(certificate, m_issuerCertificateList, m_issuerCertificateStore, true);
                }
                else
                {
                    isTrusted = true;
                }

                if (issuer != null)
                {
                    issuers.Add(issuer);
                    certificate = await issuer.Find(false);

                    // check for root.
                    if (Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer))
                    {
                        break;
                    }
                }
            }while (issuer != null);

            return(isTrusted);
        }
Example #4
0
        /// <summary>
        /// Gets the CRL file paths.
        /// </summary>
        /// <param name="thumbprint">The certificate thumbprint.</param>
        /// <returns></returns>
        public string[] GetCrlFilePaths(string thumbprint)
        {
            List <string> filePaths = new List <string>();

            Entry entry = Find(thumbprint);

            DirectoryInfo info = new DirectoryInfo(this.Directory.FullName + "\\crl");

            foreach (FileInfo file in info.GetFiles("*.crl"))
            {
                X509CRL crl = null;

                try
                {
                    crl = new X509CRL(file.FullName);
                }
                catch (Exception e)
                {
                    Utils.Trace(e, "Could not parse CRL file.");
                    continue;
                }

                if (!Utils.CompareDistinguishedName(crl.Issuer, entry.Certificate.Subject))
                {
                    continue;
                }

                filePaths.Add(file.FullName);
            }

            return(filePaths.ToArray());
        }
Example #5
0
        /// <summary>
        /// Returns true the certificate is in the CRL.
        /// </summary>
        public bool IsRevoked(X509Certificate2 certificate)
        {
            // check that the issuer matches.
            if (m_issuer == null || !Utils.CompareDistinguishedName(certificate.Issuer, m_issuer.Subject))
            {
                throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Certificate was not created by the CRL issuer.");
            }

            Org.BouncyCastle.X509.X509Certificate bccert = new X509CertificateParser().ReadCertificate(certificate.RawData);
            return(m_crl.IsRevoked(bccert));
        }
Example #6
0
        /// <summary>
        /// Returns true the certificate is in the CRL.
        /// </summary>
        public bool IsRevoked(X509Certificate2 certificate)
        {
            // check that the issuer matches.
            if (m_issuer == null || !Utils.CompareDistinguishedName(certificate.Issuer, m_issuer.Subject))
            {
                throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Certificate was not created by the CRL issuer.");
            }

            // TODO: get the cert info for the target certificate and check revocation.

            // not revoked.
            return(false);
        }
Example #7
0
        /// <summary>
        /// Returns the issuers for the certificates.
        /// </summary>
        public async Task <bool> GetIssuers(X509Certificate2Collection certificates, List <CertificateIdentifier> issuers)
        {
            bool isTrusted = false;
            CertificateIdentifier issuer      = null;
            X509Certificate2      certificate = certificates[0];

            CertificateIdentifierCollection collection = new CertificateIdentifierCollection();

            for (int ii = 1; ii < certificates.Count; ii++)
            {
                collection.Add(new CertificateIdentifier(certificates[ii]));
            }

            do
            {
                issuer = await GetIssuer(certificate, m_trustedCertificateList, m_trustedCertificateStore, true);

                if (issuer == null)
                {
                    issuer = await GetIssuer(certificate, m_issuerCertificateList, m_issuerCertificateStore, true);

                    if (issuer == null)
                    {
                        issuer = await GetIssuer(certificate, collection, null, true);
                    }
                }

                if (issuer != null)
                {
                    isTrusted = true;

                    issuers.Add(issuer);
                    certificate = await issuer.Find(false);

                    // check for root.
                    if (Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer))
                    {
                        break;
                    }
                }
                else
                {
                    isTrusted = false;
                }
            }while (issuer != null);

            return(isTrusted);
        }
Example #8
0
        /// <summary>
        /// Adds a CRL to the store.
        /// </summary>
        public void AddCRL(X509CRL crl)
        {
            if (crl == null)
            {
                throw new ArgumentNullException("crl");
            }

            X509Certificate2           issuer       = null;
            X509Certificate2Collection certificates = null;

            certificates = Enumerate().Result;
            foreach (X509Certificate2 certificate in certificates)
            {
                if (Utils.CompareDistinguishedName(certificate.Subject, crl.Issuer))
                {
                    if (crl.VerifySignature(certificate, false))
                    {
                        issuer = certificate;
                        break;
                    }
                }
            }

            if (issuer == null)
            {
                throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Could not find issuer of the CRL.");
            }

            StringBuilder builder = new StringBuilder();

            builder.Append(m_directory.FullName);

            builder.Append(Path.DirectorySeparatorChar + "crl" + Path.DirectorySeparatorChar);
            builder.Append(GetFileName(issuer));
            builder.Append(".crl");

            FileInfo fileInfo = new FileInfo(builder.ToString());

            if (!fileInfo.Directory.Exists)
            {
                fileInfo.Directory.Create();
            }

            File.WriteAllBytes(fileInfo.FullName, crl.RawData);
        }
Example #9
0
        /// <summary>
        /// Returns true if the certificate matches the criteria.
        /// </summary>
        private bool Match(
            X509Certificate2 certificate,
            string subjectName,
            string serialNumber,
            string authorityKeyId)
        {
            // check for null.
            if (certificate == null)
            {
                return(false);
            }

            // check for subject name match.
            if (!Utils.CompareDistinguishedName(certificate.SubjectName.Name, subjectName))
            {
                return(false);
            }

            // check for serial number match.
            if (!String.IsNullOrEmpty(serialNumber))
            {
                if (certificate.SerialNumber != serialNumber)
                {
                    return(false);
                }
            }

            // check for authority key id match.
            if (!String.IsNullOrEmpty(authorityKeyId))
            {
                X509SubjectKeyIdentifierExtension subjectKeyId = FindSubjectKeyIdentifierExtension(certificate);

                if (subjectKeyId != null)
                {
                    if (subjectKeyId.SubjectKeyIdentifier != authorityKeyId)
                    {
                        return(false);
                    }
                }
            }

            // found match.
            return(true);
        }
Example #10
0
        /// <summary>
        /// Returns the CRLs for the issuer.
        /// </summary>
        public List <X509CRL> EnumerateCRLs(X509Certificate2 issuer)
        {
            if (issuer == null)
            {
                throw new ArgumentNullException("issuer");
            }

            List <X509CRL> crls = new List <X509CRL>();

            // check for CRL.
            DirectoryInfo info = new DirectoryInfo(this.Directory.FullName + "\\crl");

            if (info.Exists)
            {
                foreach (FileInfo file in info.GetFiles("*.crl"))
                {
                    X509CRL crl = new X509CRL(file.FullName);

                    if (!Utils.CompareDistinguishedName(crl.Issuer, issuer.Subject))
                    {
                        continue;
                    }

                    if (!crl.VerifySignature(issuer, false))
                    {
                        continue;
                    }

                    if (crl.UpdateTime <= DateTime.UtcNow &&
                        (crl.NextUpdateTime == DateTime.MinValue || crl.NextUpdateTime >= DateTime.UtcNow))
                    {
                        crls.Add(crl);
                    }
                }
            }

            return(crls);
        }
Example #11
0
        /// <summary>
        /// Checks if issuer has revoked the certificate.
        /// </summary>
        public virtual StatusCode IsRevoked(X509Certificate2 issuer, X509Certificate2 certificate)
        {
            if (issuer == null)
            {
                throw new ArgumentNullException("issuer");
            }

            if (certificate == null)
            {
                throw new ArgumentNullException("certificate");
            }

            // check for CRL.
            DirectoryInfo info = new DirectoryInfo(this.Directory.FullName + Path.DirectorySeparatorChar + "crl");

            if (info.Exists)
            {
                bool crlExpired = true;

                foreach (FileInfo file in info.GetFiles("*.crl"))
                {
                    X509CRL crl = null;

                    try
                    {
                        crl = new X509CRL(file.FullName);
                    }
                    catch (Exception e)
                    {
                        Utils.Trace(e, "Could not parse CRL file.");
                        continue;
                    }

                    if (!Utils.CompareDistinguishedName(crl.Issuer, issuer.Subject))
                    {
                        continue;
                    }

                    if (!crl.VerifySignature(issuer, false))
                    {
                        continue;
                    }

                    if (crl.IsRevoked(certificate))
                    {
                        return(StatusCodes.BadCertificateRevoked);
                    }

                    if (crl.UpdateTime <= DateTime.UtcNow && (crl.NextUpdateTime == DateTime.MinValue || crl.NextUpdateTime >= DateTime.UtcNow))
                    {
                        crlExpired = false;
                    }
                }

                // certificate is fine.
                if (!crlExpired)
                {
                    return(StatusCodes.Good);
                }
            }

            // can't find a valid CRL.
            return(StatusCodes.BadCertificateRevocationUnknown);
        }
Example #12
0
        /// <summary>
        /// Loads the private key from a PFX file in the certificate store.
        /// </summary>
        public virtual X509Certificate2 LoadApplicationCertificate(string thumbprint, string subjectName, string applicationURI, string password)
        {
            if (m_certificateSubdir == null || !m_certificateSubdir.Exists)
            {
                return(null);
            }

            if (string.IsNullOrEmpty(thumbprint) && string.IsNullOrEmpty(subjectName))
            {
                return(null);
            }

            foreach (FileInfo file in m_certificateSubdir.GetFiles("*.der"))
            {
                try
                {
                    X509Certificate2 certificate = new X509Certificate2(file.FullName);

                    if (!String.IsNullOrEmpty(thumbprint))
                    {
                        if (!string.Equals(certificate.Thumbprint, thumbprint, StringComparison.CurrentCultureIgnoreCase))
                        {
                            continue;
                        }
                    }

                    if (!String.IsNullOrEmpty(subjectName))
                    {
                        if (!Utils.CompareDistinguishedName(subjectName, certificate.Subject))
                        {
                            if (subjectName.Contains("=") || !certificate.Subject.Contains("CN=" + subjectName))
                            {
                                continue;
                            }
                        }
                    }

                    string fileRoot = file.Name.Substring(0, file.Name.Length - file.Extension.Length);

                    StringBuilder filePath = new StringBuilder();
                    filePath.Append(m_privateKeySubdir.FullName);
                    filePath.Append(Path.DirectorySeparatorChar);
                    filePath.Append(fileRoot);

                    FileInfo privateKeyFile = new FileInfo(filePath.ToString() + ".pfx");

                    RSA rsa = null;
                    try
                    {
                        certificate = new X509Certificate2(
                            privateKeyFile.FullName,
                            (password == null) ? String.Empty : password,
                            X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
                        rsa = certificate.GetRSAPrivateKey();
                    }
                    catch (Exception)
                    {
                        certificate = new X509Certificate2(
                            privateKeyFile.FullName,
                            (password == null) ? String.Empty : password,
                            X509KeyStorageFlags.Exportable | X509KeyStorageFlags.DefaultKeySet);
                        rsa = certificate.GetRSAPrivateKey();
                    }
                    if (rsa != null)
                    {
                        int    inputBlockSize = rsa.KeySize / 8 - 42;
                        byte[] bytes1         = rsa.Encrypt(new byte[inputBlockSize], RSAEncryptionPadding.OaepSHA1);
                        byte[] bytes2         = rsa.Decrypt(bytes1, RSAEncryptionPadding.OaepSHA1);
                        if (bytes2 != null)
                        {
                            // Utils.Trace(1, "RSA: {0}", certificate.Thumbprint);
                            return(certificate);
                        }
                    }
                }
                catch (Exception e)
                {
                    Utils.Trace(e, "Could not load private key for certificate " + subjectName);
                }
            }

            return(null);
        }
Example #13
0
        private static ServiceResult CheckChainStatus(X509ChainStatus status, CertificateIdentifier id, CertificateIdentifier issuer, bool isIssuer)
        {
            switch (status.Status)
            {
            case X509ChainStatusFlags.NotValidForUsage:
            {
                return(ServiceResult.Create(
                           (isIssuer) ? StatusCodes.BadCertificateUseNotAllowed : StatusCodes.BadCertificateIssuerUseNotAllowed,
                           "Certificate may not be used as an application instance certificate. {0}: {1}",
                           status.Status,
                           status.StatusInformation));
            }

            case X509ChainStatusFlags.NoError:
            case X509ChainStatusFlags.OfflineRevocation:
            case X509ChainStatusFlags.InvalidBasicConstraints:
            case X509ChainStatusFlags.PartialChain:
            {
                break;
            }

            case X509ChainStatusFlags.UntrustedRoot:
            {
                // ignore this error because the root check is done
                // by looking the certificate up in the trusted issuer stores passed to the validator.
                // the ChainStatus uses the Windows trusted issuer stores.
                break;
            }

            case X509ChainStatusFlags.RevocationStatusUnknown:
            {
                if (issuer != null)
                {
                    if ((issuer.ValidationOptions & CertificateValidationOptions.SuppressRevocationStatusUnknown) != 0)
                    {
                        break;
                    }
                }

                // check for meaning less errors for self-signed certificates.
                if (id.Certificate != null && Utils.CompareDistinguishedName(id.Certificate.Subject, id.Certificate.Subject))
                {
                    break;
                }

                return(ServiceResult.Create(
                           (isIssuer) ? StatusCodes.BadCertificateIssuerRevocationUnknown : StatusCodes.BadCertificateRevocationUnknown,
                           "Certificate revocation status cannot be verified. {0}: {1}",
                           status.Status,
                           status.StatusInformation));
            }

            case X509ChainStatusFlags.Revoked:
            {
                return(ServiceResult.Create(
                           (isIssuer) ? StatusCodes.BadCertificateIssuerRevoked : StatusCodes.BadCertificateRevoked,
                           "Certificate has been revoked. {0}: {1}",
                           status.Status,
                           status.StatusInformation));
            }

            case X509ChainStatusFlags.NotTimeNested:
            {
                if (id != null && ((id.ValidationOptions & CertificateValidationOptions.SuppressCertificateExpired) != 0))
                {
                    break;
                }

                return(ServiceResult.Create(
                           StatusCodes.BadCertificateIssuerTimeInvalid,
                           "Certificate issuer validatity time does not overhas is expired or not yet valid. {0}: {1}",
                           status.Status,
                           status.StatusInformation));
            }


            case X509ChainStatusFlags.NotTimeValid:
            {
                if (id != null && ((id.ValidationOptions & CertificateValidationOptions.SuppressCertificateExpired) != 0))
                {
                    break;
                }

                return(ServiceResult.Create(
                           (isIssuer) ? StatusCodes.BadCertificateIssuerTimeInvalid : StatusCodes.BadCertificateTimeInvalid,
                           "Certificate has is expired or not yet valid. {0}: {1}",
                           status.Status,
                           status.StatusInformation));
            }

            default:
            {
                return(ServiceResult.Create(
                           StatusCodes.BadCertificateInvalid,
                           "Certificate validation failed. {0}: {1}",
                           status.Status,
                           status.StatusInformation));
            }
            }

            return(null);
        }
Example #14
0
        /// <summary>
        /// Throws an exception if validation fails.
        /// </summary>
        /// <param name="certificates">The certificates to be checked.</param>
        /// <exception cref="ServiceResultException">If certificate[0] cannot be accepted</exception>
        protected virtual async Task InternalValidate(X509Certificate2Collection certificates)
        {
            X509Certificate2 certificate = certificates[0];

            // check for previously validated certificate.
            X509Certificate2 certificate2 = null;

            if (m_validatedCertificates.TryGetValue(certificate.Thumbprint, out certificate2))
            {
                if (Utils.IsEqual(certificate2.RawData, certificate.RawData))
                {
                    return;
                }
            }

            CertificateIdentifier trustedCertificate = await GetTrustedCertificate(certificate);

            // get the issuers (checks the revocation lists if using directory stores).
            List <CertificateIdentifier> issuers = new List <CertificateIdentifier>();
            bool isIssuerTrusted = await GetIssuers(certificates, issuers);

            // setup policy chain
            X509ChainPolicy policy = new X509ChainPolicy();

            policy.RevocationFlag    = X509RevocationFlag.EntireChain;
            policy.RevocationMode    = X509RevocationMode.NoCheck;
            policy.VerificationFlags = X509VerificationFlags.NoFlag;

            foreach (CertificateIdentifier issuer in issuers)
            {
                if ((issuer.ValidationOptions & CertificateValidationOptions.SuppressRevocationStatusUnknown) != 0)
                {
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown;
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreCtlSignerRevocationUnknown;
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreEndRevocationUnknown;
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreRootRevocationUnknown;
                }

                // we did the revocation check in the GetIssuers call. No need here.
                policy.RevocationMode = X509RevocationMode.NoCheck;
                policy.ExtraStore.Add(issuer.Certificate);
            }

            // build chain.
            X509Chain chain = new X509Chain();

            chain.ChainPolicy = policy;
            chain.Build(certificate);

            // check the chain results.
            CertificateIdentifier target = trustedCertificate;

            if (target == null)
            {
                target = new CertificateIdentifier(certificate);
            }

            for (int ii = 0; ii < chain.ChainElements.Count; ii++)
            {
                X509ChainElement element = chain.ChainElements[ii];

                CertificateIdentifier issuer = null;

                if (ii < issuers.Count)
                {
                    issuer = issuers[ii];
                }

                // check for chain status errors.
                foreach (X509ChainStatus status in element.ChainElementStatus)
                {
                    ServiceResult result = CheckChainStatus(status, target, issuer, (ii != 0));

                    if (ServiceResult.IsBad(result))
                    {
                        // check untrusted certificates.
                        if (trustedCertificate == null)
                        {
                            throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed);
                        }

                        throw new ServiceResultException(result);
                    }
                }

                if (issuer != null)
                {
                    target = issuer;
                }
            }

            bool issuedByCA = !Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer);

            // check if certificate issuer is trusted.
            if (issuedByCA && !isIssuerTrusted)
            {
                if (m_applicationCertificate == null || !Utils.IsEqual(m_applicationCertificate.RawData, certificate.RawData))
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadCertificateUntrusted,
                              "Certificate issuer is not trusted.\r\nSubjectName: {0}\r\nIssuerName: {1}",
                              certificate.SubjectName.Name,
                              certificate.IssuerName.Name);
                }
            }

            // check if certificate is trusted.
            if (trustedCertificate == null && !isIssuerTrusted)
            {
                if (m_applicationCertificate == null || !Utils.IsEqual(m_applicationCertificate.RawData, certificate.RawData))
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadCertificateUntrusted,
                              "Certificate is not trusted.\r\nSubjectName: {0}\r\nIssuerName: {1}",
                              certificate.SubjectName.Name,
                              certificate.IssuerName.Name);
                }
            }
        }
Example #15
0
        /// <summary>
        /// Returns the issuers for the certificates.
        /// </summary>
        public bool GetIssuersWithChainSupportEnabled(X509Certificate2Collection certificates,
                                                      List <CertificateIdentifier> issuers)
        {
            bool isTrusted                    = false;
            bool isChainComplete              = false;
            CertificateIdentifier issuer      = null;
            X509Certificate2      certificate = certificates[0];

            // application certificate is trusted
            CertificateIdentifier trustedCertificate = GetTrustedCertificate(certificate);

            if (trustedCertificate != null)
            {
                isTrusted = true;
            }

            if (Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer))
            {
                if (!isTrusted)
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadCertificateUntrusted,
                              "Self Signed Certificate is not trusted.\r\nIssuerName: {0}",
                              certificate.IssuerName.Name);
                }

                return(isTrusted);
            }

            CertificateIdentifierCollection collection = new CertificateIdentifierCollection();

            for (int ii = 1; ii < certificates.Count; ii++)
            {
                collection.Add(new CertificateIdentifier(certificates[ii]));
            }

            do
            {
                issuer = GetIssuer(certificate, m_trustedCertificateList, m_trustedCertificateStore, true);
                if (issuer != null)
                {
                    isTrusted = true;
                }

                if (issuer == null)
                {
                    issuer = GetIssuer(certificate, m_issuerCertificateList, m_issuerCertificateStore, true);

                    if (issuer == null)
                    {
                        issuer = GetIssuer(certificate, collection, null, true);
                    }
                }

                if (issuer != null)
                {
                    //isTrusted = true;

                    issuers.Add(issuer);
                    certificate = issuer.Find(false);

                    // check for root.
                    if (Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer))
                    {
                        isChainComplete = true;
                        break;
                    }
                }
                else
                {
                    isTrusted = false;
                }
            } while (issuer != null);

            if (!isChainComplete)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadSecurityChecksFailed,
                          "Certificate chain not complete.\r\nSubjectName: {0}\r\nIssuerName: {1}",
                          certificates[0].SubjectName.Name,
                          certificates[0].IssuerName.Name);
            }

            if (!isTrusted)
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadCertificateUntrusted,
                          "Certificate issuer is not trusted.\r\nSubjectName: {0}\r\nIssuerName: {1}",
                          certificates[0].SubjectName.Name,
                          certificates[0].IssuerName.Name);
            }

            return(isTrusted);
        }
        /// <summary>
        /// Loads the private key from a PFX file in the certificate store.
        /// </summary>
        public X509Certificate2 LoadPrivateKey(string thumbprint, string subjectName, string password)
        {
            if (m_certificateSubdir == null || !m_certificateSubdir.Exists)
            {
                return(null);
            }

            if (string.IsNullOrEmpty(thumbprint) && string.IsNullOrEmpty(subjectName))
            {
                return(null);
            }

            foreach (FileInfo file in m_certificateSubdir.GetFiles("*.der"))
            {
                try
                {
                    X509Certificate2 certificate = new X509Certificate2(file.FullName);

                    if (!String.IsNullOrEmpty(thumbprint))
                    {
                        if (!string.Equals(certificate.Thumbprint, thumbprint, StringComparison.CurrentCultureIgnoreCase))
                        {
                            continue;
                        }
                    }

                    if (!String.IsNullOrEmpty(subjectName))
                    {
                        if (!Utils.CompareDistinguishedName(subjectName, certificate.Subject))
                        {
                            if (subjectName.Contains("="))
                            {
                                continue;
                            }

                            if (!Utils.ParseDistinguishedName(certificate.Subject).Any(s => s.Equals("CN=" + subjectName, StringComparison.OrdinalIgnoreCase)))
                            {
                                continue;
                            }
                        }
                    }

                    string fileRoot = file.Name.Substring(0, file.Name.Length - file.Extension.Length);

                    StringBuilder filePath = new StringBuilder();
                    filePath.Append(m_privateKeySubdir.FullName);
                    filePath.Append(Path.DirectorySeparatorChar);
                    filePath.Append(fileRoot);

                    FileInfo privateKeyFile = new FileInfo(filePath.ToString() + ".pfx");
                    password = password ?? String.Empty;
                    try
                    {
                        certificate = new X509Certificate2(
                            privateKeyFile.FullName,
                            password,
                            X509KeyStorageFlags.Exportable | X509KeyStorageFlags.UserKeySet);
                        if (CertificateFactory.VerifyRSAKeyPair(certificate, certificate, true))
                        {
                            return(certificate);
                        }
                    }
                    catch (Exception)
                    {
                        certificate = new X509Certificate2(
                            privateKeyFile.FullName,
                            password,
                            X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
                        if (CertificateFactory.VerifyRSAKeyPair(certificate, certificate, true))
                        {
                            return(certificate);
                        }
                    }
                }
                catch (Exception e)
                {
                    Utils.Trace(e, "Could not load private key for certificate " + subjectName);
                }
            }

            return(null);
        }
Example #17
0
        /// <summary>
        /// Loads the private key from a PFX file in the certificate store.
        /// </summary>
        public X509Certificate2 LoadPrivateKey(string thumbprint, string subjectName, System.Security.SecureString password)
        {
            if (m_certificateSubdir == null || !m_certificateSubdir.Exists)
            {
                return(null);
            }

            if (string.IsNullOrEmpty(thumbprint) && string.IsNullOrEmpty(subjectName))
            {
                return(null);
            }

            foreach (FileInfo file in m_certificateSubdir.GetFiles("*.der"))
            {
                try
                {
                    X509Certificate2 certificate = new X509Certificate2(file.FullName);

                    if (!String.IsNullOrEmpty(thumbprint))
                    {
                        if (!string.Equals(certificate.Thumbprint, thumbprint, StringComparison.CurrentCultureIgnoreCase))
                        {
                            continue;
                        }
                    }

                    if (!String.IsNullOrEmpty(subjectName))
                    {
                        if (!Utils.CompareDistinguishedName(subjectName, certificate.Subject))
                        {
                            if (subjectName.Contains("=") || !certificate.Subject.Contains("CN=" + subjectName))
                            {
                                continue;
                            }
                        }
                    }

                    string fileRoot = file.Name.Substring(0, file.Name.Length - file.Extension.Length);

                    StringBuilder filePath = new StringBuilder();
                    filePath.Append(m_privateKeySubdir.FullName);
                    filePath.Append("\\");
                    filePath.Append(fileRoot);

                    FileInfo privateKeyFile = new FileInfo(filePath.ToString() + ".pfx");

                    certificate = new X509Certificate2(
                        privateKeyFile.FullName,
                        (password == null)?new System.Security.SecureString():password,
                        X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);

                    System.Security.Cryptography.RSACryptoServiceProvider rsa = certificate.PrivateKey as System.Security.Cryptography.RSACryptoServiceProvider;

                    if (rsa != null && rsa.CspKeyContainerInfo.Exportable)
                    {
                        int    inputBlockSize = rsa.KeySize / 8 - 42;
                        byte[] bytes1         = rsa.Encrypt(new byte[inputBlockSize], true);
                        byte[] bytes2         = rsa.Decrypt(bytes1, true);

                        if (bytes2 != null)
                        {
                            // Utils.Trace(1, "RSA: {0}", certificate.Thumbprint);
                            return(certificate);
                        }
                    }

                    return(certificate);
                }
                catch (Exception e)
                {
                    Utils.Trace(e, "Could not load private key certificate from file: {0}", file.Name);
                }
            }

            return(null);
        }
        /// <summary>
        /// Throws an exception if validation fails.
        /// </summary>
        /// <param name="certificates">The certificates to be checked.</param>
        /// <exception cref="ServiceResultException">If certificate[0] cannot be accepted</exception>
        protected virtual async Task InternalValidate(X509Certificate2Collection certificates)
        {
            X509Certificate2 certificate = certificates[0];

            // check for previously validated certificate.
            X509Certificate2 certificate2 = null;

            if (m_validatedCertificates.TryGetValue(certificate.Thumbprint, out certificate2))
            {
                if (Utils.IsEqual(certificate2.RawData, certificate.RawData))
                {
                    return;
                }
            }

            CertificateIdentifier trustedCertificate = await GetTrustedCertificate(certificate);

            // get the issuers (checks the revocation lists if using directory stores).
            List <CertificateIdentifier> issuers = new List <CertificateIdentifier>();
            bool isIssuerTrusted = await GetIssuers(certificates, issuers);

            // setup policy chain
            X509ChainPolicy policy = new X509ChainPolicy();

            policy.RevocationFlag    = X509RevocationFlag.EntireChain;
            policy.RevocationMode    = X509RevocationMode.NoCheck;
            policy.VerificationFlags = X509VerificationFlags.NoFlag;

            foreach (CertificateIdentifier issuer in issuers)
            {
                if ((issuer.ValidationOptions & CertificateValidationOptions.SuppressRevocationStatusUnknown) != 0)
                {
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown;
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreCtlSignerRevocationUnknown;
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreEndRevocationUnknown;
                    policy.VerificationFlags |= X509VerificationFlags.IgnoreRootRevocationUnknown;
                }

                // we did the revocation check in the GetIssuers call. No need here.
                policy.RevocationMode = X509RevocationMode.NoCheck;
                policy.ExtraStore.Add(issuer.Certificate);
            }

            // build chain.
            bool      chainStatusChecked = false;
            X509Chain chain = new X509Chain();

            chain.ChainPolicy = policy;
            chain.Build(certificate);

            // check the chain results.
            CertificateIdentifier target = trustedCertificate;

            if (target == null)
            {
                target = new CertificateIdentifier(certificate);
            }

            for (int ii = 0; ii < chain.ChainElements.Count; ii++)
            {
                X509ChainElement element = chain.ChainElements[ii];

                CertificateIdentifier issuer = null;

                if (ii < issuers.Count)
                {
                    issuer = issuers[ii];
                }

                // check for chain status errors.
                foreach (X509ChainStatus status in element.ChainElementStatus)
                {
                    ServiceResult result = CheckChainStatus(status, target, issuer, (ii != 0));

                    if (ServiceResult.IsBad(result))
                    {
                        // check untrusted certificates.
                        if (trustedCertificate == null)
                        {
                            throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed);
                        }

                        throw new ServiceResultException(result);
                    }
                    chainStatusChecked = true;
                }

                if (issuer != null)
                {
                    target = issuer;
                }
            }

            // check whether the chain is complete (if there is a chain)
            bool issuedByCA      = !Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer);
            bool chainIncomplete = false;

            if (issuers.Count > 0)
            {
                var rootCertificate = issuers[issuers.Count - 1].Certificate;
                if (!Utils.CompareDistinguishedName(rootCertificate.Subject, rootCertificate.Issuer))
                {
                    chainIncomplete = true;
                }
            }
            else
            {
                if (issuedByCA)
                {
                    // no issuer found at all
                    chainIncomplete = true;
                }
            }

            if (issuedByCA && (!chainStatusChecked || chainIncomplete))
            {
                throw ServiceResultException.Create(
                          StatusCodes.BadCertificateChainIncomplete,
                          "Certificate chain validation incomplete.\r\nSubjectName: {0}\r\nIssuerName: {1}",
                          certificate.SubjectName.Name,
                          certificate.IssuerName.Name);
            }

            // check if certificate issuer is trusted.
            if (issuedByCA && !isIssuerTrusted && trustedCertificate == null)
            {
                if (m_applicationCertificate == null || !Utils.IsEqual(m_applicationCertificate.RawData, certificate.RawData))
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadCertificateUntrusted,
                              "Certificate issuer is not trusted.\r\nSubjectName: {0}\r\nIssuerName: {1}",
                              certificate.SubjectName.Name,
                              certificate.IssuerName.Name);
                }
            }

            // check if certificate is trusted.
            if (trustedCertificate == null && !isIssuerTrusted)
            {
                if (m_applicationCertificate == null || !Utils.IsEqual(m_applicationCertificate.RawData, certificate.RawData))
                {
                    throw ServiceResultException.Create(
                              StatusCodes.BadCertificateUntrusted,
                              "Certificate is not trusted.\r\nSubjectName: {0}\r\nIssuerName: {1}",
                              certificate.SubjectName.Name,
                              certificate.IssuerName.Name);
                }
            }

            // check if certificate is valid for use as app/sw or user cert
            X509KeyUsageFlags certificateKeyUsage = CertificateFactory.GetKeyUsage(certificate);

            if ((certificateKeyUsage & X509KeyUsageFlags.DataEncipherment) == 0)
            {
                throw new ServiceResultException(StatusCodes.BadCertificateUseNotAllowed, "Usage of certificate is not allowed.");
            }

            // check if minimum requirements are met
            if (m_rejectSHA1SignedCertificates && IsSHA1SignatureAlgorithm(certificate.SignatureAlgorithm))
            {
                throw new ServiceResultException(StatusCodes.BadCertificatePolicyCheckFailed, "SHA1 signed certificates are not trusted");
            }

            if (certificate.GetRSAPublicKey().KeySize < m_minimumCertificateKeySize)
            {
                throw new ServiceResultException(StatusCodes.BadCertificatePolicyCheckFailed, "Certificate doesn't meet minimum key length requirement");
            }
        }
        /// <summary>
        /// Returns the certificate information for a trusted issuer certificate.
        /// </summary>
        private async Task <CertificateIdentifier> GetIssuer(
            X509Certificate2 certificate,
            CertificateIdentifierCollection explicitList,
            CertificateStoreIdentifier certificateStore,
            bool checkRecovationStatus)
        {
            // check if self-signed.
            if (Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer))
            {
                return(null);
            }

            string subjectName  = certificate.IssuerName.Name;
            string keyId        = null;
            string serialNumber = null;

            // find the authority key identifier.
            X509AuthorityKeyIdentifierExtension authority = FindAuthorityKeyIdentifier(certificate);

            if (authority != null)
            {
                keyId        = authority.KeyId;
                serialNumber = authority.SerialNumber;
            }

            // check in explicit list.
            if (explicitList != null)
            {
                for (int ii = 0; ii < explicitList.Count; ii++)
                {
                    X509Certificate2 issuer = await explicitList[ii].Find(false);

                    if (issuer != null)
                    {
                        if (!IsIssuerAllowed(issuer))
                        {
                            continue;
                        }

                        if (Match(issuer, subjectName, serialNumber, keyId))
                        {
                            // can't check revocation.
                            return(new CertificateIdentifier(issuer, CertificateValidationOptions.SuppressRevocationStatusUnknown));
                        }
                    }
                }
            }

            // check in certificate store.
            if (certificateStore != null)
            {
                ICertificateStore store = certificateStore.OpenStore();

                try
                {
                    X509Certificate2Collection certificates = await store.Enumerate();

                    for (int ii = 0; ii < certificates.Count; ii++)
                    {
                        X509Certificate2 issuer = certificates[ii];

                        if (issuer != null)
                        {
                            if (!IsIssuerAllowed(issuer))
                            {
                                continue;
                            }

                            if (Match(issuer, subjectName, serialNumber, keyId))
                            {
                                CertificateValidationOptions options = certificateStore.ValidationOptions;

                                // already checked revocation for file based stores. windows based stores always suppress.
                                options |= CertificateValidationOptions.SuppressRevocationStatusUnknown;

                                if (checkRecovationStatus)
                                {
                                    StatusCode status = store.IsRevoked(issuer, certificate);

                                    if (StatusCode.IsBad(status) && status != StatusCodes.BadNotSupported)
                                    {
                                        if (status == StatusCodes.BadCertificateRevocationUnknown)
                                        {
                                            if (CertificateFactory.IsCertificateAuthority(certificate))
                                            {
                                                status.Code = StatusCodes.BadCertificateIssuerRevocationUnknown;
                                            }

                                            if (m_rejectUnknownRevocationStatus)
                                            {
                                                throw new ServiceResultException(status);
                                            }
                                        }
                                        else
                                        {
                                            throw new ServiceResultException(status);
                                        }
                                    }
                                }

                                return(new CertificateIdentifier(certificates[ii], options));
                            }
                        }
                    }
                }
                finally
                {
                    store.Close();
                }
            }

            // not a trusted issuer.
            return(null);
        }
Example #20
0
        /// <summary>
        /// Returns true the certificate is in the CRL.
        /// </summary>
        public bool IsRevoked(X509Certificate2 certificate)
        {
            IntPtr pData1      = IntPtr.Zero;
            IntPtr pData2      = IntPtr.Zero;
            int    dwDataSize1 = 0;

            try
            {
                // check that the issuer matches.
                if (m_issuer == null || !Utils.CompareDistinguishedName(certificate.Issuer, m_issuer.Subject))
                {
                    throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Certificate was not created by the CRL issuer.");
                }

                // get the cert info for the target certificate.
                Win32.CERT_CONTEXT context = (Win32.CERT_CONTEXT)Marshal.PtrToStructure(certificate.Handle, typeof(Win32.CERT_CONTEXT));

                // calculate amount of memory required.
                int bResult = Win32.CryptDecodeObjectEx(
                    Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
                    (IntPtr)Win32.X509_CERT_CRL_TO_BE_SIGNED,
                    m_signedCrl.ToBeSigned.pbData,
                    m_signedCrl.ToBeSigned.cbData,
                    Win32.CRYPT_DECODE_NOCOPY_FLAG,
                    IntPtr.Zero,
                    pData1,
                    ref dwDataSize1);

                if (bResult == 0)
                {
                    throw Win32.GetLastError(StatusCodes.BadDecodingError, "Could not get size for CRL_INFO.");
                }

                // allocate memory.
                pData1 = Marshal.AllocHGlobal(dwDataSize1);

                // decode blob.
                bResult = Win32.CryptDecodeObjectEx(
                    Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
                    (IntPtr)Win32.X509_CERT_CRL_TO_BE_SIGNED,
                    m_signedCrl.ToBeSigned.pbData,
                    m_signedCrl.ToBeSigned.cbData,
                    Win32.CRYPT_DECODE_NOCOPY_FLAG,
                    IntPtr.Zero,
                    pData1,
                    ref dwDataSize1);

                if (bResult == 0)
                {
                    throw Win32.GetLastError(StatusCodes.BadDecodingError, "Could not decode CRL_INFO.");
                }

                IntPtr[] pCRLs = new IntPtr[] { pData1 };
                pData2 = Marshal.AllocHGlobal(IntPtr.Size * pCRLs.Length);
                Marshal.Copy(pCRLs, 0, pData2, pCRLs.Length);

                // check for revocation.
                bResult = Win32.CertVerifyCRLRevocation(
                    Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
                    context.pCertInfo,
                    pCRLs.Length,
                    pData2);

                if (bResult == 0)
                {
                    return(true);
                }

                // not revoked.
                return(false);
            }
            finally
            {
                if (pData1 != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pData1);
                    pData1 = IntPtr.Zero;
                }

                if (pData2 != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pData2);
                    pData2 = IntPtr.Zero;
                }
            }
        }