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