Index: e_capi.c
===================================================================
--- e_capi.c	(revision 368495)
+++ e_capi.c	(working copy)
@@ -1554,6 +1554,44 @@
     return 0;
 }
 
+static BOOL WINAPI client_cert_find_callback(PCCERT_CONTEXT cert_context,
+                                             void* find_arg)
+{
+    // Verify the certificate key usage is appropriate or not specified.
+    BYTE key_usage;
+    DWORD size = 0;
+    DWORD err;
+
+    if (CertGetIntendedKeyUsage(X509_ASN_ENCODING, cert_context->pCertInfo,
+        &key_usage, 1)) {
+        if (!(key_usage & CERT_DIGITAL_SIGNATURE_KEY_USAGE))
+            return FALSE;
+    }
+    else {
+        DWORD err = GetLastError();
+        // If |err| is non-zero, it's an actual error. Otherwise the extension
+        // just isn't present, and we treat it as if everything was allowed.
+        if (err) {
+            return FALSE;
+        }
+    }
+
+    // Verify the current time is within the certificate's validity period.
+    if (CertVerifyTimeValidity(NULL, cert_context->pCertInfo) != 0)
+        return FALSE;
+
+    // Verify private key metadata is associated with this certificate.
+    // TODO(ppi): Is this really needed? Isn't it equivalent to leaving
+    // CERT_CHAIN_FIND_BY_ISSUER_NO_KEY_FLAG not set in |find_flags| argument of
+    // CertFindChainInStore()?
+    if (!CertGetCertificateContextProperty(
+        cert_context, CERT_KEY_PROV_INFO_PROP_ID, NULL, &size)) {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
 static int capi_load_ssl_client_cert(ENGINE *e, SSL *ssl,
                                      STACK_OF(X509_NAME) *ca_dn, X509 **pcert,
                                      EVP_PKEY **pkey, STACK_OF(X509) **pother,
@@ -1569,6 +1607,8 @@
     PCCERT_CONTEXT cert = NULL, excert = NULL;
     CAPI_CTX *ctx;
     CAPI_KEY *key;
+    CERT_NAME_BLOB* issuers;
+
     /* 1C:Boris Evtifeev: in/out hash for client cert */
     unsigned long* cert_id_out = (unsigned long*)callback_data;
     unsigned long cert_id_selmode   = cert_id_out[0]; /* 0 - any, 1 - hash, 2 - dlg/don't have */
@@ -1575,6 +1615,12 @@
     unsigned long cert_id_hash      = cert_id_out[1];
     unsigned long xhash = 0;
 
+    CERT_CHAIN_FIND_BY_ISSUER_PARA find_by_issuer_para;
+    PCCERT_CHAIN_CONTEXT chain_context = NULL;
+    DWORD find_flags = 
+        CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG |
+        CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG;
+
     STACK_OF(X509) *serial_certs = NULL;
     int serial_cert_idx = 0;
     X509 *serial_cert_x = NULL;
@@ -1592,11 +1638,45 @@
     hstore = capi_open_store(ctx, storename);
     if (!hstore)
         return 0;
+
+    issuers = OPENSSL_malloc(sizeof(CERT_NAME_BLOB) * sk_X509_NAME_num(ca_dn));
+    for (i = 0; i < sk_X509_NAME_num(ca_dn); i++) {
+        X509_NAME* nm = sk_X509_NAME_value(ca_dn, i);
+
+# ifndef OPENSSL_NO_BUFFER
+        issuers[i].cbData = nm->bytes->length;
+        issuers[i].pbData = (BYTE*)nm->bytes->data;
+# else
+        issuers[i].cbData = sizeof(nm->bytes);
+        issuers[i].pbData = (BYTE*)nm->bytes;
+# endif
+    }
+
+    // Enumerate the client certificates.
+    memset(&find_by_issuer_para, 0, sizeof(find_by_issuer_para));
+    find_by_issuer_para.cbSize = sizeof(find_by_issuer_para);
+    find_by_issuer_para.pszUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH;
+    find_by_issuer_para.cIssuer = sk_X509_NAME_num(ca_dn);
+    find_by_issuer_para.rgIssuer = issuers;
+    find_by_issuer_para.pfnFindCallback = ClientCertFindCallback;
+
+
     /* Enumerate all certificates collect any matches */
-    for (i = 0;; i++) {
-        cert = CertEnumCertificatesInStore(hstore, cert);
-        if (!cert)
+    for (;;) {
+        // Find a certificate chain.
+        chain_context = CertFindChainInStore(hstore,
+            X509_ASN_ENCODING,
+            find_flags,
+            CERT_CHAIN_FIND_BY_ISSUER,
+            &find_by_issuer_para,
+            chain_context);
+
+        if (!chain_context)
             break;
+
+        // Get the leaf certificate.
+        cert = chain_context->rgpChain[0]->rgpElement[0]->pCertContext;
+
         p = cert->pbCertEncoded;
         x = d2i_X509(NULL, &p, cert->cbCertEncoded);
         if (!x) {
@@ -1603,46 +1683,44 @@
             CAPI_trace(ctx, "Can't Parse Certificate %d\n", i);
             continue;
         }
-        if (cert_issuer_match(ca_dn, x)
-            && X509_check_purpose(x, X509_PURPOSE_SSL_CLIENT, 0)) {
-            key = capi_get_cert_key(ctx, cert);
-            if (!key) {
-                X509_free(x);
-                continue;
-            }
-            /*
-             * Match found: attach extra data to it so we can retrieve the
-             * key later.
-             */
-            excert = CertDuplicateCertificateContext(cert);
-            key->pcert = excert;
-            X509_set_ex_data(x, cert_capi_idx, key);
 
-            if (!certs)
-                certs = sk_X509_new_null();
+        key = capi_get_cert_key(ctx, cert);
+        if (!key) {
+            X509_free(x);
+            continue;
+        }
 
-            sk_X509_push(certs, x);
+        /*
+        * Match found: attach extra data to it so we can retrieve the
+        * key later.
+        */
+        excert = CertDuplicateCertificateContext(cert);
+        key->pcert = excert;
+        X509_set_ex_data(x, cert_capi_idx, key);
 
-            /* 1C:Boris Evtifeev: */
-            if( 1 == cert_id_selmode ) /* hash */
+        if (!certs)
+            certs = sk_X509_new_null();
+
+        sk_X509_push(certs, x);
+
+        /* 1C:Boris Evtifeev: */
+        if( 1 == cert_id_selmode ) /* hash */
+        {
+            xhash = X509_issuer_and_serial_hash(x);
+            if( cert_id_hash == xhash )
             {
-                xhash = X509_issuer_and_serial_hash(x);
-                if( cert_id_hash == xhash )
-                {
-                    if (!serial_certs)
-                        serial_certs = sk_X509_new_null();
-                    sk_X509_push(serial_certs, x);
-                }
+                if (!serial_certs)
+                    serial_certs = sk_X509_new_null();
+                sk_X509_push(serial_certs, x);
             }
-            /* /1C:Boris Evtifeev */
+        }
+        /* /1C:Boris Evtifeev */
+    }
 
-        } else
-            X509_free(x);
+    OPENSSL_free(issuers);
 
-    }
-
-    if (cert)
-        CertFreeCertificateContext(cert);
+    if (chain_context)
+        CertFreeCertificateChain(chain_context);
     if (hstore)
         CertCloseStore(hstore, 0);
 
@@ -1722,7 +1800,6 @@
     return 1;
 
 }
-
 /* Simple client cert selection function: always select first */
 
 static int cert_select_simple(ENGINE *e, SSL *ssl, STACK_OF(X509) *certs)
