gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnurl] 90/178: schannel: add support for CURLOPT_CAINFO


From: gnunet
Subject: [GNUnet-SVN] [gnurl] 90/178: schannel: add support for CURLOPT_CAINFO
Date: Wed, 23 May 2018 12:25:25 +0200

This is an automated email from the git hooks/post-receive script.

ng0 pushed a commit to branch master
in repository gnurl.

commit 899630021153b2a26a43008cccc6620b6c3f9bbf
Author: Dan McNulty <address@hidden>
AuthorDate: Fri Mar 10 14:27:30 2017 -0600

    schannel: add support for CURLOPT_CAINFO
    
    - Move verify_certificate functionality in schannel.c into a new
      file called schannel_verify.c. Additionally, some structure defintions
      from schannel.c have been moved to schannel.h to allow them to be
      used in schannel_verify.c.
    
    - Make verify_certificate functionality for Schannel available on
      all versions of Windows instead of just Windows CE. verify_certificate
      will be invoked on Windows CE or when the user specifies
      CURLOPT_CAINFO and CURLOPT_SSL_VERIFYPEER.
    
    - In verify_certificate, create a custom certificate chain engine that
      exclusively trusts the certificate store backed by the CURLOPT_CAINFO
      file.
    
    - doc updates of --cacert/CAINFO support for schannel
    
    - Use CERT_NAME_SEARCH_ALL_NAMES_FLAG when invoking CertGetNameString
      when available. This implements a TODO in schannel.c to improve
      handling of multiple SANs in a certificate. In particular, all SANs
      will now be searched instead of just the first name.
    
    - Update tool_operate.c to not search for the curl-ca-bundle.crt file
      when using Schannel to maintain backward compatibility. Previously,
      any curl-ca-bundle.crt file found in that search would have been
      ignored by Schannel. But, with CAINFO support, the file found by
      that search would have been used as the certificate store and
      could cause issues for any users that have curl-ca-bundle.crt in
      the search path.
    
    - Update url.c to not set the build time CURL_CA_BUNDLE if the selected
      SSL backend is Schannel. We allow setting CA location for schannel
      only when explicitly specified by the user via CURLOPT_CAINFO /
      --cacert.
    
    - Add new test cases 3000 and 3001. These test cases check that the first
      and last SAN, respectively, matches the connection hostname. New test
      certificates have been added for these cases. For 3000, the certificate
      prefix is Server-localhost-firstSAN and for 3001, the certificate
      prefix is Server-localhost-secondSAN.
    
    - Remove TODO 15.2 (Add support for custom server certificate
      validation), this commit addresses it.
    
    Closes https://github.com/curl/curl/pull/1325
---
 docs/TODO                                        |  12 -
 docs/cmdline-opts/cacert.d                       |   5 +
 docs/libcurl/opts/CURLOPT_CAINFO.3               |   5 +
 lib/Makefile.inc                                 |   4 +-
 lib/hostcheck.c                                  |   2 +-
 lib/url.c                                        |  34 +-
 lib/vtls/schannel.c                              | 233 ++--------
 lib/vtls/schannel.h                              |  40 ++
 lib/vtls/schannel_verify.c                       | 551 +++++++++++++++++++++++
 src/tool_doswin.c                                |  11 +-
 src/tool_doswin.h                                |   1 +
 src/tool_operate.c                               |  76 ++--
 tests/certs/Makefile.am                          |  29 +-
 tests/certs/Server-localhost-firstSAN-sv.crl     |  13 +
 tests/certs/Server-localhost-firstSAN-sv.crt     |  80 ++++
 tests/certs/Server-localhost-firstSAN-sv.csr     |  11 +
 tests/certs/Server-localhost-firstSAN-sv.der     | Bin 0 -> 862 bytes
 tests/certs/Server-localhost-firstSAN-sv.dhp     |   0
 tests/certs/Server-localhost-firstSAN-sv.key     |  15 +
 tests/certs/Server-localhost-firstSAN-sv.pem     | 120 +++++
 tests/certs/Server-localhost-firstSAN-sv.prm     |  25 +
 tests/certs/Server-localhost-firstSAN-sv.pub.der | Bin 0 -> 162 bytes
 tests/certs/Server-localhost-firstSAN-sv.pub.pem |   6 +
 tests/certs/Server-localhost-lastSAN-sv.crl      |  14 +
 tests/certs/Server-localhost-lastSAN-sv.crt      |  80 ++++
 tests/certs/Server-localhost-lastSAN-sv.csr      |  11 +
 tests/certs/Server-localhost-lastSAN-sv.der      | Bin 0 -> 862 bytes
 tests/certs/Server-localhost-lastSAN-sv.dhp      |   0
 tests/certs/Server-localhost-lastSAN-sv.key      |  15 +
 tests/certs/Server-localhost-lastSAN-sv.pem      | 120 +++++
 tests/certs/Server-localhost-lastSAN-sv.prm      |  25 +
 tests/certs/Server-localhost-lastSAN-sv.pub.der  | Bin 0 -> 162 bytes
 tests/certs/Server-localhost-lastSAN-sv.pub.pem  |   6 +
 tests/data/Makefile.inc                          |   4 +-
 tests/data/test3000                              |  57 +++
 tests/data/test3001                              |  57 +++
 winbuild/MakefileBuild.vc                        |   2 +-
 37 files changed, 1406 insertions(+), 258 deletions(-)

diff --git a/docs/TODO b/docs/TODO
index 337620924..b6b6dfe0d 100644
--- a/docs/TODO
+++ b/docs/TODO
@@ -121,7 +121,6 @@
 
  15. WinSSL/SChannel
  15.1 Add support for client certificate authentication
- 15.2 Add support for custom server certificate validation
  15.3 Add support for the --ciphers option
 
  16. SASL
@@ -823,17 +822,6 @@ that doesn't exist on the server, just like 
--ftp-create-dirs.
  - Getting a Certificate for Schannel
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa375447.aspx
 
-15.2 Add support for custom server certificate validation
-
- WinSSL/SChannel currently makes use of the OS-level system and user
- certificate trust store. This does not allow the application or user to
- customize the server certificate validation process using curl or libcurl.
-
- Therefore support for the existing --cacert or --capath options should be
- implemented by supplying a custom certificate to the SChannel APIs, see:
- - Getting a Certificate for Schannel
-   https://msdn.microsoft.com/en-us/library/windows/desktop/aa375447.aspx
-
 15.3 Add support for the --ciphers option
 
  The cipher suites used by WinSSL/SChannel are configured on an OS-level
diff --git a/docs/cmdline-opts/cacert.d b/docs/cmdline-opts/cacert.d
index b2ecf9088..073ad3a9a 100644
--- a/docs/cmdline-opts/cacert.d
+++ b/docs/cmdline-opts/cacert.d
@@ -25,4 +25,9 @@ should not be set. If the option is not set, then curl will 
use the
 certificates in the system and user Keychain to verify the peer, which is the
 preferred method of verifying the peer's certificate chain.
 
+(Schannel/WinSSL only) This option is supported for WinSSL in Windows 7 or
+later with libcurl 7.60 or later. This option is supported for backward
+compatibility with other SSL engines; instead it is recommended to use Windows'
+store of root certificates (the default for WinSSL).
+
 If this option is used several times, the last one will be used.
diff --git a/docs/libcurl/opts/CURLOPT_CAINFO.3 
b/docs/libcurl/opts/CURLOPT_CAINFO.3
index bc094ef00..4e7db0448 100644
--- a/docs/libcurl/opts/CURLOPT_CAINFO.3
+++ b/docs/libcurl/opts/CURLOPT_CAINFO.3
@@ -52,6 +52,11 @@ should not be set. If the option is not set, then curl will 
use the
 certificates in the system and user Keychain to verify the peer, which is the
 preferred method of verifying the peer's certificate chain.
 
+(Schannel/WinSSL only) This option is supported for WinSSL in Windows 7 or
+later with libcurl 7.60 or later. This option is supported for backward
+compatibility with other SSL engines; instead it is recommended to use Windows'
+store of root certificates (the default for WinSSL).
+
 The application does not have to keep the string around after setting this
 option.
 .SH DEFAULT
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index 69f9b403d..61c23411d 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -29,8 +29,8 @@ LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h
 
 LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c     \
   vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c               \
-  vtls/cyassl.c vtls/schannel.c vtls/darwinssl.c vtls/gskit.c           \
-  vtls/mbedtls.c
+  vtls/cyassl.c vtls/schannel.c vtls/schannel_verify.c                  \
+  vtls/darwinssl.c vtls/gskit.c vtls/mbedtls.c
 
 LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h                \
   vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h vtls/axtls.h   \
diff --git a/lib/hostcheck.c b/lib/hostcheck.c
index 37bcc12c1..c9d8112d8 100644
--- a/lib/hostcheck.c
+++ b/lib/hostcheck.c
@@ -25,7 +25,7 @@
 #if defined(USE_OPENSSL)                                \
   || defined(USE_AXTLS)                                 \
   || defined(USE_GSKIT)                                 \
-  || (defined(USE_SCHANNEL) && defined(_WIN32_WCE))
+  || defined(USE_SCHANNEL)
 /* these backends use functions from this file */
 
 #ifdef HAVE_NETINET_IN_H
diff --git a/lib/url.c b/lib/url.c
index 8c9c69141..2491fa2da 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -488,25 +488,33 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
   set->socks5_gssapi_nec = FALSE;
 #endif
 
-  /* This is our preferred CA cert bundle/path since install time */
+  /* Set the default CA cert bundle/path detected/specified at build time.
+   *
+   * If Schannel (WinSSL) is the selected SSL backend then these locations
+   * are ignored. We allow setting CA location for schannel only when
+   * explicitly specified by the user via CURLOPT_CAINFO / --cacert.
+   */
+  if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
 #if defined(CURL_CA_BUNDLE)
-  result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE);
-  if(result)
-    return result;
+    result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE);
+    if(result)
+      return result;
 
-  result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], CURL_CA_BUNDLE);
-  if(result)
-    return result;
+    result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
+                            CURL_CA_BUNDLE);
+    if(result)
+      return result;
 #endif
 #if defined(CURL_CA_PATH)
-  result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH);
-  if(result)
-    return result;
+    result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH);
+    if(result)
+      return result;
 
-  result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
-  if(result)
-    return result;
+    result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
+    if(result)
+      return result;
 #endif
+  }
 
   set->wildcard_enabled = FALSE;
   set->chunk_bgn      = ZERO_NULL;
diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index 4f3f0ce85..5387d8713 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -42,13 +42,12 @@
 
 #ifdef USE_SCHANNEL
 
+#define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
+
 #ifndef USE_WINDOWS_SSPI
 #  error "Can't compile SCHANNEL support without SSPI."
 #endif
 
-#include <schnlsp.h>
-#include <schannel.h>
-#include "curl_sspi.h"
 #include "schannel.h"
 #include "vtls.h"
 #include "sendf.h"
@@ -61,7 +60,6 @@
 #include "x509asn1.h"
 #include "curl_printf.h"
 #include "system_win32.h"
-#include "hostcheck.h"
 
  /* The last #include file should be: */
 #include "curl_memory.h"
@@ -142,37 +140,6 @@
 #  define CALG_SHA_256 0x0000800c
 #endif
 
-/* Structs to store Schannel handles */
-struct curl_schannel_cred {
-  CredHandle cred_handle;
-  TimeStamp time_stamp;
-  int refcount;
-};
-
-struct curl_schannel_ctxt {
-  CtxtHandle ctxt_handle;
-  TimeStamp time_stamp;
-};
-
-struct ssl_backend_data {
-  struct curl_schannel_cred *cred;
-  struct curl_schannel_ctxt *ctxt;
-  SecPkgContext_StreamSizes stream_sizes;
-  size_t encdata_length, decdata_length;
-  size_t encdata_offset, decdata_offset;
-  unsigned char *encdata_buffer, *decdata_buffer;
-  /* encdata_is_incomplete: if encdata contains only a partial record that
-     can't be decrypted without another Curl_read_plain (that is, status is
-     SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes
-     more bytes into encdata then set this back to false. */
-  bool encdata_is_incomplete;
-  unsigned long req_flags, ret_flags;
-  CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
-  bool recv_sspi_close_notify; /* true if connection closed by close_notify */
-  bool recv_connection_closed; /* true if connection closed, regardless how */
-  bool use_alpn; /* true if ALPN is used for this connection */
-};
-
 #define BACKEND connssl->backend
 
 static Curl_recv schannel_recv;
@@ -181,10 +148,6 @@ static Curl_send schannel_send;
 static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
                                     const char *pinnedpubkey);
 
-#ifdef _WIN32_WCE
-static CURLcode verify_certificate(struct connectdata *conn, int sockindex);
-#endif
-
 static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
                           void *BufDataPtr, unsigned long BufByteSize)
 {
@@ -335,6 +298,26 @@ schannel_connect_step1(struct connectdata *conn, int 
sockindex)
   BACKEND->use_alpn = false;
 #endif
 
+#ifdef _WIN32_WCE
+  /* certificate validation on CE doesn't seem to work right; we'll
+   * do it following a more manual process. */
+  BACKEND->use_manual_cred_validation = true;
+#else
+  if(SSL_CONN_CONFIG(CAfile)) {
+    if(Curl_verify_windows_version(6, 1, PLATFORM_WINNT,
+                                   VERSION_GREATER_THAN_EQUAL)) {
+      BACKEND->use_manual_cred_validation = true;
+    }
+    else {
+      failf(data, "schannel: this version of Windows is too old to support "
+            "certificate verification via CA bundle file.");
+      return CURLE_SSL_CACERT_BADFILE;
+    }
+  }
+  else
+    BACKEND->use_manual_cred_validation = false;
+#endif
+
   BACKEND->cred = NULL;
 
   /* check for an existing re-usable credential handle */
@@ -358,26 +341,23 @@ schannel_connect_step1(struct connectdata *conn, int 
sockindex)
     schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
 
     if(conn->ssl_config.verifypeer) {
-#ifdef _WIN32_WCE
-      /* certificate validation on CE doesn't seem to work right; we'll
-         do it following a more manual process. */
-      schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
-        SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
-        SCH_CRED_IGNORE_REVOCATION_OFFLINE;
-#else
-      schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
+      if(BACKEND->use_manual_cred_validation)
+        schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
+      else
+        schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
+
       /* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */
-      if(data->set.ssl.no_revoke)
+      if(data->set.ssl.no_revoke) {
         schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
           SCH_CRED_IGNORE_REVOCATION_OFFLINE;
-      else
-        schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
-#endif
-      if(data->set.ssl.no_revoke)
+
         infof(data, "schannel: disabled server certificate revocation "
                     "checks\n");
-      else
+      }
+      else {
+        schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
         infof(data, "schannel: checking server certificate revocation\n");
+      }
     }
     else {
       schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
@@ -898,12 +878,9 @@ schannel_connect_step2(struct connectdata *conn, int 
sockindex)
     }
   }
 
-#ifdef _WIN32_WCE
-  /* Windows CE doesn't do any server certificate validation.
-     We have to do it manually. */
-  if(conn->ssl_config.verifypeer)
+  if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) {
     return verify_certificate(conn, sockindex);
-#endif
+  }
 
   return CURLE_OK;
 }
@@ -1868,146 +1845,6 @@ static CURLcode pkp_pin_peer_pubkey(struct connectdata 
*conn, int sockindex,
   return result;
 }
 
-#ifdef _WIN32_WCE
-static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
-{
-  SECURITY_STATUS status;
-  struct Curl_easy *data = conn->data;
-  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  CURLcode result = CURLE_OK;
-  CERT_CONTEXT *pCertContextServer = NULL;
-  const CERT_CHAIN_CONTEXT *pChainContext = NULL;
-  const char * const conn_hostname = SSL_IS_PROXY() ?
-    conn->http_proxy.host.name :
-    conn->host.name;
-
-  status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
-                                            SECPKG_ATTR_REMOTE_CERT_CONTEXT,
-                                            &pCertContextServer);
-
-  if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
-    failf(data, "schannel: Failed to read remote certificate context: %s",
-          Curl_sspi_strerror(conn, status));
-    result = CURLE_PEER_FAILED_VERIFICATION;
-  }
-
-  if(result == CURLE_OK) {
-    CERT_CHAIN_PARA ChainPara;
-    memset(&ChainPara, 0, sizeof(ChainPara));
-    ChainPara.cbSize = sizeof(ChainPara);
-
-    if(!CertGetCertificateChain(NULL,
-                                pCertContextServer,
-                                NULL,
-                                pCertContextServer->hCertStore,
-                                &ChainPara,
-                                (data->set.ssl.no_revoke ? 0 :
-                                 CERT_CHAIN_REVOCATION_CHECK_CHAIN),
-                                NULL,
-                                &pChainContext)) {
-      failf(data, "schannel: CertGetCertificateChain failed: %s",
-            Curl_sspi_strerror(conn, GetLastError()));
-      pChainContext = NULL;
-      result = CURLE_PEER_FAILED_VERIFICATION;
-    }
-
-    if(result == CURLE_OK) {
-      CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
-      DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
-      dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
-      if(dwTrustErrorMask) {
-        if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
-          failf(data, "schannel: CertGetCertificateChain trust error"
-                " CERT_TRUST_IS_REVOKED");
-        else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
-          failf(data, "schannel: CertGetCertificateChain trust error"
-                " CERT_TRUST_IS_PARTIAL_CHAIN");
-        else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
-          failf(data, "schannel: CertGetCertificateChain trust error"
-                " CERT_TRUST_IS_UNTRUSTED_ROOT");
-        else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
-          failf(data, "schannel: CertGetCertificateChain trust error"
-                " CERT_TRUST_IS_NOT_TIME_VALID");
-        else
-          failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
-                dwTrustErrorMask);
-        result = CURLE_PEER_FAILED_VERIFICATION;
-      }
-    }
-  }
-
-  if(result == CURLE_OK) {
-    if(conn->ssl_config.verifyhost) {
-      TCHAR cert_hostname_buff[256];
-      DWORD len;
-
-      /* TODO: Fix this for certificates with multiple alternative names.
-      Right now we're only asking for the first preferred alternative name.
-      Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG
-      (if WinCE supports that?) and run this section in a loop for each.
-      https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx
-      curl: (51) schannel: CertGetNameString() certificate hostname
-      (.google.com) did not match connection (google.com)
-      */
-      len = CertGetNameString(pCertContextServer,
-                              CERT_NAME_DNS_TYPE,
-                              CERT_NAME_DISABLE_IE4_UTF8_FLAG,
-                              NULL,
-                              cert_hostname_buff,
-                              256);
-      if(len > 0) {
-        const char *cert_hostname;
-
-        /* Comparing the cert name and the connection hostname encoded as UTF-8
-         * is acceptable since both values are assumed to use ASCII
-         * (or some equivalent) encoding
-         */
-        cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname_buff);
-        if(!cert_hostname) {
-          result = CURLE_OUT_OF_MEMORY;
-        }
-        else{
-          int match_result;
-
-          match_result = Curl_cert_hostcheck(cert_hostname, conn->host.name);
-          if(match_result == CURL_HOST_MATCH) {
-            infof(data,
-                  "schannel: connection hostname (%s) validated "
-                  "against certificate name (%s)\n",
-                  conn->host.name,
-                  cert_hostname);
-            result = CURLE_OK;
-          }
-          else{
-            failf(data,
-                  "schannel: connection hostname (%s) "
-                  "does not match certificate name (%s)",
-                  conn->host.name,
-                  cert_hostname);
-            result = CURLE_PEER_FAILED_VERIFICATION;
-          }
-          Curl_unicodefree(cert_hostname);
-        }
-      }
-      else {
-        failf(data,
-              "schannel: CertGetNameString did not provide any "
-              "certificate name information");
-        result = CURLE_PEER_FAILED_VERIFICATION;
-      }
-    }
-  }
-
-  if(pChainContext)
-    CertFreeCertificateChain(pChainContext);
-
-  if(pCertContextServer)
-    CertFreeCertificateContext(pCertContextServer);
-
-  return result;
-}
-#endif /* _WIN32_WCE */
-
 static void Curl_schannel_checksum(const unsigned char *input,
                       size_t inputlen,
                       unsigned char *checksum,
diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h
index 932103da4..447690027 100644
--- a/lib/vtls/schannel.h
+++ b/lib/vtls/schannel.h
@@ -26,9 +26,49 @@
 
 #ifdef USE_SCHANNEL
 
+#include <schnlsp.h>
+#include <schannel.h>
+#include "curl_sspi.h"
+
 #include "urldata.h"
 
 extern const struct Curl_ssl Curl_ssl_schannel;
 
+CURLcode verify_certificate(struct connectdata *conn, int sockindex);
+
+/* structs to expose only in schannel.c and schannel_verify.c */
+#ifdef EXPOSE_SCHANNEL_INTERNAL_STRUCTS
+struct curl_schannel_cred {
+  CredHandle cred_handle;
+  TimeStamp time_stamp;
+  int refcount;
+};
+
+struct curl_schannel_ctxt {
+  CtxtHandle ctxt_handle;
+  TimeStamp time_stamp;
+};
+
+struct ssl_backend_data {
+  struct curl_schannel_cred *cred;
+  struct curl_schannel_ctxt *ctxt;
+  SecPkgContext_StreamSizes stream_sizes;
+  size_t encdata_length, decdata_length;
+  size_t encdata_offset, decdata_offset;
+  unsigned char *encdata_buffer, *decdata_buffer;
+  /* encdata_is_incomplete: if encdata contains only a partial record that
+     can't be decrypted without another Curl_read_plain (that is, status is
+     SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes
+     more bytes into encdata then set this back to false. */
+  bool encdata_is_incomplete;
+  unsigned long req_flags, ret_flags;
+  CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
+  bool recv_sspi_close_notify; /* true if connection closed by close_notify */
+  bool recv_connection_closed; /* true if connection closed, regardless how */
+  bool use_alpn; /* true if ALPN is used for this connection */
+  bool use_manual_cred_validation; /* true if manual cred validation is used */
+};
+#endif /* EXPOSE_SCHANNEL_INTERNAL_STRUCTS */
+
 #endif /* USE_SCHANNEL */
 #endif /* HEADER_CURL_SCHANNEL_H */
diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c
new file mode 100644
index 000000000..db187dd6b
--- /dev/null
+++ b/lib/vtls/schannel_verify.c
@@ -0,0 +1,551 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2016, Marc Hoersken, <address@hidden>
+ * Copyright (C) 2012, Mark Salisbury, <address@hidden>
+ * Copyright (C) 2012 - 2018, Daniel Stenberg, <address@hidden>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for SChannel-specific certificate verification. This code should
+ * only be invoked by code in schannel.c.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_SCHANNEL
+
+#define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
+
+#ifndef USE_WINDOWS_SSPI
+#  error "Can't compile SCHANNEL support without SSPI."
+#endif
+
+#include "schannel.h"
+#include "vtls.h"
+#include "sendf.h"
+#include "strerror.h"
+#include "curl_multibyte.h"
+#include "curl_printf.h"
+#include "hostcheck.h"
+#include "system_win32.h"
+
+/* The last #include file should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define BACKEND connssl->backend
+
+#define MAX_CAFILE_SIZE 1048576 /* 1 MiB */
+#define BEGIN_CERT "-----BEGIN CERTIFICATE-----\n"
+#define END_CERT "\n-----END CERTIFICATE-----"
+
+typedef struct {
+  DWORD cbSize;
+  HCERTSTORE hRestrictedRoot;
+  HCERTSTORE hRestrictedTrust;
+  HCERTSTORE hRestrictedOther;
+  DWORD cAdditionalStore;
+  HCERTSTORE *rghAdditionalStore;
+  DWORD dwFlags;
+  DWORD dwUrlRetrievalTimeout;
+  DWORD MaximumCachedCertificates;
+  DWORD CycleDetectionModulus;
+  HCERTSTORE hExclusiveRoot;
+  HCERTSTORE hExclusiveTrustedPeople;
+} CERT_CHAIN_ENGINE_CONFIG_WIN7, *PCERT_CHAIN_ENGINE_CONFIG_WIN7;
+
+
+static CURLcode add_certs_to_store(HCERTSTORE trust_store,
+                                   const char *ca_file,
+                                   struct connectdata *conn)
+{
+  CURLcode result;
+  struct Curl_easy *data = conn->data;
+  HANDLE ca_file_handle = INVALID_HANDLE_VALUE;
+  LARGE_INTEGER file_size;
+  char *ca_file_buffer = NULL;
+  char *current_ca_file_ptr = NULL;
+  const TCHAR *ca_file_tstr = NULL;
+  size_t ca_file_bufsize = 0;
+  DWORD total_bytes_read = 0;
+  bool more_certs = 0;
+  int num_certs = 0;
+  size_t END_CERT_LEN;
+
+  ca_file_tstr = Curl_convert_UTF8_to_tchar(ca_file);
+  if(!ca_file_tstr) {
+    failf(data,
+          "schannel: invalid path name for CA file '%s': %s",
+          ca_file, Curl_strerror(conn, GetLastError()));
+    result = CURLE_SSL_CACERT_BADFILE;
+    goto cleanup;
+  }
+
+  /*
+   * Read the CA file completely into memory before parsing it. This
+   * optimizes for the common case where the CA file will be relatively
+   * small ( < 1 MiB ).
+   */
+  ca_file_handle = CreateFile(ca_file_tstr,
+                              GENERIC_READ,
+                              0,
+                              NULL,
+                              OPEN_EXISTING,
+                              FILE_ATTRIBUTE_NORMAL,
+                              NULL);
+  if(ca_file_handle == INVALID_HANDLE_VALUE) {
+    failf(data,
+          "schannel: failed to open CA file '%s': %s",
+          ca_file, Curl_strerror(conn, GetLastError()));
+    result = CURLE_SSL_CACERT_BADFILE;
+    goto cleanup;
+  }
+
+  if(!GetFileSizeEx(ca_file_handle, &file_size)) {
+    failf(data,
+          "schannel: failed to determine size of CA file '%s': %s",
+          ca_file, Curl_strerror(conn, GetLastError()));
+    result = CURLE_SSL_CACERT_BADFILE;
+    goto cleanup;
+  }
+
+  if(file_size.QuadPart > MAX_CAFILE_SIZE) {
+    failf(data,
+          "schannel: CA file exceeds max size of %u bytes",
+          MAX_CAFILE_SIZE);
+    result = CURLE_OUT_OF_MEMORY;
+    goto cleanup;
+  }
+
+  ca_file_bufsize = (size_t)file_size.QuadPart;
+  ca_file_buffer = (char *)malloc(ca_file_bufsize + 1);
+  if(!ca_file_buffer) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto cleanup;
+  }
+
+  result = CURLE_OK;
+  while(total_bytes_read < ca_file_bufsize) {
+    DWORD bytes_to_read = (DWORD)(ca_file_bufsize - total_bytes_read);
+    DWORD bytes_read = 0;
+
+    if(!ReadFile(ca_file_handle, ca_file_buffer + total_bytes_read,
+                 bytes_to_read, &bytes_read, NULL)) {
+
+      failf(data,
+            "schannel: failed to read from CA file '%s': %s",
+            ca_file, Curl_strerror(conn, GetLastError()));
+      result = CURLE_SSL_CACERT_BADFILE;
+      goto cleanup;
+    }
+    if(bytes_read == 0) {
+      /* Premature EOF -- adjust the bufsize to the new value */
+      ca_file_bufsize = total_bytes_read;
+    }
+    else {
+      total_bytes_read += bytes_read;
+    }
+  }
+
+  /* Null terminate the buffer */
+  ca_file_buffer[ca_file_bufsize] = '\0';
+
+  if(result != CURLE_OK) {
+    goto cleanup;
+  }
+
+  END_CERT_LEN = strlen(END_CERT);
+
+  more_certs = 1;
+  current_ca_file_ptr = ca_file_buffer;
+  while(more_certs && *current_ca_file_ptr != '\0') {
+    char *begin_cert_ptr = strstr(current_ca_file_ptr, BEGIN_CERT);
+    if(!begin_cert_ptr) {
+      more_certs = 0;
+    }
+    else {
+      char *end_cert_ptr = strstr(begin_cert_ptr, END_CERT);
+      if(!end_cert_ptr) {
+        failf(data,
+              "schannel: CA file '%s' is not correctly formatted",
+              ca_file);
+        result = CURLE_SSL_CACERT_BADFILE;
+        more_certs = 0;
+      }
+      else {
+        CERT_BLOB cert_blob;
+        CERT_CONTEXT *cert_context = NULL;
+        BOOL add_cert_result = FALSE;
+        DWORD actual_content_type = 0;
+        DWORD cert_size = (DWORD)
+          ((end_cert_ptr + END_CERT_LEN) - begin_cert_ptr);
+
+        cert_blob.pbData = (BYTE *)begin_cert_ptr;
+        cert_blob.cbData = cert_size;
+        if(!CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
+                             &cert_blob,
+                             CERT_QUERY_CONTENT_FLAG_CERT,
+                             CERT_QUERY_FORMAT_FLAG_ALL,
+                             0,
+                             NULL,
+                             &actual_content_type,
+                             NULL,
+                             NULL,
+                             NULL,
+                             &cert_context)) {
+
+          failf(data,
+                "schannel: failed to extract certificate from CA file "
+                "'%s': %s",
+                ca_file, Curl_strerror(conn, GetLastError()));
+          result = CURLE_SSL_CACERT_BADFILE;
+          more_certs = 0;
+        }
+        else {
+          current_ca_file_ptr = begin_cert_ptr + cert_size;
+
+          /* Sanity check that the cert_context object is the right type */
+          if(CERT_QUERY_CONTENT_CERT != actual_content_type) {
+            failf(data,
+                  "schannel: unexpected content type '%d' when extracting "
+                  "certificate from CA file '%s'",
+                  actual_content_type, ca_file);
+            result = CURLE_SSL_CACERT_BADFILE;
+            more_certs = 0;
+          }
+          else {
+            add_cert_result =
+              CertAddCertificateContextToStore(trust_store,
+                                               cert_context,
+                                               CERT_STORE_ADD_ALWAYS,
+                                               NULL);
+            CertFreeCertificateContext(cert_context);
+            if(!add_cert_result) {
+              failf(data,
+                    "schannel: failed to add certificate from CA file '%s'"
+                    "to certificate store: %s",
+                    ca_file, Curl_strerror(conn, GetLastError()));
+              result = CURLE_SSL_CACERT_BADFILE;
+              more_certs = 0;
+            }
+            else {
+              num_certs++;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  if(result == CURLE_OK) {
+    if(!num_certs) {
+      infof(data,
+            "schannel: did not add any certificates from CA file '%s'\n",
+            ca_file);
+    }
+    else {
+      infof(data,
+            "schannel: added %d certificate(s) from CA file '%s'\n",
+            num_certs, ca_file);
+    }
+  }
+
+cleanup:
+  if(ca_file_handle != INVALID_HANDLE_VALUE) {
+    CloseHandle(ca_file_handle);
+  }
+  Curl_safefree(ca_file_buffer);
+  Curl_unicodefree(ca_file_tstr);
+
+  return result;
+}
+
+static CURLcode verify_host(struct Curl_easy *data,
+                            CERT_CONTEXT *pCertContextServer,
+                            const char * const conn_hostname)
+{
+  CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
+  TCHAR *cert_hostname_buff = NULL;
+  size_t cert_hostname_buff_index = 0;
+  DWORD len = 0;
+  DWORD actual_len = 0;
+
+  /* CertGetNameString will provide the 8-bit character string without
+   * any decoding */
+  DWORD name_flags = CERT_NAME_DISABLE_IE4_UTF8_FLAG;
+
+#ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
+  name_flags |= CERT_NAME_SEARCH_ALL_NAMES_FLAG;
+#endif
+
+  /* Determine the size of the string needed for the cert hostname */
+  len = CertGetNameString(pCertContextServer,
+                          CERT_NAME_DNS_TYPE,
+                          name_flags,
+                          NULL,
+                          NULL,
+                          0);
+  if(len == 0) {
+    failf(data,
+          "schannel: CertGetNameString() returned no "
+          "certificate name information");
+    result = CURLE_PEER_FAILED_VERIFICATION;
+    goto cleanup;
+  }
+
+  /* CertGetNameString guarantees that the returned name will not contain
+   * embedded null bytes. This appears to be undocumented behavior.
+   */
+  cert_hostname_buff = (LPTSTR)malloc(len * sizeof(TCHAR));
+  actual_len = CertGetNameString(pCertContextServer,
+                                 CERT_NAME_DNS_TYPE,
+                                 name_flags,
+                                 NULL,
+                                 (LPTSTR) cert_hostname_buff,
+                                 len);
+
+  /* Sanity check */
+  if(actual_len != len) {
+    failf(data,
+          "schannel: CertGetNameString() returned certificate "
+          "name information of unexpected size");
+    result = CURLE_PEER_FAILED_VERIFICATION;
+    goto cleanup;
+  }
+
+  /* If HAVE_CERT_NAME_SEARCH_ALL_NAMES is available, the output
+   * will contain all DNS names, where each name is null-terminated
+   * and the last DNS name is double null-terminated. Due to this
+   * encoding, use the length of the buffer to iterate over all names.
+   */
+  result = CURLE_PEER_FAILED_VERIFICATION;
+  while(cert_hostname_buff_index < len &&
+        cert_hostname_buff[cert_hostname_buff_index] != TEXT('\0') &&
+        result == CURLE_PEER_FAILED_VERIFICATION) {
+
+    char *cert_hostname;
+
+    /* Comparing the cert name and the connection hostname encoded as UTF-8
+     * is acceptable since both values are assumed to use ASCII
+     * (or some equivalent) encoding
+     */
+    cert_hostname = Curl_convert_tchar_to_UTF8(
+        &cert_hostname_buff[cert_hostname_buff_index]);
+    if(!cert_hostname) {
+      result = CURLE_OUT_OF_MEMORY;
+    }
+    else {
+      int match_result;
+
+      match_result = Curl_cert_hostcheck(cert_hostname, conn_hostname);
+      if(match_result == CURL_HOST_MATCH) {
+        infof(data,
+              "schannel: connection hostname (%s) validated "
+              "against certificate name (%s)\n",
+              conn_hostname, cert_hostname);
+        result = CURLE_OK;
+      }
+      else {
+        size_t cert_hostname_len;
+
+        infof(data,
+              "schannel: connection hostname (%s) did not match "
+              "against certificate name (%s)\n",
+              conn_hostname, cert_hostname);
+
+        cert_hostname_len = _tcslen(
+            &cert_hostname_buff[cert_hostname_buff_index]);
+
+        /* Move on to next cert name */
+        cert_hostname_buff_index += cert_hostname_len + 1;
+
+        result = CURLE_PEER_FAILED_VERIFICATION;
+      }
+      Curl_unicodefree(cert_hostname);
+    }
+  }
+
+  if(result == CURLE_PEER_FAILED_VERIFICATION) {
+    failf(data,
+          "schannel: CertGetNameString() failed to match "
+          "connection hostname (%s) against server certificate names",
+          conn_hostname);
+  }
+  else if(result != CURLE_OK)
+    failf(data, "schannel: server certificate name verification failed");
+
+cleanup:
+  Curl_unicodefree(cert_hostname_buff);
+
+  return result;
+}
+
+CURLcode verify_certificate(struct connectdata *conn, int sockindex)
+{
+  SECURITY_STATUS status;
+  struct Curl_easy *data = conn->data;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  CURLcode result = CURLE_OK;
+  CERT_CONTEXT *pCertContextServer = NULL;
+  const CERT_CHAIN_CONTEXT *pChainContext = NULL;
+  HCERTCHAINENGINE cert_chain_engine = NULL;
+  HCERTSTORE trust_store = NULL;
+  const char * const conn_hostname = SSL_IS_PROXY() ?
+    conn->http_proxy.host.name :
+    conn->host.name;
+
+  status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+                                            SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+                                            &pCertContextServer);
+
+  if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
+    failf(data, "schannel: Failed to read remote certificate context: %s",
+          Curl_sspi_strerror(conn, status));
+    result = CURLE_PEER_FAILED_VERIFICATION;
+  }
+
+  if(result == CURLE_OK && SSL_CONN_CONFIG(CAfile) &&
+      BACKEND->use_manual_cred_validation) {
+    /*
+     * Create a chain engine that uses the certificates in the CA file as
+     * trusted certificates. This is only supported on Windows 7+.
+     */
+
+    if(Curl_verify_windows_version(6, 1, PLATFORM_WINNT, VERSION_LESS_THAN)) {
+      failf(data, "schannel: this version of Windows is too old to support "
+            "certificate verification via CA bundle file.");
+      result = CURLE_SSL_CACERT_BADFILE;
+    }
+    else {
+      /* Open the certificate store */
+      trust_store = CertOpenStore(CERT_STORE_PROV_MEMORY,
+                                  0,
+                                  (HCRYPTPROV)NULL,
+                                  CERT_STORE_CREATE_NEW_FLAG,
+                                  NULL);
+      if(!trust_store) {
+        failf(data, "schannel: failed to create certificate store: %s",
+              Curl_strerror(conn, GetLastError()));
+        result = CURLE_SSL_CACERT_BADFILE;
+      }
+      else {
+        result = add_certs_to_store(trust_store, SSL_CONN_CONFIG(CAfile),
+                                    conn);
+      }
+    }
+
+    if(result == CURLE_OK) {
+      CERT_CHAIN_ENGINE_CONFIG_WIN7 engine_config;
+      BOOL create_engine_result;
+
+      memset(&engine_config, 0, sizeof(engine_config));
+      engine_config.cbSize = sizeof(engine_config);
+      engine_config.hExclusiveRoot = trust_store;
+
+      /* CertCreateCertificateChainEngine will check the expected size of the
+       * CERT_CHAIN_ENGINE_CONFIG structure and fail if the specified size
+       * does not match the expected size. When this occurs, it indicates that
+       * CAINFO is not supported on the version of Windows in use.
+       */
+      create_engine_result =
+        CertCreateCertificateChainEngine(
+          (CERT_CHAIN_ENGINE_CONFIG *)&engine_config, &cert_chain_engine);
+      if(!create_engine_result) {
+        failf(data,
+              "schannel: failed to create certificate chain engine: %s",
+              Curl_strerror(conn, GetLastError()));
+        result = CURLE_SSL_CACERT_BADFILE;
+      }
+    }
+  }
+
+  if(result == CURLE_OK) {
+    CERT_CHAIN_PARA ChainPara;
+
+    memset(&ChainPara, 0, sizeof(ChainPara));
+    ChainPara.cbSize = sizeof(ChainPara);
+
+    if(!CertGetCertificateChain(cert_chain_engine,
+                                pCertContextServer,
+                                NULL,
+                                pCertContextServer->hCertStore,
+                                &ChainPara,
+                                (data->set.ssl.no_revoke ? 0 :
+                                 CERT_CHAIN_REVOCATION_CHECK_CHAIN),
+                                NULL,
+                                &pChainContext)) {
+      failf(data, "schannel: CertGetCertificateChain failed: %s",
+            Curl_sspi_strerror(conn, GetLastError()));
+      pChainContext = NULL;
+      result = CURLE_PEER_FAILED_VERIFICATION;
+    }
+
+    if(result == CURLE_OK) {
+      CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
+      DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
+      dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
+      if(dwTrustErrorMask) {
+        if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
+          failf(data, "schannel: CertGetCertificateChain trust error"
+                " CERT_TRUST_IS_REVOKED");
+        else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
+          failf(data, "schannel: CertGetCertificateChain trust error"
+                " CERT_TRUST_IS_PARTIAL_CHAIN");
+        else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
+          failf(data, "schannel: CertGetCertificateChain trust error"
+                " CERT_TRUST_IS_UNTRUSTED_ROOT");
+        else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
+          failf(data, "schannel: CertGetCertificateChain trust error"
+                " CERT_TRUST_IS_NOT_TIME_VALID");
+        else if(dwTrustErrorMask & CERT_TRUST_REVOCATION_STATUS_UNKNOWN)
+          failf(data, "schannel: CertGetCertificateChain trust error"
+                " CERT_TRUST_REVOCATION_STATUS_UNKNOWN");
+        else
+          failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
+                dwTrustErrorMask);
+        result = CURLE_PEER_FAILED_VERIFICATION;
+      }
+    }
+  }
+
+  if(result == CURLE_OK) {
+    if(SSL_CONN_CONFIG(verifyhost)) {
+      result = verify_host(conn->data, pCertContextServer, conn_hostname);
+    }
+  }
+
+  if(cert_chain_engine) {
+    CertFreeCertificateChainEngine(cert_chain_engine);
+  }
+
+  if(trust_store) {
+    CertCloseStore(trust_store, 0);
+  }
+
+  if(pChainContext)
+    CertFreeCertificateChain(pChainContext);
+
+  if(pCertContextServer)
+    CertFreeCertificateContext(pCertContextServer);
+
+  return result;
+}
+
+#endif /* USE_SCHANNEL */
diff --git a/src/tool_doswin.c b/src/tool_doswin.c
index 91299986a..c3a8826ff 100644
--- a/src/tool_doswin.c
+++ b/src/tool_doswin.c
@@ -638,12 +638,19 @@ char **__crt0_glob_function(char *arg)
  */
 
 CURLcode FindWin32CACert(struct OperationConfig *config,
+                         curl_sslbackend backend,
                          const char *bundle_file)
 {
   CURLcode result = CURLE_OK;
 
-  /* search and set cert file only if libcurl supports SSL */
-  if(curlinfo->features & CURL_VERSION_SSL) {
+  /* Search and set cert file only if libcurl supports SSL.
+   *
+   * If Schannel (WinSSL) is the selected SSL backend then these locations
+   * are ignored. We allow setting CA location for schannel only when
+   * explicitly specified by the user via CURLOPT_CAINFO / --cacert.
+   */
+  if((curlinfo->features & CURL_VERSION_SSL) &&
+     backend != CURLSSLBACKEND_SCHANNEL) {
 
     DWORD res_len;
     char buf[PATH_MAX];
diff --git a/src/tool_doswin.h b/src/tool_doswin.h
index f649ef023..289281f4f 100644
--- a/src/tool_doswin.h
+++ b/src/tool_doswin.h
@@ -58,6 +58,7 @@ char **__crt0_glob_function(char *arg);
 #ifdef WIN32
 
 CURLcode FindWin32CACert(struct OperationConfig *config,
+                         curl_sslbackend backend,
                          const char *bundle_file);
 
 #endif /* WIN32 */
diff --git a/src/tool_operate.c b/src/tool_operate.c
index 8eac65d6a..932dda6e0 100644
--- a/src/tool_operate.c
+++ b/src/tool_operate.c
@@ -228,52 +228,76 @@ static CURLcode operate_do(struct GlobalConfig *global,
   if(!config->cacert &&
      !config->capath &&
      !config->insecure_ok) {
-    char *env;
-    env = curlx_getenv("CURL_CA_BUNDLE");
-    if(env) {
-      config->cacert = strdup(env);
-      if(!config->cacert) {
-        curl_free(env);
-        helpf(global->errors, "out of memory\n");
-        result = CURLE_OUT_OF_MEMORY;
-        goto quit_curl;
-      }
+    struct curl_tlssessioninfo *tls_backend_info = NULL;
+
+    /* With the addition of CAINFO support for Schannel, this search could find
+     * a certificate bundle that was previously ignored. To maintain backward
+     * compatibility, only perform this search if not using Schannel.
+     */
+    result = curl_easy_getinfo(config->easy,
+                               CURLINFO_TLS_SSL_PTR,
+                               &tls_backend_info);
+    if(result) {
+      goto quit_curl;
     }
-    else {
-      env = curlx_getenv("SSL_CERT_DIR");
+
+    /* Set the CA cert locations specified in the environment. For Windows if
+     * no environment-specified filename is found then check for CA bundle
+     * default filename curl-ca-bundle.crt in the user's PATH.
+     *
+     * If Schannel (WinSSL) is the selected SSL backend then these locations
+     * are ignored. We allow setting CA location for schannel only when
+     * explicitly specified by the user via CURLOPT_CAINFO / --cacert.
+     */
+    if(tls_backend_info->backend != CURLSSLBACKEND_SCHANNEL) {
+      char *env;
+      env = curlx_getenv("CURL_CA_BUNDLE");
       if(env) {
-        config->capath = strdup(env);
-        if(!config->capath) {
+        config->cacert = strdup(env);
+        if(!config->cacert) {
           curl_free(env);
           helpf(global->errors, "out of memory\n");
           result = CURLE_OUT_OF_MEMORY;
           goto quit_curl;
         }
-        capath_from_env = true;
       }
       else {
-        env = curlx_getenv("SSL_CERT_FILE");
+        env = curlx_getenv("SSL_CERT_DIR");
         if(env) {
-          config->cacert = strdup(env);
-          if(!config->cacert) {
+          config->capath = strdup(env);
+          if(!config->capath) {
             curl_free(env);
             helpf(global->errors, "out of memory\n");
             result = CURLE_OUT_OF_MEMORY;
             goto quit_curl;
           }
+          capath_from_env = true;
+        }
+        else {
+          env = curlx_getenv("SSL_CERT_FILE");
+          if(env) {
+            config->cacert = strdup(env);
+            if(!config->cacert) {
+              curl_free(env);
+              helpf(global->errors, "out of memory\n");
+              result = CURLE_OUT_OF_MEMORY;
+              goto quit_curl;
+            }
+          }
         }
       }
-    }
 
-    if(env)
-      curl_free(env);
+      if(env)
+        curl_free(env);
 #ifdef WIN32
-    else {
-      result = FindWin32CACert(config, "curl-ca-bundle.crt");
-      if(result)
-        goto quit_curl;
-    }
+      else {
+        result = FindWin32CACert(config, tls_backend_info->backend,
+                                 "curl-ca-bundle.crt");
+        if(result)
+          goto quit_curl;
+      }
 #endif
+    }
   }
 
   if(config->postfields) {
diff --git a/tests/certs/Makefile.am b/tests/certs/Makefile.am
index 7e7f1fa3d..6a1c22aa6 100644
--- a/tests/certs/Makefile.am
+++ b/tests/certs/Makefile.am
@@ -62,7 +62,25 @@ GENERATEDCERTS = \
   Server-localhost0h-sv.key \
   Server-localhost0h-sv.pem \
   Server-localhost0h-sv.pub.der \
-  Server-localhost0h-sv.pub.pem
+  Server-localhost0h-sv.pub.pem \
+  Server-localhost-firstSAN-sv.crl \
+  Server-localhost-firstSAN-sv.crt \
+  Server-localhost-firstSAN-sv.csr \
+  Server-localhost-firstSAN-sv.der \
+  Server-localhost-firstSAN-sv.dhp \
+  Server-localhost-firstSAN-sv.key \
+  Server-localhost-firstSAN-sv.pem \
+  Server-localhost-firstSAN-sv.pub.der \
+  Server-localhost-firstSAN-sv.pub.pem \
+  Server-localhost-lastSAN-sv.crl \
+  Server-localhost-lastSAN-sv.crt \
+  Server-localhost-lastSAN-sv.csr \
+  Server-localhost-lastSAN-sv.der \
+  Server-localhost-lastSAN-sv.dhp \
+  Server-localhost-lastSAN-sv.key \
+  Server-localhost-lastSAN-sv.pem \
+  Server-localhost-lastSAN-sv.pub.der \
+  Server-localhost-lastSAN-sv.pub.pem
 
 SRPFILES = \
   srp-verifier-conf \
@@ -76,7 +94,8 @@ clean-certs:
        cd $(srcdir); rm -f $(GENERATEDCERTS)
 
 build-certs: $(srcdir)/EdelCurlRoot-ca.cacert 
$(srcdir)/Server-localhost-sv.pem \
-       $(srcdir)/Server-localhost.nn-sv.pem $(srcdir)/Server-localhost0h-sv.pem
+       $(srcdir)/Server-localhost.nn-sv.pem 
$(srcdir)/Server-localhost0h-sv.pem \
+       $(srcdir)/Server-localhost-firstSAN-sv.pem 
$(srcdir)/Server-localhost-lastSAN-sv.pem
 
 $(srcdir)/EdelCurlRoot-ca.cacert:
        cd $(srcdir); scripts/genroot.sh EdelCurlRoot
@@ -89,3 +108,9 @@ $(srcdir)/Server-localhost.nn-sv.pem: 
$(srcdir)/EdelCurlRoot-ca.cacert
 
 $(srcdir)/Server-localhost0h-sv.pem: $(srcdir)/EdelCurlRoot-ca.cacert
        cd $(srcdir); scripts/genserv.sh Server-localhost0h EdelCurlRoot
+
+$(srcdir)/Server-localhost-firstSAN-sv.pem: $(srcdir)/EdelCurlRoot-ca.cacert
+       cd $(srcdir); scripts/genserv.sh Server-localhost-firstSAN EdelCurlRoot
+
+$(srcdir)/Server-localhost-lastSAN-sv.pem: $(srcdir)/EdelCurlRoot-ca.cacert
+       cd $(srcdir); scripts/genserv.sh Server-localhost-firstSAN EdelCurlRoot
diff --git a/tests/certs/Server-localhost-firstSAN-sv.crl 
b/tests/certs/Server-localhost-firstSAN-sv.crl
new file mode 100644
index 000000000..af0be0d39
--- /dev/null
+++ b/tests/certs/Server-localhost-firstSAN-sv.crl
@@ -0,0 +1,13 @@
+-----BEGIN X509 CRL-----
+MIIB9TCB3gIBATANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJOTjExMC8GA1UE
+CgwoRWRlbCBDdXJsIEFyY3RpYyBJbGx1ZGl1bSBSZXNlYXJjaCBDbG91ZDEmMCQG
+A1UEAwwdTm9ydGhlcm4gTm93aGVyZSBUcnVzdCBBbmNob3IXDTE2MDgzMDE4MzIx
+NVoXDTE2MDkyOTE4MzIxNVowMjAXAgYNZJ8o86IXDTE2MDgzMDE4MzAxNVowFwIG
+DWSfO0UqFw0xNjA4MzAxODMyMTVaoA4wDDAKBgNVHRQEAwIBATANBgkqhkiG9w0B
+AQUFAAOCAQEAOUlXQDrOURgODds6feyO+87oPHkgTveOiTm8CtSVHObxwkPkHTIg
+pivd7iXccgEc8CstcGF9Pk5KLVJrXXxEKgGr69NZNGtHa8xXlYSIh+Vre0Pni3Px
+sUAMcsnvGt+cYw/5s/2Wy9u5UVzfJwdxjkxMMp9X648AqeSop229541zGV47M4ox
+h0wh2Mj/w/CFUKw0ijVgVWff5DhKXVaLPCXdh7hhgXcsYUZ4W3G/iOL/jd+Ji88o
+OmZvoP+MOco6or13rz178bGB1mS626z7EU/HNgP8sn25TyQwwopr9uW6H7VvRMaI
+6uwWvihKgoGCRVSVwYEfX+oOLadfJqdHdg==
+-----END X509 CRL-----
diff --git a/tests/certs/Server-localhost-firstSAN-sv.crt 
b/tests/certs/Server-localhost-firstSAN-sv.crt
new file mode 100644
index 000000000..5e37ef0e2
--- /dev/null
+++ b/tests/certs/Server-localhost-firstSAN-sv.crt
@@ -0,0 +1,80 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 14725819352362 (0xd649f3b452a)
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer:
+            countryName               = NN
+            organizationName          = Edel Curl Arctic Illudium Research 
Cloud
+            commonName                = Northern Nowhere Trust Anchor
+        Validity
+            Not Before: Aug 30 18:32:15 2016 GMT
+            Not After : Nov 16 18:32:15 2024 GMT
+        Subject:
+            countryName               = NN
+            organizationName          = Edel Curl Arctic Illudium Research 
Cloud
+            commonName                = localhost.nn
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (1024 bit)
+                Modulus:
+                    00:c5:87:2e:fb:f5:88:8a:39:4c:62:88:9f:fb:4a:
+                    02:1c:27:92:9d:0b:65:a2:70:1f:d1:b7:de:c8:1d:
+                    87:28:4b:9c:4b:cc:f6:f6:7c:83:1f:2d:76:be:41:
+                    29:5e:31:fa:23:0c:2d:7d:cb:38:c2:8b:54:8f:fc:
+                    6a:50:6d:c7:d7:af:72:fb:3b:a1:a7:4d:c4:1b:d2:
+                    0d:75:7c:92:62:97:48:c4:e8:12:c0:00:33:66:0e:
+                    28:17:0f:5c:36:d6:50:70:ec:c8:9f:a2:ae:b9:eb:
+                    eb:19:05:f0:53:83:42:2a:ae:40:1f:fa:fb:7a:b7:
+                    86:4c:ab:6b:28:0b:2f:7f:81
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Alternative Name: 
+                DNS:localhost, DNS:localhost1, DNS:localhost2
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment, Key Agreement
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication
+            X509v3 Subject Key Identifier: 
+                2C:4D:DD:54:88:59:3F:A4:34:9C:E3:56:FF:95:0F:E2:CE:51:20:95
+            X509v3 Authority Key Identifier: 
+                
keyid:12:CA:BA:4B:46:04:A7:75:8A:2C:E8:0E:54:94:BC:12:65:A6:7B:CE
+
+            X509v3 Basic Constraints: 
+                CA:FALSE
+    Signature Algorithm: sha1WithRSAEncryption
+         77:cd:d2:17:91:a6:4b:70:de:79:6a:20:82:a3:56:a3:d0:6a:
+         ba:f7:7d:6f:00:69:d2:06:06:0b:da:cd:49:9d:36:fd:d0:cc:
+         bd:8a:dc:e1:d6:89:c9:23:02:8a:19:2d:14:ca:c6:06:87:66:
+         c7:f4:32:37:95:0d:f1:a7:1c:a1:fe:43:4f:3b:03:03:e2:1a:
+         c6:fc:91:d5:0d:a0:7e:82:60:14:31:2f:6d:b8:f4:57:98:8d:
+         04:74:a3:82:28:6d:1c:b4:de:1a:70:bd:fe:73:ac:b7:96:ec:
+         7c:9b:6d:64:c6:f8:67:39:c7:ea:f4:aa:48:26:b8:14:85:f0:
+         00:ab:8f:bd:1a:95:e2:a7:63:92:35:1e:37:04:c2:70:2c:1c:
+         56:95:b1:83:70:8c:99:88:1c:8a:6f:7a:a2:0d:84:dd:4f:0e:
+         3e:8b:fb:31:cf:ae:ee:b0:e4:f6:c1:8d:d1:98:a9:8d:17:1f:
+         5d:5a:79:e8:7c:97:ab:40:bc:aa:7e:c4:0b:19:30:ad:18:aa:
+         9c:9b:eb:3f:35:d3:86:9c:3a:cc:e6:9a:2c:47:d1:bb:36:6e:
+         f2:c5:d4:e3:0c:5b:c6:eb:30:e6:0d:3a:4b:3a:a3:6b:62:93:
+         8b:6a:59:1f:48:66:2e:d9:70:14:b6:aa:4f:d1:3b:38:5e:e6:
+         79:7f:b7:00
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIGDWSfO0UqMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNVBAYT
+Ak5OMTEwLwYDVQQKDChFZGVsIEN1cmwgQXJjdGljIElsbHVkaXVtIFJlc2VhcmNo
+IENsb3VkMSYwJAYDVQQDDB1Ob3J0aGVybiBOb3doZXJlIFRydXN0IEFuY2hvcjAe
+Fw0xNjA4MzAxODMyMTVaFw0yNDExMTYxODMyMTVaMFcxCzAJBgNVBAYTAk5OMTEw
+LwYDVQQKDChFZGVsIEN1cmwgQXJjdGljIElsbHVkaXVtIFJlc2VhcmNoIENsb3Vk
+MRUwEwYDVQQDDAxsb2NhbGhvc3Qubm4wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ
+AoGBAMWHLvv1iIo5TGKIn/tKAhwnkp0LZaJwH9G33sgdhyhLnEvM9vZ8gx8tdr5B
+KV4x+iMMLX3LOMKLVI/8alBtx9evcvs7oadNxBvSDXV8kmKXSMToEsAAM2YOKBcP
+XDbWUHDsyJ+irrnr6xkF8FODQiquQB/6+3q3hkyraygLL3+BAgMBAAGjgZ4wgZsw
+LAYDVR0RBCUwI4IJbG9jYWxob3N0ggpsb2NhbGhvc3Qxggpsb2NhbGhvc3QyMAsG
+A1UdDwQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQULE3dVIhZ
+P6Q0nONW/5UP4s5RIJUwHwYDVR0jBBgwFoAUEsq6S0YEp3WKLOgOVJS8EmWme84w
+CQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEAd83SF5GmS3DeeWoggqNWo9Bq
+uvd9bwBp0gYGC9rNSZ02/dDMvYrc4daJySMCihktFMrGBodmx/QyN5UN8accof5D
+TzsDA+IaxvyR1Q2gfoJgFDEvbbj0V5iNBHSjgihtHLTeGnC9/nOst5bsfJttZMb4
+ZznH6vSqSCa4FIXwAKuPvRqV4qdjkjUeNwTCcCwcVpWxg3CMmYgcim96og2E3U8O
+Pov7Mc+u7rDk9sGN0ZipjRcfXVp56HyXq0C8qn7ECxkwrRiqnJvrPzXThpw6zOaa
+LEfRuzZu8sXU4wxbxusw5g06Szqja2KTi2pZH0hmLtlwFLaqT9E7OF7meX+3AA==
+-----END CERTIFICATE-----
diff --git a/tests/certs/Server-localhost-firstSAN-sv.csr 
b/tests/certs/Server-localhost-firstSAN-sv.csr
new file mode 100644
index 000000000..729034e47
--- /dev/null
+++ b/tests/certs/Server-localhost-firstSAN-sv.csr
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBlzCCAQACAQAwVzELMAkGA1UEBhMCTk4xMTAvBgNVBAoMKEVkZWwgQ3VybCBB
+cmN0aWMgSWxsdWRpdW0gUmVzZWFyY2ggQ2xvdWQxFTATBgNVBAMMDGxvY2FsaG9z
+dC5ubjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxYcu+/WIijlMYoif+0oC
+HCeSnQtlonAf0bfeyB2HKEucS8z29nyDHy12vkEpXjH6Iwwtfcs4wotUj/xqUG3H
+169y+zuhp03EG9INdXySYpdIxOgSwAAzZg4oFw9cNtZQcOzIn6KuuevrGQXwU4NC
+Kq5AH/r7ereGTKtrKAsvf4ECAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4GBADlhAYRy
+2heMP/fGllGXW/uAEm2q6ubWhqgd3/5d+06LjTIs57qT/nwbr79e1PxholGWM+Zb
+/NGKZ4geZK0mJT/gnaJCyUsrjdp2KIEw9zmBoZyypJd/5Fhe1tzX0xwG40+3np9K
+orpp7wcILLeMho8+I4mNEzOJHidxy/9uia5U
+-----END CERTIFICATE REQUEST-----
diff --git a/tests/certs/Server-localhost-firstSAN-sv.der 
b/tests/certs/Server-localhost-firstSAN-sv.der
new file mode 100644
index 000000000..c878bfb1d
Binary files /dev/null and b/tests/certs/Server-localhost-firstSAN-sv.der differ
diff --git a/tests/certs/Server-localhost-firstSAN-sv.dhp 
b/tests/certs/Server-localhost-firstSAN-sv.dhp
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/certs/Server-localhost-firstSAN-sv.key 
b/tests/certs/Server-localhost-firstSAN-sv.key
new file mode 100644
index 000000000..490326634
--- /dev/null
+++ b/tests/certs/Server-localhost-firstSAN-sv.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQDFhy779YiKOUxiiJ/7SgIcJ5KdC2WicB/Rt97IHYcoS5xLzPb2
+fIMfLXa+QSleMfojDC19yzjCi1SP/GpQbcfXr3L7O6GnTcQb0g11fJJil0jE6BLA
+ADNmDigXD1w21lBw7Mifoq656+sZBfBTg0IqrkAf+vt6t4ZMq2soCy9/gQIDAQAB
+AoGAUjKXErJyR1LgvoAsUt3RUvYExOVhPd963kKtqojfHZ2ZRNHeU2QtDGRW7YUg
+OdqCRONkatyOmiZw4hogA6graJKiqKLvM/F4qRoLsxH9T/cSOIl9QjZVkUd1HV/Z
+iJluibPTewVyfoYzkq48GN+QIi//msYKBjI5Q2Yybn4WrgECQQDk/mDp4sAvuLXL
+NxaQKuDZA5TxU2u8GTItFqOoHneVFSJLE4O3kr7wh47O817mnljZfskZwVXBYx6R
+VbXsy8ZJAkEA3NLRFh8cR03CN+eYPi33JrUVRSrn8eAB5MNOaOdO4mT0pTAzfVfe
+g6rMDnK2n7WZzwf6YmvRVyppW2/kQjyPeQJAXoa3ILTuWoSn3owN71MT3+E/oWKr
+LUlFUiFvSx3QhSTlNBKJI8UatpVumPUTbqVczeMtRkltidfNrXaxE1+GqQJAW9WU
+vMVtZj3xUnyPNPS6vy85zE0ertmBEBklJ71icgaYM4aLM0pysIE8YZnVVzAX6iCg
+QYQjSEPMEwnCfMVgyQJAcWnk6HPLbJmUt+ZGGAcqzfycR6jMKFnm4st2Ld6JuDT2
+h2lb40Uma9gO+aXLIf+K9prCxb+7nR1M3qLwV4krkQ==
+-----END RSA PRIVATE KEY-----
diff --git a/tests/certs/Server-localhost-firstSAN-sv.pem 
b/tests/certs/Server-localhost-firstSAN-sv.pem
new file mode 100644
index 000000000..2b5ada518
--- /dev/null
+++ b/tests/certs/Server-localhost-firstSAN-sv.pem
@@ -0,0 +1,120 @@
+extensions = x509v3
+[ x509v3 ]
+subjectAltName = DNS:localhost,DNS:localhost1,DNS:localhost2
+keyUsage       = keyEncipherment,digitalSignature,keyAgreement
+extendedKeyUsage = serverAuth
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid
+basicConstraints = CA:false
+[ req ]
+default_bits                    = 1024
+distinguished_name              = req_DN
+default_md                     = sha256
+string_mask                    = utf8only
+[ req_DN ]
+countryName                     = "Country Name is Northern Nowhere"
+countryName_value            = NN
+organizationName              = "Organization Name"
+organizationName_value     = Edel Curl Arctic Illudium Research Cloud
+commonName                      = "Common Name"
+commonName_value              = localhost.nn
+
+[something]
+# The key
+# the certificate
+# some dhparam
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQDFhy779YiKOUxiiJ/7SgIcJ5KdC2WicB/Rt97IHYcoS5xLzPb2
+fIMfLXa+QSleMfojDC19yzjCi1SP/GpQbcfXr3L7O6GnTcQb0g11fJJil0jE6BLA
+ADNmDigXD1w21lBw7Mifoq656+sZBfBTg0IqrkAf+vt6t4ZMq2soCy9/gQIDAQAB
+AoGAUjKXErJyR1LgvoAsUt3RUvYExOVhPd963kKtqojfHZ2ZRNHeU2QtDGRW7YUg
+OdqCRONkatyOmiZw4hogA6graJKiqKLvM/F4qRoLsxH9T/cSOIl9QjZVkUd1HV/Z
+iJluibPTewVyfoYzkq48GN+QIi//msYKBjI5Q2Yybn4WrgECQQDk/mDp4sAvuLXL
+NxaQKuDZA5TxU2u8GTItFqOoHneVFSJLE4O3kr7wh47O817mnljZfskZwVXBYx6R
+VbXsy8ZJAkEA3NLRFh8cR03CN+eYPi33JrUVRSrn8eAB5MNOaOdO4mT0pTAzfVfe
+g6rMDnK2n7WZzwf6YmvRVyppW2/kQjyPeQJAXoa3ILTuWoSn3owN71MT3+E/oWKr
+LUlFUiFvSx3QhSTlNBKJI8UatpVumPUTbqVczeMtRkltidfNrXaxE1+GqQJAW9WU
+vMVtZj3xUnyPNPS6vy85zE0ertmBEBklJ71icgaYM4aLM0pysIE8YZnVVzAX6iCg
+QYQjSEPMEwnCfMVgyQJAcWnk6HPLbJmUt+ZGGAcqzfycR6jMKFnm4st2Ld6JuDT2
+h2lb40Uma9gO+aXLIf+K9prCxb+7nR1M3qLwV4krkQ==
+-----END RSA PRIVATE KEY-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 14725819352362 (0xd649f3b452a)
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer:
+            countryName               = NN
+            organizationName          = Edel Curl Arctic Illudium Research 
Cloud
+            commonName                = Northern Nowhere Trust Anchor
+        Validity
+            Not Before: Aug 30 18:32:15 2016 GMT
+            Not After : Nov 16 18:32:15 2024 GMT
+        Subject:
+            countryName               = NN
+            organizationName          = Edel Curl Arctic Illudium Research 
Cloud
+            commonName                = localhost.nn
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (1024 bit)
+                Modulus:
+                    00:c5:87:2e:fb:f5:88:8a:39:4c:62:88:9f:fb:4a:
+                    02:1c:27:92:9d:0b:65:a2:70:1f:d1:b7:de:c8:1d:
+                    87:28:4b:9c:4b:cc:f6:f6:7c:83:1f:2d:76:be:41:
+                    29:5e:31:fa:23:0c:2d:7d:cb:38:c2:8b:54:8f:fc:
+                    6a:50:6d:c7:d7:af:72:fb:3b:a1:a7:4d:c4:1b:d2:
+                    0d:75:7c:92:62:97:48:c4:e8:12:c0:00:33:66:0e:
+                    28:17:0f:5c:36:d6:50:70:ec:c8:9f:a2:ae:b9:eb:
+                    eb:19:05:f0:53:83:42:2a:ae:40:1f:fa:fb:7a:b7:
+                    86:4c:ab:6b:28:0b:2f:7f:81
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Alternative Name: 
+                DNS:localhost, DNS:localhost1, DNS:localhost2
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment, Key Agreement
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication
+            X509v3 Subject Key Identifier: 
+                2C:4D:DD:54:88:59:3F:A4:34:9C:E3:56:FF:95:0F:E2:CE:51:20:95
+            X509v3 Authority Key Identifier: 
+                
keyid:12:CA:BA:4B:46:04:A7:75:8A:2C:E8:0E:54:94:BC:12:65:A6:7B:CE
+
+            X509v3 Basic Constraints: 
+                CA:FALSE
+    Signature Algorithm: sha1WithRSAEncryption
+         77:cd:d2:17:91:a6:4b:70:de:79:6a:20:82:a3:56:a3:d0:6a:
+         ba:f7:7d:6f:00:69:d2:06:06:0b:da:cd:49:9d:36:fd:d0:cc:
+         bd:8a:dc:e1:d6:89:c9:23:02:8a:19:2d:14:ca:c6:06:87:66:
+         c7:f4:32:37:95:0d:f1:a7:1c:a1:fe:43:4f:3b:03:03:e2:1a:
+         c6:fc:91:d5:0d:a0:7e:82:60:14:31:2f:6d:b8:f4:57:98:8d:
+         04:74:a3:82:28:6d:1c:b4:de:1a:70:bd:fe:73:ac:b7:96:ec:
+         7c:9b:6d:64:c6:f8:67:39:c7:ea:f4:aa:48:26:b8:14:85:f0:
+         00:ab:8f:bd:1a:95:e2:a7:63:92:35:1e:37:04:c2:70:2c:1c:
+         56:95:b1:83:70:8c:99:88:1c:8a:6f:7a:a2:0d:84:dd:4f:0e:
+         3e:8b:fb:31:cf:ae:ee:b0:e4:f6:c1:8d:d1:98:a9:8d:17:1f:
+         5d:5a:79:e8:7c:97:ab:40:bc:aa:7e:c4:0b:19:30:ad:18:aa:
+         9c:9b:eb:3f:35:d3:86:9c:3a:cc:e6:9a:2c:47:d1:bb:36:6e:
+         f2:c5:d4:e3:0c:5b:c6:eb:30:e6:0d:3a:4b:3a:a3:6b:62:93:
+         8b:6a:59:1f:48:66:2e:d9:70:14:b6:aa:4f:d1:3b:38:5e:e6:
+         79:7f:b7:00
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIGDWSfO0UqMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNVBAYT
+Ak5OMTEwLwYDVQQKDChFZGVsIEN1cmwgQXJjdGljIElsbHVkaXVtIFJlc2VhcmNo
+IENsb3VkMSYwJAYDVQQDDB1Ob3J0aGVybiBOb3doZXJlIFRydXN0IEFuY2hvcjAe
+Fw0xNjA4MzAxODMyMTVaFw0yNDExMTYxODMyMTVaMFcxCzAJBgNVBAYTAk5OMTEw
+LwYDVQQKDChFZGVsIEN1cmwgQXJjdGljIElsbHVkaXVtIFJlc2VhcmNoIENsb3Vk
+MRUwEwYDVQQDDAxsb2NhbGhvc3Qubm4wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ
+AoGBAMWHLvv1iIo5TGKIn/tKAhwnkp0LZaJwH9G33sgdhyhLnEvM9vZ8gx8tdr5B
+KV4x+iMMLX3LOMKLVI/8alBtx9evcvs7oadNxBvSDXV8kmKXSMToEsAAM2YOKBcP
+XDbWUHDsyJ+irrnr6xkF8FODQiquQB/6+3q3hkyraygLL3+BAgMBAAGjgZ4wgZsw
+LAYDVR0RBCUwI4IJbG9jYWxob3N0ggpsb2NhbGhvc3Qxggpsb2NhbGhvc3QyMAsG
+A1UdDwQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQULE3dVIhZ
+P6Q0nONW/5UP4s5RIJUwHwYDVR0jBBgwFoAUEsq6S0YEp3WKLOgOVJS8EmWme84w
+CQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEAd83SF5GmS3DeeWoggqNWo9Bq
+uvd9bwBp0gYGC9rNSZ02/dDMvYrc4daJySMCihktFMrGBodmx/QyN5UN8accof5D
+TzsDA+IaxvyR1Q2gfoJgFDEvbbj0V5iNBHSjgihtHLTeGnC9/nOst5bsfJttZMb4
+ZznH6vSqSCa4FIXwAKuPvRqV4qdjkjUeNwTCcCwcVpWxg3CMmYgcim96og2E3U8O
+Pov7Mc+u7rDk9sGN0ZipjRcfXVp56HyXq0C8qn7ECxkwrRiqnJvrPzXThpw6zOaa
+LEfRuzZu8sXU4wxbxusw5g06Szqja2KTi2pZH0hmLtlwFLaqT9E7OF7meX+3AA==
+-----END CERTIFICATE-----
diff --git a/tests/certs/Server-localhost-firstSAN-sv.prm 
b/tests/certs/Server-localhost-firstSAN-sv.prm
new file mode 100644
index 000000000..f299a3cbf
--- /dev/null
+++ b/tests/certs/Server-localhost-firstSAN-sv.prm
@@ -0,0 +1,25 @@
+extensions = x509v3
+[ x509v3 ]
+subjectAltName = DNS:localhost,DNS:localhost1,DNS:localhost2
+keyUsage       = keyEncipherment,digitalSignature,keyAgreement
+extendedKeyUsage = serverAuth
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid
+basicConstraints = CA:false
+[ req ]
+default_bits                    = 1024
+distinguished_name              = req_DN
+default_md                     = sha256
+string_mask                    = utf8only
+[ req_DN ]
+countryName                     = "Country Name is Northern Nowhere"
+countryName_value            = NN
+organizationName              = "Organization Name"
+organizationName_value     = Edel Curl Arctic Illudium Research Cloud
+commonName                      = "Common Name"
+commonName_value              = localhost.nn
+
+[something]
+# The key
+# the certificate
+# some dhparam
diff --git a/tests/certs/Server-localhost-firstSAN-sv.pub.der 
b/tests/certs/Server-localhost-firstSAN-sv.pub.der
new file mode 100644
index 000000000..fb1b486a6
Binary files /dev/null and b/tests/certs/Server-localhost-firstSAN-sv.pub.der 
differ
diff --git a/tests/certs/Server-localhost-firstSAN-sv.pub.pem 
b/tests/certs/Server-localhost-firstSAN-sv.pub.pem
new file mode 100644
index 000000000..ef1459476
--- /dev/null
+++ b/tests/certs/Server-localhost-firstSAN-sv.pub.pem
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFhy779YiKOUxiiJ/7SgIcJ5Kd
+C2WicB/Rt97IHYcoS5xLzPb2fIMfLXa+QSleMfojDC19yzjCi1SP/GpQbcfXr3L7
+O6GnTcQb0g11fJJil0jE6BLAADNmDigXD1w21lBw7Mifoq656+sZBfBTg0IqrkAf
++vt6t4ZMq2soCy9/gQIDAQAB
+-----END PUBLIC KEY-----
diff --git a/tests/certs/Server-localhost-lastSAN-sv.crl 
b/tests/certs/Server-localhost-lastSAN-sv.crl
new file mode 100644
index 000000000..486bf926a
--- /dev/null
+++ b/tests/certs/Server-localhost-lastSAN-sv.crl
@@ -0,0 +1,14 @@
+-----BEGIN X509 CRL-----
+MIICDjCB9wIBATANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJOTjExMC8GA1UE
+CgwoRWRlbCBDdXJsIEFyY3RpYyBJbGx1ZGl1bSBSZXNlYXJjaCBDbG91ZDEmMCQG
+A1UEAwwdTm9ydGhlcm4gTm93aGVyZSBUcnVzdCBBbmNob3IXDTE2MDgzMDE4MzI1
+N1oXDTE2MDkyOTE4MzI1N1owSzAXAgYNZJ8o86IXDTE2MDgzMDE4MzAxNVowFwIG
+DWSfO0UqFw0xNjA4MzAxODMyMTVaMBcCBg1kn0GuixcNMTYwODMwMTgzMjU3WqAO
+MAwwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQEFBQADggEBAE0v3zGBeKKuODAUugh7
+l6bJi7Cs0CDhuBJ8wCpwL5XRGwWhYChJtEXWFUKLBhMarIPYKEv3f3rd8gtFII/8
+wmnxoTL6eXZNL+FpHkZJ+blsHi73G7xzpB6kdFHIxI4tixwiUCe85u6WIRWkIEBs
+kyPPAgbnosF37umQfEaBrweVy+EztrYw8jgd0oDBybQp25p7Noa0N4uDoDInuOgP
+A7Q1Zf0ndWjrlEQtjMAUdA6blGKlb8BjMPtX50mbXuXctLeICns8TVUSQSiKU+oR
+1QTgbkl+AfdaFlfNAum4a42bCLyeBQ/O31NydZbCE8o2q9PqPepAkL9dXhMLiK/a
+tjA=
+-----END X509 CRL-----
diff --git a/tests/certs/Server-localhost-lastSAN-sv.crt 
b/tests/certs/Server-localhost-lastSAN-sv.crt
new file mode 100644
index 000000000..a6d8ae9c2
--- /dev/null
+++ b/tests/certs/Server-localhost-lastSAN-sv.crt
@@ -0,0 +1,80 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 14725819772555 (0xd649f41ae8b)
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer:
+            countryName               = NN
+            organizationName          = Edel Curl Arctic Illudium Research 
Cloud
+            commonName                = Northern Nowhere Trust Anchor
+        Validity
+            Not Before: Aug 30 18:32:57 2016 GMT
+            Not After : Nov 16 18:32:57 2024 GMT
+        Subject:
+            countryName               = NN
+            organizationName          = Edel Curl Arctic Illudium Research 
Cloud
+            commonName                = localhost.nn
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (1024 bit)
+                Modulus:
+                    00:a3:2a:75:d7:bf:75:41:40:be:42:b8:b9:00:28:
+                    f1:45:29:55:bc:36:ca:a6:b7:86:93:97:25:84:aa:
+                    c9:80:ac:41:d9:28:fb:b0:68:4b:5b:ee:bd:94:83:
+                    da:2b:f6:cc:cc:11:df:fb:48:e6:e9:d5:97:41:7f:
+                    9a:0d:b7:87:96:12:22:41:2a:7f:95:8a:14:d6:6c:
+                    4b:34:df:18:29:01:0d:b2:3c:4d:c8:c4:5e:87:fa:
+                    9f:aa:ee:a4:73:e9:bb:74:57:85:24:2a:51:e4:43:
+                    5c:4b:97:51:52:b9:82:6e:9c:ce:ae:0f:91:45:25:
+                    f9:b4:24:66:8e:47:1f:d7:d5
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Alternative Name: 
+                DNS:localhost1, DNS:localhost2, DNS:localhost
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment, Key Agreement
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication
+            X509v3 Subject Key Identifier: 
+                2C:CF:E3:6E:08:F9:CE:9B:98:3B:B3:17:7F:0C:9D:E4:5B:1B:76:8A
+            X509v3 Authority Key Identifier: 
+                
keyid:12:CA:BA:4B:46:04:A7:75:8A:2C:E8:0E:54:94:BC:12:65:A6:7B:CE
+
+            X509v3 Basic Constraints: 
+                CA:FALSE
+    Signature Algorithm: sha1WithRSAEncryption
+         2e:3d:c1:a2:a7:e4:70:f8:a8:13:86:c3:af:22:1f:e9:e1:62:
+         f4:cf:16:66:a8:3b:70:f6:12:30:be:fe:8e:44:1b:71:b5:c1:
+         e0:4b:66:c4:5d:d4:d7:7d:49:43:4a:6d:22:1b:ce:3d:e3:14:
+         14:b3:6d:3a:93:39:0c:9b:2c:83:35:1d:7e:7c:29:29:3c:51:
+         6b:27:c3:5b:2d:f2:61:18:f8:c7:90:be:3b:68:3f:08:9b:ac:
+         68:01:d2:0c:ec:aa:5d:9e:78:b7:8b:84:04:01:b2:08:ef:df:
+         0c:f2:29:99:fe:61:d1:65:80:aa:ef:df:8e:28:55:a6:f9:88:
+         0c:01:bb:fc:1c:9e:9c:08:8d:c5:34:24:91:c1:ac:71:22:e1:
+         12:78:e0:45:d5:e2:39:c4:3c:16:09:80:d0:5b:bc:49:0a:4c:
+         a3:5b:e1:36:40:ed:26:6d:8d:a0:d3:4a:3c:86:93:2f:d4:0a:
+         3c:72:08:62:d7:66:d0:b3:05:c2:0f:1d:af:3c:65:67:f2:6c:
+         76:a5:9c:37:ac:c4:ac:96:b7:e4:c0:ef:a4:5b:28:1e:16:09:
+         15:f6:7b:bb:5d:a2:94:9a:df:52:7b:ae:c9:39:f4:18:9e:84:
+         57:6c:d3:6d:ae:35:38:8f:8f:9b:0d:df:77:69:ae:25:ec:ce:
+         d0:2b:bd:8d
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIGDWSfQa6LMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNVBAYT
+Ak5OMTEwLwYDVQQKDChFZGVsIEN1cmwgQXJjdGljIElsbHVkaXVtIFJlc2VhcmNo
+IENsb3VkMSYwJAYDVQQDDB1Ob3J0aGVybiBOb3doZXJlIFRydXN0IEFuY2hvcjAe
+Fw0xNjA4MzAxODMyNTdaFw0yNDExMTYxODMyNTdaMFcxCzAJBgNVBAYTAk5OMTEw
+LwYDVQQKDChFZGVsIEN1cmwgQXJjdGljIElsbHVkaXVtIFJlc2VhcmNoIENsb3Vk
+MRUwEwYDVQQDDAxsb2NhbGhvc3Qubm4wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ
+AoGBAKMqdde/dUFAvkK4uQAo8UUpVbw2yqa3hpOXJYSqyYCsQdko+7BoS1vuvZSD
+2iv2zMwR3/tI5unVl0F/mg23h5YSIkEqf5WKFNZsSzTfGCkBDbI8TcjEXof6n6ru
+pHPpu3RXhSQqUeRDXEuXUVK5gm6czq4PkUUl+bQkZo5HH9fVAgMBAAGjgZ4wgZsw
+LAYDVR0RBCUwI4IKbG9jYWxob3N0MYIKbG9jYWxob3N0MoIJbG9jYWxob3N0MAsG
+A1UdDwQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQULM/jbgj5
+zpuYO7MXfwyd5FsbdoowHwYDVR0jBBgwFoAUEsq6S0YEp3WKLOgOVJS8EmWme84w
+CQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEALj3BoqfkcPioE4bDryIf6eFi
+9M8WZqg7cPYSML7+jkQbcbXB4EtmxF3U131JQ0ptIhvOPeMUFLNtOpM5DJssgzUd
+fnwpKTxRayfDWy3yYRj4x5C+O2g/CJusaAHSDOyqXZ54t4uEBAGyCO/fDPIpmf5h
+0WWAqu/fjihVpvmIDAG7/ByenAiNxTQkkcGscSLhEnjgRdXiOcQ8FgmA0Fu8SQpM
+o1vhNkDtJm2NoNNKPIaTL9QKPHIIYtdm0LMFwg8drzxlZ/JsdqWcN6zErJa35MDv
+pFsoHhYJFfZ7u12ilJrfUnuuyTn0GJ6EV2zTba41OI+Pmw3fd2muJezO0Cu9jQ==
+-----END CERTIFICATE-----
diff --git a/tests/certs/Server-localhost-lastSAN-sv.csr 
b/tests/certs/Server-localhost-lastSAN-sv.csr
new file mode 100644
index 000000000..bf6355540
--- /dev/null
+++ b/tests/certs/Server-localhost-lastSAN-sv.csr
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBlzCCAQACAQAwVzELMAkGA1UEBhMCTk4xMTAvBgNVBAoMKEVkZWwgQ3VybCBB
+cmN0aWMgSWxsdWRpdW0gUmVzZWFyY2ggQ2xvdWQxFTATBgNVBAMMDGxvY2FsaG9z
+dC5ubjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAoyp11791QUC+Qri5ACjx
+RSlVvDbKpreGk5clhKrJgKxB2Sj7sGhLW+69lIPaK/bMzBHf+0jm6dWXQX+aDbeH
+lhIiQSp/lYoU1mxLNN8YKQENsjxNyMReh/qfqu6kc+m7dFeFJCpR5ENcS5dRUrmC
+bpzOrg+RRSX5tCRmjkcf19UCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4GBACoIAlf0
+hSnZJOBBt7FS7iXlNRyKZAD881jhHFux+Gxq3gtbJsP57c+ALZ3MswjjUXW0Iq11
+IZLeZQGCAHYp4/GuTHbaq0qo1LjgpTqgQfwEB3BqNGs6yJiST+3risgawFbfqEDY
+LCm7rs/yyaOdMjwdwrUMciSv5KtlXZ1VThyt
+-----END CERTIFICATE REQUEST-----
diff --git a/tests/certs/Server-localhost-lastSAN-sv.der 
b/tests/certs/Server-localhost-lastSAN-sv.der
new file mode 100644
index 000000000..5ffa9ce38
Binary files /dev/null and b/tests/certs/Server-localhost-lastSAN-sv.der differ
diff --git a/tests/certs/Server-localhost-lastSAN-sv.dhp 
b/tests/certs/Server-localhost-lastSAN-sv.dhp
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/certs/Server-localhost-lastSAN-sv.key 
b/tests/certs/Server-localhost-lastSAN-sv.key
new file mode 100644
index 000000000..824ee6fec
--- /dev/null
+++ b/tests/certs/Server-localhost-lastSAN-sv.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQCjKnXXv3VBQL5CuLkAKPFFKVW8Nsqmt4aTlyWEqsmArEHZKPuw
+aEtb7r2Ug9or9szMEd/7SObp1ZdBf5oNt4eWEiJBKn+VihTWbEs03xgpAQ2yPE3I
+xF6H+p+q7qRz6bt0V4UkKlHkQ1xLl1FSuYJunM6uD5FFJfm0JGaORx/X1QIDAQAB
+AoGAaC2QGDSSNRuVXxx6YnPBuJrvtsB1G4VKU6nJtq8lARb65CCassOkegow2UZm
+YnOtxw4SqGqfpOVPMe66+c8Yrd+6zimC7VorxmfhNxqOO34bxzztKKk8Q7c+odl3
++c4aVnFBk2hzuOW4PuJoFfFNQZWmh/XJdKK85X+bkryS/oECQQDTdzwYyDxvrPaw
+ZeR5oDleopk5W5QwmBAq4ehtie1oZfhzlNZzPOjnI9I71MRYdCwkesKHL2k6q7cT
+jA4sSmx5AkEAxYc6+o8l0/HE8HzypWe/ZfozaY3ccIFzmvcwQorbCvAxDtZ1DbFy
+VWLOgM/6gwDIUDF6ckaInaVmiVJl60Y3PQJAZFBOuO7cBJoHWDytuqiwLl1x1EzG
+KpsoKD+MU9I3RewBhUrYxEfjsCpFA8716YQKoK9/ckOiZouoyGQLISWY+QJAG5id
+AMxm+Ilafk62h61K7DBcZm7PUViEki3erC1CFPEhqXUEvXkBBDTdrNlholPFqI6B
+EN4R0BR/ksfUPV598QJAF8jl/8gz8pmAWmqw8tKbWdQeDgisyTHeYlPMxq4fUbLH
+mJk05csSX9CTg4eO7NRRwPxODKmPCd88sZZSOuTQmQ==
+-----END RSA PRIVATE KEY-----
diff --git a/tests/certs/Server-localhost-lastSAN-sv.pem 
b/tests/certs/Server-localhost-lastSAN-sv.pem
new file mode 100644
index 000000000..b563e0a76
--- /dev/null
+++ b/tests/certs/Server-localhost-lastSAN-sv.pem
@@ -0,0 +1,120 @@
+extensions = x509v3
+[ x509v3 ]
+subjectAltName = DNS:localhost1,DNS:localhost2,DNS:localhost
+keyUsage       = keyEncipherment,digitalSignature,keyAgreement
+extendedKeyUsage = serverAuth
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid
+basicConstraints = CA:false
+[ req ]
+default_bits                    = 1024
+distinguished_name              = req_DN
+default_md                     = sha256
+string_mask                    = utf8only
+[ req_DN ]
+countryName                     = "Country Name is Northern Nowhere"
+countryName_value            = NN
+organizationName              = "Organization Name"
+organizationName_value     = Edel Curl Arctic Illudium Research Cloud
+commonName                      = "Common Name"
+commonName_value              = localhost.nn
+
+[something]
+# The key
+# the certificate
+# some dhparam
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQCjKnXXv3VBQL5CuLkAKPFFKVW8Nsqmt4aTlyWEqsmArEHZKPuw
+aEtb7r2Ug9or9szMEd/7SObp1ZdBf5oNt4eWEiJBKn+VihTWbEs03xgpAQ2yPE3I
+xF6H+p+q7qRz6bt0V4UkKlHkQ1xLl1FSuYJunM6uD5FFJfm0JGaORx/X1QIDAQAB
+AoGAaC2QGDSSNRuVXxx6YnPBuJrvtsB1G4VKU6nJtq8lARb65CCassOkegow2UZm
+YnOtxw4SqGqfpOVPMe66+c8Yrd+6zimC7VorxmfhNxqOO34bxzztKKk8Q7c+odl3
++c4aVnFBk2hzuOW4PuJoFfFNQZWmh/XJdKK85X+bkryS/oECQQDTdzwYyDxvrPaw
+ZeR5oDleopk5W5QwmBAq4ehtie1oZfhzlNZzPOjnI9I71MRYdCwkesKHL2k6q7cT
+jA4sSmx5AkEAxYc6+o8l0/HE8HzypWe/ZfozaY3ccIFzmvcwQorbCvAxDtZ1DbFy
+VWLOgM/6gwDIUDF6ckaInaVmiVJl60Y3PQJAZFBOuO7cBJoHWDytuqiwLl1x1EzG
+KpsoKD+MU9I3RewBhUrYxEfjsCpFA8716YQKoK9/ckOiZouoyGQLISWY+QJAG5id
+AMxm+Ilafk62h61K7DBcZm7PUViEki3erC1CFPEhqXUEvXkBBDTdrNlholPFqI6B
+EN4R0BR/ksfUPV598QJAF8jl/8gz8pmAWmqw8tKbWdQeDgisyTHeYlPMxq4fUbLH
+mJk05csSX9CTg4eO7NRRwPxODKmPCd88sZZSOuTQmQ==
+-----END RSA PRIVATE KEY-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 14725819772555 (0xd649f41ae8b)
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer:
+            countryName               = NN
+            organizationName          = Edel Curl Arctic Illudium Research 
Cloud
+            commonName                = Northern Nowhere Trust Anchor
+        Validity
+            Not Before: Aug 30 18:32:57 2016 GMT
+            Not After : Nov 16 18:32:57 2024 GMT
+        Subject:
+            countryName               = NN
+            organizationName          = Edel Curl Arctic Illudium Research 
Cloud
+            commonName                = localhost.nn
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (1024 bit)
+                Modulus:
+                    00:a3:2a:75:d7:bf:75:41:40:be:42:b8:b9:00:28:
+                    f1:45:29:55:bc:36:ca:a6:b7:86:93:97:25:84:aa:
+                    c9:80:ac:41:d9:28:fb:b0:68:4b:5b:ee:bd:94:83:
+                    da:2b:f6:cc:cc:11:df:fb:48:e6:e9:d5:97:41:7f:
+                    9a:0d:b7:87:96:12:22:41:2a:7f:95:8a:14:d6:6c:
+                    4b:34:df:18:29:01:0d:b2:3c:4d:c8:c4:5e:87:fa:
+                    9f:aa:ee:a4:73:e9:bb:74:57:85:24:2a:51:e4:43:
+                    5c:4b:97:51:52:b9:82:6e:9c:ce:ae:0f:91:45:25:
+                    f9:b4:24:66:8e:47:1f:d7:d5
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Alternative Name: 
+                DNS:localhost1, DNS:localhost2, DNS:localhost
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment, Key Agreement
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication
+            X509v3 Subject Key Identifier: 
+                2C:CF:E3:6E:08:F9:CE:9B:98:3B:B3:17:7F:0C:9D:E4:5B:1B:76:8A
+            X509v3 Authority Key Identifier: 
+                
keyid:12:CA:BA:4B:46:04:A7:75:8A:2C:E8:0E:54:94:BC:12:65:A6:7B:CE
+
+            X509v3 Basic Constraints: 
+                CA:FALSE
+    Signature Algorithm: sha1WithRSAEncryption
+         2e:3d:c1:a2:a7:e4:70:f8:a8:13:86:c3:af:22:1f:e9:e1:62:
+         f4:cf:16:66:a8:3b:70:f6:12:30:be:fe:8e:44:1b:71:b5:c1:
+         e0:4b:66:c4:5d:d4:d7:7d:49:43:4a:6d:22:1b:ce:3d:e3:14:
+         14:b3:6d:3a:93:39:0c:9b:2c:83:35:1d:7e:7c:29:29:3c:51:
+         6b:27:c3:5b:2d:f2:61:18:f8:c7:90:be:3b:68:3f:08:9b:ac:
+         68:01:d2:0c:ec:aa:5d:9e:78:b7:8b:84:04:01:b2:08:ef:df:
+         0c:f2:29:99:fe:61:d1:65:80:aa:ef:df:8e:28:55:a6:f9:88:
+         0c:01:bb:fc:1c:9e:9c:08:8d:c5:34:24:91:c1:ac:71:22:e1:
+         12:78:e0:45:d5:e2:39:c4:3c:16:09:80:d0:5b:bc:49:0a:4c:
+         a3:5b:e1:36:40:ed:26:6d:8d:a0:d3:4a:3c:86:93:2f:d4:0a:
+         3c:72:08:62:d7:66:d0:b3:05:c2:0f:1d:af:3c:65:67:f2:6c:
+         76:a5:9c:37:ac:c4:ac:96:b7:e4:c0:ef:a4:5b:28:1e:16:09:
+         15:f6:7b:bb:5d:a2:94:9a:df:52:7b:ae:c9:39:f4:18:9e:84:
+         57:6c:d3:6d:ae:35:38:8f:8f:9b:0d:df:77:69:ae:25:ec:ce:
+         d0:2b:bd:8d
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIGDWSfQa6LMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNVBAYT
+Ak5OMTEwLwYDVQQKDChFZGVsIEN1cmwgQXJjdGljIElsbHVkaXVtIFJlc2VhcmNo
+IENsb3VkMSYwJAYDVQQDDB1Ob3J0aGVybiBOb3doZXJlIFRydXN0IEFuY2hvcjAe
+Fw0xNjA4MzAxODMyNTdaFw0yNDExMTYxODMyNTdaMFcxCzAJBgNVBAYTAk5OMTEw
+LwYDVQQKDChFZGVsIEN1cmwgQXJjdGljIElsbHVkaXVtIFJlc2VhcmNoIENsb3Vk
+MRUwEwYDVQQDDAxsb2NhbGhvc3Qubm4wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ
+AoGBAKMqdde/dUFAvkK4uQAo8UUpVbw2yqa3hpOXJYSqyYCsQdko+7BoS1vuvZSD
+2iv2zMwR3/tI5unVl0F/mg23h5YSIkEqf5WKFNZsSzTfGCkBDbI8TcjEXof6n6ru
+pHPpu3RXhSQqUeRDXEuXUVK5gm6czq4PkUUl+bQkZo5HH9fVAgMBAAGjgZ4wgZsw
+LAYDVR0RBCUwI4IKbG9jYWxob3N0MYIKbG9jYWxob3N0MoIJbG9jYWxob3N0MAsG
+A1UdDwQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQULM/jbgj5
+zpuYO7MXfwyd5FsbdoowHwYDVR0jBBgwFoAUEsq6S0YEp3WKLOgOVJS8EmWme84w
+CQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEALj3BoqfkcPioE4bDryIf6eFi
+9M8WZqg7cPYSML7+jkQbcbXB4EtmxF3U131JQ0ptIhvOPeMUFLNtOpM5DJssgzUd
+fnwpKTxRayfDWy3yYRj4x5C+O2g/CJusaAHSDOyqXZ54t4uEBAGyCO/fDPIpmf5h
+0WWAqu/fjihVpvmIDAG7/ByenAiNxTQkkcGscSLhEnjgRdXiOcQ8FgmA0Fu8SQpM
+o1vhNkDtJm2NoNNKPIaTL9QKPHIIYtdm0LMFwg8drzxlZ/JsdqWcN6zErJa35MDv
+pFsoHhYJFfZ7u12ilJrfUnuuyTn0GJ6EV2zTba41OI+Pmw3fd2muJezO0Cu9jQ==
+-----END CERTIFICATE-----
diff --git a/tests/certs/Server-localhost-lastSAN-sv.prm 
b/tests/certs/Server-localhost-lastSAN-sv.prm
new file mode 100644
index 000000000..faefe6802
--- /dev/null
+++ b/tests/certs/Server-localhost-lastSAN-sv.prm
@@ -0,0 +1,25 @@
+extensions = x509v3
+[ x509v3 ]
+subjectAltName = DNS:localhost1,DNS:localhost2,DNS:localhost
+keyUsage       = keyEncipherment,digitalSignature,keyAgreement
+extendedKeyUsage = serverAuth
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid
+basicConstraints = CA:false
+[ req ]
+default_bits                    = 1024
+distinguished_name              = req_DN
+default_md                     = sha256
+string_mask                    = utf8only
+[ req_DN ]
+countryName                     = "Country Name is Northern Nowhere"
+countryName_value            = NN
+organizationName              = "Organization Name"
+organizationName_value     = Edel Curl Arctic Illudium Research Cloud
+commonName                      = "Common Name"
+commonName_value              = localhost.nn
+
+[something]
+# The key
+# the certificate
+# some dhparam
diff --git a/tests/certs/Server-localhost-lastSAN-sv.pub.der 
b/tests/certs/Server-localhost-lastSAN-sv.pub.der
new file mode 100644
index 000000000..06fe6d066
Binary files /dev/null and b/tests/certs/Server-localhost-lastSAN-sv.pub.der 
differ
diff --git a/tests/certs/Server-localhost-lastSAN-sv.pub.pem 
b/tests/certs/Server-localhost-lastSAN-sv.pub.pem
new file mode 100644
index 000000000..a8e2dd4c7
--- /dev/null
+++ b/tests/certs/Server-localhost-lastSAN-sv.pub.pem
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjKnXXv3VBQL5CuLkAKPFFKVW8
+Nsqmt4aTlyWEqsmArEHZKPuwaEtb7r2Ug9or9szMEd/7SObp1ZdBf5oNt4eWEiJB
+Kn+VihTWbEs03xgpAQ2yPE3IxF6H+p+q7qRz6bt0V4UkKlHkQ1xLl1FSuYJunM6u
+D5FFJfm0JGaORx/X1QIDAQAB
+-----END PUBLIC KEY-----
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
index 2f5721318..fbda6008f 100644
--- a/tests/data/Makefile.inc
+++ b/tests/data/Makefile.inc
@@ -195,4 +195,6 @@ test2048 test2049 test2050 test2051 test2052 test2053 
test2054 test2055 \
 test2056 test2057 test2058 test2059 test2060 test2061 test2062 test2063 \
 test2064 test2065 test2066 test2067 test2068 test2069 \
 \
-test2070 test2071 test2072 test2073
+test2070 test2071 test2072 test2073 \
+\
+test3000 test3001
diff --git a/tests/data/test3000 b/tests/data/test3000
new file mode 100644
index 000000000..e62e53168
--- /dev/null
+++ b/tests/data/test3000
@@ -0,0 +1,57 @@
+<testcase>
+<info>
+<keywords>
+HTTPS
+HTTP GET
+PEM certificate
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data>
+HTTP/1.1 200 OK
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Length: 7
+
+MooMoo
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<features>
+SSL
+</features>
+<server>
+https Server-localhost-firstSAN-sv.pem
+</server>
+<name>
+HTTPS GET to localhost, first subject alt name matches, CN does not match
+</name>
+<command>
+--cacert %SRCDIR/certs/EdelCurlRoot-ca.crt https://localhost:%HTTPSPORT/3000
+</command>
+# Ensure that we're running on localhost because we're checking the host name
+<precheck>
+perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne 
'127.0.0.1' );"
+</precheck>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol>
+GET /3000 HTTP/1.1
+Host: localhost:%HTTPSPORT
+Accept: */*
+
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test3001 b/tests/data/test3001
new file mode 100644
index 000000000..706c3f752
--- /dev/null
+++ b/tests/data/test3001
@@ -0,0 +1,57 @@
+<testcase>
+<info>
+<keywords>
+HTTPS
+HTTP GET
+PEM certificate
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data>
+HTTP/1.1 200 OK
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Length: 7
+
+MooMoo
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<features>
+SSL
+</features>
+<server>
+https Server-localhost-lastSAN-sv.pem
+</server>
+<name>
+HTTPS GET to localhost, last subject alt name matches, CN does not match
+</name>
+<command>
+--cacert %SRCDIR/certs/EdelCurlRoot-ca.crt https://localhost:%HTTPSPORT/3001
+</command>
+# Ensure that we're running on localhost because we're checking the host name
+<precheck>
+perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne 
'127.0.0.1' );"
+</precheck>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol>
+GET /3001 HTTP/1.1
+Host: localhost:%HTTPSPORT
+Accept: */*
+
+</protocol>
+</verify>
+</testcase>
diff --git a/winbuild/MakefileBuild.vc b/winbuild/MakefileBuild.vc
index 5f994cb30..bf79db376 100644
--- a/winbuild/MakefileBuild.vc
+++ b/winbuild/MakefileBuild.vc
@@ -82,7 +82,7 @@ LFLAGS_PDB = /incremental:no /opt:ref,icf /DEBUG
 
 CFLAGS_LIBCURL_STATIC  = /DCURL_STATICLIB
 
-WIN_LIBS    = ws2_32.lib wldap32.lib advapi32.lib
+WIN_LIBS    = ws2_32.lib wldap32.lib advapi32.lib crypt32.lib
 
 BASE_NAME              = libcurl
 BASE_NAME_DEBUG        = $(BASE_NAME)_debug

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]