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