Home | History | Annotate | Download | only in vtls
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 2012 - 2016, Marc Hoersken, <info (at) marc-hoersken.de>
      9  * Copyright (C) 2012, Mark Salisbury, <mark.salisbury (at) hp.com>
     10  * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel (at) haxx.se>, et al.
     11  *
     12  * This software is licensed as described in the file COPYING, which
     13  * you should have received as part of this distribution. The terms
     14  * are also available at https://curl.haxx.se/docs/copyright.html.
     15  *
     16  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     17  * copies of the Software, and permit persons to whom the Software is
     18  * furnished to do so, under the terms of the COPYING file.
     19  *
     20  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     21  * KIND, either express or implied.
     22  *
     23  ***************************************************************************/
     24 
     25 /*
     26  * Source file for all SChannel-specific code for the TLS/SSL layer. No code
     27  * but vtls.c should ever call or use these functions.
     28  *
     29  */
     30 
     31 /*
     32  * Based upon the PolarSSL implementation in polarssl.c and polarssl.h:
     33  *   Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan (at) gmail.com>
     34  *
     35  * Based upon the CyaSSL implementation in cyassl.c and cyassl.h:
     36  *   Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel (at) haxx.se>, et al.
     37  *
     38  * Thanks for code and inspiration!
     39  */
     40 
     41 #include "curl_setup.h"
     42 
     43 #ifdef USE_SCHANNEL
     44 
     45 #ifndef USE_WINDOWS_SSPI
     46 #  error "Can't compile SCHANNEL support without SSPI."
     47 #endif
     48 
     49 #include "curl_sspi.h"
     50 #include "schannel.h"
     51 #include "vtls.h"
     52 #include "sendf.h"
     53 #include "connect.h" /* for the connect timeout */
     54 #include "strerror.h"
     55 #include "select.h" /* for the socket readyness */
     56 #include "inet_pton.h" /* for IP addr SNI check */
     57 #include "curl_multibyte.h"
     58 #include "warnless.h"
     59 #include "x509asn1.h"
     60 #include "curl_printf.h"
     61 #include "system_win32.h"
     62 
     63  /* The last #include file should be: */
     64 #include "curl_memory.h"
     65 #include "memdebug.h"
     66 
     67 /* ALPN requires version 8.1 of the Windows SDK, which was
     68    shipped with Visual Studio 2013, aka _MSC_VER 1800:
     69 
     70    https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
     71 */
     72 #if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
     73 #  define HAS_ALPN 1
     74 #endif
     75 
     76 /* Uncomment to force verbose output
     77  * #define infof(x, y, ...) printf(y, __VA_ARGS__)
     78  * #define failf(x, y, ...) printf(y, __VA_ARGS__)
     79  */
     80 
     81 static Curl_recv schannel_recv;
     82 static Curl_send schannel_send;
     83 
     84 #ifdef _WIN32_WCE
     85 static CURLcode verify_certificate(struct connectdata *conn, int sockindex);
     86 #endif
     87 
     88 static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
     89                           void *BufDataPtr, unsigned long BufByteSize)
     90 {
     91   buffer->cbBuffer = BufByteSize;
     92   buffer->BufferType = BufType;
     93   buffer->pvBuffer = BufDataPtr;
     94 }
     95 
     96 static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
     97                               unsigned long NumArrElem)
     98 {
     99   desc->ulVersion = SECBUFFER_VERSION;
    100   desc->pBuffers = BufArr;
    101   desc->cBuffers = NumArrElem;
    102 }
    103 
    104 static CURLcode
    105 schannel_connect_step1(struct connectdata *conn, int sockindex)
    106 {
    107   ssize_t written = -1;
    108   struct Curl_easy *data = conn->data;
    109   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    110   SecBuffer outbuf;
    111   SecBufferDesc outbuf_desc;
    112   SecBuffer inbuf;
    113   SecBufferDesc inbuf_desc;
    114 #ifdef HAS_ALPN
    115   unsigned char alpn_buffer[128];
    116 #endif
    117   SCHANNEL_CRED schannel_cred;
    118   SECURITY_STATUS sspi_status = SEC_E_OK;
    119   struct curl_schannel_cred *old_cred = NULL;
    120   struct in_addr addr;
    121 #ifdef ENABLE_IPV6
    122   struct in6_addr addr6;
    123 #endif
    124   TCHAR *host_name;
    125   CURLcode result;
    126 
    127   infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
    128         conn->host.name, conn->remote_port);
    129 
    130   connssl->cred = NULL;
    131 
    132   /* check for an existing re-usable credential handle */
    133   if(conn->ssl_config.sessionid) {
    134     Curl_ssl_sessionid_lock(conn);
    135     if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) {
    136       connssl->cred = old_cred;
    137       infof(data, "schannel: re-using existing credential handle\n");
    138 
    139       /* increment the reference counter of the credential/session handle */
    140       connssl->cred->refcount++;
    141       infof(data, "schannel: incremented credential handle refcount = %d\n",
    142             connssl->cred->refcount);
    143     }
    144     Curl_ssl_sessionid_unlock(conn);
    145   }
    146 
    147   if(!connssl->cred) {
    148     /* setup Schannel API options */
    149     memset(&schannel_cred, 0, sizeof(schannel_cred));
    150     schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
    151 
    152     if(data->set.ssl.verifypeer) {
    153 #ifdef _WIN32_WCE
    154       /* certificate validation on CE doesn't seem to work right; we'll
    155          do it following a more manual process. */
    156       schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
    157         SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
    158         SCH_CRED_IGNORE_REVOCATION_OFFLINE;
    159 #else
    160       schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
    161       if(data->set.ssl_no_revoke)
    162         schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
    163                                  SCH_CRED_IGNORE_REVOCATION_OFFLINE;
    164       else
    165         schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
    166 #endif
    167       if(data->set.ssl_no_revoke)
    168         infof(data, "schannel: disabled server certificate revocation "
    169                     "checks\n");
    170       else
    171         infof(data, "schannel: checking server certificate revocation\n");
    172     }
    173     else {
    174       schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
    175         SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
    176         SCH_CRED_IGNORE_REVOCATION_OFFLINE;
    177       infof(data, "schannel: disabled server certificate revocation checks\n");
    178     }
    179 
    180     if(!data->set.ssl.verifyhost) {
    181       schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
    182       infof(data, "schannel: verifyhost setting prevents Schannel from "
    183             "comparing the supplied target name with the subject "
    184             "names in server certificates. Also disables SNI.\n");
    185     }
    186 
    187     switch(data->set.ssl.version) {
    188     default:
    189     case CURL_SSLVERSION_DEFAULT:
    190     case CURL_SSLVERSION_TLSv1:
    191       schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
    192         SP_PROT_TLS1_1_CLIENT |
    193         SP_PROT_TLS1_2_CLIENT;
    194       break;
    195     case CURL_SSLVERSION_TLSv1_0:
    196       schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT;
    197       break;
    198     case CURL_SSLVERSION_TLSv1_1:
    199       schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT;
    200       break;
    201     case CURL_SSLVERSION_TLSv1_2:
    202       schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT;
    203       break;
    204     case CURL_SSLVERSION_SSLv3:
    205       schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
    206       break;
    207     case CURL_SSLVERSION_SSLv2:
    208       schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
    209       break;
    210     }
    211 
    212     /* allocate memory for the re-usable credential handle */
    213     connssl->cred = (struct curl_schannel_cred *)
    214       malloc(sizeof(struct curl_schannel_cred));
    215     if(!connssl->cred) {
    216       failf(data, "schannel: unable to allocate memory");
    217       return CURLE_OUT_OF_MEMORY;
    218     }
    219     memset(connssl->cred, 0, sizeof(struct curl_schannel_cred));
    220     connssl->cred->refcount = 1;
    221 
    222     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
    223        */
    224     sspi_status =
    225       s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
    226                                          SECPKG_CRED_OUTBOUND, NULL,
    227                                          &schannel_cred, NULL, NULL,
    228                                          &connssl->cred->cred_handle,
    229                                          &connssl->cred->time_stamp);
    230 
    231     if(sspi_status != SEC_E_OK) {
    232       if(sspi_status == SEC_E_WRONG_PRINCIPAL)
    233         failf(data, "schannel: SNI or certificate check failed: %s",
    234               Curl_sspi_strerror(conn, sspi_status));
    235       else
    236         failf(data, "schannel: AcquireCredentialsHandle failed: %s",
    237               Curl_sspi_strerror(conn, sspi_status));
    238       Curl_safefree(connssl->cred);
    239       return CURLE_SSL_CONNECT_ERROR;
    240     }
    241   }
    242 
    243   /* Warn if SNI is disabled due to use of an IP address */
    244   if(Curl_inet_pton(AF_INET, conn->host.name, &addr)
    245 #ifdef ENABLE_IPV6
    246      || Curl_inet_pton(AF_INET6, conn->host.name, &addr6)
    247 #endif
    248     ) {
    249     infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
    250   }
    251 
    252 #ifdef HAS_ALPN
    253   /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above */
    254   if(conn->bits.tls_enable_alpn &&
    255      Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
    256                                  VERSION_GREATER_THAN_EQUAL)) {
    257     int cur = 0;
    258     int list_start_index = 0;
    259     unsigned int* extension_len = NULL;
    260     unsigned short* list_len = NULL;
    261 
    262     /* The first four bytes will be an unsigned int indicating number
    263        of bytes of data in the rest of the the buffer. */
    264     extension_len = (unsigned int*)(&alpn_buffer[cur]);
    265     cur += sizeof(unsigned int);
    266 
    267     /* The next four bytes are an indicator that this buffer will contain
    268        ALPN data, as opposed to NPN, for example. */
    269     *(unsigned int*)&alpn_buffer[cur] =
    270       SecApplicationProtocolNegotiationExt_ALPN;
    271     cur += sizeof(unsigned int);
    272 
    273     /* The next two bytes will be an unsigned short indicating the number
    274        of bytes used to list the preferred protocols. */
    275     list_len = (unsigned short*)(&alpn_buffer[cur]);
    276     cur += sizeof(unsigned short);
    277 
    278     list_start_index = cur;
    279 
    280 #ifdef USE_NGHTTP2
    281     if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
    282       memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
    283       cur += NGHTTP2_PROTO_ALPN_LEN;
    284       infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
    285     }
    286 #endif
    287 
    288     alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
    289     memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
    290     cur += ALPN_HTTP_1_1_LENGTH;
    291     infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1);
    292 
    293     *list_len = curlx_uitous(cur - list_start_index);
    294     *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
    295 
    296     InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
    297     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
    298   }
    299   else
    300   {
    301     InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
    302     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
    303   }
    304 #else /* HAS_ALPN */
    305   InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
    306   InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
    307 #endif
    308 
    309   /* setup output buffer */
    310   InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
    311   InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
    312 
    313   /* setup request flags */
    314   connssl->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
    315     ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
    316     ISC_REQ_STREAM;
    317 
    318   /* allocate memory for the security context handle */
    319   connssl->ctxt = (struct curl_schannel_ctxt *)
    320     malloc(sizeof(struct curl_schannel_ctxt));
    321   if(!connssl->ctxt) {
    322     failf(data, "schannel: unable to allocate memory");
    323     return CURLE_OUT_OF_MEMORY;
    324   }
    325   memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt));
    326 
    327   host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
    328   if(!host_name)
    329     return CURLE_OUT_OF_MEMORY;
    330 
    331   /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
    332 
    333   sspi_status = s_pSecFn->InitializeSecurityContext(
    334     &connssl->cred->cred_handle, NULL, host_name,
    335     connssl->req_flags, 0, 0, &inbuf_desc, 0, &connssl->ctxt->ctxt_handle,
    336     &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
    337 
    338   Curl_unicodefree(host_name);
    339 
    340   if(sspi_status != SEC_I_CONTINUE_NEEDED) {
    341     if(sspi_status == SEC_E_WRONG_PRINCIPAL)
    342       failf(data, "schannel: SNI or certificate check failed: %s",
    343             Curl_sspi_strerror(conn, sspi_status));
    344     else
    345       failf(data, "schannel: initial InitializeSecurityContext failed: %s",
    346             Curl_sspi_strerror(conn, sspi_status));
    347     Curl_safefree(connssl->ctxt);
    348     return CURLE_SSL_CONNECT_ERROR;
    349   }
    350 
    351   infof(data, "schannel: sending initial handshake data: "
    352         "sending %lu bytes...\n", outbuf.cbBuffer);
    353 
    354   /* send initial handshake data which is now stored in output buffer */
    355   result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
    356                             outbuf.cbBuffer, &written);
    357   s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
    358   if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
    359     failf(data, "schannel: failed to send initial handshake data: "
    360           "sent %zd of %lu bytes", written, outbuf.cbBuffer);
    361     return CURLE_SSL_CONNECT_ERROR;
    362   }
    363 
    364   infof(data, "schannel: sent initial handshake data: "
    365         "sent %zd bytes\n", written);
    366 
    367   connssl->recv_unrecoverable_err = CURLE_OK;
    368   connssl->recv_sspi_close_notify = false;
    369   connssl->recv_connection_closed = false;
    370 
    371   /* continue to second handshake step */
    372   connssl->connecting_state = ssl_connect_2;
    373 
    374   return CURLE_OK;
    375 }
    376 
    377 static CURLcode
    378 schannel_connect_step2(struct connectdata *conn, int sockindex)
    379 {
    380   int i;
    381   ssize_t nread = -1, written = -1;
    382   struct Curl_easy *data = conn->data;
    383   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    384   unsigned char *reallocated_buffer;
    385   size_t reallocated_length;
    386   SecBuffer outbuf[3];
    387   SecBufferDesc outbuf_desc;
    388   SecBuffer inbuf[2];
    389   SecBufferDesc inbuf_desc;
    390   SECURITY_STATUS sspi_status = SEC_E_OK;
    391   TCHAR *host_name;
    392   CURLcode result;
    393   bool doread;
    394 
    395   doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
    396 
    397   infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
    398         conn->host.name, conn->remote_port);
    399 
    400   if(!connssl->cred || !connssl->ctxt)
    401     return CURLE_SSL_CONNECT_ERROR;
    402 
    403   /* buffer to store previously received and decrypted data */
    404   if(connssl->decdata_buffer == NULL) {
    405     connssl->decdata_offset = 0;
    406     connssl->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
    407     connssl->decdata_buffer = malloc(connssl->decdata_length);
    408     if(connssl->decdata_buffer == NULL) {
    409       failf(data, "schannel: unable to allocate memory");
    410       return CURLE_OUT_OF_MEMORY;
    411     }
    412   }
    413 
    414   /* buffer to store previously received and encrypted data */
    415   if(connssl->encdata_buffer == NULL) {
    416     connssl->encdata_offset = 0;
    417     connssl->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
    418     connssl->encdata_buffer = malloc(connssl->encdata_length);
    419     if(connssl->encdata_buffer == NULL) {
    420       failf(data, "schannel: unable to allocate memory");
    421       return CURLE_OUT_OF_MEMORY;
    422     }
    423   }
    424 
    425   /* if we need a bigger buffer to read a full message, increase buffer now */
    426   if(connssl->encdata_length - connssl->encdata_offset <
    427      CURL_SCHANNEL_BUFFER_FREE_SIZE) {
    428     /* increase internal encrypted data buffer */
    429     reallocated_length = connssl->encdata_offset +
    430       CURL_SCHANNEL_BUFFER_FREE_SIZE;
    431     reallocated_buffer = realloc(connssl->encdata_buffer,
    432                                  reallocated_length);
    433 
    434     if(reallocated_buffer == NULL) {
    435       failf(data, "schannel: unable to re-allocate memory");
    436       return CURLE_OUT_OF_MEMORY;
    437     }
    438     else {
    439       connssl->encdata_buffer = reallocated_buffer;
    440       connssl->encdata_length = reallocated_length;
    441     }
    442   }
    443 
    444   for(;;) {
    445     if(doread) {
    446       /* read encrypted handshake data from socket */
    447       result = Curl_read_plain(conn->sock[sockindex],
    448                                (char *) (connssl->encdata_buffer +
    449                                          connssl->encdata_offset),
    450                                connssl->encdata_length -
    451                                connssl->encdata_offset,
    452                                &nread);
    453       if(result == CURLE_AGAIN) {
    454         if(connssl->connecting_state != ssl_connect_2_writing)
    455           connssl->connecting_state = ssl_connect_2_reading;
    456         infof(data, "schannel: failed to receive handshake, "
    457               "need more data\n");
    458         return CURLE_OK;
    459       }
    460       else if((result != CURLE_OK) || (nread == 0)) {
    461         failf(data, "schannel: failed to receive handshake, "
    462               "SSL/TLS connection failed");
    463         return CURLE_SSL_CONNECT_ERROR;
    464       }
    465 
    466       /* increase encrypted data buffer offset */
    467       connssl->encdata_offset += nread;
    468     }
    469 
    470     infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
    471           connssl->encdata_offset, connssl->encdata_length);
    472 
    473     /* setup input buffers */
    474     InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(connssl->encdata_offset),
    475                   curlx_uztoul(connssl->encdata_offset));
    476     InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
    477     InitSecBufferDesc(&inbuf_desc, inbuf, 2);
    478 
    479     /* setup output buffers */
    480     InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
    481     InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
    482     InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
    483     InitSecBufferDesc(&outbuf_desc, outbuf, 3);
    484 
    485     if(inbuf[0].pvBuffer == NULL) {
    486       failf(data, "schannel: unable to allocate memory");
    487       return CURLE_OUT_OF_MEMORY;
    488     }
    489 
    490     /* copy received handshake data into input buffer */
    491     memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer,
    492            connssl->encdata_offset);
    493 
    494     host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
    495     if(!host_name)
    496       return CURLE_OUT_OF_MEMORY;
    497 
    498     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
    499        */
    500     sspi_status = s_pSecFn->InitializeSecurityContext(
    501       &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle,
    502       host_name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL,
    503       &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
    504 
    505     Curl_unicodefree(host_name);
    506 
    507     /* free buffer for received handshake data */
    508     Curl_safefree(inbuf[0].pvBuffer);
    509 
    510     /* check if the handshake was incomplete */
    511     if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
    512       connssl->connecting_state = ssl_connect_2_reading;
    513       infof(data, "schannel: received incomplete message, need more data\n");
    514       return CURLE_OK;
    515     }
    516 
    517     /* If the server has requested a client certificate, attempt to continue
    518        the handshake without one. This will allow connections to servers which
    519        request a client certificate but do not require it. */
    520     if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
    521        !(connssl->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
    522       connssl->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
    523       connssl->connecting_state = ssl_connect_2_writing;
    524       infof(data, "schannel: a client certificate has been requested\n");
    525       return CURLE_OK;
    526     }
    527 
    528     /* check if the handshake needs to be continued */
    529     if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
    530       for(i = 0; i < 3; i++) {
    531         /* search for handshake tokens that need to be send */
    532         if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
    533           infof(data, "schannel: sending next handshake data: "
    534                 "sending %lu bytes...\n", outbuf[i].cbBuffer);
    535 
    536           /* send handshake token to server */
    537           result = Curl_write_plain(conn, conn->sock[sockindex],
    538                                     outbuf[i].pvBuffer, outbuf[i].cbBuffer,
    539                                     &written);
    540           if((result != CURLE_OK) ||
    541              (outbuf[i].cbBuffer != (size_t) written)) {
    542             failf(data, "schannel: failed to send next handshake data: "
    543                   "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
    544             return CURLE_SSL_CONNECT_ERROR;
    545           }
    546         }
    547 
    548         /* free obsolete buffer */
    549         if(outbuf[i].pvBuffer != NULL) {
    550           s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
    551         }
    552       }
    553     }
    554     else {
    555       if(sspi_status == SEC_E_WRONG_PRINCIPAL)
    556         failf(data, "schannel: SNI or certificate check failed: %s",
    557               Curl_sspi_strerror(conn, sspi_status));
    558       else
    559         failf(data, "schannel: next InitializeSecurityContext failed: %s",
    560               Curl_sspi_strerror(conn, sspi_status));
    561       return CURLE_SSL_CONNECT_ERROR;
    562     }
    563 
    564     /* check if there was additional remaining encrypted data */
    565     if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
    566       infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer);
    567       /*
    568         There are two cases where we could be getting extra data here:
    569         1) If we're renegotiating a connection and the handshake is already
    570         complete (from the server perspective), it can encrypted app data
    571         (not handshake data) in an extra buffer at this point.
    572         2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
    573         connection and this extra data is part of the handshake.
    574         We should process the data immediately; waiting for the socket to
    575         be ready may fail since the server is done sending handshake data.
    576       */
    577       /* check if the remaining data is less than the total amount
    578          and therefore begins after the already processed data */
    579       if(connssl->encdata_offset > inbuf[1].cbBuffer) {
    580         memmove(connssl->encdata_buffer,
    581                 (connssl->encdata_buffer + connssl->encdata_offset) -
    582                 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
    583         connssl->encdata_offset = inbuf[1].cbBuffer;
    584         if(sspi_status == SEC_I_CONTINUE_NEEDED) {
    585           doread = FALSE;
    586           continue;
    587         }
    588       }
    589     }
    590     else {
    591       connssl->encdata_offset = 0;
    592     }
    593     break;
    594   }
    595 
    596   /* check if the handshake needs to be continued */
    597   if(sspi_status == SEC_I_CONTINUE_NEEDED) {
    598     connssl->connecting_state = ssl_connect_2_reading;
    599     return CURLE_OK;
    600   }
    601 
    602   /* check if the handshake is complete */
    603   if(sspi_status == SEC_E_OK) {
    604     connssl->connecting_state = ssl_connect_3;
    605     infof(data, "schannel: SSL/TLS handshake complete\n");
    606   }
    607 
    608 #ifdef _WIN32_WCE
    609   /* Windows CE doesn't do any server certificate validation.
    610      We have to do it manually. */
    611   if(data->set.ssl.verifypeer)
    612     return verify_certificate(conn, sockindex);
    613 #endif
    614 
    615   return CURLE_OK;
    616 }
    617 
    618 static CURLcode
    619 schannel_connect_step3(struct connectdata *conn, int sockindex)
    620 {
    621   CURLcode result = CURLE_OK;
    622   struct Curl_easy *data = conn->data;
    623   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    624   SECURITY_STATUS sspi_status = SEC_E_OK;
    625   CERT_CONTEXT *ccert_context = NULL;
    626 #ifdef HAS_ALPN
    627   SecPkgContext_ApplicationProtocol alpn_result;
    628 #endif
    629 
    630   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
    631 
    632   infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
    633         conn->host.name, conn->remote_port);
    634 
    635   if(!connssl->cred)
    636     return CURLE_SSL_CONNECT_ERROR;
    637 
    638   /* check if the required context attributes are met */
    639   if(connssl->ret_flags != connssl->req_flags) {
    640     if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT))
    641       failf(data, "schannel: failed to setup sequence detection");
    642     if(!(connssl->ret_flags & ISC_RET_REPLAY_DETECT))
    643       failf(data, "schannel: failed to setup replay detection");
    644     if(!(connssl->ret_flags & ISC_RET_CONFIDENTIALITY))
    645       failf(data, "schannel: failed to setup confidentiality");
    646     if(!(connssl->ret_flags & ISC_RET_ALLOCATED_MEMORY))
    647       failf(data, "schannel: failed to setup memory allocation");
    648     if(!(connssl->ret_flags & ISC_RET_STREAM))
    649       failf(data, "schannel: failed to setup stream orientation");
    650     return CURLE_SSL_CONNECT_ERROR;
    651   }
    652 
    653 #ifdef HAS_ALPN
    654   /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above */
    655   if(conn->bits.tls_enable_alpn &&
    656      Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
    657                                  VERSION_GREATER_THAN_EQUAL)) {
    658     sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
    659       SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
    660 
    661     if(sspi_status != SEC_E_OK) {
    662       failf(data, "schannel: failed to retrieve ALPN result");
    663       return CURLE_SSL_CONNECT_ERROR;
    664     }
    665 
    666     if(alpn_result.ProtoNegoStatus ==
    667        SecApplicationProtocolNegotiationStatus_Success) {
    668 
    669       infof(data, "schannel: ALPN, server accepted to use %.*s\n",
    670         alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
    671 
    672 #ifdef USE_NGHTTP2
    673       if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
    674          !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
    675           NGHTTP2_PROTO_VERSION_ID_LEN)) {
    676         conn->negnpn = CURL_HTTP_VERSION_2;
    677       }
    678       else
    679 #endif
    680       if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
    681          !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
    682            ALPN_HTTP_1_1_LENGTH)) {
    683         conn->negnpn = CURL_HTTP_VERSION_1_1;
    684       }
    685     }
    686     else
    687       infof(data, "ALPN, server did not agree to a protocol\n");
    688   }
    689 #endif
    690 
    691   /* save the current session data for possible re-use */
    692   if(conn->ssl_config.sessionid) {
    693     bool incache;
    694     struct curl_schannel_cred *old_cred = NULL;
    695 
    696     Curl_ssl_sessionid_lock(conn);
    697     incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL));
    698     if(incache) {
    699       if(old_cred != connssl->cred) {
    700         infof(data, "schannel: old credential handle is stale, removing\n");
    701         /* we're not taking old_cred ownership here, no refcount++ is needed */
    702         Curl_ssl_delsessionid(conn, (void *)old_cred);
    703         incache = FALSE;
    704       }
    705     }
    706     if(!incache) {
    707       result = Curl_ssl_addsessionid(conn, (void *)connssl->cred,
    708                                      sizeof(struct curl_schannel_cred));
    709       if(result) {
    710         Curl_ssl_sessionid_unlock(conn);
    711         failf(data, "schannel: failed to store credential handle");
    712         return result;
    713       }
    714       else {
    715         /* this cred session is now also referenced by sessionid cache */
    716         connssl->cred->refcount++;
    717         infof(data, "schannel: stored credential handle in session cache\n");
    718       }
    719     }
    720     Curl_ssl_sessionid_unlock(conn);
    721   }
    722 
    723   if(data->set.ssl.certinfo) {
    724     sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
    725       SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
    726 
    727     if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
    728       failf(data, "schannel: failed to retrieve remote cert context");
    729       return CURLE_SSL_CONNECT_ERROR;
    730     }
    731 
    732     result = Curl_ssl_init_certinfo(data, 1);
    733     if(!result) {
    734       if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
    735          (ccert_context->cbCertEncoded > 0)) {
    736 
    737         const char *beg = (const char *) ccert_context->pbCertEncoded;
    738         const char *end = beg + ccert_context->cbCertEncoded;
    739         result = Curl_extract_certinfo(conn, 0, beg, end);
    740       }
    741     }
    742     CertFreeCertificateContext(ccert_context);
    743     if(result)
    744       return result;
    745   }
    746 
    747   connssl->connecting_state = ssl_connect_done;
    748 
    749   return CURLE_OK;
    750 }
    751 
    752 static CURLcode
    753 schannel_connect_common(struct connectdata *conn, int sockindex,
    754                         bool nonblocking, bool *done)
    755 {
    756   CURLcode result;
    757   struct Curl_easy *data = conn->data;
    758   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    759   curl_socket_t sockfd = conn->sock[sockindex];
    760   long timeout_ms;
    761   int what;
    762 
    763   /* check if the connection has already been established */
    764   if(ssl_connection_complete == connssl->state) {
    765     *done = TRUE;
    766     return CURLE_OK;
    767   }
    768 
    769   if(ssl_connect_1 == connssl->connecting_state) {
    770     /* check out how much more time we're allowed */
    771     timeout_ms = Curl_timeleft(data, NULL, TRUE);
    772 
    773     if(timeout_ms < 0) {
    774       /* no need to continue if time already is up */
    775       failf(data, "SSL/TLS connection timeout");
    776       return CURLE_OPERATION_TIMEDOUT;
    777     }
    778 
    779     result = schannel_connect_step1(conn, sockindex);
    780     if(result)
    781       return result;
    782   }
    783 
    784   while(ssl_connect_2 == connssl->connecting_state ||
    785         ssl_connect_2_reading == connssl->connecting_state ||
    786         ssl_connect_2_writing == connssl->connecting_state) {
    787 
    788     /* check out how much more time we're allowed */
    789     timeout_ms = Curl_timeleft(data, NULL, TRUE);
    790 
    791     if(timeout_ms < 0) {
    792       /* no need to continue if time already is up */
    793       failf(data, "SSL/TLS connection timeout");
    794       return CURLE_OPERATION_TIMEDOUT;
    795     }
    796 
    797     /* if ssl is expecting something, check if it's available. */
    798     if(connssl->connecting_state == ssl_connect_2_reading
    799        || connssl->connecting_state == ssl_connect_2_writing) {
    800 
    801       curl_socket_t writefd = ssl_connect_2_writing ==
    802         connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
    803       curl_socket_t readfd = ssl_connect_2_reading ==
    804         connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
    805 
    806       what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms);
    807       if(what < 0) {
    808         /* fatal error */
    809         failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
    810         return CURLE_SSL_CONNECT_ERROR;
    811       }
    812       else if(0 == what) {
    813         if(nonblocking) {
    814           *done = FALSE;
    815           return CURLE_OK;
    816         }
    817         else {
    818           /* timeout */
    819           failf(data, "SSL/TLS connection timeout");
    820           return CURLE_OPERATION_TIMEDOUT;
    821         }
    822       }
    823       /* socket is readable or writable */
    824     }
    825 
    826     /* Run transaction, and return to the caller if it failed or if
    827      * this connection is part of a multi handle and this loop would
    828      * execute again. This permits the owner of a multi handle to
    829      * abort a connection attempt before step2 has completed while
    830      * ensuring that a client using select() or epoll() will always
    831      * have a valid fdset to wait on.
    832      */
    833     result = schannel_connect_step2(conn, sockindex);
    834     if(result || (nonblocking &&
    835                   (ssl_connect_2 == connssl->connecting_state ||
    836                    ssl_connect_2_reading == connssl->connecting_state ||
    837                    ssl_connect_2_writing == connssl->connecting_state)))
    838       return result;
    839 
    840   } /* repeat step2 until all transactions are done. */
    841 
    842   if(ssl_connect_3 == connssl->connecting_state) {
    843     result = schannel_connect_step3(conn, sockindex);
    844     if(result)
    845       return result;
    846   }
    847 
    848   if(ssl_connect_done == connssl->connecting_state) {
    849     connssl->state = ssl_connection_complete;
    850     conn->recv[sockindex] = schannel_recv;
    851     conn->send[sockindex] = schannel_send;
    852     *done = TRUE;
    853   }
    854   else
    855     *done = FALSE;
    856 
    857   /* reset our connection state machine */
    858   connssl->connecting_state = ssl_connect_1;
    859 
    860   return CURLE_OK;
    861 }
    862 
    863 static ssize_t
    864 schannel_send(struct connectdata *conn, int sockindex,
    865               const void *buf, size_t len, CURLcode *err)
    866 {
    867   ssize_t written = -1;
    868   size_t data_len = 0;
    869   unsigned char *data = NULL;
    870   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
    871   SecBuffer outbuf[4];
    872   SecBufferDesc outbuf_desc;
    873   SECURITY_STATUS sspi_status = SEC_E_OK;
    874   CURLcode result;
    875 
    876   /* check if the maximum stream sizes were queried */
    877   if(connssl->stream_sizes.cbMaximumMessage == 0) {
    878     sspi_status = s_pSecFn->QueryContextAttributes(
    879       &connssl->ctxt->ctxt_handle,
    880       SECPKG_ATTR_STREAM_SIZES,
    881       &connssl->stream_sizes);
    882     if(sspi_status != SEC_E_OK) {
    883       *err = CURLE_SEND_ERROR;
    884       return -1;
    885     }
    886   }
    887 
    888   /* check if the buffer is longer than the maximum message length */
    889   if(len > connssl->stream_sizes.cbMaximumMessage) {
    890     *err = CURLE_SEND_ERROR;
    891     return -1;
    892   }
    893 
    894   /* calculate the complete message length and allocate a buffer for it */
    895   data_len = connssl->stream_sizes.cbHeader + len +
    896     connssl->stream_sizes.cbTrailer;
    897   data = (unsigned char *) malloc(data_len);
    898   if(data == NULL) {
    899     *err = CURLE_OUT_OF_MEMORY;
    900     return -1;
    901   }
    902 
    903   /* setup output buffers (header, data, trailer, empty) */
    904   InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
    905                 data, connssl->stream_sizes.cbHeader);
    906   InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
    907                 data + connssl->stream_sizes.cbHeader, curlx_uztoul(len));
    908   InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
    909                 data + connssl->stream_sizes.cbHeader + len,
    910                 connssl->stream_sizes.cbTrailer);
    911   InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
    912   InitSecBufferDesc(&outbuf_desc, outbuf, 4);
    913 
    914   /* copy data into output buffer */
    915   memcpy(outbuf[1].pvBuffer, buf, len);
    916 
    917   /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
    918   sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt->ctxt_handle, 0,
    919                                          &outbuf_desc, 0);
    920 
    921   /* check if the message was encrypted */
    922   if(sspi_status == SEC_E_OK) {
    923     written = 0;
    924 
    925     /* send the encrypted message including header, data and trailer */
    926     len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
    927 
    928     /*
    929       It's important to send the full message which includes the header,
    930       encrypted payload, and trailer.  Until the client receives all the
    931       data a coherent message has not been delivered and the client
    932       can't read any of it.
    933 
    934       If we wanted to buffer the unwritten encrypted bytes, we would
    935       tell the client that all data it has requested to be sent has been
    936       sent. The unwritten encrypted bytes would be the first bytes to
    937       send on the next invocation.
    938       Here's the catch with this - if we tell the client that all the
    939       bytes have been sent, will the client call this method again to
    940       send the buffered data?  Looking at who calls this function, it
    941       seems the answer is NO.
    942     */
    943 
    944     /* send entire message or fail */
    945     while(len > (size_t)written) {
    946       ssize_t this_write;
    947       long timeleft;
    948       int what;
    949 
    950       this_write = 0;
    951 
    952       timeleft = Curl_timeleft(conn->data, NULL, FALSE);
    953       if(timeleft < 0) {
    954         /* we already got the timeout */
    955         failf(conn->data, "schannel: timed out sending data "
    956               "(bytes sent: %zd)", written);
    957         *err = CURLE_OPERATION_TIMEDOUT;
    958         written = -1;
    959         break;
    960       }
    961 
    962       what = Curl_socket_ready(CURL_SOCKET_BAD, conn->sock[sockindex],
    963                                timeleft);
    964       if(what < 0) {
    965         /* fatal error */
    966         failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
    967         *err = CURLE_SEND_ERROR;
    968         written = -1;
    969         break;
    970       }
    971       else if(0 == what) {
    972         failf(conn->data, "schannel: timed out sending data "
    973               "(bytes sent: %zd)", written);
    974         *err = CURLE_OPERATION_TIMEDOUT;
    975         written = -1;
    976         break;
    977       }
    978       /* socket is writable */
    979 
    980       result = Curl_write_plain(conn, conn->sock[sockindex], data + written,
    981                                 len - written, &this_write);
    982       if(result == CURLE_AGAIN)
    983         continue;
    984       else if(result != CURLE_OK) {
    985         *err = result;
    986         written = -1;
    987         break;
    988       }
    989 
    990       written += this_write;
    991     }
    992   }
    993   else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
    994     *err = CURLE_OUT_OF_MEMORY;
    995   }
    996   else{
    997     *err = CURLE_SEND_ERROR;
    998   }
    999 
   1000   Curl_safefree(data);
   1001 
   1002   if(len == (size_t)written)
   1003     /* Encrypted message including header, data and trailer entirely sent.
   1004        The return value is the number of unencrypted bytes that were sent. */
   1005     written = outbuf[1].cbBuffer;
   1006 
   1007   return written;
   1008 }
   1009 
   1010 static ssize_t
   1011 schannel_recv(struct connectdata *conn, int sockindex,
   1012               char *buf, size_t len, CURLcode *err)
   1013 {
   1014   size_t size = 0;
   1015   ssize_t nread = -1;
   1016   struct Curl_easy *data = conn->data;
   1017   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   1018   unsigned char *reallocated_buffer;
   1019   size_t reallocated_length;
   1020   bool done = FALSE;
   1021   SecBuffer inbuf[4];
   1022   SecBufferDesc inbuf_desc;
   1023   SECURITY_STATUS sspi_status = SEC_E_OK;
   1024   /* we want the length of the encrypted buffer to be at least large enough
   1025      that it can hold all the bytes requested and some TLS record overhead. */
   1026   size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
   1027 
   1028   /****************************************************************************
   1029    * Don't return or set connssl->recv_unrecoverable_err unless in the cleanup.
   1030    * The pattern for return error is set *err, optional infof, goto cleanup.
   1031    *
   1032    * Our priority is to always return as much decrypted data to the caller as
   1033    * possible, even if an error occurs. The state of the decrypted buffer must
   1034    * always be valid. Transfer of decrypted data to the caller's buffer is
   1035    * handled in the cleanup.
   1036    */
   1037 
   1038   infof(data, "schannel: client wants to read %zu bytes\n", len);
   1039   *err = CURLE_OK;
   1040 
   1041   if(len && len <= connssl->decdata_offset) {
   1042     infof(data, "schannel: enough decrypted data is already available\n");
   1043     goto cleanup;
   1044   }
   1045   else if(connssl->recv_unrecoverable_err) {
   1046     *err = connssl->recv_unrecoverable_err;
   1047     infof(data, "schannel: an unrecoverable error occurred in a prior call\n");
   1048     goto cleanup;
   1049   }
   1050   else if(connssl->recv_sspi_close_notify) {
   1051     /* once a server has indicated shutdown there is no more encrypted data */
   1052     infof(data, "schannel: server indicated shutdown in a prior call\n");
   1053     goto cleanup;
   1054   }
   1055   else if(!len) {
   1056     /* It's debatable what to return when !len. Regardless we can't return
   1057     immediately because there may be data to decrypt (in the case we want to
   1058     decrypt all encrypted cached data) so handle !len later in cleanup.
   1059     */
   1060     ; /* do nothing */
   1061   }
   1062   else if(!connssl->recv_connection_closed) {
   1063     /* increase enc buffer in order to fit the requested amount of data */
   1064     size = connssl->encdata_length - connssl->encdata_offset;
   1065     if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
   1066        connssl->encdata_length < min_encdata_length) {
   1067       reallocated_length = connssl->encdata_offset +
   1068                            CURL_SCHANNEL_BUFFER_FREE_SIZE;
   1069       if(reallocated_length < min_encdata_length) {
   1070         reallocated_length = min_encdata_length;
   1071       }
   1072       reallocated_buffer = realloc(connssl->encdata_buffer,
   1073                                    reallocated_length);
   1074       if(reallocated_buffer == NULL) {
   1075         *err = CURLE_OUT_OF_MEMORY;
   1076         failf(data, "schannel: unable to re-allocate memory");
   1077         goto cleanup;
   1078       }
   1079 
   1080       connssl->encdata_buffer = reallocated_buffer;
   1081       connssl->encdata_length = reallocated_length;
   1082       size = connssl->encdata_length - connssl->encdata_offset;
   1083       infof(data, "schannel: encdata_buffer resized %zu\n",
   1084             connssl->encdata_length);
   1085     }
   1086 
   1087     infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
   1088           connssl->encdata_offset, connssl->encdata_length);
   1089 
   1090     /* read encrypted data from socket */
   1091     *err = Curl_read_plain(conn->sock[sockindex],
   1092                            (char *)(connssl->encdata_buffer +
   1093                                     connssl->encdata_offset),
   1094                            size, &nread);
   1095     if(*err) {
   1096       nread = -1;
   1097       if(*err == CURLE_AGAIN)
   1098         infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n");
   1099       else if(*err == CURLE_RECV_ERROR)
   1100         infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
   1101       else
   1102         infof(data, "schannel: Curl_read_plain returned error %d\n", *err);
   1103     }
   1104     else if(nread == 0) {
   1105       connssl->recv_connection_closed = true;
   1106       infof(data, "schannel: server closed the connection\n");
   1107     }
   1108     else if(nread > 0) {
   1109       connssl->encdata_offset += (size_t)nread;
   1110       infof(data, "schannel: encrypted data got %zd\n", nread);
   1111     }
   1112   }
   1113 
   1114   infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
   1115         connssl->encdata_offset, connssl->encdata_length);
   1116 
   1117   /* decrypt loop */
   1118   while(connssl->encdata_offset > 0 && sspi_status == SEC_E_OK &&
   1119         (!len || connssl->decdata_offset < len ||
   1120          connssl->recv_connection_closed)) {
   1121     /* prepare data buffer for DecryptMessage call */
   1122     InitSecBuffer(&inbuf[0], SECBUFFER_DATA, connssl->encdata_buffer,
   1123                   curlx_uztoul(connssl->encdata_offset));
   1124 
   1125     /* we need 3 more empty input buffers for possible output */
   1126     InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
   1127     InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
   1128     InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
   1129     InitSecBufferDesc(&inbuf_desc, inbuf, 4);
   1130 
   1131     /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
   1132        */
   1133     sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle,
   1134                                            &inbuf_desc, 0, NULL);
   1135 
   1136     /* check if everything went fine (server may want to renegotiate
   1137        or shutdown the connection context) */
   1138     if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
   1139        sspi_status == SEC_I_CONTEXT_EXPIRED) {
   1140       /* check for successfully decrypted data, even before actual
   1141          renegotiation or shutdown of the connection context */
   1142       if(inbuf[1].BufferType == SECBUFFER_DATA) {
   1143         infof(data, "schannel: decrypted data length: %lu\n",
   1144               inbuf[1].cbBuffer);
   1145 
   1146         /* increase buffer in order to fit the received amount of data */
   1147         size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
   1148                inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
   1149         if(connssl->decdata_length - connssl->decdata_offset < size ||
   1150            connssl->decdata_length < len) {
   1151           /* increase internal decrypted data buffer */
   1152           reallocated_length = connssl->decdata_offset + size;
   1153           /* make sure that the requested amount of data fits */
   1154           if(reallocated_length < len) {
   1155             reallocated_length = len;
   1156           }
   1157           reallocated_buffer = realloc(connssl->decdata_buffer,
   1158                                        reallocated_length);
   1159           if(reallocated_buffer == NULL) {
   1160             *err = CURLE_OUT_OF_MEMORY;
   1161             failf(data, "schannel: unable to re-allocate memory");
   1162             goto cleanup;
   1163           }
   1164           connssl->decdata_buffer = reallocated_buffer;
   1165           connssl->decdata_length = reallocated_length;
   1166         }
   1167 
   1168         /* copy decrypted data to internal buffer */
   1169         size = inbuf[1].cbBuffer;
   1170         if(size) {
   1171           memcpy(connssl->decdata_buffer + connssl->decdata_offset,
   1172                  inbuf[1].pvBuffer, size);
   1173           connssl->decdata_offset += size;
   1174         }
   1175 
   1176         infof(data, "schannel: decrypted data added: %zu\n", size);
   1177         infof(data, "schannel: decrypted data cached: offset %zu length %zu\n",
   1178               connssl->decdata_offset, connssl->decdata_length);
   1179       }
   1180 
   1181       /* check for remaining encrypted data */
   1182       if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
   1183         infof(data, "schannel: encrypted data length: %lu\n",
   1184               inbuf[3].cbBuffer);
   1185 
   1186         /* check if the remaining data is less than the total amount
   1187          * and therefore begins after the already processed data
   1188          */
   1189         if(connssl->encdata_offset > inbuf[3].cbBuffer) {
   1190           /* move remaining encrypted data forward to the beginning of
   1191              buffer */
   1192           memmove(connssl->encdata_buffer,
   1193                   (connssl->encdata_buffer + connssl->encdata_offset) -
   1194                   inbuf[3].cbBuffer, inbuf[3].cbBuffer);
   1195           connssl->encdata_offset = inbuf[3].cbBuffer;
   1196         }
   1197 
   1198         infof(data, "schannel: encrypted data cached: offset %zu length %zu\n",
   1199               connssl->encdata_offset, connssl->encdata_length);
   1200       }
   1201       else {
   1202         /* reset encrypted buffer offset, because there is no data remaining */
   1203         connssl->encdata_offset = 0;
   1204       }
   1205 
   1206       /* check if server wants to renegotiate the connection context */
   1207       if(sspi_status == SEC_I_RENEGOTIATE) {
   1208         infof(data, "schannel: remote party requests renegotiation\n");
   1209         if(*err && *err != CURLE_AGAIN) {
   1210           infof(data, "schannel: can't renogotiate, an error is pending\n");
   1211           goto cleanup;
   1212         }
   1213         if(connssl->encdata_offset) {
   1214           *err = CURLE_RECV_ERROR;
   1215           infof(data, "schannel: can't renogotiate, "
   1216                       "encrypted data available\n");
   1217           goto cleanup;
   1218         }
   1219         /* begin renegotiation */
   1220         infof(data, "schannel: renegotiating SSL/TLS connection\n");
   1221         connssl->state = ssl_connection_negotiating;
   1222         connssl->connecting_state = ssl_connect_2_writing;
   1223         *err = schannel_connect_common(conn, sockindex, FALSE, &done);
   1224         if(*err) {
   1225           infof(data, "schannel: renegotiation failed\n");
   1226           goto cleanup;
   1227         }
   1228         /* now retry receiving data */
   1229         sspi_status = SEC_E_OK;
   1230         infof(data, "schannel: SSL/TLS connection renegotiated\n");
   1231         continue;
   1232       }
   1233       /* check if the server closed the connection */
   1234       else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
   1235         /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
   1236            returned so we have to work around that in cleanup. */
   1237         connssl->recv_sspi_close_notify = true;
   1238         if(!connssl->recv_connection_closed) {
   1239           connssl->recv_connection_closed = true;
   1240           infof(data, "schannel: server closed the connection\n");
   1241         }
   1242         goto cleanup;
   1243       }
   1244     }
   1245     else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
   1246       if(!*err)
   1247         *err = CURLE_AGAIN;
   1248       infof(data, "schannel: failed to decrypt data, need more data\n");
   1249       goto cleanup;
   1250     }
   1251     else {
   1252       *err = CURLE_RECV_ERROR;
   1253       infof(data, "schannel: failed to read data from server: %s\n",
   1254             Curl_sspi_strerror(conn, sspi_status));
   1255       goto cleanup;
   1256     }
   1257   }
   1258 
   1259   infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
   1260         connssl->encdata_offset, connssl->encdata_length);
   1261 
   1262   infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
   1263         connssl->decdata_offset, connssl->decdata_length);
   1264 
   1265 cleanup:
   1266   /* Warning- there is no guarantee the encdata state is valid at this point */
   1267   infof(data, "schannel: schannel_recv cleanup\n");
   1268 
   1269   /* Error if the connection has closed without a close_notify.
   1270   Behavior here is a matter of debate. We don't want to be vulnerable to a
   1271   truncation attack however there's some browser precedent for ignoring the
   1272   close_notify for compatibility reasons.
   1273   Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't
   1274   return close_notify. In that case if the connection was closed we assume it
   1275   was graceful (close_notify) since there doesn't seem to be a way to tell.
   1276   */
   1277   if(len && !connssl->decdata_offset && connssl->recv_connection_closed &&
   1278      !connssl->recv_sspi_close_notify) {
   1279     bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
   1280                                                VERSION_EQUAL);
   1281 
   1282     if(isWin2k && sspi_status == SEC_E_OK)
   1283       connssl->recv_sspi_close_notify = true;
   1284     else {
   1285       *err = CURLE_RECV_ERROR;
   1286       infof(data, "schannel: server closed abruptly (missing close_notify)\n");
   1287     }
   1288   }
   1289 
   1290   /* Any error other than CURLE_AGAIN is an unrecoverable error. */
   1291   if(*err && *err != CURLE_AGAIN)
   1292       connssl->recv_unrecoverable_err = *err;
   1293 
   1294   size = len < connssl->decdata_offset ? len : connssl->decdata_offset;
   1295   if(size) {
   1296     memcpy(buf, connssl->decdata_buffer, size);
   1297     memmove(connssl->decdata_buffer, connssl->decdata_buffer + size,
   1298             connssl->decdata_offset - size);
   1299     connssl->decdata_offset -= size;
   1300 
   1301     infof(data, "schannel: decrypted data returned %zu\n", size);
   1302     infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
   1303           connssl->decdata_offset, connssl->decdata_length);
   1304     *err = CURLE_OK;
   1305     return (ssize_t)size;
   1306   }
   1307 
   1308   if(!*err && !connssl->recv_connection_closed)
   1309       *err = CURLE_AGAIN;
   1310 
   1311   /* It's debatable what to return when !len. We could return whatever error we
   1312   got from decryption but instead we override here so the return is consistent.
   1313   */
   1314   if(!len)
   1315     *err = CURLE_OK;
   1316 
   1317   return *err ? -1 : 0;
   1318 }
   1319 
   1320 CURLcode
   1321 Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex,
   1322                                   bool *done)
   1323 {
   1324   return schannel_connect_common(conn, sockindex, TRUE, done);
   1325 }
   1326 
   1327 CURLcode
   1328 Curl_schannel_connect(struct connectdata *conn, int sockindex)
   1329 {
   1330   CURLcode result;
   1331   bool done = FALSE;
   1332 
   1333   result = schannel_connect_common(conn, sockindex, FALSE, &done);
   1334   if(result)
   1335     return result;
   1336 
   1337   DEBUGASSERT(done);
   1338 
   1339   return CURLE_OK;
   1340 }
   1341 
   1342 bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex)
   1343 {
   1344   const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   1345 
   1346   if(connssl->use) /* SSL/TLS is in use */
   1347     return (connssl->encdata_offset > 0 ||
   1348             connssl->decdata_offset > 0) ? TRUE : FALSE;
   1349   else
   1350     return FALSE;
   1351 }
   1352 
   1353 void Curl_schannel_close(struct connectdata *conn, int sockindex)
   1354 {
   1355   if(conn->ssl[sockindex].use)
   1356     /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
   1357     Curl_ssl_shutdown(conn, sockindex);
   1358 }
   1359 
   1360 int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
   1361 {
   1362   /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
   1363    * Shutting Down an Schannel Connection
   1364    */
   1365   struct Curl_easy *data = conn->data;
   1366   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   1367 
   1368   infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
   1369         conn->host.name, conn->remote_port);
   1370 
   1371   if(connssl->cred && connssl->ctxt) {
   1372     SecBufferDesc BuffDesc;
   1373     SecBuffer Buffer;
   1374     SECURITY_STATUS sspi_status;
   1375     SecBuffer outbuf;
   1376     SecBufferDesc outbuf_desc;
   1377     CURLcode result;
   1378     TCHAR *host_name;
   1379     DWORD dwshut = SCHANNEL_SHUTDOWN;
   1380 
   1381     InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
   1382     InitSecBufferDesc(&BuffDesc, &Buffer, 1);
   1383 
   1384     sspi_status = s_pSecFn->ApplyControlToken(&connssl->ctxt->ctxt_handle,
   1385                                               &BuffDesc);
   1386 
   1387     if(sspi_status != SEC_E_OK)
   1388       failf(data, "schannel: ApplyControlToken failure: %s",
   1389             Curl_sspi_strerror(conn, sspi_status));
   1390 
   1391     host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
   1392     if(!host_name)
   1393       return CURLE_OUT_OF_MEMORY;
   1394 
   1395     /* setup output buffer */
   1396     InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
   1397     InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
   1398 
   1399     sspi_status = s_pSecFn->InitializeSecurityContext(
   1400       &connssl->cred->cred_handle,
   1401       &connssl->ctxt->ctxt_handle,
   1402       host_name,
   1403       connssl->req_flags,
   1404       0,
   1405       0,
   1406       NULL,
   1407       0,
   1408       &connssl->ctxt->ctxt_handle,
   1409       &outbuf_desc,
   1410       &connssl->ret_flags,
   1411       &connssl->ctxt->time_stamp);
   1412 
   1413     Curl_unicodefree(host_name);
   1414 
   1415     if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
   1416       /* send close message which is in output buffer */
   1417       ssize_t written;
   1418       result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
   1419                                 outbuf.cbBuffer, &written);
   1420 
   1421       s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
   1422       if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
   1423         infof(data, "schannel: failed to send close msg: %s"
   1424               " (bytes written: %zd)\n", curl_easy_strerror(result), written);
   1425       }
   1426     }
   1427   }
   1428 
   1429   /* free SSPI Schannel API security context handle */
   1430   if(connssl->ctxt) {
   1431     infof(data, "schannel: clear security context handle\n");
   1432     s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle);
   1433     Curl_safefree(connssl->ctxt);
   1434   }
   1435 
   1436   /* free SSPI Schannel API credential handle */
   1437   if(connssl->cred) {
   1438     Curl_ssl_sessionid_lock(conn);
   1439     Curl_schannel_session_free(connssl->cred);
   1440     Curl_ssl_sessionid_unlock(conn);
   1441     connssl->cred = NULL;
   1442   }
   1443 
   1444   /* free internal buffer for received encrypted data */
   1445   if(connssl->encdata_buffer != NULL) {
   1446     Curl_safefree(connssl->encdata_buffer);
   1447     connssl->encdata_length = 0;
   1448     connssl->encdata_offset = 0;
   1449   }
   1450 
   1451   /* free internal buffer for received decrypted data */
   1452   if(connssl->decdata_buffer != NULL) {
   1453     Curl_safefree(connssl->decdata_buffer);
   1454     connssl->decdata_length = 0;
   1455     connssl->decdata_offset = 0;
   1456   }
   1457 
   1458   return CURLE_OK;
   1459 }
   1460 
   1461 void Curl_schannel_session_free(void *ptr)
   1462 {
   1463   /* this is expected to be called under sessionid lock */
   1464   struct curl_schannel_cred *cred = ptr;
   1465 
   1466   cred->refcount--;
   1467   if(cred->refcount == 0) {
   1468     s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
   1469     Curl_safefree(cred);
   1470   }
   1471 }
   1472 
   1473 int Curl_schannel_init(void)
   1474 {
   1475   return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
   1476 }
   1477 
   1478 void Curl_schannel_cleanup(void)
   1479 {
   1480   Curl_sspi_global_cleanup();
   1481 }
   1482 
   1483 size_t Curl_schannel_version(char *buffer, size_t size)
   1484 {
   1485   size = snprintf(buffer, size, "WinSSL");
   1486 
   1487   return size;
   1488 }
   1489 
   1490 int Curl_schannel_random(unsigned char *entropy, size_t length)
   1491 {
   1492   HCRYPTPROV hCryptProv = 0;
   1493 
   1494   if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
   1495                           CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
   1496     return 1;
   1497 
   1498   if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
   1499     CryptReleaseContext(hCryptProv, 0UL);
   1500     return 1;
   1501   }
   1502 
   1503   CryptReleaseContext(hCryptProv, 0UL);
   1504   return 0;
   1505 }
   1506 
   1507 #ifdef _WIN32_WCE
   1508 static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
   1509 {
   1510   SECURITY_STATUS status;
   1511   struct Curl_easy *data = conn->data;
   1512   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   1513   CURLcode result = CURLE_OK;
   1514   CERT_CONTEXT *pCertContextServer = NULL;
   1515   const CERT_CHAIN_CONTEXT *pChainContext = NULL;
   1516 
   1517   status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
   1518                                             SECPKG_ATTR_REMOTE_CERT_CONTEXT,
   1519                                             &pCertContextServer);
   1520 
   1521   if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
   1522     failf(data, "schannel: Failed to read remote certificate context: %s",
   1523           Curl_sspi_strerror(conn, status));
   1524     result = CURLE_PEER_FAILED_VERIFICATION;
   1525   }
   1526 
   1527   if(result == CURLE_OK) {
   1528     CERT_CHAIN_PARA ChainPara;
   1529     memset(&ChainPara, 0, sizeof(ChainPara));
   1530     ChainPara.cbSize = sizeof(ChainPara);
   1531 
   1532     if(!CertGetCertificateChain(NULL,
   1533                                 pCertContextServer,
   1534                                 NULL,
   1535                                 pCertContextServer->hCertStore,
   1536                                 &ChainPara,
   1537                                 (data->set.ssl_no_revoke ? 0 :
   1538                                  CERT_CHAIN_REVOCATION_CHECK_CHAIN),
   1539                                 NULL,
   1540                                 &pChainContext)) {
   1541       failf(data, "schannel: CertGetCertificateChain failed: %s",
   1542             Curl_sspi_strerror(conn, GetLastError()));
   1543       pChainContext = NULL;
   1544       result = CURLE_PEER_FAILED_VERIFICATION;
   1545     }
   1546 
   1547     if(result == CURLE_OK) {
   1548       CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
   1549       DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
   1550       dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
   1551       if(dwTrustErrorMask) {
   1552         if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
   1553           failf(data, "schannel: CertGetCertificateChain trust error"
   1554                 " CERT_TRUST_IS_REVOKED");
   1555         else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
   1556           failf(data, "schannel: CertGetCertificateChain trust error"
   1557                 " CERT_TRUST_IS_PARTIAL_CHAIN");
   1558         else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
   1559           failf(data, "schannel: CertGetCertificateChain trust error"
   1560                 " CERT_TRUST_IS_UNTRUSTED_ROOT");
   1561         else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
   1562           failf(data, "schannel: CertGetCertificateChain trust error"
   1563                 " CERT_TRUST_IS_NOT_TIME_VALID");
   1564         else
   1565           failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
   1566                 dwTrustErrorMask);
   1567         result = CURLE_PEER_FAILED_VERIFICATION;
   1568       }
   1569     }
   1570   }
   1571 
   1572   if(result == CURLE_OK) {
   1573     if(data->set.ssl.verifyhost) {
   1574       TCHAR cert_hostname_buff[128];
   1575       xcharp_u hostname;
   1576       xcharp_u cert_hostname;
   1577       DWORD len;
   1578 
   1579       cert_hostname.const_tchar_ptr = cert_hostname_buff;
   1580       hostname.tchar_ptr = Curl_convert_UTF8_to_tchar(conn->host.name);
   1581 
   1582       /* TODO: Fix this for certificates with multiple alternative names.
   1583       Right now we're only asking for the first preferred alternative name.
   1584       Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG
   1585       (if WinCE supports that?) and run this section in a loop for each.
   1586       https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx
   1587       curl: (51) schannel: CertGetNameString() certificate hostname
   1588       (.google.com) did not match connection (google.com)
   1589       */
   1590       len = CertGetNameString(pCertContextServer,
   1591                               CERT_NAME_DNS_TYPE,
   1592                               0,
   1593                               NULL,
   1594                               cert_hostname.tchar_ptr,
   1595                               128);
   1596       if(len > 0 && *cert_hostname.tchar_ptr == '*') {
   1597         /* this is a wildcard cert.  try matching the last len - 1 chars */
   1598         int hostname_len = strlen(conn->host.name);
   1599         cert_hostname.tchar_ptr++;
   1600         if(_tcsicmp(cert_hostname.const_tchar_ptr,
   1601                     hostname.const_tchar_ptr + hostname_len - len + 2) != 0)
   1602           result = CURLE_PEER_FAILED_VERIFICATION;
   1603       }
   1604       else if(len == 0 || _tcsicmp(hostname.const_tchar_ptr,
   1605                                    cert_hostname.const_tchar_ptr) != 0) {
   1606         result = CURLE_PEER_FAILED_VERIFICATION;
   1607       }
   1608       if(result == CURLE_PEER_FAILED_VERIFICATION) {
   1609         char *_cert_hostname;
   1610         _cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname.tchar_ptr);
   1611         failf(data, "schannel: CertGetNameString() certificate hostname "
   1612               "(%s) did not match connection (%s)",
   1613               _cert_hostname, conn->host.name);
   1614         Curl_unicodefree(_cert_hostname);
   1615       }
   1616       Curl_unicodefree(hostname.tchar_ptr);
   1617     }
   1618   }
   1619 
   1620   if(pChainContext)
   1621     CertFreeCertificateChain(pChainContext);
   1622 
   1623   if(pCertContextServer)
   1624     CertFreeCertificateContext(pCertContextServer);
   1625 
   1626   return result;
   1627 }
   1628 #endif /* _WIN32_WCE */
   1629 
   1630 #endif /* USE_SCHANNEL */
   1631