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