Beispiel #1
0
		public X509KeyUsageExtension (X509KeyUsageFlags keyUsages, bool critical)
		{
			_oid = new Oid (oid, friendlyName);
			base.Critical = critical;
			_keyUsages = GetValidFlags (keyUsages);
			RawData = Encode ();
		}
        public unsafe void DecodeX509KeyUsageExtension(byte[] encoded, out X509KeyUsageFlags keyUsages)
        {
            using (SafeAsn1BitStringHandle bitString = Interop.libcrypto.OpenSslD2I(Interop.libcrypto.d2i_ASN1_BIT_STRING, encoded))
            {
                Interop.libcrypto.CheckValidOpenSslHandle(bitString);

                byte[] decoded = Interop.NativeCrypto.GetAsn1StringBytes(bitString.DangerousGetHandle());

                // Only 9 bits are defined.
                if (decoded.Length > 2)
                {
                    throw new CryptographicException();
                }

                // DER encodings of BIT_STRING values number the bits as
                // 01234567 89 (big endian), plus a number saying how many bits of the last byte were padding.
                //
                // So digitalSignature (0) doesn't mean 2^0 (0x01), it means the most significant bit
                // is set in this byte stream.
                //
                // BIT_STRING values are compact.  So a value of cRLSign (6) | keyEncipherment (2), which
                // is 0b0010001 => 0b0010 0010 (1 bit padding) => 0x22 encoded is therefore
                // 0x02 (length remaining) 0x01 (1 bit padding) 0x22.
                //
                // OpenSSL's d2i_ASN1_BIT_STRING is going to take that, and return 0x22.  0x22 lines up
                // exactly with X509KeyUsageFlags.CrlSign (0x20) | X509KeyUsageFlags.KeyEncipherment (0x02)
                //
                // Once the decipherOnly (8) bit is added to the mix, the values become:
                // 0b001000101 => 0b0010 0010 1000 0000 (7 bits padding)
                // { 0x03 0x07 0x22 0x80 }
                // And OpenSSL returns new byte[] { 0x22 0x80 }
                //
                // The value of X509KeyUsageFlags.DecipherOnly is 0x8000.  0x8000 in a little endian
                // representation is { 0x00 0x80 }.  This means that the DER storage mechanism has effectively
                // ended up being little-endian for BIT_STRING values.  Untwist the bytes, and now the bits all
                // line up with the existing X509KeyUsageFlags.

                int value = 0;

                if (decoded.Length > 0)
                {
                    value = decoded[0];
                }

                if (decoded.Length > 1)
                {
                    value |= decoded[1] << 8;
                }

                keyUsages = (X509KeyUsageFlags)value;
            }
        }
        private X509CertificateKeyUsage(X509KeyUsageFlags keyUsage, string description)
        {
            if (Map == null)
            {
                Map = new Dictionary<X509KeyUsageFlags, X509CertificateKeyUsage>();
            }


            KeyUsage = keyUsage;
            Description = description;

            Map[KeyUsage] = this;
        }
 private static unsafe byte[] EncodeExtension(X509KeyUsageFlags keyUsages)
 {
     CAPIBase.CRYPT_BIT_BLOB crypt_bit_blob = new CAPIBase.CRYPT_BIT_BLOB {
         cbData = 2,
         pbData = new IntPtr((void*) &keyUsages),
         cUnusedBits = 0
     };
     byte[] encodedData = null;
     if (!CAPI.EncodeObject("2.5.29.15", new IntPtr((void*) &crypt_bit_blob), out encodedData))
     {
         throw new CryptographicException(Marshal.GetLastWin32Error());
     }
     return encodedData;
 }
 public byte[] EncodeX509KeyUsageExtension(X509KeyUsageFlags keyUsages)
 {
     unsafe
     {
         ushort keyUsagesAsShort = (ushort)keyUsages;
         CRYPT_BIT_BLOB blob = new CRYPT_BIT_BLOB()
         {
             cbData = 2,
             pbData = (byte*)&keyUsagesAsShort,
             cUnusedBits = 0,
         };
         return Interop.crypt32.EncodeObject(CryptDecodeObjectStructType.X509_KEY_USAGE, &blob);
     }
 }
Beispiel #6
0
    /// <summary>
    /// Verify RSA key pair of two certificates.
    /// </summary>
    public static bool VerifyRSAKeyPair(
        X509Certificate2 certWithPublicKey,
        X509Certificate2 certWithPrivateKey,
        bool throwOnError = false)
    {
        bool result        = false;
        RSA  rsaPrivateKey = null;
        RSA  rsaPublicKey  = null;

        try
        {
            // verify the public and private key match
            rsaPrivateKey = certWithPrivateKey.GetRSAPrivateKey();
            rsaPublicKey  = certWithPublicKey.GetRSAPublicKey();
            X509KeyUsageFlags keyUsage = GetKeyUsage(certWithPublicKey);
            if ((keyUsage & X509KeyUsageFlags.DataEncipherment) != 0)
            {
                result = VerifyRSAKeyPairCrypt(rsaPublicKey, rsaPrivateKey);
            }
            else if ((keyUsage & X509KeyUsageFlags.DigitalSignature) != 0)
            {
                result = VerifyRSAKeyPairSign(rsaPublicKey, rsaPrivateKey);
            }
            else
            {
                throw new CryptographicException("Don't know how to verify the public/private key pair.");
            }
        }
        catch (Exception e)
        {
            if (throwOnError)
            {
                throw e;
            }
        }
        finally
        {
            RsaUtils.RSADispose(rsaPrivateKey);
            RsaUtils.RSADispose(rsaPublicKey);
            if (!result && throwOnError)
            {
                throw new CryptographicException("The public/private key pair in the certficates do not match.");
            }
        }
        return(result);
    }
        public byte[] EncodeX509KeyUsageExtension(X509KeyUsageFlags keyUsages)
        {
            // The numeric values of X509KeyUsageFlags mean that if we interpret it as a little-endian
            // ushort it will line up with the flags in the spec.
            ushort ushortValue = unchecked ((ushort)(int)keyUsages);

            byte[] data = BitConverter.GetBytes(ushortValue);

            // RFC 3280 section 4.2.1.3 (https://tools.ietf.org/html/rfc3280#section-4.2.1.3) defines
            // digitalSignature (0) through decipherOnly (8), making 9 named bits.
            const int namedBitsCount = 9;

            // The expected output of this method isn't the SEQUENCE value, but just the payload bytes.
            byte[][] segments = DerEncoder.SegmentedEncodeNamedBitList(data, namedBitsCount);
            Debug.Assert(segments.Length == 3);
            return(ConcatenateArrays(segments));
        }
Beispiel #8
0
        public static bool IsForUsage(this X509Certificate2 certificate, X509KeyUsageFlags usageFlag)
        {
            ThrowHelpers.CheckNull(nameof(certificate), certificate);

            foreach (X509Extension certificateExtension in certificate.Extensions)
            {
                if (certificateExtension is X509KeyUsageExtension usage)
                {
                    if (usage.KeyUsages.HasFlag(usageFlag))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        public X509Certificate2 NewECDsaSelfSignedCertificate(
            BasicConstraints basicConstraints,
            ValidityPeriod validityPeriod,
            SubjectAlternativeName subjectAlternativeName,
            OidCollection enhancedKeyUsages,
            X509KeyUsageFlags x509KeyUsageFlags,
            CertificateRequest request)
        {
            X509Certificate2 generatedCertificate = SelfSignedConfiguration(
                basicConstraints,
                validityPeriod,
                subjectAlternativeName,
                enhancedKeyUsages,
                x509KeyUsageFlags,
                request);

            return(generatedCertificate);
        }
        public void FindByKeyUsage(X509KeyUsageFlags keyUsage)
        {
            FindCore(
                cert =>
            {
                X509Extension ext = FindExtension(cert, Oids.KeyUsage);

                if (ext == null)
                {
                    // A certificate with no key usage extension is considered valid for all key usages.
                    return(true);
                }

                var kuExt = (X509KeyUsageExtension)ext;

                return((kuExt.KeyUsages & keyUsage) == keyUsage);
            });
        }
Beispiel #11
0
        private static string CreateCert(string cn, X509KeyUsageFlags usage)
        {
            using var algo = RSA.Create(keySizeInBits: 4096);
            var request = new CertificateRequest(
                new X500DistinguishedName($"CN={cn}"),
                algo,
                HashAlgorithmName.SHA256,
                RSASignaturePadding.Pkcs1
                );

            request.CertificateExtensions.Add(
                new X509KeyUsageExtension(usage, critical: true)
                );

            var cert = request.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(4));
            var data = cert.Export(X509ContentType.Pfx, string.Empty);

            return(Convert.ToBase64String(data));
        }
Beispiel #12
0
        public virtual void DecodeX509KeyUsageExtension(byte[] encoded, out X509KeyUsageFlags keyUsages)
        {
            KeyUsageFlagsAsn keyUsagesAsn;

            try
            {
                AsnReader reader = new AsnReader(encoded, AsnEncodingRules.BER);
                keyUsagesAsn = reader.ReadNamedBitListValue <KeyUsageFlagsAsn>();
                reader.ThrowIfNotEmpty();
            }
            catch (AsnContentException e)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
            }

            // DER encodings of BIT_STRING values number the bits as
            // 01234567 89 (big endian), plus a number saying how many bits of the last byte were padding.
            //
            // So digitalSignature (0) doesn't mean 2^0 (0x01), it means the most significant bit
            // is set in this byte stream.
            //
            // BIT_STRING values are compact.  So a value of cRLSign (6) | keyEncipherment (2), which
            // is 0b0010001 => 0b0010 0010 (1 bit padding) => 0x22 encoded is therefore
            // 0x02 (length remaining) 0x01 (1 bit padding) 0x22.
            //
            // We will read that, and return 0x22.  0x22 lines up
            // exactly with X509KeyUsageFlags.CrlSign (0x20) | X509KeyUsageFlags.KeyEncipherment (0x02)
            //
            // Once the decipherOnly (8) bit is added to the mix, the values become:
            // 0b001000101 => 0b0010 0010 1000 0000 (7 bits padding)
            // { 0x03 0x07 0x22 0x80 }
            // And we read new byte[] { 0x22 0x80 }
            //
            // The value of X509KeyUsageFlags.DecipherOnly is 0x8000.  0x8000 in a little endian
            // representation is { 0x00 0x80 }.  This means that the DER storage mechanism has effectively
            // ended up being little-endian for BIT_STRING values.  Untwist the bytes, and now the bits all
            // line up with the existing X509KeyUsageFlags.

            keyUsages =
                (X509KeyUsageFlags)ReverseBitOrder((byte)keyUsagesAsn) |
                (X509KeyUsageFlags)(ReverseBitOrder((byte)(((ushort)keyUsagesAsn >> 8))) << 8);
        }
 public void DecodeX509KeyUsageExtension(byte[] encoded, out X509KeyUsageFlags keyUsages)
 {
     unsafe
     {
         uint keyUsagesAsUint = 0;
         encoded.DecodeObject(
             CryptDecodeObjectStructType.X509_KEY_USAGE,
             delegate(void *pvDecoded)
         {
             CRYPT_BIT_BLOB *pBlob = (CRYPT_BIT_BLOB *)pvDecoded;
             keyUsagesAsUint       = 0;
             if (pBlob->pbData != null)
             {
                 keyUsagesAsUint = *(uint *)(pBlob->pbData);
             }
         }
             );
         keyUsages = (X509KeyUsageFlags)keyUsagesAsUint;
     }
 }
Beispiel #14
0
        public static bool IsForUsage(this X509Certificate2 certificate, X509KeyUsageFlags usageFlag)
        {
            if (certificate == null)
            {
                throw new ArgumentNullException(nameof(certificate));
            }

            foreach (X509Extension certificateExtension in certificate.Extensions)
            {
                if (certificateExtension is X509KeyUsageExtension usage)
                {
                    if (usage.KeyUsages.HasFlag(usageFlag))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
 public void DecodeX509KeyUsageExtension(byte[] encoded, out X509KeyUsageFlags keyUsages)
 {
     unsafe
     {
         uint keyUsagesAsUint = 0;
         encoded.DecodeObject(
             CryptDecodeObjectStructType.X509_KEY_USAGE,
             delegate (void* pvDecoded)
             {
                 CRYPT_BIT_BLOB* pBlob = (CRYPT_BIT_BLOB*)pvDecoded;
                 keyUsagesAsUint = 0;
                 if (pBlob->pbData != null)
                 {
                     keyUsagesAsUint = *(uint*)(pBlob->pbData);
                 }
             }
         );
         keyUsages = (X509KeyUsageFlags)keyUsagesAsUint;
     }
 }
Beispiel #16
0
        /// <summary>
        /// Verify ECDsa key pair of two certificates.
        /// </summary>
        public static bool VerifyECDsaKeyPair(
            X509Certificate2 certWithPublicKey,
            X509Certificate2 certWithPrivateKey,
            bool throwOnError = false)
        {
            bool result = false;

            using (ECDsa ecdsaPublicKey = certWithPrivateKey.GetECDsaPublicKey())
                using (ECDsa ecdsaPrivateKey = certWithPublicKey.GetECDsaPrivateKey())
                {
                    try
                    {
                        // verify the public and private key match
                        X509KeyUsageFlags keyUsage = GetKeyUsage(certWithPublicKey);
                        if ((keyUsage & X509KeyUsageFlags.DigitalSignature) != 0)
                        {
                            result = VerifyECDsaKeyPairSign(ecdsaPublicKey, ecdsaPrivateKey);
                        }
                        else
                        {
                            if (throwOnError)
                            {
                                throw new CryptographicException("Don't know how to verify the public/private key pair.");
                            }
                        }
                    }
                    catch (Exception)
                    {
                        if (throwOnError)
                        {
                            throwOnError = false;
                            throw;
                        }
                    }
                }
            if (!result && throwOnError)
            {
                throw new CryptographicException("The public/private key pair in the certficates do not match.");
            }
            return(result);
        }
Beispiel #17
0
        internal AsnDecodeStatus Decode(byte[] extension)
        {
            if ((extension == null) || (extension.Length == 0))
            {
                return(AsnDecodeStatus.BadAsn);
            }
            if (extension [0] != 0x03)
            {
                return(AsnDecodeStatus.BadTag);
            }
            if (extension.Length < 3)
            {
                return(AsnDecodeStatus.BadLength);
            }
            if (extension.Length < 4)
            {
                return(AsnDecodeStatus.InformationNotAvailable);
            }

            try
            {
                ASN1 ex     = new ASN1(extension);
                int  kubits = 0;
                int  i      = 1; // byte zero has the number of unused bits (ASN1's BITSTRING)
                while (i < ex.Value.Length)
                {
                    kubits = (kubits << 8) + ex.Value [i++];
                }

                _keyUsages = GetValidFlags((X509KeyUsageFlags)kubits);
            }
            catch
            {
                return(AsnDecodeStatus.BadAsn);
            }

            return(AsnDecodeStatus.Ok);
        }
        public X509Certificate2 NewRsaSelfSignedCertificate(
            DistinguishedName distinguishedName,
            BasicConstraints basicConstraints,
            ValidityPeriod validityPeriod,
            SubjectAlternativeName subjectAlternativeName,
            OidCollection enhancedKeyUsages,
            X509KeyUsageFlags x509KeyUsageFlags,
            RsaConfiguration rsaConfiguration)
        {
            using var rsa = RSA.Create(rsaConfiguration.KeySize); // 1024, 2048 or 4096
            var request = new CertificateRequest(
                _certificateUtility.CreateIssuerOrSubject(distinguishedName),
                rsa,
                rsaConfiguration.HashAlgorithmName,
                rsaConfiguration.RSASignaturePadding);

            return(NewRsaSelfSignedCertificate(basicConstraints,
                                               validityPeriod,
                                               subjectAlternativeName,
                                               enhancedKeyUsages,
                                               x509KeyUsageFlags,
                                               request));
        }
        /// <summary>
        /// Create a Self signed certificate with all options which can also be used as a root certificate
        /// </summary>
        /// <param name="distinguishedName">Distinguished Name used for the subject and the issuer properties</param>
        /// <param name="validityPeriod">Valid from, Valid to certificate properties</param>
        /// <param name="subjectAlternativeName">SAN but only DnsNames can be added as a list + Email property</param>
        /// <param name="enhancedKeyUsages">Defines how the certificate key can be used.
        /// OidLookup.ServerAuthentication,
        /// OidLookup.ClientAuthentication,
        /// OidLookup.CodeSigning,
        /// OidLookup.SecureEmail,
        /// OidLookup.TimeStamping
        /// </param>
        /// <param name="x509KeyUsageFlags">Defines how the certificate key can be used.
        ///  None             No key usage parameters.
        ///  EncipherOnly     The key can be used for encryption only.
        ///  CrlSign          The key can be used to sign a certificate revocation list (CRL).
        ///  KeyCertSign      The key can be used to sign certificates.
        ///  KeyAgreement     The key can be used to determine key agreement, such as a key created using the Diffie-Hellman key agreement algorithm.
        ///  DataEncipherment The key can be used for data encryption.
        ///  KeyEncipherment  The key can be used for key encryption.
        ///  NonRepudiation   The key can be used for authentication.
        ///  DecipherOnly     The key can be used for decryption only.
        ///  </param>
        /// <returns>Self signed certificate</returns>
        public X509Certificate2 NewECDsaSelfSignedCertificate(
            DistinguishedName distinguishedName,
            BasicConstraints basicConstraints,
            ValidityPeriod validityPeriod,
            SubjectAlternativeName subjectAlternativeName,
            OidCollection enhancedKeyUsages,
            X509KeyUsageFlags x509KeyUsageFlags,
            ECDsaConfiguration eCDsaConfiguration)
        {
            using var ecdsa = ECDsa.Create("ECDsa");
            ecdsa.KeySize   = eCDsaConfiguration.KeySize;
            var request = new CertificateRequest(
                _certificateUtility.CreateIssuerOrSubject(distinguishedName),
                ecdsa,
                eCDsaConfiguration.HashAlgorithmName);

            return(NewECDsaSelfSignedCertificate(basicConstraints,
                                                 validityPeriod,
                                                 subjectAlternativeName,
                                                 enhancedKeyUsages,
                                                 x509KeyUsageFlags,
                                                 request));
        }
        public X509Certificate2 NewECDsaChainedCertificate(
            BasicConstraints basicConstraints,
            ValidityPeriod validityPeriod,
            SubjectAlternativeName subjectAlternativeName,
            X509Certificate2 signingCertificate,
            OidCollection enhancedKeyUsages,
            X509KeyUsageFlags x509KeyUsageFlags,
            CertificateRequest request,
            ECDsa ecdsa)
        {
            if (signingCertificate == null)
            {
                throw new ArgumentNullException(nameof(signingCertificate));
            }
            if (!signingCertificate.HasPrivateKey)
            {
                throw new Exception("Signing cert must have private key");
            }

            X509Certificate2 cert = ChainedConfiguration(
                basicConstraints,
                validityPeriod,
                subjectAlternativeName,
                signingCertificate,
                enhancedKeyUsages,
                x509KeyUsageFlags,
                request);

            if (ecdsa == null)
            {
                return(cert);
            }
            else
            {
                return(cert.CopyWithPrivateKey(ecdsa));
            }
        }
Beispiel #21
0
        public X509Certificate2 NewRsaChainedCertificate(
            DistinguishedName distinguishedName,
            BasicConstraints basicConstraints,
            ValidityPeriod validityPeriod,
            SubjectAlternativeName subjectAlternativeName,
            X509Certificate2 signingCertificate,
            OidCollection enhancedKeyUsages,
            X509KeyUsageFlags x509KeyUsageFlags,
            RsaConfiguration rsaConfiguration)
        {
            if (signingCertificate == null)
            {
                throw new ArgumentNullException(nameof(signingCertificate));
            }
            if (!signingCertificate.HasPrivateKey)
            {
                throw new Exception("Signing cert must have private key");
            }

            using var rsa = RSA.Create(rsaConfiguration.KeySize);
            var request = new CertificateRequest(
                _certificateUtility.CreateIssuerOrSubject(distinguishedName),
                rsa,
                rsaConfiguration.HashAlgorithmName,
                rsaConfiguration.RSASignaturePadding);

            X509Certificate2 cert = ChainedConfiguration(
                basicConstraints,
                validityPeriod,
                subjectAlternativeName,
                signingCertificate,
                enhancedKeyUsages,
                x509KeyUsageFlags,
                request);

            return(cert.CopyWithPrivateKey(rsa));
        }
        private static CertificateRequest CreateChainRequest(
            string dn,
            AsymmetricAlgorithm key,
            HashAlgorithmName hashAlgorithm,
            bool isCa,
            int?pathLen)
        {
            const X509KeyUsageFlags CAFlags = X509KeyUsageFlags.CrlSign | X509KeyUsageFlags.KeyCertSign;
            const X509KeyUsageFlags EEFlags =
                X509KeyUsageFlags.DataEncipherment |
                X509KeyUsageFlags.KeyEncipherment |
                X509KeyUsageFlags.DigitalSignature |
                X509KeyUsageFlags.NonRepudiation;

            CertificateRequest request = OpenCertRequest(dn, key, hashAlgorithm);

            request.CertificateExtensions.Add(
                new X509SubjectKeyIdentifierExtension(
                    request.PublicKey,
                    X509SubjectKeyIdentifierHashAlgorithm.Sha1,
                    false));

            request.CertificateExtensions.Add(
                new X509KeyUsageExtension(
                    isCa ? CAFlags : EEFlags,
                    true));

            request.CertificateExtensions.Add(
                new X509BasicConstraintsExtension(
                    isCa,
                    pathLen.HasValue,
                    pathLen.GetValueOrDefault(),
                    true));

            return(request);
        }
        public X509Certificate2Collection Find(X509FindType findType, object findValue, bool validOnly)
        {
            if (findValue == null)
            {
                throw new ArgumentNullException("findValue");
            }

            string            str = String.Empty;
            string            oid = String.Empty;
            X509KeyUsageFlags ku  = X509KeyUsageFlags.None;
            DateTime          dt  = DateTime.MinValue;

            switch (findType)
            {
            case X509FindType.FindByThumbprint:
            case X509FindType.FindBySubjectName:
            case X509FindType.FindBySubjectDistinguishedName:
            case X509FindType.FindByIssuerName:
            case X509FindType.FindByIssuerDistinguishedName:
            case X509FindType.FindBySerialNumber:
            case X509FindType.FindByTemplateName:
            case X509FindType.FindBySubjectKeyIdentifier:
                try {
                    str = (string)findValue;
                }
                catch (Exception e) {
                    string msg = Locale.GetText("Invalid find value type '{0}', expected '{1}'.",
                                                findValue.GetType(), "string");
                    throw new CryptographicException(msg, e);
                }
                break;

            case X509FindType.FindByApplicationPolicy:
            case X509FindType.FindByCertificatePolicy:
            case X509FindType.FindByExtension:
                try {
                    oid = (string)findValue;
                }
                catch (Exception e) {
                    string msg = Locale.GetText("Invalid find value type '{0}', expected '{1}'.",
                                                findValue.GetType(), "X509KeyUsageFlags");
                    throw new CryptographicException(msg, e);
                }
                // OID validation
                try {
                    CryptoConfig.EncodeOID(oid);
                }
                catch (CryptographicUnexpectedOperationException) {
                    string msg = Locale.GetText("Invalid OID value '{0}'.", oid);
                    throw new ArgumentException("findValue", msg);
                }
                break;

            case X509FindType.FindByKeyUsage:
                try {
                    ku = (X509KeyUsageFlags)findValue;
                }
                catch (Exception e) {
                    string msg = Locale.GetText("Invalid find value type '{0}', expected '{1}'.",
                                                findValue.GetType(), "X509KeyUsageFlags");
                    throw new CryptographicException(msg, e);
                }
                break;

            case X509FindType.FindByTimeValid:
            case X509FindType.FindByTimeNotYetValid:
            case X509FindType.FindByTimeExpired:
                try {
                    dt = (DateTime)findValue;
                }
                catch (Exception e) {
                    string msg = Locale.GetText("Invalid find value type '{0}', expected '{1}'.",
                                                findValue.GetType(), "X509DateTime");
                    throw new CryptographicException(msg, e);
                }
                break;

            default:
            {
                string msg = Locale.GetText("Invalid find type '{0}'.", findType);
                throw new CryptographicException(msg);
            }
            }

            CultureInfo cinv = CultureInfo.InvariantCulture;
            X509Certificate2Collection results = new  X509Certificate2Collection();

            foreach (X509Certificate2 x in InnerList)
            {
                bool value_match = false;

                switch (findType)
                {
                case X509FindType.FindByThumbprint:
                    // works with Thumbprint, GetCertHashString in both normal (upper) and lower case
                    value_match = ((String.Compare(str, x.Thumbprint, true, cinv) == 0) ||
                                   (String.Compare(str, x.GetCertHashString(), true, cinv) == 0));
                    break;

                case X509FindType.FindBySubjectName:
                    string [] names = x.SubjectName.Format(true).Split(newline_split, StringSplitOptions.RemoveEmptyEntries);
                    foreach (string name in names)
                    {
                        int pos = name.IndexOf('=');
                        value_match = (name.IndexOf(str, pos, StringComparison.InvariantCultureIgnoreCase) >= 0);
                        if (value_match)
                        {
                            break;
                        }
                    }
                    break;

                case X509FindType.FindBySubjectDistinguishedName:
                    value_match = (String.Compare(str, x.Subject, true, cinv) == 0);
                    break;

                case X509FindType.FindByIssuerName:
                    string iname = x.GetNameInfo(X509NameType.SimpleName, true);
                    value_match = (iname.IndexOf(str, StringComparison.InvariantCultureIgnoreCase) >= 0);
                    break;

                case X509FindType.FindByIssuerDistinguishedName:
                    value_match = (String.Compare(str, x.Issuer, true, cinv) == 0);
                    break;

                case X509FindType.FindBySerialNumber:
                    value_match = (String.Compare(str, x.SerialNumber, true, cinv) == 0);
                    break;

                case X509FindType.FindByTemplateName:
                    // TODO - find a valid test case
                    break;

                case X509FindType.FindBySubjectKeyIdentifier:
                    value_match = (String.Compare(str, GetKeyIdentifier(x), true, cinv) == 0);
                    break;

                case X509FindType.FindByApplicationPolicy:
                    // note: include when no extensions are present (even if v3)
                    value_match = (x.Extensions.Count == 0);
                    // TODO - find test case with extension
                    break;

                case X509FindType.FindByCertificatePolicy:
                    // TODO - find test case with extension
                    break;

                case X509FindType.FindByExtension:
                    value_match = (x.Extensions [oid] != null);
                    break;

                case X509FindType.FindByKeyUsage:
                    X509KeyUsageExtension kue = (x.Extensions ["2.5.29.15"] as X509KeyUsageExtension);
                    if (kue == null)
                    {
                        // key doesn't have any hard coded limitations
                        // note: MS doesn't check for ExtendedKeyUsage
                        value_match = true;
                    }
                    else
                    {
                        value_match = ((kue.KeyUsages & ku) == ku);
                    }
                    break;

                case X509FindType.FindByTimeValid:
                    value_match = ((dt >= x.NotBefore) && (dt <= x.NotAfter));
                    break;

                case X509FindType.FindByTimeNotYetValid:
                    value_match = (dt < x.NotBefore);
                    break;

                case X509FindType.FindByTimeExpired:
                    value_match = (dt > x.NotAfter);
                    break;
                }

                if (!value_match)
                {
                    continue;
                }

                if (validOnly)
                {
                    try {
                        if (x.Verify())
                        {
                            results.Add(x);
                        }
                    }
                    catch {
                    }
                }
                else
                {
                    results.Add(x);
                }
            }
            return(results);
        }
        public static void ChainCertRequirements(bool useIntermed, bool?isCA, X509KeyUsageFlags keyUsage, bool expectSuccess)
        {
            HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA384;

            ECDsa rootKey     = null;
            ECDsa intermedKey = null;
            ECDsa leafKey     = null;

            X509Certificate2 rootCert     = null;
            X509Certificate2 intermedCert = null;
            X509Certificate2 leafCert     = null;

            try
            {
                rootKey = ECDsa.Create(ECCurve.NamedCurves.nistP384);

                var request = new CertificateRequest("CN=Root", rootKey, hashAlgorithm);

                if (useIntermed || isCA.HasValue)
                {
                    request.CertificateExtensions.Add(
                        new X509BasicConstraintsExtension(useIntermed || isCA.Value, false, 0, true));
                }

                X509KeyUsageFlags rootFlags = useIntermed ? X509KeyUsageFlags.KeyCertSign : keyUsage;

                if (rootFlags != X509KeyUsageFlags.None)
                {
                    request.CertificateExtensions.Add(new X509KeyUsageExtension(rootFlags, true));
                }

                DateTimeOffset start = DateTimeOffset.UtcNow.AddHours(-1);
                DateTimeOffset end   = start.AddHours(2);

                rootCert = request.CreateSelfSigned(start, end);

                X509Certificate2 signerCert = rootCert;

                if (useIntermed)
                {
                    intermedKey = ECDsa.Create(ECCurve.NamedCurves.nistP384);
                    request     = new CertificateRequest("CN=Intermediate", intermedKey, hashAlgorithm);

                    if (isCA.HasValue)
                    {
                        request.CertificateExtensions.Add(
                            new X509BasicConstraintsExtension(isCA.Value, false, 0, true));
                    }

                    if (keyUsage != X509KeyUsageFlags.None)
                    {
                        request.CertificateExtensions.Add(new X509KeyUsageExtension(keyUsage, true));
                    }

                    using (X509Certificate2 tmp = request.Create(rootCert, start, end, new byte[] { 6, 0, 2, 2, 10, 23 }))
                    {
                        intermedCert = tmp.CopyWithPrivateKey(intermedKey);
                    }

                    signerCert = intermedCert;
                }

                leafKey = ECDsa.Create(ECCurve.NamedCurves.nistP256);
                request = new CertificateRequest("CN=Leaf", leafKey, hashAlgorithm);

                byte[] leafSerialNumber = { 2, 4, 6, 0, 1 };

                if (!expectSuccess)
                {
                    AssertExtensions.Throws <ArgumentException>(
                        "issuerCertificate",
                        () =>
                    {
                        request.Create(signerCert, start, end, leafSerialNumber)?.Dispose();
                    });

                    return;
                }

                leafCert = request.Create(signerCert, start, end, leafSerialNumber);

                using (X509Chain chain = new X509Chain())
                {
                    chain.ChainPolicy.RevocationMode    = X509RevocationMode.NoCheck;
                    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
                    chain.ChainPolicy.ExtraStore.Add(rootCert);
                    chain.ChainPolicy.VerificationTime = start.ToLocalTime().DateTime;

                    if (useIntermed)
                    {
                        chain.ChainPolicy.ExtraStore.Add(intermedCert);
                    }

                    RunChain(chain, leafCert, true, "Chain verification");
                    DisposeChainCerts(chain);
                }
            }
            finally
            {
                leafCert?.Dispose();
                leafKey?.Dispose();
                intermedCert?.Dispose();
                intermedKey?.Dispose();
                rootCert?.Dispose();
                rootKey?.Dispose();
            }
        }
 public X509KeyUsageExtension(X509KeyUsageFlags keyUsages, bool critical)
     : base(Oids.KeyUsage, X509Pal.Instance.EncodeX509KeyUsageExtension(keyUsages), critical)
 {
 }
 public X509KeyUsageExtension (X509KeyUsageFlags keyUsages, bool critical) :
     base (CAPI.szOID_KEY_USAGE, EncodeExtension(keyUsages), critical) {}
 public static void TraceAndLog(string subject, string thumbPrint, X509KeyUsageFlags keyUsage)
 {
     DiagnosticUtility.EventLog.LogEvent(TraceEventType.Information, EventLogCategory.Wsat, (EventLogEventId) (-1073545195), new string[] { subject, thumbPrint, keyUsage.ToString() });
 }
 public X509KeyUsageExtension(X509KeyUsageFlags keyUsages, bool critical);
Beispiel #29
0
        private StorePal CreatedLinkedStoreWithFindResults(X509FindType findType, Object findValue, bool validOnly)
        {
            unsafe
            {
                switch (findType)
                {
                case X509FindType.FindByThumbprint:
                {
                    byte[] thumbPrint = ConfirmedCast <String>(findValue).DecodeHexString();
                    fixed(byte *pThumbPrint = thumbPrint)
                    {
                        CRYPTOAPI_BLOB blob = new CRYPTOAPI_BLOB(thumbPrint.Length, pThumbPrint);

                        return(FindCore(CertFindType.CERT_FIND_HASH, &blob, validOnly));
                    }
                }

                case X509FindType.FindBySubjectName:
                {
                    String subjectName = ConfirmedCast <String>(findValue);
                    fixed(char *pSubjectName = subjectName)
                    {
                        return(FindCore(CertFindType.CERT_FIND_SUBJECT_STR, pSubjectName, validOnly));
                    }
                }

                case X509FindType.FindBySubjectDistinguishedName:
                {
                    String subjectDistinguishedName = ConfirmedCast <String>(findValue);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            String actual = GetCertNameInfo(pCertContext, CertNameType.CERT_NAME_RDN_TYPE, CertNameFlags.None);
                            return subjectDistinguishedName.Equals(actual, StringComparison.OrdinalIgnoreCase);
                        }
                                    ));
                }

                case X509FindType.FindByIssuerName:
                {
                    String issuerName = ConfirmedCast <String>(findValue);
                    fixed(char *pIssuerName = issuerName)
                    {
                        return(FindCore(CertFindType.CERT_FIND_ISSUER_STR, pIssuerName, validOnly));
                    }
                }

                case X509FindType.FindByIssuerDistinguishedName:
                {
                    String issuerDistinguishedName = ConfirmedCast <String>(findValue);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            String actual = GetCertNameInfo(pCertContext, CertNameType.CERT_NAME_RDN_TYPE, CertNameFlags.CERT_NAME_ISSUER_FLAG);
                            return issuerDistinguishedName.Equals(actual, StringComparison.OrdinalIgnoreCase);
                        }
                                    ));
                }

                case X509FindType.FindBySerialNumber:
                {
                    String decimalOrHexString = ConfirmedCast <String>(findValue);

                    // FindBySerialNumber allows the input format to be either in hex or decimal. Since we can't know which one was intended,
                    // it compares against both interpretations and treats a match of either as a successful find.

                    byte[] hexBytes = decimalOrHexString.DecodeHexString();
                    Array.Reverse(hexBytes);           // String is big-endian, BigInteger constructor requires little-endian.
                    BigInteger expected1 = PositiveBigIntegerFromByteArray(hexBytes);

                    BigInteger ten       = new BigInteger(10);
                    BigInteger expected2 = BigInteger.Zero;
                    foreach (char c in decimalOrHexString)
                    {
                        if (c >= '0' && c <= '9')
                        {
                            expected2 = BigInteger.Multiply(expected2, ten);
                            expected2 = BigInteger.Add(expected2, c - '0');
                        }
                    }

                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            byte[] actual = pCertContext.CertContext->pCertInfo->SerialNumber.ToByteArray();
                            BigInteger actualAsBigInteger = PositiveBigIntegerFromByteArray(actual);           // Convert to BigInteger as the comparison must not fail due to spurious leading zeros
                            GC.KeepAlive(pCertContext);
                            return expected1.Equals(actualAsBigInteger) || expected2.Equals(actualAsBigInteger);
                        }
                                    ));
                }

                case X509FindType.FindByTimeValid:
                {
                    DateTime dateTime = ConfirmedCast <DateTime>(findValue);
                    FILETIME fileTime = FILETIME.FromDateTime(dateTime);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            int comparison = Interop.crypt32.CertVerifyTimeValidity(ref fileTime, pCertContext.CertContext->pCertInfo);
                            GC.KeepAlive(pCertContext);
                            return comparison == 0;
                        }
                                    ));
                }

                case X509FindType.FindByTimeNotYetValid:
                {
                    DateTime dateTime = ConfirmedCast <DateTime>(findValue);
                    FILETIME fileTime = FILETIME.FromDateTime(dateTime);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            int comparison = Interop.crypt32.CertVerifyTimeValidity(ref fileTime, pCertContext.CertContext->pCertInfo);
                            GC.KeepAlive(pCertContext);
                            return comparison == -1;
                        }
                                    ));
                }

                case X509FindType.FindByTimeExpired:
                {
                    DateTime dateTime = ConfirmedCast <DateTime>(findValue);
                    FILETIME fileTime = FILETIME.FromDateTime(dateTime);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            int comparison = Interop.crypt32.CertVerifyTimeValidity(ref fileTime, pCertContext.CertContext->pCertInfo);
                            GC.KeepAlive(pCertContext);
                            return comparison == 1;
                        }
                                    ));
                }

                case X509FindType.FindByTemplateName:
                {
                    String expected = ConfirmedCast <String>(findValue);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            // The template name can have 2 different formats: V1 format (<= Win2K) is just a string
                            // V2 format (XP only) can be a friendly name or an OID.
                            // An example of Template Name can be "ClientAuth".

                            bool foundMatch = false;
                            CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo;
                            {
                                CERT_EXTENSION *pV1Template = Interop.crypt32.CertFindExtension(Oids.EnrollCertTypeExtension, pCertInfo->cExtension, pCertInfo->rgExtension);
                                if (pV1Template != null)
                                {
                                    byte[] extensionRawData = pV1Template->Value.ToByteArray();
                                    if (!extensionRawData.DecodeObjectNoThrow(
                                            CryptDecodeObjectStructType.X509_UNICODE_ANY_STRING,
                                            delegate(void *pvDecoded)
                                    {
                                        CERT_NAME_VALUE *pNameValue = (CERT_NAME_VALUE *)pvDecoded;
                                        String actual = Marshal.PtrToStringUni(new IntPtr(pNameValue->Value.pbData));
                                        if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase))
                                        {
                                            foundMatch = true;
                                        }
                                    }))
                                    {
                                        return false;
                                    }
                                }
                            }

                            if (!foundMatch)
                            {
                                CERT_EXTENSION *pV2Template = Interop.crypt32.CertFindExtension(Oids.CertificateTemplate, pCertInfo->cExtension, pCertInfo->rgExtension);
                                if (pV2Template != null)
                                {
                                    byte[] extensionRawData = pV2Template->Value.ToByteArray();
                                    if (!extensionRawData.DecodeObjectNoThrow(
                                            CryptDecodeObjectStructType.X509_CERTIFICATE_TEMPLATE,
                                            delegate(void *pvDecoded)
                                    {
                                        CERT_TEMPLATE_EXT *pTemplateExt = (CERT_TEMPLATE_EXT *)pvDecoded;
                                        String actual = Marshal.PtrToStringAnsi(pTemplateExt->pszObjId);
                                        String expectedOidValue = OidInfo.FindOidInfo(CryptOidInfoKeyType.CRYPT_OID_INFO_NAME_KEY, expected, OidGroup.Template, fallBackToAllGroups: true).OID;
                                        if (expectedOidValue == null)
                                        {
                                            expectedOidValue = expected;
                                        }
                                        if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase))
                                        {
                                            foundMatch = true;
                                        }
                                    }))
                                    {
                                        return false;
                                    }
                                }
                            }

                            GC.KeepAlive(pCertContext);
                            return foundMatch;
                        }));
                }

                case X509FindType.FindByApplicationPolicy:
                {
                    String expected = ConfirmedOidValue(findValue, OidGroup.Policy);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            int numOids;
                            int cbData = 0;
                            if (!Interop.crypt32.CertGetValidUsages(1, ref pCertContext, out numOids, null, ref cbData))
                            {
                                return false;
                            }

                            // -1 means the certificate is good for all usages.
                            if (numOids == -1)
                            {
                                return true;
                            }

                            fixed(byte *pOidsPointer = new byte[cbData])
                            {
                                if (!Interop.crypt32.CertGetValidUsages(1, ref pCertContext, out numOids, pOidsPointer, ref cbData))
                                {
                                    return false;
                                }

                                IntPtr *pOids = (IntPtr *)pOidsPointer;
                                for (int i = 0; i < numOids; i++)
                                {
                                    String actual = Marshal.PtrToStringAnsi(pOids[i]);
                                    if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase))
                                    {
                                        return true;
                                    }
                                }
                                return false;
                            }
                        }
                                    ));
                }

                case X509FindType.FindByCertificatePolicy:
                {
                    String expected = ConfirmedOidValue(findValue, OidGroup.Policy);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo;
                            CERT_EXTENSION *pCertExtension = Interop.crypt32.CertFindExtension(Oids.CertPolicies, pCertInfo->cExtension, pCertInfo->rgExtension);
                            if (pCertExtension == null)
                            {
                                return false;
                            }

                            bool foundMatch = false;
                            byte[] extensionRawData = pCertExtension->Value.ToByteArray();
                            if (!extensionRawData.DecodeObjectNoThrow(
                                    CryptDecodeObjectStructType.X509_CERT_POLICIES,
                                    delegate(void *pvDecoded)
                            {
                                CERT_POLICIES_INFO *pCertPoliciesInfo = (CERT_POLICIES_INFO *)pvDecoded;
                                for (int i = 0; i < pCertPoliciesInfo->cPolicyInfo; i++)
                                {
                                    CERT_POLICY_INFO *pCertPolicyInfo = &(pCertPoliciesInfo->rgPolicyInfo[i]);
                                    String actual = Marshal.PtrToStringAnsi(pCertPolicyInfo->pszPolicyIdentifier);
                                    if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase))
                                    {
                                        foundMatch = true;
                                        break;
                                    }
                                }
                            }
                                    ))
                            {
                                return false;
                            }

                            GC.KeepAlive(pCertContext);
                            return foundMatch;
                        }
                                    ));
                }

                case X509FindType.FindByExtension:
                {
                    String oidValue = ConfirmedOidValue(findValue, OidGroup.ExtensionOrAttribute);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo;
                            CERT_EXTENSION *pCertExtension = Interop.crypt32.CertFindExtension(oidValue, pCertInfo->cExtension, pCertInfo->rgExtension);
                            GC.KeepAlive(pCertContext);
                            return pCertExtension != null;
                        }
                                    ));
                }

                case X509FindType.FindByKeyUsage:
                {
                    X509KeyUsageFlags expected = ConfirmedX509KeyUsage(findValue);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo;
                            X509KeyUsageFlags actual;
                            if (!Interop.crypt32.CertGetIntendedKeyUsage(CertEncodingType.All, pCertInfo, out actual, sizeof(X509KeyUsageFlags)))
                            {
                                return true;          // no key usage means it is valid for all key usages.
                            }
                            GC.KeepAlive(pCertContext);
                            return (actual & expected) == expected;
                        }
                                    ));
                }

                case X509FindType.FindBySubjectKeyIdentifier:
                {
                    byte[] expected = ConfirmedCast <String>(findValue).DecodeHexString();
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            int cbData = 0;
                            if (!Interop.crypt32.CertGetCertificateContextProperty(pCertContext, CertContextPropId.CERT_KEY_IDENTIFIER_PROP_ID, null, ref cbData))
                            {
                                return false;
                            }

                            byte[] actual = new byte[cbData];
                            if (!Interop.crypt32.CertGetCertificateContextProperty(pCertContext, CertContextPropId.CERT_KEY_IDENTIFIER_PROP_ID, actual, ref cbData))
                            {
                                return false;
                            }

                            return expected.ContentsEqual(actual);
                        }
                                    ));
                }

                default:
                    throw new CryptographicException(SR.Cryptography_X509_InvalidFindType);
                }
            }
        }
Beispiel #30
0
        public static void FindByValidThumbprint_RootCert()
        {
            using (X509Store machineRoot = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
            {
                machineRoot.Open(OpenFlags.ReadOnly);

                using (var watchedStoreCerts = new ImportedCollection(machineRoot.Certificates))
                {
                    X509Certificate2Collection storeCerts = watchedStoreCerts.Collection;
                    X509Certificate2           rootCert   = null;
                    TimeSpan tolerance = TimeSpan.FromHours(12);

                    // These APIs use local time, so use DateTime.Now, not DateTime.UtcNow.
                    DateTime notBefore = DateTime.Now;
                    DateTime notAfter  = DateTime.Now.Subtract(tolerance);

                    foreach (X509Certificate2 cert in storeCerts)
                    {
                        if (cert.NotBefore >= notBefore || cert.NotAfter <= notAfter)
                        {
                            // Not (safely) valid, skip.
                            continue;
                        }

                        X509KeyUsageExtension keyUsageExtension = null;

                        foreach (X509Extension extension in cert.Extensions)
                        {
                            keyUsageExtension = extension as X509KeyUsageExtension;

                            if (keyUsageExtension != null)
                            {
                                break;
                            }
                        }

                        // Some tool is putting the com.apple.systemdefault utility cert in the
                        // LM\Root store on OSX machines; but it gets rejected by OpenSSL as an
                        // invalid root for not having the Certificate Signing key usage value.
                        //
                        // While the real problem seems to be with whatever tool is putting it
                        // in the bundle; we can work around it here.
                        const X509KeyUsageFlags RequiredFlags = X509KeyUsageFlags.KeyCertSign;

                        // No key usage extension means "good for all usages"
                        if (keyUsageExtension != null &&
                            (keyUsageExtension.KeyUsages & RequiredFlags) != RequiredFlags)
                        {
                            // Not a valid KeyUsage, skip.
                            continue;
                        }

                        using (ChainHolder chainHolder = new ChainHolder())
                        {
                            chainHolder.Chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

                            if (!chainHolder.Chain.Build(cert))
                            {
                                // Despite being not expired and having a valid KeyUsage, it's
                                // not considered a valid root/chain.
                                continue;
                            }
                        }

                        rootCert = cert;
                        break;
                    }

                    // Just in case someone has a system with no valid trusted root certs whatsoever.
                    if (rootCert != null)
                    {
                        X509Certificate2Collection matches =
                            storeCerts.Find(X509FindType.FindByThumbprint, rootCert.Thumbprint, true);

                        using (new ImportedCollection(matches))
                        {
                            // Improve the debuggability, since the root cert found on each
                            // machine might be different
                            if (matches.Count == 0)
                            {
                                Assert.True(
                                    false,
                                    $"Root certificate '{rootCert.Subject}' ({rootCert.NotBefore} - {rootCert.NotAfter}) is findable with thumbprint '{rootCert.Thumbprint}' and validOnly=true");
                            }

                            Assert.NotSame(rootCert, matches[0]);
                            Assert.Equal(rootCert, matches[0]);
                        }
                    }
                }
            }
        }
        // CTL == Certificate Trust List / NOT SUPPORTED
        // TODO - check for X509ChainStatusFlags.CtlNotTimeValid
        // TODO - check for X509ChainStatusFlags.CtlNotSignatureValid
        // TODO - check for X509ChainStatusFlags.CtlNotValidForUsage

        private void PrepareForNextCertificate(int n)
        {
            X509ChainElement element     = elements [n];
            X509Certificate2 certificate = element.Certificate;

            // TODO 6.1.4.a-b

            // 6.1.4.c
            working_issuer_name = certificate.SubjectName;
            // 6.1.4.d-e - our key includes both the public key and it's parameters
            working_public_key = certificate.PublicKey.Key;
            // 6.1.4.f
//			working_public_key_algorithm = certificate.PublicKey.Oid.Value;

            // TODO 6.1.4.g-j

            // 6.1.4.k - Verify that the certificate is a CA certificate
            X509BasicConstraintsExtension bce = (certificate.Extensions["2.5.29.19"] as X509BasicConstraintsExtension);

            if (bce != null)
            {
                if (!bce.CertificateAuthority)
                {
                    element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
                }
            }
            else if (certificate.Version >= 3)
            {
                // recent (v3+) CA certificates must include BCE
                element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
            }

            // 6.1.4.l - if the certificate isn't self-issued...
            if (!IsSelfIssued(certificate))
            {
                // ... verify that max_path_length > 0
                if (max_path_length > 0)
                {
                    max_path_length--;
                }
                else
                {
                    // to match MS the reported status must be against the certificate
                    // with the BCE and not where the path is too long. It also means
                    // that this condition has to be reported only once
                    if (bce_restriction != null)
                    {
                        bce_restriction.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
                    }
                }
            }

            // 6.1.4.m - if pathLengthConstraint is present...
            if ((bce != null) && (bce.HasPathLengthConstraint))
            {
                // ... and is less that max_path_length, set max_path_length to it's value
                if (bce.PathLengthConstraint < max_path_length)
                {
                    max_path_length = bce.PathLengthConstraint;
                    bce_restriction = element;
                }
            }

            // 6.1.4.n - if key usage extension is present...
            X509KeyUsageExtension kue = (certificate.Extensions["2.5.29.15"] as X509KeyUsageExtension);

            if (kue != null)
            {
                // ... verify keyCertSign is set
                X509KeyUsageFlags success = X509KeyUsageFlags.KeyCertSign;
                if ((kue.KeyUsages & success) != success)
                {
                    element.StatusFlags |= X509ChainStatusFlags.NotValidForUsage;
                }
            }

            // 6.1.4.o - recognize and process other critical extension present in the certificate
            ProcessCertificateExtensions(element);
        }
Beispiel #32
0
        private static bool CertHasKeyUsage(X509Certificate2 c, X509KeyUsageFlags keyUsage)
        {
            foreach (X509Extension extension in c.Extensions)
            {
                X509KeyUsageExtension keyUsageExtension = extension as X509KeyUsageExtension;
                if (keyUsageExtension != null)
                {
                    if ((keyUsageExtension.KeyUsages & keyUsage) == keyUsage)
                    {
                        return true;
                    }
                    break;
                }
            }

            return false;
        }
Beispiel #33
0
 public X509KeyUsageExtension(X509KeyUsageFlags keyUsages, bool critical)
     : base(Oids.KeyUsage, X509Pal.Instance.EncodeX509KeyUsageExtension(keyUsages), critical)
 {
 }
Beispiel #34
0
        public byte[] EncodeX509KeyUsageExtension(X509KeyUsageFlags keyUsages)
        {
            // The numeric values of X509KeyUsageFlags mean that if we interpret it as a little-endian
            // ushort it will line up with the flags in the spec.
            ushort ushortValue = unchecked((ushort)(int)keyUsages);
            byte[] data = BitConverter.GetBytes(ushortValue);

            // RFC 3280 section 4.2.1.3 (https://tools.ietf.org/html/rfc3280#section-4.2.1.3) defines
            // digitalSignature (0) through decipherOnly (8), making 9 named bits.
            const int namedBitsCount = 9;

            // The expected output of this method isn't the SEQUENCE value, but just the payload bytes.
            byte[][] segments = DerEncoder.SegmentedEncodeNamedBitList(data, namedBitsCount);
            Debug.Assert(segments.Length == 3);
            return ConcatenateArrays(segments);
        }
Beispiel #35
0
		// internal

		internal X509KeyUsageFlags GetValidFlags (X509KeyUsageFlags flags)
		{
			if ((flags & all) != flags)
				return (X509KeyUsageFlags) 0;
			return flags;
		}
Beispiel #36
0
 public static extern unsafe bool CertGetIntendedKeyUsage(CertEncodingType dwCertEncodingType, CERT_INFO *pCertInfo, out X509KeyUsageFlags pbKeyUsage, int cbKeyUsage);
Beispiel #37
0
		internal AsnDecodeStatus Decode (byte[] extension)
		{
			if ((extension == null) || (extension.Length == 0))
				return AsnDecodeStatus.BadAsn;
			if (extension [0] != 0x03)
				return AsnDecodeStatus.BadTag;
			if (extension.Length < 3)
				return AsnDecodeStatus.BadLength;
			if (extension.Length < 4)
				return AsnDecodeStatus.InformationNotAvailable;

			try {
				ASN1 ex = new ASN1 (extension);
				int kubits = 0;
				int i = 1; // byte zero has the number of unused bits (ASN1's BITSTRING)
				while (i < ex.Value.Length)
					kubits = (kubits << 8) + ex.Value [i++];

				_keyUsages = GetValidFlags ((X509KeyUsageFlags)kubits);
			}
			catch {
				return AsnDecodeStatus.BadAsn;
			}

			return AsnDecodeStatus.Ok;
		}
        private static unsafe byte[] EncodeExtension (X509KeyUsageFlags keyUsages) {
            CAPI.CRYPT_BIT_BLOB blob = new CAPI.CRYPT_BIT_BLOB();
            blob.cbData = 2;
            blob.pbData = new IntPtr(&keyUsages);
            blob.cUnusedBits = 0;

            byte[] encodedKeyUsages = null;
            if (!CAPI.EncodeObject(CAPI.szOID_KEY_USAGE, new IntPtr(&blob), out encodedKeyUsages))
                throw new CryptographicException(Marshal.GetLastWin32Error());

            return encodedKeyUsages;
        }
Beispiel #39
0
 private static X509Certificate2 AskCertificate(X509KeyUsageFlags flags)
 {
     X509Store my = new X509Store(StoreName.My, StoreLocation.CurrentUser);
     my.Open(OpenFlags.ReadOnly);
     try
     {
         X509Certificate2Collection nonRep = my.Certificates.Find(X509FindType.FindByKeyUsage, flags, true);
         return X509Certificate2UI.SelectFromCollection(nonRep, "Select your cert", "Select the cert you want to used to sign the msg", X509SelectionFlag.SingleSelection)[0];
     }
     finally
     {
         my.Close();
     }
 }
Beispiel #40
0
 public unsafe void FindByKeyUsage(X509KeyUsageFlags keyUsage)
 {
     FindCore(
         delegate (SafeCertContextHandle pCertContext)
         {
             CERT_INFO* pCertInfo = pCertContext.CertContext->pCertInfo;
             X509KeyUsageFlags actual;
             if (!Interop.crypt32.CertGetIntendedKeyUsage(CertEncodingType.All, pCertInfo, out actual, sizeof(X509KeyUsageFlags)))
                 return true;  // no key usage means it is valid for all key usages.
             GC.KeepAlive(pCertContext);
             return (actual & keyUsage) == keyUsage;
         });
 }
		private X509KeyUsageExtension ValidateKeyUsage (X509KeyUsageFlags kuf, string rawdata)
		{
			X509KeyUsageExtension ku = new X509KeyUsageExtension (kuf, false);
			Assert.IsFalse (ku.Critical, kuf.ToString () + ".Critical");
			Assert.AreEqual (rawdata, BitConverter.ToString (ku.RawData), kuf.ToString () + ".RawData");
			Assert.AreEqual (oid, ku.Oid.Value, kuf.ToString () + ".Oid.Value");
			Assert.AreEqual (fname, ku.Oid.FriendlyName, kuf.ToString () + ".Oid.FriendlyName");
			Assert.AreEqual (kuf, ku.KeyUsages, kuf.ToString () + ".KeyUsages");
			return ku;
		}
        public void FindByKeyUsage(X509KeyUsageFlags keyUsage)
        {
            FindCore(
                cert =>
                {
                    X509Extension ext = FindExtension(cert, Oids.KeyUsage);

                    if (ext == null)
                    {
                        // A certificate with no key usage extension is considered valid for all key usages.
                        return true;
                    }

                    var kuExt = (X509KeyUsageExtension)ext;

                    return (kuExt.KeyUsages & keyUsage) == keyUsage;
                });
        }
 public X509KeyUsageExtension(X509KeyUsageFlags keyUsages, bool critical) : base("2.5.29.15", EncodeExtension(keyUsages), critical)
 {
 }
Beispiel #44
0
        private static void TestKeyUsageExtension(X509KeyUsageFlags flags, bool critical, byte[] expectedDer)
        {
            X509KeyUsageExtension ext = new X509KeyUsageExtension(flags, critical);
            byte[] rawData = ext.RawData;
            Assert.Equal(expectedDer, rawData);

            // Assert that format doesn't crash
            string s = ext.Format(false);

            // Rebuild it from the RawData.
            ext = new X509KeyUsageExtension(new AsnEncodedData(rawData), critical);
            Assert.Equal(flags, ext.KeyUsages);
        }
		private X509KeyUsageExtension ValidateKeyUsage (X509KeyUsageFlags kuf, string rawdata)
		{
			X509KeyUsageExtension ku = new X509KeyUsageExtension (kuf, false);
			Assert.IsFalse (ku.Critical, kuf.ToString () + ".Critical");
			Assert.AreEqual (rawdata, BitConverter.ToString (ku.RawData), kuf.ToString () + ".RawData");
			Assert.AreEqual (oid, ku.Oid.Value, kuf.ToString () + ".Oid.Value");
			// FIXME: Don't expect that FriendlyName is English. This test fails under non-English Windows.
			//Assert.AreEqual (fname, ku.Oid.FriendlyName, kuf.ToString () + ".Oid.FriendlyName");
			Assert.AreEqual (kuf, ku.KeyUsages, kuf.ToString () + ".KeyUsages");
			return ku;
		}
Beispiel #46
0
        public static X509Certificate2Collection FindFromCollection(
            X509Certificate2Collection coll,
            X509FindType findType,
            object findValue,
            bool validOnly)
        {
            X509Certificate2Collection results = new X509Certificate2Collection();

            using (IFindPal findPal = OpenPal(coll, results, validOnly))
            {
                switch (findType)
                {
                case X509FindType.FindByThumbprint:
                {
                    byte[] thumbPrint = ConfirmedCast <string>(findValue).LaxDecodeHexString();
                    findPal.FindByThumbprint(thumbPrint);
                    break;
                }

                case X509FindType.FindBySubjectName:
                {
                    string subjectName = ConfirmedCast <string>(findValue);
                    findPal.FindBySubjectName(subjectName);
                    break;
                }

                case X509FindType.FindBySubjectDistinguishedName:
                {
                    string subjectDistinguishedName = ConfirmedCast <string>(findValue);
                    findPal.FindBySubjectDistinguishedName(subjectDistinguishedName);
                    break;
                }

                case X509FindType.FindByIssuerName:
                {
                    string issuerName = ConfirmedCast <string>(findValue);
                    findPal.FindByIssuerName(issuerName);
                    break;
                }

                case X509FindType.FindByIssuerDistinguishedName:
                {
                    string issuerDistinguishedName = ConfirmedCast <string>(findValue);
                    findPal.FindByIssuerDistinguishedName(issuerDistinguishedName);
                    break;
                }

                case X509FindType.FindBySerialNumber:
                {
                    string decimalOrHexString = ConfirmedCast <string>(findValue);

                    // FindBySerialNumber allows the input format to be either in
                    // hex or decimal. Since we can't know which one was intended,
                    // it compares against both interpretations and treats a match
                    // of either as a successful find.

                    // string is big-endian
                    byte[] hexBytes = decimalOrHexString.LaxDecodeHexString();

                    BigInteger hexValue     = new BigInteger(hexBytes, isUnsigned: true, isBigEndian: true);
                    BigInteger decimalValue = LaxParseDecimalBigInteger(decimalOrHexString);
                    findPal.FindBySerialNumber(hexValue, decimalValue);
                    break;
                }

                case X509FindType.FindByTimeValid:
                {
                    DateTime dateTime = ConfirmedCast <DateTime>(findValue);
                    findPal.FindByTimeValid(dateTime);
                    break;
                }

                case X509FindType.FindByTimeNotYetValid:
                {
                    DateTime dateTime = ConfirmedCast <DateTime>(findValue);
                    findPal.FindByTimeNotYetValid(dateTime);
                    break;
                }

                case X509FindType.FindByTimeExpired:
                {
                    DateTime dateTime = ConfirmedCast <DateTime>(findValue);
                    findPal.FindByTimeExpired(dateTime);
                    break;
                }

                case X509FindType.FindByTemplateName:
                {
                    string expected = ConfirmedCast <string>(findValue);
                    findPal.FindByTemplateName(expected);
                    break;
                }

                case X509FindType.FindByApplicationPolicy:
                {
                    string oidValue = ConfirmedOidValue(findPal, findValue, OidGroup.Policy);
                    findPal.FindByApplicationPolicy(oidValue);
                    break;
                }

                case X509FindType.FindByCertificatePolicy:
                {
                    string oidValue = ConfirmedOidValue(findPal, findValue, OidGroup.Policy);
                    findPal.FindByCertificatePolicy(oidValue);
                    break;
                }

                case X509FindType.FindByExtension:
                {
                    string oidValue = ConfirmedOidValue(findPal, findValue, OidGroup.ExtensionOrAttribute);
                    findPal.FindByExtension(oidValue);
                    break;
                }

                case X509FindType.FindByKeyUsage:
                {
                    X509KeyUsageFlags keyUsage = ConfirmedX509KeyUsage(findValue);
                    findPal.FindByKeyUsage(keyUsage);
                    break;
                }

                case X509FindType.FindBySubjectKeyIdentifier:
                {
                    byte[] keyIdentifier = ConfirmedCast <string>(findValue).LaxDecodeHexString();
                    findPal.FindBySubjectKeyIdentifier(keyIdentifier);
                    break;
                }

                default:
                    throw new CryptographicException(SR.Cryptography_X509_InvalidFindType);
                }
            }

            return(results);
        }
Beispiel #47
0
 public byte[] EncodeX509KeyUsageExtension(X509KeyUsageFlags keyUsages)
 {
     throw new NotImplementedException();
 }
        private X509ChainStatusFlags CheckRevocation(X509Certificate2 certificate, X509Certificate2 ca_cert, bool online)
        {
            // change this if/when we support OCSP
            X509KeyUsageExtension kue = (ca_cert.Extensions["2.5.29.15"] as X509KeyUsageExtension);

            if (kue != null)
            {
                // ... verify CrlSign is set
                X509KeyUsageFlags success = X509KeyUsageFlags.CrlSign;
                if ((kue.KeyUsages & success) != success)
                {
                    // FIXME - we should try to find an alternative CA that has the CrlSign bit
                    return(X509ChainStatusFlags.RevocationStatusUnknown);
                }
            }

            MX.X509Crl crl = FindCrl(ca_cert);

            if ((crl == null) && online)
            {
                // FIXME - download and install new CRL
                // then you get a second chance
                // crl = FindCrl (ca_cert, ref valid, ref out_of_date);

                // We need to get the subjectAltName and an URI from there (or use OCSP)
                // X509KeyUsageExtension subjectAltName = (ca_cert.Extensions["2.5.29.17"] as X509KeyUsageExtension);
            }

            if (crl != null)
            {
                // validate the digital signature on the CRL using the CA public key
                // note #1: we can't use X509Crl.VerifySignature(X509Certificate) because it duplicates
                // checks and we loose the "why" of the failure
                // note #2: we do this before other tests as an invalid signature could be a hacked CRL
                // (so anything within can't be trusted)
                if (!crl.VerifySignature(ca_cert.PublicKey.Key))
                {
                    return(X509ChainStatusFlags.RevocationStatusUnknown);
                }

                MX.X509Crl.X509CrlEntry entry = crl.GetCrlEntry(certificate.MonoCertificate);
                if (entry != null)
                {
                    // We have an entry for this CRL that includes an unknown CRITICAL extension
                    // See [X.509 7.3] NOTE 4
                    if (!ProcessCrlEntryExtensions(entry))
                    {
                        return(X509ChainStatusFlags.Revoked);
                    }

                    // FIXME - a little more is involved
                    if (entry.RevocationDate <= ChainPolicy.VerificationTime)
                    {
                        return(X509ChainStatusFlags.Revoked);
                    }
                }

                // are we overdue for a CRL update ? if so we can't be sure of any certificate status
                if (crl.NextUpdate < ChainPolicy.VerificationTime)
                {
                    return(X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation);
                }

                // we have a CRL that includes an unknown CRITICAL extension
                // we put this check at the end so we do not "hide" any Revoked flags
                if (!ProcessCrlExtensions(crl))
                {
                    return(X509ChainStatusFlags.RevocationStatusUnknown);
                }
            }
            else
            {
                return(X509ChainStatusFlags.RevocationStatusUnknown);
            }

            return(X509ChainStatusFlags.NoError);
        }
        /// <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");
            }
        }
 public X509KeyUsageExtension(X509KeyUsageFlags keyUsages, bool critical)
 {
 }
Beispiel #51
0
 public X509KeyUsageExtension(X509KeyUsageFlags keyUsages, bool critical) :
     base(CAPI.szOID_KEY_USAGE, EncodeExtension(keyUsages), critical)
 {
 }
Beispiel #52
0
 internal static unsafe partial bool CertGetIntendedKeyUsage(
     CertEncodingType dwCertEncodingType,
     CERT_INFO *pCertInfo,
     out X509KeyUsageFlags pbKeyUsage,
     int cbKeyUsage);
Beispiel #53
0
        /// <summary>
        /// Finds a certificate in the user's local store based on its subject and usage flags
        /// </summary>
        /// <param name="subjectDistinguishedName">The subject distinguished name of the certificate</param>
        /// <param name="usage">The minimum usage flags the certificate must contain</param>
        /// <returns>The requested certificate, or null if the certificate is not found</returns>
        public static X509Certificate2 FindCertificate(string subjectDistinguishedName, X509KeyUsageFlags usage)
        {
            X509Store localStore = new X509Store(StoreName.My);

            localStore.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

            try
            {
                X509Certificate2Collection matches = localStore.Certificates.Find(
                    X509FindType.FindBySubjectDistinguishedName,
                    subjectDistinguishedName,
                    true);

                if (matches.Count > 0)
                {
                    foreach (X509Certificate2 cert in matches)
                    {
                        foreach (X509Extension extension in cert.Extensions)
                        {
                            X509KeyUsageExtension usageExtension = extension as X509KeyUsageExtension;

                            if (usageExtension != null)
                            {
                                bool matchesUsageRequirements = ((usage & usageExtension.KeyUsages) == usage);

                                if (matchesUsageRequirements)
                                {
                                    return(cert);
                                }
                            }
                        }
                    }

                    return(null);
                }
                else
                {
                    return(null);
                }
            }
            finally
            {
                localStore.Close();
            }
        }