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