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 - 2020, 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 #include "curl_setup.h"
31
32 #ifdef USE_SCHANNEL
33
34 #define EXPOSE_SCHANNEL_INTERNAL_STRUCTS
35
36 #ifndef USE_WINDOWS_SSPI
37 # error "Can't compile SCHANNEL support without SSPI."
38 #endif
39
40 #include "schannel.h"
41 #include "vtls.h"
42 #include "strcase.h"
43 #include "sendf.h"
44 #include "connect.h" /* for the connect timeout */
45 #include "strerror.h"
46 #include "select.h" /* for the socket readiness */
47 #include "inet_pton.h" /* for IP addr SNI check */
48 #include "curl_multibyte.h"
49 #include "warnless.h"
50 #include "x509asn1.h"
51 #include "curl_printf.h"
52 #include "multiif.h"
53 #include "version_win32.h"
54
55 /* The last #include file should be: */
56 #include "curl_memory.h"
57 #include "memdebug.h"
58
59 /* ALPN requires version 8.1 of the Windows SDK, which was
60 shipped with Visual Studio 2013, aka _MSC_VER 1800:
61
62 https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
63 */
64 #if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
65 # define HAS_ALPN 1
66 #endif
67
68 #ifndef UNISP_NAME_A
69 #define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
70 #endif
71
72 #ifndef UNISP_NAME_W
73 #define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
74 #endif
75
76 #ifndef UNISP_NAME
77 #ifdef UNICODE
78 #define UNISP_NAME UNISP_NAME_W
79 #else
80 #define UNISP_NAME UNISP_NAME_A
81 #endif
82 #endif
83
84 #if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX)
85 #define HAS_CLIENT_CERT_PATH
86 #endif
87
88 #ifdef HAS_CLIENT_CERT_PATH
89 #ifdef UNICODE
90 #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W
91 #else
92 #define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_A
93 #endif
94 #endif
95
96 #ifndef SP_PROT_SSL2_CLIENT
97 #define SP_PROT_SSL2_CLIENT 0x00000008
98 #endif
99
100 #ifndef SP_PROT_SSL3_CLIENT
101 #define SP_PROT_SSL3_CLIENT 0x00000008
102 #endif
103
104 #ifndef SP_PROT_TLS1_CLIENT
105 #define SP_PROT_TLS1_CLIENT 0x00000080
106 #endif
107
108 #ifndef SP_PROT_TLS1_0_CLIENT
109 #define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
110 #endif
111
112 #ifndef SP_PROT_TLS1_1_CLIENT
113 #define SP_PROT_TLS1_1_CLIENT 0x00000200
114 #endif
115
116 #ifndef SP_PROT_TLS1_2_CLIENT
117 #define SP_PROT_TLS1_2_CLIENT 0x00000800
118 #endif
119
120 #ifndef SECBUFFER_ALERT
121 #define SECBUFFER_ALERT 17
122 #endif
123
124 /* Both schannel buffer sizes must be > 0 */
125 #define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
126 #define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
127
128 #define CERT_THUMBPRINT_STR_LEN 40
129 #define CERT_THUMBPRINT_DATA_LEN 20
130
131 /* Uncomment to force verbose output
132 * #define infof(x, y, ...) printf(y, __VA_ARGS__)
133 * #define failf(x, y, ...) printf(y, __VA_ARGS__)
134 */
135
136 #ifndef CALG_SHA_256
137 # define CALG_SHA_256 0x0000800c
138 #endif
139
140 #define BACKEND connssl->backend
141
142 static Curl_recv schannel_recv;
143 static Curl_send schannel_send;
144
145 static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
146 const char *pinnedpubkey);
147
InitSecBuffer(SecBuffer * buffer,unsigned long BufType,void * BufDataPtr,unsigned long BufByteSize)148 static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
149 void *BufDataPtr, unsigned long BufByteSize)
150 {
151 buffer->cbBuffer = BufByteSize;
152 buffer->BufferType = BufType;
153 buffer->pvBuffer = BufDataPtr;
154 }
155
InitSecBufferDesc(SecBufferDesc * desc,SecBuffer * BufArr,unsigned long NumArrElem)156 static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
157 unsigned long NumArrElem)
158 {
159 desc->ulVersion = SECBUFFER_VERSION;
160 desc->pBuffers = BufArr;
161 desc->cBuffers = NumArrElem;
162 }
163
164 static CURLcode
set_ssl_version_min_max(SCHANNEL_CRED * schannel_cred,struct connectdata * conn)165 set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
166 {
167 struct Curl_easy *data = conn->data;
168 long ssl_version = SSL_CONN_CONFIG(version);
169 long ssl_version_max = SSL_CONN_CONFIG(version_max);
170 long i = ssl_version;
171
172 switch(ssl_version_max) {
173 case CURL_SSLVERSION_MAX_NONE:
174 case CURL_SSLVERSION_MAX_DEFAULT:
175 ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
176 break;
177 }
178 for(; i <= (ssl_version_max >> 16); ++i) {
179 switch(i) {
180 case CURL_SSLVERSION_TLSv1_0:
181 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
182 break;
183 case CURL_SSLVERSION_TLSv1_1:
184 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
185 break;
186 case CURL_SSLVERSION_TLSv1_2:
187 schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
188 break;
189 case CURL_SSLVERSION_TLSv1_3:
190 failf(data, "schannel: TLS 1.3 is not yet supported");
191 return CURLE_SSL_CONNECT_ERROR;
192 }
193 }
194 return CURLE_OK;
195 }
196
197 /*longest is 26, buffer is slightly bigger*/
198 #define LONGEST_ALG_ID 32
199 #define CIPHEROPTION(X) \
200 if(strcmp(#X, tmp) == 0) \
201 return X
202
203 static int
get_alg_id_by_name(char * name)204 get_alg_id_by_name(char *name)
205 {
206 char tmp[LONGEST_ALG_ID] = { 0 };
207 char *nameEnd = strchr(name, ':');
208 size_t n = nameEnd ? min((size_t)(nameEnd - name), LONGEST_ALG_ID - 1) : \
209 min(strlen(name), LONGEST_ALG_ID - 1);
210 strncpy(tmp, name, n);
211 tmp[n] = 0;
212 CIPHEROPTION(CALG_MD2);
213 CIPHEROPTION(CALG_MD4);
214 CIPHEROPTION(CALG_MD5);
215 CIPHEROPTION(CALG_SHA);
216 CIPHEROPTION(CALG_SHA1);
217 CIPHEROPTION(CALG_MAC);
218 CIPHEROPTION(CALG_RSA_SIGN);
219 CIPHEROPTION(CALG_DSS_SIGN);
220 /*ifdefs for the options that are defined conditionally in wincrypt.h*/
221 #ifdef CALG_NO_SIGN
222 CIPHEROPTION(CALG_NO_SIGN);
223 #endif
224 CIPHEROPTION(CALG_RSA_KEYX);
225 CIPHEROPTION(CALG_DES);
226 #ifdef CALG_3DES_112
227 CIPHEROPTION(CALG_3DES_112);
228 #endif
229 CIPHEROPTION(CALG_3DES);
230 CIPHEROPTION(CALG_DESX);
231 CIPHEROPTION(CALG_RC2);
232 CIPHEROPTION(CALG_RC4);
233 CIPHEROPTION(CALG_SEAL);
234 #ifdef CALG_DH_SF
235 CIPHEROPTION(CALG_DH_SF);
236 #endif
237 CIPHEROPTION(CALG_DH_EPHEM);
238 #ifdef CALG_AGREEDKEY_ANY
239 CIPHEROPTION(CALG_AGREEDKEY_ANY);
240 #endif
241 #ifdef CALG_HUGHES_MD5
242 CIPHEROPTION(CALG_HUGHES_MD5);
243 #endif
244 CIPHEROPTION(CALG_SKIPJACK);
245 #ifdef CALG_TEK
246 CIPHEROPTION(CALG_TEK);
247 #endif
248 CIPHEROPTION(CALG_CYLINK_MEK);
249 CIPHEROPTION(CALG_SSL3_SHAMD5);
250 #ifdef CALG_SSL3_MASTER
251 CIPHEROPTION(CALG_SSL3_MASTER);
252 #endif
253 #ifdef CALG_SCHANNEL_MASTER_HASH
254 CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH);
255 #endif
256 #ifdef CALG_SCHANNEL_MAC_KEY
257 CIPHEROPTION(CALG_SCHANNEL_MAC_KEY);
258 #endif
259 #ifdef CALG_SCHANNEL_ENC_KEY
260 CIPHEROPTION(CALG_SCHANNEL_ENC_KEY);
261 #endif
262 #ifdef CALG_PCT1_MASTER
263 CIPHEROPTION(CALG_PCT1_MASTER);
264 #endif
265 #ifdef CALG_SSL2_MASTER
266 CIPHEROPTION(CALG_SSL2_MASTER);
267 #endif
268 #ifdef CALG_TLS1_MASTER
269 CIPHEROPTION(CALG_TLS1_MASTER);
270 #endif
271 #ifdef CALG_RC5
272 CIPHEROPTION(CALG_RC5);
273 #endif
274 #ifdef CALG_HMAC
275 CIPHEROPTION(CALG_HMAC);
276 #endif
277 #if !defined(__W32API_MAJOR_VERSION) || \
278 !defined(__W32API_MINOR_VERSION) || \
279 defined(__MINGW64_VERSION_MAJOR) || \
280 (__W32API_MAJOR_VERSION > 5) || \
281 ((__W32API_MAJOR_VERSION == 5) && (__W32API_MINOR_VERSION > 0))
282 /* CALG_TLS1PRF has a syntax error in MinGW's w32api up to version 5.0,
283 see https://osdn.net/projects/mingw/ticket/38391 */
284 CIPHEROPTION(CALG_TLS1PRF);
285 #endif
286 #ifdef CALG_HASH_REPLACE_OWF
287 CIPHEROPTION(CALG_HASH_REPLACE_OWF);
288 #endif
289 #ifdef CALG_AES_128
290 CIPHEROPTION(CALG_AES_128);
291 #endif
292 #ifdef CALG_AES_192
293 CIPHEROPTION(CALG_AES_192);
294 #endif
295 #ifdef CALG_AES_256
296 CIPHEROPTION(CALG_AES_256);
297 #endif
298 #ifdef CALG_AES
299 CIPHEROPTION(CALG_AES);
300 #endif
301 #ifdef CALG_SHA_256
302 CIPHEROPTION(CALG_SHA_256);
303 #endif
304 #ifdef CALG_SHA_384
305 CIPHEROPTION(CALG_SHA_384);
306 #endif
307 #ifdef CALG_SHA_512
308 CIPHEROPTION(CALG_SHA_512);
309 #endif
310 #ifdef CALG_ECDH
311 CIPHEROPTION(CALG_ECDH);
312 #endif
313 #ifdef CALG_ECMQV
314 CIPHEROPTION(CALG_ECMQV);
315 #endif
316 #ifdef CALG_ECDSA
317 CIPHEROPTION(CALG_ECDSA);
318 #endif
319 #ifdef CALG_ECDH_EPHEM
320 CIPHEROPTION(CALG_ECDH_EPHEM);
321 #endif
322 return 0;
323 }
324
325 static CURLcode
set_ssl_ciphers(SCHANNEL_CRED * schannel_cred,char * ciphers)326 set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers)
327 {
328 char *startCur = ciphers;
329 int algCount = 0;
330 static ALG_ID algIds[45]; /*There are 45 listed in the MS headers*/
331 while(startCur && (0 != *startCur) && (algCount < 45)) {
332 long alg = strtol(startCur, 0, 0);
333 if(!alg)
334 alg = get_alg_id_by_name(startCur);
335 if(alg)
336 algIds[algCount++] = alg;
337 else
338 return CURLE_SSL_CIPHER;
339 startCur = strchr(startCur, ':');
340 if(startCur)
341 startCur++;
342 }
343 schannel_cred->palgSupportedAlgs = algIds;
344 schannel_cred->cSupportedAlgs = algCount;
345 return CURLE_OK;
346 }
347
348 #ifdef HAS_CLIENT_CERT_PATH
349
350 /* Function allocates memory for store_path only if CURLE_OK is returned */
351 static CURLcode
get_cert_location(TCHAR * path,DWORD * store_name,TCHAR ** store_path,TCHAR ** thumbprint)352 get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
353 TCHAR **thumbprint)
354 {
355 TCHAR *sep;
356 TCHAR *store_path_start;
357 size_t store_name_len;
358
359 sep = _tcschr(path, TEXT('\\'));
360 if(sep == NULL)
361 return CURLE_SSL_CERTPROBLEM;
362
363 store_name_len = sep - path;
364
365 if(_tcsnccmp(path, TEXT("CurrentUser"), store_name_len) == 0)
366 *store_name = CERT_SYSTEM_STORE_CURRENT_USER;
367 else if(_tcsnccmp(path, TEXT("LocalMachine"), store_name_len) == 0)
368 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE;
369 else if(_tcsnccmp(path, TEXT("CurrentService"), store_name_len) == 0)
370 *store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE;
371 else if(_tcsnccmp(path, TEXT("Services"), store_name_len) == 0)
372 *store_name = CERT_SYSTEM_STORE_SERVICES;
373 else if(_tcsnccmp(path, TEXT("Users"), store_name_len) == 0)
374 *store_name = CERT_SYSTEM_STORE_USERS;
375 else if(_tcsnccmp(path, TEXT("CurrentUserGroupPolicy"),
376 store_name_len) == 0)
377 *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY;
378 else if(_tcsnccmp(path, TEXT("LocalMachineGroupPolicy"),
379 store_name_len) == 0)
380 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY;
381 else if(_tcsnccmp(path, TEXT("LocalMachineEnterprise"),
382 store_name_len) == 0)
383 *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
384 else
385 return CURLE_SSL_CERTPROBLEM;
386
387 store_path_start = sep + 1;
388
389 sep = _tcschr(store_path_start, TEXT('\\'));
390 if(sep == NULL)
391 return CURLE_SSL_CERTPROBLEM;
392
393 *thumbprint = sep + 1;
394 if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
395 return CURLE_SSL_CERTPROBLEM;
396
397 *sep = TEXT('\0');
398 *store_path = _tcsdup(store_path_start);
399 *sep = TEXT('\\');
400 if(*store_path == NULL)
401 return CURLE_OUT_OF_MEMORY;
402
403 return CURLE_OK;
404 }
405 #endif
406
407 static CURLcode
schannel_connect_step1(struct connectdata * conn,int sockindex)408 schannel_connect_step1(struct connectdata *conn, int sockindex)
409 {
410 ssize_t written = -1;
411 struct Curl_easy *data = conn->data;
412 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
413 SecBuffer outbuf;
414 SecBufferDesc outbuf_desc;
415 SecBuffer inbuf;
416 SecBufferDesc inbuf_desc;
417 #ifdef HAS_ALPN
418 unsigned char alpn_buffer[128];
419 #endif
420 SCHANNEL_CRED schannel_cred;
421 PCCERT_CONTEXT client_certs[1] = { NULL };
422 SECURITY_STATUS sspi_status = SEC_E_OK;
423 struct Curl_schannel_cred *old_cred = NULL;
424 struct in_addr addr;
425 #ifdef ENABLE_IPV6
426 struct in6_addr addr6;
427 #endif
428 TCHAR *host_name;
429 CURLcode result;
430 #ifndef CURL_DISABLE_PROXY
431 char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
432 conn->host.name;
433 #else
434 char * const hostname = conn->host.name;
435 #endif
436
437 DEBUGF(infof(data,
438 "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
439 hostname, conn->remote_port));
440
441 if(curlx_verify_windows_version(5, 1, PLATFORM_WINNT,
442 VERSION_LESS_THAN_EQUAL)) {
443 /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
444 algorithms that may not be supported by all servers. */
445 infof(data, "schannel: Windows version is old and may not be able to "
446 "connect to some servers due to lack of SNI, algorithms, etc.\n");
447 }
448
449 #ifdef HAS_ALPN
450 /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
451 Also it doesn't seem to be supported for Wine, see curl bug #983. */
452 BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
453 !GetProcAddress(GetModuleHandle(TEXT("ntdll")),
454 "wine_get_version") &&
455 curlx_verify_windows_version(6, 3, PLATFORM_WINNT,
456 VERSION_GREATER_THAN_EQUAL);
457 #else
458 BACKEND->use_alpn = false;
459 #endif
460
461 #ifdef _WIN32_WCE
462 #ifdef HAS_MANUAL_VERIFY_API
463 /* certificate validation on CE doesn't seem to work right; we'll
464 * do it following a more manual process. */
465 BACKEND->use_manual_cred_validation = true;
466 #else
467 #error "compiler too old to support requisite manual cert verify for Win CE"
468 #endif
469 #else
470 #ifdef HAS_MANUAL_VERIFY_API
471 if(SSL_CONN_CONFIG(CAfile)) {
472 if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT,
473 VERSION_GREATER_THAN_EQUAL)) {
474 BACKEND->use_manual_cred_validation = true;
475 }
476 else {
477 failf(data, "schannel: this version of Windows is too old to support "
478 "certificate verification via CA bundle file.");
479 return CURLE_SSL_CACERT_BADFILE;
480 }
481 }
482 else
483 BACKEND->use_manual_cred_validation = false;
484 #else
485 if(SSL_CONN_CONFIG(CAfile)) {
486 failf(data, "schannel: CA cert support not built in");
487 return CURLE_NOT_BUILT_IN;
488 }
489 #endif
490 #endif
491
492 BACKEND->cred = NULL;
493
494 /* check for an existing re-usable credential handle */
495 if(SSL_SET_OPTION(primary.sessionid)) {
496 Curl_ssl_sessionid_lock(conn);
497 if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
498 BACKEND->cred = old_cred;
499 DEBUGF(infof(data, "schannel: re-using existing credential handle\n"));
500
501 /* increment the reference counter of the credential/session handle */
502 BACKEND->cred->refcount++;
503 DEBUGF(infof(data,
504 "schannel: incremented credential handle refcount = %d\n",
505 BACKEND->cred->refcount));
506 }
507 Curl_ssl_sessionid_unlock(conn);
508 }
509
510 if(!BACKEND->cred) {
511 /* setup Schannel API options */
512 memset(&schannel_cred, 0, sizeof(schannel_cred));
513 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
514
515 if(conn->ssl_config.verifypeer) {
516 #ifdef HAS_MANUAL_VERIFY_API
517 if(BACKEND->use_manual_cred_validation)
518 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
519 else
520 #endif
521 schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
522
523 if(data->set.ssl.no_revoke) {
524 schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
525 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
526
527 DEBUGF(infof(data, "schannel: disabled server certificate revocation "
528 "checks\n"));
529 }
530 else if(data->set.ssl.revoke_best_effort) {
531 schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
532 SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN;
533
534 DEBUGF(infof(data, "schannel: ignore revocation offline errors"));
535 }
536 else {
537 schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
538
539 DEBUGF(infof(data,
540 "schannel: checking server certificate revocation\n"));
541 }
542 }
543 else {
544 schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
545 SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
546 SCH_CRED_IGNORE_REVOCATION_OFFLINE;
547 DEBUGF(infof(data,
548 "schannel: disabled server cert revocation checks\n"));
549 }
550
551 if(!conn->ssl_config.verifyhost) {
552 schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
553 DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
554 "comparing the supplied target name with the subject "
555 "names in server certificates.\n"));
556 }
557
558 switch(conn->ssl_config.version) {
559 case CURL_SSLVERSION_DEFAULT:
560 case CURL_SSLVERSION_TLSv1:
561 case CURL_SSLVERSION_TLSv1_0:
562 case CURL_SSLVERSION_TLSv1_1:
563 case CURL_SSLVERSION_TLSv1_2:
564 case CURL_SSLVERSION_TLSv1_3:
565 {
566 result = set_ssl_version_min_max(&schannel_cred, conn);
567 if(result != CURLE_OK)
568 return result;
569 break;
570 }
571 case CURL_SSLVERSION_SSLv3:
572 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
573 break;
574 case CURL_SSLVERSION_SSLv2:
575 schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
576 break;
577 default:
578 failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
579 return CURLE_SSL_CONNECT_ERROR;
580 }
581
582 if(SSL_CONN_CONFIG(cipher_list)) {
583 result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list));
584 if(CURLE_OK != result) {
585 failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
586 return result;
587 }
588 }
589
590
591 #ifdef HAS_CLIENT_CERT_PATH
592 /* client certificate */
593 if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
594 DWORD cert_store_name = 0;
595 TCHAR *cert_store_path = NULL;
596 TCHAR *cert_thumbprint_str = NULL;
597 CRYPT_HASH_BLOB cert_thumbprint;
598 BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
599 HCERTSTORE cert_store = NULL;
600 FILE *fInCert = NULL;
601 void *certdata = NULL;
602 size_t certsize = 0;
603 bool blob = data->set.ssl.primary.cert_blob != NULL;
604 TCHAR *cert_path = NULL;
605 if(blob) {
606 certdata = data->set.ssl.primary.cert_blob->data;
607 certsize = data->set.ssl.primary.cert_blob->len;
608 }
609 else {
610 cert_path = curlx_convert_UTF8_to_tchar(
611 data->set.ssl.primary.clientcert);
612 if(!cert_path)
613 return CURLE_OUT_OF_MEMORY;
614
615 result = get_cert_location(cert_path, &cert_store_name,
616 &cert_store_path, &cert_thumbprint_str);
617
618 if(result && (data->set.ssl.primary.clientcert[0]!='\0'))
619 fInCert = fopen(data->set.ssl.primary.clientcert, "rb");
620
621 if(result && !fInCert) {
622 failf(data, "schannel: Failed to get certificate location"
623 " or file for %s",
624 data->set.ssl.primary.clientcert);
625 curlx_unicodefree(cert_path);
626 return result;
627 }
628 }
629
630 if((fInCert || blob) && (data->set.ssl.cert_type) &&
631 (!strcasecompare(data->set.ssl.cert_type, "P12"))) {
632 failf(data, "schannel: certificate format compatibility error "
633 " for %s",
634 blob ? "(memory blob)" : data->set.ssl.primary.clientcert);
635 curlx_unicodefree(cert_path);
636 return CURLE_SSL_CERTPROBLEM;
637 }
638
639 if(fInCert || blob) {
640 /* Reading a .P12 or .pfx file, like the example at bottom of
641 https://social.msdn.microsoft.com/Forums/windowsdesktop/
642 en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
643 */
644 CRYPT_DATA_BLOB datablob;
645 WCHAR* pszPassword;
646 size_t pwd_len = 0;
647 int str_w_len = 0;
648 const char *cert_showfilename_error = blob ?
649 "(memory blob)" : data->set.ssl.primary.clientcert;
650 curlx_unicodefree(cert_path);
651 if(fInCert) {
652 long cert_tell = 0;
653 bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
654 if(continue_reading)
655 cert_tell = ftell(fInCert);
656 if(cert_tell < 0)
657 continue_reading = FALSE;
658 else
659 certsize = (size_t)cert_tell;
660 if(continue_reading)
661 continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
662 if(continue_reading)
663 certdata = malloc(certsize + 1);
664 if((!certdata) ||
665 ((int) fread(certdata, certsize, 1, fInCert) != 1))
666 continue_reading = FALSE;
667 fclose(fInCert);
668 if(!continue_reading) {
669 failf(data, "schannel: Failed to read cert file %s",
670 data->set.ssl.primary.clientcert);
671 free(certdata);
672 return CURLE_SSL_CERTPROBLEM;
673 }
674 }
675
676 /* Convert key-pair data to the in-memory certificate store */
677 datablob.pbData = (BYTE*)certdata;
678 datablob.cbData = (DWORD)certsize;
679
680 if(data->set.ssl.key_passwd != NULL)
681 pwd_len = strlen(data->set.ssl.key_passwd);
682 pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
683 if(pszPassword) {
684 if(pwd_len > 0)
685 str_w_len = MultiByteToWideChar(CP_UTF8,
686 MB_ERR_INVALID_CHARS,
687 data->set.ssl.key_passwd, (int)pwd_len,
688 pszPassword, (int)(pwd_len + 1));
689
690 if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
691 pszPassword[str_w_len] = 0;
692 else
693 pszPassword[0] = 0;
694
695 cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
696 free(pszPassword);
697 }
698 if(!blob)
699 free(certdata);
700 if(cert_store == NULL) {
701 DWORD errorcode = GetLastError();
702 if(errorcode == ERROR_INVALID_PASSWORD)
703 failf(data, "schannel: Failed to import cert file %s, "
704 "password is bad",
705 cert_showfilename_error);
706 else
707 failf(data, "schannel: Failed to import cert file %s, "
708 "last error is 0x%x",
709 cert_showfilename_error, errorcode);
710 return CURLE_SSL_CERTPROBLEM;
711 }
712
713 client_certs[0] = CertFindCertificateInStore(
714 cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
715 CERT_FIND_ANY, NULL, NULL);
716
717 if(client_certs[0] == NULL) {
718 failf(data, "schannel: Failed to get certificate from file %s"
719 ", last error is 0x%x",
720 cert_showfilename_error, GetLastError());
721 CertCloseStore(cert_store, 0);
722 return CURLE_SSL_CERTPROBLEM;
723 }
724
725 schannel_cred.cCreds = 1;
726 schannel_cred.paCred = client_certs;
727 }
728 else {
729 cert_store =
730 CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
731 (HCRYPTPROV)NULL,
732 CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
733 cert_store_path);
734 if(!cert_store) {
735 failf(data, "schannel: Failed to open cert store %x %s, "
736 "last error is 0x%x",
737 cert_store_name, cert_store_path, GetLastError());
738 free(cert_store_path);
739 curlx_unicodefree(cert_path);
740 return CURLE_SSL_CERTPROBLEM;
741 }
742 free(cert_store_path);
743
744 cert_thumbprint.pbData = cert_thumbprint_data;
745 cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
746
747 if(!CryptStringToBinary(cert_thumbprint_str,
748 CERT_THUMBPRINT_STR_LEN,
749 CRYPT_STRING_HEX,
750 cert_thumbprint_data,
751 &cert_thumbprint.cbData,
752 NULL, NULL)) {
753 curlx_unicodefree(cert_path);
754 CertCloseStore(cert_store, 0);
755 return CURLE_SSL_CERTPROBLEM;
756 }
757
758 client_certs[0] = CertFindCertificateInStore(
759 cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
760 CERT_FIND_HASH, &cert_thumbprint, NULL);
761
762 curlx_unicodefree(cert_path);
763
764 if(client_certs[0]) {
765 schannel_cred.cCreds = 1;
766 schannel_cred.paCred = client_certs;
767 }
768 else {
769 /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
770 CertCloseStore(cert_store, 0);
771 return CURLE_SSL_CERTPROBLEM;
772 }
773 }
774 CertCloseStore(cert_store, 0);
775 }
776 #else
777 if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
778 failf(data, "schannel: client cert support not built in");
779 return CURLE_NOT_BUILT_IN;
780 }
781 #endif
782
783 /* allocate memory for the re-usable credential handle */
784 BACKEND->cred = (struct Curl_schannel_cred *)
785 calloc(1, sizeof(struct Curl_schannel_cred));
786 if(!BACKEND->cred) {
787 failf(data, "schannel: unable to allocate memory");
788
789 if(client_certs[0])
790 CertFreeCertificateContext(client_certs[0]);
791
792 return CURLE_OUT_OF_MEMORY;
793 }
794 BACKEND->cred->refcount = 1;
795
796 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
797 */
798 sspi_status =
799 s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
800 SECPKG_CRED_OUTBOUND, NULL,
801 &schannel_cred, NULL, NULL,
802 &BACKEND->cred->cred_handle,
803 &BACKEND->cred->time_stamp);
804
805 if(client_certs[0])
806 CertFreeCertificateContext(client_certs[0]);
807
808 if(sspi_status != SEC_E_OK) {
809 char buffer[STRERROR_LEN];
810 failf(data, "schannel: AcquireCredentialsHandle failed: %s",
811 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
812 Curl_safefree(BACKEND->cred);
813 switch(sspi_status) {
814 case SEC_E_INSUFFICIENT_MEMORY:
815 return CURLE_OUT_OF_MEMORY;
816 case SEC_E_NO_CREDENTIALS:
817 case SEC_E_SECPKG_NOT_FOUND:
818 case SEC_E_NOT_OWNER:
819 case SEC_E_UNKNOWN_CREDENTIALS:
820 case SEC_E_INTERNAL_ERROR:
821 default:
822 return CURLE_SSL_CONNECT_ERROR;
823 }
824 }
825 }
826
827 /* Warn if SNI is disabled due to use of an IP address */
828 if(Curl_inet_pton(AF_INET, hostname, &addr)
829 #ifdef ENABLE_IPV6
830 || Curl_inet_pton(AF_INET6, hostname, &addr6)
831 #endif
832 ) {
833 infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
834 }
835
836 #ifdef HAS_ALPN
837 if(BACKEND->use_alpn) {
838 int cur = 0;
839 int list_start_index = 0;
840 unsigned int *extension_len = NULL;
841 unsigned short* list_len = NULL;
842
843 /* The first four bytes will be an unsigned int indicating number
844 of bytes of data in the rest of the buffer. */
845 extension_len = (unsigned int *)(&alpn_buffer[cur]);
846 cur += sizeof(unsigned int);
847
848 /* The next four bytes are an indicator that this buffer will contain
849 ALPN data, as opposed to NPN, for example. */
850 *(unsigned int *)&alpn_buffer[cur] =
851 SecApplicationProtocolNegotiationExt_ALPN;
852 cur += sizeof(unsigned int);
853
854 /* The next two bytes will be an unsigned short indicating the number
855 of bytes used to list the preferred protocols. */
856 list_len = (unsigned short*)(&alpn_buffer[cur]);
857 cur += sizeof(unsigned short);
858
859 list_start_index = cur;
860
861 #ifdef USE_NGHTTP2
862 if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
863 memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
864 cur += NGHTTP2_PROTO_ALPN_LEN;
865 infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
866 }
867 #endif
868
869 alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
870 memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
871 cur += ALPN_HTTP_1_1_LENGTH;
872 infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1);
873
874 *list_len = curlx_uitous(cur - list_start_index);
875 *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
876
877 InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
878 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
879 }
880 else {
881 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
882 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
883 }
884 #else /* HAS_ALPN */
885 InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
886 InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
887 #endif
888
889 /* setup output buffer */
890 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
891 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
892
893 /* setup request flags */
894 BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
895 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
896 ISC_REQ_STREAM;
897
898 /* allocate memory for the security context handle */
899 BACKEND->ctxt = (struct Curl_schannel_ctxt *)
900 calloc(1, sizeof(struct Curl_schannel_ctxt));
901 if(!BACKEND->ctxt) {
902 failf(data, "schannel: unable to allocate memory");
903 return CURLE_OUT_OF_MEMORY;
904 }
905
906 host_name = curlx_convert_UTF8_to_tchar(hostname);
907 if(!host_name)
908 return CURLE_OUT_OF_MEMORY;
909
910 /* Schannel InitializeSecurityContext:
911 https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
912
913 At the moment we don't pass inbuf unless we're using ALPN since we only
914 use it for that, and Wine (for which we currently disable ALPN) is giving
915 us problems with inbuf regardless. https://github.com/curl/curl/issues/983
916 */
917 sspi_status = s_pSecFn->InitializeSecurityContext(
918 &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0,
919 (BACKEND->use_alpn ? &inbuf_desc : NULL),
920 0, &BACKEND->ctxt->ctxt_handle,
921 &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
922
923 curlx_unicodefree(host_name);
924
925 if(sspi_status != SEC_I_CONTINUE_NEEDED) {
926 char buffer[STRERROR_LEN];
927 Curl_safefree(BACKEND->ctxt);
928 switch(sspi_status) {
929 case SEC_E_INSUFFICIENT_MEMORY:
930 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
931 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
932 return CURLE_OUT_OF_MEMORY;
933 case SEC_E_WRONG_PRINCIPAL:
934 failf(data, "schannel: SNI or certificate check failed: %s",
935 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
936 return CURLE_PEER_FAILED_VERIFICATION;
937 /*
938 case SEC_E_INVALID_HANDLE:
939 case SEC_E_INVALID_TOKEN:
940 case SEC_E_LOGON_DENIED:
941 case SEC_E_TARGET_UNKNOWN:
942 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
943 case SEC_E_INTERNAL_ERROR:
944 case SEC_E_NO_CREDENTIALS:
945 case SEC_E_UNSUPPORTED_FUNCTION:
946 case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
947 */
948 default:
949 failf(data, "schannel: initial InitializeSecurityContext failed: %s",
950 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
951 return CURLE_SSL_CONNECT_ERROR;
952 }
953 }
954
955 DEBUGF(infof(data, "schannel: sending initial handshake data: "
956 "sending %lu bytes...\n", outbuf.cbBuffer));
957
958 /* send initial handshake data which is now stored in output buffer */
959 result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
960 outbuf.cbBuffer, &written);
961 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
962 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
963 failf(data, "schannel: failed to send initial handshake data: "
964 "sent %zd of %lu bytes", written, outbuf.cbBuffer);
965 return CURLE_SSL_CONNECT_ERROR;
966 }
967
968 DEBUGF(infof(data, "schannel: sent initial handshake data: "
969 "sent %zd bytes\n", written));
970
971 BACKEND->recv_unrecoverable_err = CURLE_OK;
972 BACKEND->recv_sspi_close_notify = false;
973 BACKEND->recv_connection_closed = false;
974 BACKEND->encdata_is_incomplete = false;
975
976 /* continue to second handshake step */
977 connssl->connecting_state = ssl_connect_2;
978
979 return CURLE_OK;
980 }
981
982 static CURLcode
schannel_connect_step2(struct connectdata * conn,int sockindex)983 schannel_connect_step2(struct connectdata *conn, int sockindex)
984 {
985 int i;
986 ssize_t nread = -1, written = -1;
987 struct Curl_easy *data = conn->data;
988 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
989 unsigned char *reallocated_buffer;
990 SecBuffer outbuf[3];
991 SecBufferDesc outbuf_desc;
992 SecBuffer inbuf[2];
993 SecBufferDesc inbuf_desc;
994 SECURITY_STATUS sspi_status = SEC_E_OK;
995 CURLcode result;
996 bool doread;
997 #ifndef CURL_DISABLE_PROXY
998 char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
999 conn->host.name;
1000 #else
1001 char * const hostname = conn->host.name;
1002 #endif
1003 const char *pubkey_ptr;
1004
1005 doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
1006
1007 DEBUGF(infof(data,
1008 "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
1009 hostname, conn->remote_port));
1010
1011 if(!BACKEND->cred || !BACKEND->ctxt)
1012 return CURLE_SSL_CONNECT_ERROR;
1013
1014 /* buffer to store previously received and decrypted data */
1015 if(BACKEND->decdata_buffer == NULL) {
1016 BACKEND->decdata_offset = 0;
1017 BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1018 BACKEND->decdata_buffer = malloc(BACKEND->decdata_length);
1019 if(BACKEND->decdata_buffer == NULL) {
1020 failf(data, "schannel: unable to allocate memory");
1021 return CURLE_OUT_OF_MEMORY;
1022 }
1023 }
1024
1025 /* buffer to store previously received and encrypted data */
1026 if(BACKEND->encdata_buffer == NULL) {
1027 BACKEND->encdata_is_incomplete = false;
1028 BACKEND->encdata_offset = 0;
1029 BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
1030 BACKEND->encdata_buffer = malloc(BACKEND->encdata_length);
1031 if(BACKEND->encdata_buffer == NULL) {
1032 failf(data, "schannel: unable to allocate memory");
1033 return CURLE_OUT_OF_MEMORY;
1034 }
1035 }
1036
1037 /* if we need a bigger buffer to read a full message, increase buffer now */
1038 if(BACKEND->encdata_length - BACKEND->encdata_offset <
1039 CURL_SCHANNEL_BUFFER_FREE_SIZE) {
1040 /* increase internal encrypted data buffer */
1041 size_t reallocated_length = BACKEND->encdata_offset +
1042 CURL_SCHANNEL_BUFFER_FREE_SIZE;
1043 reallocated_buffer = realloc(BACKEND->encdata_buffer,
1044 reallocated_length);
1045
1046 if(reallocated_buffer == NULL) {
1047 failf(data, "schannel: unable to re-allocate memory");
1048 return CURLE_OUT_OF_MEMORY;
1049 }
1050 else {
1051 BACKEND->encdata_buffer = reallocated_buffer;
1052 BACKEND->encdata_length = reallocated_length;
1053 }
1054 }
1055
1056 for(;;) {
1057 TCHAR *host_name;
1058 if(doread) {
1059 /* read encrypted handshake data from socket */
1060 result = Curl_read_plain(conn->sock[sockindex],
1061 (char *) (BACKEND->encdata_buffer +
1062 BACKEND->encdata_offset),
1063 BACKEND->encdata_length -
1064 BACKEND->encdata_offset,
1065 &nread);
1066 if(result == CURLE_AGAIN) {
1067 if(connssl->connecting_state != ssl_connect_2_writing)
1068 connssl->connecting_state = ssl_connect_2_reading;
1069 DEBUGF(infof(data, "schannel: failed to receive handshake, "
1070 "need more data\n"));
1071 return CURLE_OK;
1072 }
1073 else if((result != CURLE_OK) || (nread == 0)) {
1074 failf(data, "schannel: failed to receive handshake, "
1075 "SSL/TLS connection failed");
1076 return CURLE_SSL_CONNECT_ERROR;
1077 }
1078
1079 /* increase encrypted data buffer offset */
1080 BACKEND->encdata_offset += nread;
1081 BACKEND->encdata_is_incomplete = false;
1082 DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread));
1083 }
1084
1085 DEBUGF(infof(data,
1086 "schannel: encrypted data buffer: offset %zu length %zu\n",
1087 BACKEND->encdata_offset, BACKEND->encdata_length));
1088
1089 /* setup input buffers */
1090 InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset),
1091 curlx_uztoul(BACKEND->encdata_offset));
1092 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1093 InitSecBufferDesc(&inbuf_desc, inbuf, 2);
1094
1095 /* setup output buffers */
1096 InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
1097 InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
1098 InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
1099 InitSecBufferDesc(&outbuf_desc, outbuf, 3);
1100
1101 if(inbuf[0].pvBuffer == NULL) {
1102 failf(data, "schannel: unable to allocate memory");
1103 return CURLE_OUT_OF_MEMORY;
1104 }
1105
1106 /* copy received handshake data into input buffer */
1107 memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer,
1108 BACKEND->encdata_offset);
1109
1110 host_name = curlx_convert_UTF8_to_tchar(hostname);
1111 if(!host_name)
1112 return CURLE_OUT_OF_MEMORY;
1113
1114 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
1115 */
1116 sspi_status = s_pSecFn->InitializeSecurityContext(
1117 &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle,
1118 host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL,
1119 &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
1120
1121 curlx_unicodefree(host_name);
1122
1123 /* free buffer for received handshake data */
1124 Curl_safefree(inbuf[0].pvBuffer);
1125
1126 /* check if the handshake was incomplete */
1127 if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1128 BACKEND->encdata_is_incomplete = true;
1129 connssl->connecting_state = ssl_connect_2_reading;
1130 DEBUGF(infof(data,
1131 "schannel: received incomplete message, need more data\n"));
1132 return CURLE_OK;
1133 }
1134
1135 /* If the server has requested a client certificate, attempt to continue
1136 the handshake without one. This will allow connections to servers which
1137 request a client certificate but do not require it. */
1138 if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
1139 !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
1140 BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
1141 connssl->connecting_state = ssl_connect_2_writing;
1142 DEBUGF(infof(data,
1143 "schannel: a client certificate has been requested\n"));
1144 return CURLE_OK;
1145 }
1146
1147 /* check if the handshake needs to be continued */
1148 if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
1149 for(i = 0; i < 3; i++) {
1150 /* search for handshake tokens that need to be send */
1151 if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
1152 DEBUGF(infof(data, "schannel: sending next handshake data: "
1153 "sending %lu bytes...\n", outbuf[i].cbBuffer));
1154
1155 /* send handshake token to server */
1156 result = Curl_write_plain(conn, conn->sock[sockindex],
1157 outbuf[i].pvBuffer, outbuf[i].cbBuffer,
1158 &written);
1159 if((result != CURLE_OK) ||
1160 (outbuf[i].cbBuffer != (size_t) written)) {
1161 failf(data, "schannel: failed to send next handshake data: "
1162 "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
1163 return CURLE_SSL_CONNECT_ERROR;
1164 }
1165 }
1166
1167 /* free obsolete buffer */
1168 if(outbuf[i].pvBuffer != NULL) {
1169 s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
1170 }
1171 }
1172 }
1173 else {
1174 char buffer[STRERROR_LEN];
1175 switch(sspi_status) {
1176 case SEC_E_INSUFFICIENT_MEMORY:
1177 failf(data, "schannel: next InitializeSecurityContext failed: %s",
1178 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1179 return CURLE_OUT_OF_MEMORY;
1180 case SEC_E_WRONG_PRINCIPAL:
1181 failf(data, "schannel: SNI or certificate check failed: %s",
1182 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1183 return CURLE_PEER_FAILED_VERIFICATION;
1184 case SEC_E_UNTRUSTED_ROOT:
1185 failf(data, "schannel: %s",
1186 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1187 return CURLE_PEER_FAILED_VERIFICATION;
1188 /*
1189 case SEC_E_INVALID_HANDLE:
1190 case SEC_E_INVALID_TOKEN:
1191 case SEC_E_LOGON_DENIED:
1192 case SEC_E_TARGET_UNKNOWN:
1193 case SEC_E_NO_AUTHENTICATING_AUTHORITY:
1194 case SEC_E_INTERNAL_ERROR:
1195 case SEC_E_NO_CREDENTIALS:
1196 case SEC_E_UNSUPPORTED_FUNCTION:
1197 case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
1198 */
1199 default:
1200 failf(data, "schannel: next InitializeSecurityContext failed: %s",
1201 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1202 return CURLE_SSL_CONNECT_ERROR;
1203 }
1204 }
1205
1206 /* check if there was additional remaining encrypted data */
1207 if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
1208 DEBUGF(infof(data, "schannel: encrypted data length: %lu\n",
1209 inbuf[1].cbBuffer));
1210 /*
1211 There are two cases where we could be getting extra data here:
1212 1) If we're renegotiating a connection and the handshake is already
1213 complete (from the server perspective), it can encrypted app data
1214 (not handshake data) in an extra buffer at this point.
1215 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
1216 connection and this extra data is part of the handshake.
1217 We should process the data immediately; waiting for the socket to
1218 be ready may fail since the server is done sending handshake data.
1219 */
1220 /* check if the remaining data is less than the total amount
1221 and therefore begins after the already processed data */
1222 if(BACKEND->encdata_offset > inbuf[1].cbBuffer) {
1223 memmove(BACKEND->encdata_buffer,
1224 (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
1225 inbuf[1].cbBuffer, inbuf[1].cbBuffer);
1226 BACKEND->encdata_offset = inbuf[1].cbBuffer;
1227 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1228 doread = FALSE;
1229 continue;
1230 }
1231 }
1232 }
1233 else {
1234 BACKEND->encdata_offset = 0;
1235 }
1236 break;
1237 }
1238
1239 /* check if the handshake needs to be continued */
1240 if(sspi_status == SEC_I_CONTINUE_NEEDED) {
1241 connssl->connecting_state = ssl_connect_2_reading;
1242 return CURLE_OK;
1243 }
1244
1245 /* check if the handshake is complete */
1246 if(sspi_status == SEC_E_OK) {
1247 connssl->connecting_state = ssl_connect_3;
1248 DEBUGF(infof(data, "schannel: SSL/TLS handshake complete\n"));
1249 }
1250
1251 pubkey_ptr = SSL_IS_PROXY() ?
1252 data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
1253 data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
1254 if(pubkey_ptr) {
1255 result = pkp_pin_peer_pubkey(conn, sockindex, pubkey_ptr);
1256 if(result) {
1257 failf(data, "SSL: public key does not match pinned public key!");
1258 return result;
1259 }
1260 }
1261
1262 #ifdef HAS_MANUAL_VERIFY_API
1263 if(conn->ssl_config.verifypeer && BACKEND->use_manual_cred_validation) {
1264 return Curl_verify_certificate(conn, sockindex);
1265 }
1266 #endif
1267
1268 return CURLE_OK;
1269 }
1270
1271 static bool
valid_cert_encoding(const CERT_CONTEXT * cert_context)1272 valid_cert_encoding(const CERT_CONTEXT *cert_context)
1273 {
1274 return (cert_context != NULL) &&
1275 ((cert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
1276 (cert_context->pbCertEncoded != NULL) &&
1277 (cert_context->cbCertEncoded > 0);
1278 }
1279
1280 typedef bool(*Read_crt_func)(const CERT_CONTEXT *ccert_context, void *arg);
1281
1282 static void
traverse_cert_store(const CERT_CONTEXT * context,Read_crt_func func,void * arg)1283 traverse_cert_store(const CERT_CONTEXT *context, Read_crt_func func,
1284 void *arg)
1285 {
1286 const CERT_CONTEXT *current_context = NULL;
1287 bool should_continue = true;
1288 while(should_continue &&
1289 (current_context = CertEnumCertificatesInStore(
1290 context->hCertStore,
1291 current_context)) != NULL)
1292 should_continue = func(current_context, arg);
1293
1294 if(current_context)
1295 CertFreeCertificateContext(current_context);
1296 }
1297
1298 static bool
cert_counter_callback(const CERT_CONTEXT * ccert_context,void * certs_count)1299 cert_counter_callback(const CERT_CONTEXT *ccert_context, void *certs_count)
1300 {
1301 if(valid_cert_encoding(ccert_context))
1302 (*(int *)certs_count)++;
1303 return true;
1304 }
1305
1306 struct Adder_args
1307 {
1308 struct connectdata *conn;
1309 CURLcode result;
1310 int idx;
1311 int certs_count;
1312 };
1313
1314 static bool
add_cert_to_certinfo(const CERT_CONTEXT * ccert_context,void * raw_arg)1315 add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, void *raw_arg)
1316 {
1317 struct Adder_args *args = (struct Adder_args*)raw_arg;
1318 args->result = CURLE_OK;
1319 if(valid_cert_encoding(ccert_context)) {
1320 const char *beg = (const char *) ccert_context->pbCertEncoded;
1321 const char *end = beg + ccert_context->cbCertEncoded;
1322 int insert_index = (args->certs_count - 1) - args->idx;
1323 args->result = Curl_extract_certinfo(args->conn, insert_index, beg, end);
1324 args->idx++;
1325 }
1326 return args->result == CURLE_OK;
1327 }
1328
1329 static CURLcode
schannel_connect_step3(struct connectdata * conn,int sockindex)1330 schannel_connect_step3(struct connectdata *conn, int sockindex)
1331 {
1332 CURLcode result = CURLE_OK;
1333 struct Curl_easy *data = conn->data;
1334 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1335 SECURITY_STATUS sspi_status = SEC_E_OK;
1336 CERT_CONTEXT *ccert_context = NULL;
1337 #ifdef DEBUGBUILD
1338 const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
1339 conn->host.name;
1340 #endif
1341 #ifdef HAS_ALPN
1342 SecPkgContext_ApplicationProtocol alpn_result;
1343 #endif
1344
1345 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
1346
1347 DEBUGF(infof(data,
1348 "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
1349 hostname, conn->remote_port));
1350
1351 if(!BACKEND->cred)
1352 return CURLE_SSL_CONNECT_ERROR;
1353
1354 /* check if the required context attributes are met */
1355 if(BACKEND->ret_flags != BACKEND->req_flags) {
1356 if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT))
1357 failf(data, "schannel: failed to setup sequence detection");
1358 if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT))
1359 failf(data, "schannel: failed to setup replay detection");
1360 if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY))
1361 failf(data, "schannel: failed to setup confidentiality");
1362 if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY))
1363 failf(data, "schannel: failed to setup memory allocation");
1364 if(!(BACKEND->ret_flags & ISC_RET_STREAM))
1365 failf(data, "schannel: failed to setup stream orientation");
1366 return CURLE_SSL_CONNECT_ERROR;
1367 }
1368
1369 #ifdef HAS_ALPN
1370 if(BACKEND->use_alpn) {
1371 sspi_status =
1372 s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1373 SECPKG_ATTR_APPLICATION_PROTOCOL,
1374 &alpn_result);
1375
1376 if(sspi_status != SEC_E_OK) {
1377 failf(data, "schannel: failed to retrieve ALPN result");
1378 return CURLE_SSL_CONNECT_ERROR;
1379 }
1380
1381 if(alpn_result.ProtoNegoStatus ==
1382 SecApplicationProtocolNegotiationStatus_Success) {
1383
1384 infof(data, "schannel: ALPN, server accepted to use %.*s\n",
1385 alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
1386
1387 #ifdef USE_NGHTTP2
1388 if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
1389 !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
1390 NGHTTP2_PROTO_VERSION_ID_LEN)) {
1391 conn->negnpn = CURL_HTTP_VERSION_2;
1392 }
1393 else
1394 #endif
1395 if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
1396 !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
1397 ALPN_HTTP_1_1_LENGTH)) {
1398 conn->negnpn = CURL_HTTP_VERSION_1_1;
1399 }
1400 }
1401 else
1402 infof(data, "ALPN, server did not agree to a protocol\n");
1403 Curl_multiuse_state(conn, conn->negnpn == CURL_HTTP_VERSION_2 ?
1404 BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
1405 }
1406 #endif
1407
1408 /* save the current session data for possible re-use */
1409 if(SSL_SET_OPTION(primary.sessionid)) {
1410 bool incache;
1411 struct Curl_schannel_cred *old_cred = NULL;
1412
1413 Curl_ssl_sessionid_lock(conn);
1414 incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
1415 sockindex));
1416 if(incache) {
1417 if(old_cred != BACKEND->cred) {
1418 DEBUGF(infof(data,
1419 "schannel: old credential handle is stale, removing\n"));
1420 /* we're not taking old_cred ownership here, no refcount++ is needed */
1421 Curl_ssl_delsessionid(conn, (void *)old_cred);
1422 incache = FALSE;
1423 }
1424 }
1425 if(!incache) {
1426 result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred,
1427 sizeof(struct Curl_schannel_cred),
1428 sockindex);
1429 if(result) {
1430 Curl_ssl_sessionid_unlock(conn);
1431 failf(data, "schannel: failed to store credential handle");
1432 return result;
1433 }
1434 else {
1435 /* this cred session is now also referenced by sessionid cache */
1436 BACKEND->cred->refcount++;
1437 DEBUGF(infof(data,
1438 "schannel: stored credential handle in session cache\n"));
1439 }
1440 }
1441 Curl_ssl_sessionid_unlock(conn);
1442 }
1443
1444 if(data->set.ssl.certinfo) {
1445 int certs_count = 0;
1446 sspi_status =
1447 s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
1448 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1449 &ccert_context);
1450
1451 if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
1452 failf(data, "schannel: failed to retrieve remote cert context");
1453 return CURLE_PEER_FAILED_VERIFICATION;
1454 }
1455
1456 traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
1457
1458 result = Curl_ssl_init_certinfo(data, certs_count);
1459 if(!result) {
1460 struct Adder_args args;
1461 args.conn = conn;
1462 args.idx = 0;
1463 args.certs_count = certs_count;
1464 traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
1465 result = args.result;
1466 }
1467 CertFreeCertificateContext(ccert_context);
1468 if(result)
1469 return result;
1470 }
1471
1472 connssl->connecting_state = ssl_connect_done;
1473
1474 return CURLE_OK;
1475 }
1476
1477 static CURLcode
schannel_connect_common(struct connectdata * conn,int sockindex,bool nonblocking,bool * done)1478 schannel_connect_common(struct connectdata *conn, int sockindex,
1479 bool nonblocking, bool *done)
1480 {
1481 CURLcode result;
1482 struct Curl_easy *data = conn->data;
1483 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1484 curl_socket_t sockfd = conn->sock[sockindex];
1485 timediff_t timeout_ms;
1486 int what;
1487
1488 /* check if the connection has already been established */
1489 if(ssl_connection_complete == connssl->state) {
1490 *done = TRUE;
1491 return CURLE_OK;
1492 }
1493
1494 if(ssl_connect_1 == connssl->connecting_state) {
1495 /* check out how much more time we're allowed */
1496 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1497
1498 if(timeout_ms < 0) {
1499 /* no need to continue if time already is up */
1500 failf(data, "SSL/TLS connection timeout");
1501 return CURLE_OPERATION_TIMEDOUT;
1502 }
1503
1504 result = schannel_connect_step1(conn, sockindex);
1505 if(result)
1506 return result;
1507 }
1508
1509 while(ssl_connect_2 == connssl->connecting_state ||
1510 ssl_connect_2_reading == connssl->connecting_state ||
1511 ssl_connect_2_writing == connssl->connecting_state) {
1512
1513 /* check out how much more time we're allowed */
1514 timeout_ms = Curl_timeleft(data, NULL, TRUE);
1515
1516 if(timeout_ms < 0) {
1517 /* no need to continue if time already is up */
1518 failf(data, "SSL/TLS connection timeout");
1519 return CURLE_OPERATION_TIMEDOUT;
1520 }
1521
1522 /* if ssl is expecting something, check if it's available. */
1523 if(connssl->connecting_state == ssl_connect_2_reading
1524 || connssl->connecting_state == ssl_connect_2_writing) {
1525
1526 curl_socket_t writefd = ssl_connect_2_writing ==
1527 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1528 curl_socket_t readfd = ssl_connect_2_reading ==
1529 connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
1530
1531 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
1532 nonblocking ? 0 : timeout_ms);
1533 if(what < 0) {
1534 /* fatal error */
1535 failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
1536 return CURLE_SSL_CONNECT_ERROR;
1537 }
1538 else if(0 == what) {
1539 if(nonblocking) {
1540 *done = FALSE;
1541 return CURLE_OK;
1542 }
1543 else {
1544 /* timeout */
1545 failf(data, "SSL/TLS connection timeout");
1546 return CURLE_OPERATION_TIMEDOUT;
1547 }
1548 }
1549 /* socket is readable or writable */
1550 }
1551
1552 /* Run transaction, and return to the caller if it failed or if
1553 * this connection is part of a multi handle and this loop would
1554 * execute again. This permits the owner of a multi handle to
1555 * abort a connection attempt before step2 has completed while
1556 * ensuring that a client using select() or epoll() will always
1557 * have a valid fdset to wait on.
1558 */
1559 result = schannel_connect_step2(conn, sockindex);
1560 if(result || (nonblocking &&
1561 (ssl_connect_2 == connssl->connecting_state ||
1562 ssl_connect_2_reading == connssl->connecting_state ||
1563 ssl_connect_2_writing == connssl->connecting_state)))
1564 return result;
1565
1566 } /* repeat step2 until all transactions are done. */
1567
1568 if(ssl_connect_3 == connssl->connecting_state) {
1569 result = schannel_connect_step3(conn, sockindex);
1570 if(result)
1571 return result;
1572 }
1573
1574 if(ssl_connect_done == connssl->connecting_state) {
1575 connssl->state = ssl_connection_complete;
1576 conn->recv[sockindex] = schannel_recv;
1577 conn->send[sockindex] = schannel_send;
1578
1579 #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
1580 /* When SSPI is used in combination with Schannel
1581 * we need the Schannel context to create the Schannel
1582 * binding to pass the IIS extended protection checks.
1583 * Available on Windows 7 or later.
1584 */
1585 conn->sslContext = &BACKEND->ctxt->ctxt_handle;
1586 #endif
1587
1588 *done = TRUE;
1589 }
1590 else
1591 *done = FALSE;
1592
1593 /* reset our connection state machine */
1594 connssl->connecting_state = ssl_connect_1;
1595
1596 return CURLE_OK;
1597 }
1598
1599 static ssize_t
schannel_send(struct connectdata * conn,int sockindex,const void * buf,size_t len,CURLcode * err)1600 schannel_send(struct connectdata *conn, int sockindex,
1601 const void *buf, size_t len, CURLcode *err)
1602 {
1603 ssize_t written = -1;
1604 size_t data_len = 0;
1605 unsigned char *data = NULL;
1606 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1607 SecBuffer outbuf[4];
1608 SecBufferDesc outbuf_desc;
1609 SECURITY_STATUS sspi_status = SEC_E_OK;
1610 CURLcode result;
1611
1612 /* check if the maximum stream sizes were queried */
1613 if(BACKEND->stream_sizes.cbMaximumMessage == 0) {
1614 sspi_status = s_pSecFn->QueryContextAttributes(
1615 &BACKEND->ctxt->ctxt_handle,
1616 SECPKG_ATTR_STREAM_SIZES,
1617 &BACKEND->stream_sizes);
1618 if(sspi_status != SEC_E_OK) {
1619 *err = CURLE_SEND_ERROR;
1620 return -1;
1621 }
1622 }
1623
1624 /* check if the buffer is longer than the maximum message length */
1625 if(len > BACKEND->stream_sizes.cbMaximumMessage) {
1626 len = BACKEND->stream_sizes.cbMaximumMessage;
1627 }
1628
1629 /* calculate the complete message length and allocate a buffer for it */
1630 data_len = BACKEND->stream_sizes.cbHeader + len +
1631 BACKEND->stream_sizes.cbTrailer;
1632 data = (unsigned char *) malloc(data_len);
1633 if(data == NULL) {
1634 *err = CURLE_OUT_OF_MEMORY;
1635 return -1;
1636 }
1637
1638 /* setup output buffers (header, data, trailer, empty) */
1639 InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
1640 data, BACKEND->stream_sizes.cbHeader);
1641 InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
1642 data + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len));
1643 InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
1644 data + BACKEND->stream_sizes.cbHeader + len,
1645 BACKEND->stream_sizes.cbTrailer);
1646 InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
1647 InitSecBufferDesc(&outbuf_desc, outbuf, 4);
1648
1649 /* copy data into output buffer */
1650 memcpy(outbuf[1].pvBuffer, buf, len);
1651
1652 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
1653 sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0,
1654 &outbuf_desc, 0);
1655
1656 /* check if the message was encrypted */
1657 if(sspi_status == SEC_E_OK) {
1658 written = 0;
1659
1660 /* send the encrypted message including header, data and trailer */
1661 len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
1662
1663 /*
1664 It's important to send the full message which includes the header,
1665 encrypted payload, and trailer. Until the client receives all the
1666 data a coherent message has not been delivered and the client
1667 can't read any of it.
1668
1669 If we wanted to buffer the unwritten encrypted bytes, we would
1670 tell the client that all data it has requested to be sent has been
1671 sent. The unwritten encrypted bytes would be the first bytes to
1672 send on the next invocation.
1673 Here's the catch with this - if we tell the client that all the
1674 bytes have been sent, will the client call this method again to
1675 send the buffered data? Looking at who calls this function, it
1676 seems the answer is NO.
1677 */
1678
1679 /* send entire message or fail */
1680 while(len > (size_t)written) {
1681 ssize_t this_write = 0;
1682 int what;
1683 timediff_t timeout_ms = Curl_timeleft(conn->data, NULL, FALSE);
1684 if(timeout_ms < 0) {
1685 /* we already got the timeout */
1686 failf(conn->data, "schannel: timed out sending data "
1687 "(bytes sent: %zd)", written);
1688 *err = CURLE_OPERATION_TIMEDOUT;
1689 written = -1;
1690 break;
1691 }
1692 else if(!timeout_ms)
1693 timeout_ms = TIMEDIFF_T_MAX;
1694 what = SOCKET_WRITABLE(conn->sock[sockindex], timeout_ms);
1695 if(what < 0) {
1696 /* fatal error */
1697 failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
1698 *err = CURLE_SEND_ERROR;
1699 written = -1;
1700 break;
1701 }
1702 else if(0 == what) {
1703 failf(conn->data, "schannel: timed out sending data "
1704 "(bytes sent: %zd)", written);
1705 *err = CURLE_OPERATION_TIMEDOUT;
1706 written = -1;
1707 break;
1708 }
1709 /* socket is writable */
1710
1711 result = Curl_write_plain(conn, conn->sock[sockindex], data + written,
1712 len - written, &this_write);
1713 if(result == CURLE_AGAIN)
1714 continue;
1715 else if(result != CURLE_OK) {
1716 *err = result;
1717 written = -1;
1718 break;
1719 }
1720
1721 written += this_write;
1722 }
1723 }
1724 else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
1725 *err = CURLE_OUT_OF_MEMORY;
1726 }
1727 else{
1728 *err = CURLE_SEND_ERROR;
1729 }
1730
1731 Curl_safefree(data);
1732
1733 if(len == (size_t)written)
1734 /* Encrypted message including header, data and trailer entirely sent.
1735 The return value is the number of unencrypted bytes that were sent. */
1736 written = outbuf[1].cbBuffer;
1737
1738 return written;
1739 }
1740
1741 static ssize_t
schannel_recv(struct connectdata * conn,int sockindex,char * buf,size_t len,CURLcode * err)1742 schannel_recv(struct connectdata *conn, int sockindex,
1743 char *buf, size_t len, CURLcode *err)
1744 {
1745 size_t size = 0;
1746 ssize_t nread = -1;
1747 struct Curl_easy *data = conn->data;
1748 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
1749 unsigned char *reallocated_buffer;
1750 size_t reallocated_length;
1751 bool done = FALSE;
1752 SecBuffer inbuf[4];
1753 SecBufferDesc inbuf_desc;
1754 SECURITY_STATUS sspi_status = SEC_E_OK;
1755 /* we want the length of the encrypted buffer to be at least large enough
1756 that it can hold all the bytes requested and some TLS record overhead. */
1757 size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
1758
1759 /****************************************************************************
1760 * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup.
1761 * The pattern for return error is set *err, optional infof, goto cleanup.
1762 *
1763 * Our priority is to always return as much decrypted data to the caller as
1764 * possible, even if an error occurs. The state of the decrypted buffer must
1765 * always be valid. Transfer of decrypted data to the caller's buffer is
1766 * handled in the cleanup.
1767 */
1768
1769 DEBUGF(infof(data, "schannel: client wants to read %zu bytes\n", len));
1770 *err = CURLE_OK;
1771
1772 if(len && len <= BACKEND->decdata_offset) {
1773 infof(data, "schannel: enough decrypted data is already available\n");
1774 goto cleanup;
1775 }
1776 else if(BACKEND->recv_unrecoverable_err) {
1777 *err = BACKEND->recv_unrecoverable_err;
1778 infof(data, "schannel: an unrecoverable error occurred in a prior call\n");
1779 goto cleanup;
1780 }
1781 else if(BACKEND->recv_sspi_close_notify) {
1782 /* once a server has indicated shutdown there is no more encrypted data */
1783 infof(data, "schannel: server indicated shutdown in a prior call\n");
1784 goto cleanup;
1785 }
1786 else if(!len) {
1787 /* It's debatable what to return when !len. Regardless we can't return
1788 immediately because there may be data to decrypt (in the case we want to
1789 decrypt all encrypted cached data) so handle !len later in cleanup.
1790 */
1791 ; /* do nothing */
1792 }
1793 else if(!BACKEND->recv_connection_closed) {
1794 /* increase enc buffer in order to fit the requested amount of data */
1795 size = BACKEND->encdata_length - BACKEND->encdata_offset;
1796 if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
1797 BACKEND->encdata_length < min_encdata_length) {
1798 reallocated_length = BACKEND->encdata_offset +
1799 CURL_SCHANNEL_BUFFER_FREE_SIZE;
1800 if(reallocated_length < min_encdata_length) {
1801 reallocated_length = min_encdata_length;
1802 }
1803 reallocated_buffer = realloc(BACKEND->encdata_buffer,
1804 reallocated_length);
1805 if(reallocated_buffer == NULL) {
1806 *err = CURLE_OUT_OF_MEMORY;
1807 failf(data, "schannel: unable to re-allocate memory");
1808 goto cleanup;
1809 }
1810
1811 BACKEND->encdata_buffer = reallocated_buffer;
1812 BACKEND->encdata_length = reallocated_length;
1813 size = BACKEND->encdata_length - BACKEND->encdata_offset;
1814 DEBUGF(infof(data, "schannel: encdata_buffer resized %zu\n",
1815 BACKEND->encdata_length));
1816 }
1817
1818 DEBUGF(infof(data,
1819 "schannel: encrypted data buffer: offset %zu length %zu\n",
1820 BACKEND->encdata_offset, BACKEND->encdata_length));
1821
1822 /* read encrypted data from socket */
1823 *err = Curl_read_plain(conn->sock[sockindex],
1824 (char *)(BACKEND->encdata_buffer +
1825 BACKEND->encdata_offset),
1826 size, &nread);
1827 if(*err) {
1828 nread = -1;
1829 if(*err == CURLE_AGAIN)
1830 DEBUGF(infof(data,
1831 "schannel: Curl_read_plain returned CURLE_AGAIN\n"));
1832 else if(*err == CURLE_RECV_ERROR)
1833 infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
1834 else
1835 infof(data, "schannel: Curl_read_plain returned error %d\n", *err);
1836 }
1837 else if(nread == 0) {
1838 BACKEND->recv_connection_closed = true;
1839 DEBUGF(infof(data, "schannel: server closed the connection\n"));
1840 }
1841 else if(nread > 0) {
1842 BACKEND->encdata_offset += (size_t)nread;
1843 BACKEND->encdata_is_incomplete = false;
1844 DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread));
1845 }
1846 }
1847
1848 DEBUGF(infof(data,
1849 "schannel: encrypted data buffer: offset %zu length %zu\n",
1850 BACKEND->encdata_offset, BACKEND->encdata_length));
1851
1852 /* decrypt loop */
1853 while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK &&
1854 (!len || BACKEND->decdata_offset < len ||
1855 BACKEND->recv_connection_closed)) {
1856 /* prepare data buffer for DecryptMessage call */
1857 InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer,
1858 curlx_uztoul(BACKEND->encdata_offset));
1859
1860 /* we need 3 more empty input buffers for possible output */
1861 InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
1862 InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
1863 InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
1864 InitSecBufferDesc(&inbuf_desc, inbuf, 4);
1865
1866 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
1867 */
1868 sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle,
1869 &inbuf_desc, 0, NULL);
1870
1871 /* check if everything went fine (server may want to renegotiate
1872 or shutdown the connection context) */
1873 if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
1874 sspi_status == SEC_I_CONTEXT_EXPIRED) {
1875 /* check for successfully decrypted data, even before actual
1876 renegotiation or shutdown of the connection context */
1877 if(inbuf[1].BufferType == SECBUFFER_DATA) {
1878 DEBUGF(infof(data, "schannel: decrypted data length: %lu\n",
1879 inbuf[1].cbBuffer));
1880
1881 /* increase buffer in order to fit the received amount of data */
1882 size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
1883 inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
1884 if(BACKEND->decdata_length - BACKEND->decdata_offset < size ||
1885 BACKEND->decdata_length < len) {
1886 /* increase internal decrypted data buffer */
1887 reallocated_length = BACKEND->decdata_offset + size;
1888 /* make sure that the requested amount of data fits */
1889 if(reallocated_length < len) {
1890 reallocated_length = len;
1891 }
1892 reallocated_buffer = realloc(BACKEND->decdata_buffer,
1893 reallocated_length);
1894 if(reallocated_buffer == NULL) {
1895 *err = CURLE_OUT_OF_MEMORY;
1896 failf(data, "schannel: unable to re-allocate memory");
1897 goto cleanup;
1898 }
1899 BACKEND->decdata_buffer = reallocated_buffer;
1900 BACKEND->decdata_length = reallocated_length;
1901 }
1902
1903 /* copy decrypted data to internal buffer */
1904 size = inbuf[1].cbBuffer;
1905 if(size) {
1906 memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset,
1907 inbuf[1].pvBuffer, size);
1908 BACKEND->decdata_offset += size;
1909 }
1910
1911 DEBUGF(infof(data, "schannel: decrypted data added: %zu\n", size));
1912 DEBUGF(infof(data,
1913 "schannel: decrypted cached: offset %zu length %zu\n",
1914 BACKEND->decdata_offset, BACKEND->decdata_length));
1915 }
1916
1917 /* check for remaining encrypted data */
1918 if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
1919 DEBUGF(infof(data, "schannel: encrypted data length: %lu\n",
1920 inbuf[3].cbBuffer));
1921
1922 /* check if the remaining data is less than the total amount
1923 * and therefore begins after the already processed data
1924 */
1925 if(BACKEND->encdata_offset > inbuf[3].cbBuffer) {
1926 /* move remaining encrypted data forward to the beginning of
1927 buffer */
1928 memmove(BACKEND->encdata_buffer,
1929 (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
1930 inbuf[3].cbBuffer, inbuf[3].cbBuffer);
1931 BACKEND->encdata_offset = inbuf[3].cbBuffer;
1932 }
1933
1934 DEBUGF(infof(data,
1935 "schannel: encrypted cached: offset %zu length %zu\n",
1936 BACKEND->encdata_offset, BACKEND->encdata_length));
1937 }
1938 else {
1939 /* reset encrypted buffer offset, because there is no data remaining */
1940 BACKEND->encdata_offset = 0;
1941 }
1942
1943 /* check if server wants to renegotiate the connection context */
1944 if(sspi_status == SEC_I_RENEGOTIATE) {
1945 infof(data, "schannel: remote party requests renegotiation\n");
1946 if(*err && *err != CURLE_AGAIN) {
1947 infof(data, "schannel: can't renogotiate, an error is pending\n");
1948 goto cleanup;
1949 }
1950 if(BACKEND->encdata_offset) {
1951 *err = CURLE_RECV_ERROR;
1952 infof(data, "schannel: can't renogotiate, "
1953 "encrypted data available\n");
1954 goto cleanup;
1955 }
1956 /* begin renegotiation */
1957 infof(data, "schannel: renegotiating SSL/TLS connection\n");
1958 connssl->state = ssl_connection_negotiating;
1959 connssl->connecting_state = ssl_connect_2_writing;
1960 *err = schannel_connect_common(conn, sockindex, FALSE, &done);
1961 if(*err) {
1962 infof(data, "schannel: renegotiation failed\n");
1963 goto cleanup;
1964 }
1965 /* now retry receiving data */
1966 sspi_status = SEC_E_OK;
1967 infof(data, "schannel: SSL/TLS connection renegotiated\n");
1968 continue;
1969 }
1970 /* check if the server closed the connection */
1971 else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
1972 /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
1973 returned so we have to work around that in cleanup. */
1974 BACKEND->recv_sspi_close_notify = true;
1975 if(!BACKEND->recv_connection_closed) {
1976 BACKEND->recv_connection_closed = true;
1977 infof(data, "schannel: server closed the connection\n");
1978 }
1979 goto cleanup;
1980 }
1981 }
1982 else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
1983 BACKEND->encdata_is_incomplete = true;
1984 if(!*err)
1985 *err = CURLE_AGAIN;
1986 infof(data, "schannel: failed to decrypt data, need more data\n");
1987 goto cleanup;
1988 }
1989 else {
1990 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1991 char buffer[STRERROR_LEN];
1992 #endif
1993 *err = CURLE_RECV_ERROR;
1994 infof(data, "schannel: failed to read data from server: %s\n",
1995 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
1996 goto cleanup;
1997 }
1998 }
1999
2000 DEBUGF(infof(data,
2001 "schannel: encrypted data buffer: offset %zu length %zu\n",
2002 BACKEND->encdata_offset, BACKEND->encdata_length));
2003
2004 DEBUGF(infof(data,
2005 "schannel: decrypted data buffer: offset %zu length %zu\n",
2006 BACKEND->decdata_offset, BACKEND->decdata_length));
2007
2008 cleanup:
2009 /* Warning- there is no guarantee the encdata state is valid at this point */
2010 DEBUGF(infof(data, "schannel: schannel_recv cleanup\n"));
2011
2012 /* Error if the connection has closed without a close_notify.
2013
2014 The behavior here is a matter of debate. We don't want to be vulnerable
2015 to a truncation attack however there's some browser precedent for
2016 ignoring the close_notify for compatibility reasons.
2017
2018 Additionally, Windows 2000 (v5.0) is a special case since it seems it
2019 doesn't return close_notify. In that case if the connection was closed we
2020 assume it was graceful (close_notify) since there doesn't seem to be a
2021 way to tell.
2022 */
2023 if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
2024 !BACKEND->recv_sspi_close_notify) {
2025 bool isWin2k = curlx_verify_windows_version(5, 0, PLATFORM_WINNT,
2026 VERSION_EQUAL);
2027
2028 if(isWin2k && sspi_status == SEC_E_OK)
2029 BACKEND->recv_sspi_close_notify = true;
2030 else {
2031 *err = CURLE_RECV_ERROR;
2032 infof(data, "schannel: server closed abruptly (missing close_notify)\n");
2033 }
2034 }
2035
2036 /* Any error other than CURLE_AGAIN is an unrecoverable error. */
2037 if(*err && *err != CURLE_AGAIN)
2038 BACKEND->recv_unrecoverable_err = *err;
2039
2040 size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset;
2041 if(size) {
2042 memcpy(buf, BACKEND->decdata_buffer, size);
2043 memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
2044 BACKEND->decdata_offset - size);
2045 BACKEND->decdata_offset -= size;
2046 DEBUGF(infof(data, "schannel: decrypted data returned %zu\n", size));
2047 DEBUGF(infof(data,
2048 "schannel: decrypted data buffer: offset %zu length %zu\n",
2049 BACKEND->decdata_offset, BACKEND->decdata_length));
2050 *err = CURLE_OK;
2051 return (ssize_t)size;
2052 }
2053
2054 if(!*err && !BACKEND->recv_connection_closed)
2055 *err = CURLE_AGAIN;
2056
2057 /* It's debatable what to return when !len. We could return whatever error
2058 we got from decryption but instead we override here so the return is
2059 consistent.
2060 */
2061 if(!len)
2062 *err = CURLE_OK;
2063
2064 return *err ? -1 : 0;
2065 }
2066
Curl_schannel_connect_nonblocking(struct connectdata * conn,int sockindex,bool * done)2067 static CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
2068 int sockindex, bool *done)
2069 {
2070 return schannel_connect_common(conn, sockindex, TRUE, done);
2071 }
2072
Curl_schannel_connect(struct connectdata * conn,int sockindex)2073 static CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex)
2074 {
2075 CURLcode result;
2076 bool done = FALSE;
2077
2078 result = schannel_connect_common(conn, sockindex, FALSE, &done);
2079 if(result)
2080 return result;
2081
2082 DEBUGASSERT(done);
2083
2084 return CURLE_OK;
2085 }
2086
Curl_schannel_data_pending(const struct connectdata * conn,int sockindex)2087 static bool Curl_schannel_data_pending(const struct connectdata *conn,
2088 int sockindex)
2089 {
2090 const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2091
2092 if(connssl->use) /* SSL/TLS is in use */
2093 return (BACKEND->decdata_offset > 0 ||
2094 (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete));
2095 else
2096 return FALSE;
2097 }
2098
Curl_schannel_close(struct connectdata * conn,int sockindex)2099 static void Curl_schannel_close(struct connectdata *conn, int sockindex)
2100 {
2101 if(conn->ssl[sockindex].use)
2102 /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
2103 Curl_ssl_shutdown(conn, sockindex);
2104 }
2105
Curl_schannel_session_free(void * ptr)2106 static void Curl_schannel_session_free(void *ptr)
2107 {
2108 /* this is expected to be called under sessionid lock */
2109 struct Curl_schannel_cred *cred = ptr;
2110
2111 cred->refcount--;
2112 if(cred->refcount == 0) {
2113 s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
2114 Curl_safefree(cred);
2115 }
2116 }
2117
Curl_schannel_shutdown(struct connectdata * conn,int sockindex)2118 static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
2119 {
2120 /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
2121 * Shutting Down an Schannel Connection
2122 */
2123 struct Curl_easy *data = conn->data;
2124 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2125 #ifndef CURL_DISABLE_PROXY
2126 char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
2127 conn->host.name;
2128 #else
2129 char * const hostname = conn->host.name;
2130 #endif
2131
2132 DEBUGASSERT(data);
2133
2134 infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
2135 hostname, conn->remote_port);
2136
2137 if(BACKEND->cred && BACKEND->ctxt) {
2138 SecBufferDesc BuffDesc;
2139 SecBuffer Buffer;
2140 SECURITY_STATUS sspi_status;
2141 SecBuffer outbuf;
2142 SecBufferDesc outbuf_desc;
2143 CURLcode result;
2144 TCHAR *host_name;
2145 DWORD dwshut = SCHANNEL_SHUTDOWN;
2146
2147 InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
2148 InitSecBufferDesc(&BuffDesc, &Buffer, 1);
2149
2150 sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle,
2151 &BuffDesc);
2152
2153 if(sspi_status != SEC_E_OK) {
2154 char buffer[STRERROR_LEN];
2155 failf(data, "schannel: ApplyControlToken failure: %s",
2156 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2157 }
2158
2159 host_name = curlx_convert_UTF8_to_tchar(hostname);
2160 if(!host_name)
2161 return CURLE_OUT_OF_MEMORY;
2162
2163 /* setup output buffer */
2164 InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
2165 InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
2166
2167 sspi_status = s_pSecFn->InitializeSecurityContext(
2168 &BACKEND->cred->cred_handle,
2169 &BACKEND->ctxt->ctxt_handle,
2170 host_name,
2171 BACKEND->req_flags,
2172 0,
2173 0,
2174 NULL,
2175 0,
2176 &BACKEND->ctxt->ctxt_handle,
2177 &outbuf_desc,
2178 &BACKEND->ret_flags,
2179 &BACKEND->ctxt->time_stamp);
2180
2181 curlx_unicodefree(host_name);
2182
2183 if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
2184 /* send close message which is in output buffer */
2185 ssize_t written;
2186 result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
2187 outbuf.cbBuffer, &written);
2188
2189 s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
2190 if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
2191 infof(data, "schannel: failed to send close msg: %s"
2192 " (bytes written: %zd)\n", curl_easy_strerror(result), written);
2193 }
2194 }
2195 }
2196
2197 /* free SSPI Schannel API security context handle */
2198 if(BACKEND->ctxt) {
2199 DEBUGF(infof(data, "schannel: clear security context handle\n"));
2200 s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
2201 Curl_safefree(BACKEND->ctxt);
2202 }
2203
2204 /* free SSPI Schannel API credential handle */
2205 if(BACKEND->cred) {
2206 /*
2207 * When this function is called from Curl_schannel_close() the connection
2208 * might not have an associated transfer so the check for conn->data is
2209 * necessary.
2210 */
2211 Curl_ssl_sessionid_lock(conn);
2212 Curl_schannel_session_free(BACKEND->cred);
2213 Curl_ssl_sessionid_unlock(conn);
2214 BACKEND->cred = NULL;
2215 }
2216
2217 /* free internal buffer for received encrypted data */
2218 if(BACKEND->encdata_buffer != NULL) {
2219 Curl_safefree(BACKEND->encdata_buffer);
2220 BACKEND->encdata_length = 0;
2221 BACKEND->encdata_offset = 0;
2222 BACKEND->encdata_is_incomplete = false;
2223 }
2224
2225 /* free internal buffer for received decrypted data */
2226 if(BACKEND->decdata_buffer != NULL) {
2227 Curl_safefree(BACKEND->decdata_buffer);
2228 BACKEND->decdata_length = 0;
2229 BACKEND->decdata_offset = 0;
2230 }
2231
2232 return CURLE_OK;
2233 }
2234
Curl_schannel_init(void)2235 static int Curl_schannel_init(void)
2236 {
2237 return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
2238 }
2239
Curl_schannel_cleanup(void)2240 static void Curl_schannel_cleanup(void)
2241 {
2242 Curl_sspi_global_cleanup();
2243 }
2244
Curl_schannel_version(char * buffer,size_t size)2245 static size_t Curl_schannel_version(char *buffer, size_t size)
2246 {
2247 size = msnprintf(buffer, size, "Schannel");
2248
2249 return size;
2250 }
2251
Curl_schannel_random(struct Curl_easy * data UNUSED_PARAM,unsigned char * entropy,size_t length)2252 static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM,
2253 unsigned char *entropy, size_t length)
2254 {
2255 HCRYPTPROV hCryptProv = 0;
2256
2257 (void)data;
2258
2259 if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
2260 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2261 return CURLE_FAILED_INIT;
2262
2263 if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
2264 CryptReleaseContext(hCryptProv, 0UL);
2265 return CURLE_FAILED_INIT;
2266 }
2267
2268 CryptReleaseContext(hCryptProv, 0UL);
2269 return CURLE_OK;
2270 }
2271
pkp_pin_peer_pubkey(struct connectdata * conn,int sockindex,const char * pinnedpubkey)2272 static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
2273 const char *pinnedpubkey)
2274 {
2275 struct Curl_easy *data = conn->data;
2276 struct ssl_connect_data *connssl = &conn->ssl[sockindex];
2277 CERT_CONTEXT *pCertContextServer = NULL;
2278
2279 /* Result is returned to caller */
2280 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
2281
2282 /* if a path wasn't specified, don't pin */
2283 if(!pinnedpubkey)
2284 return CURLE_OK;
2285
2286 do {
2287 SECURITY_STATUS sspi_status;
2288 const char *x509_der;
2289 DWORD x509_der_len;
2290 struct Curl_X509certificate x509_parsed;
2291 struct Curl_asn1Element *pubkey;
2292
2293 sspi_status =
2294 s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
2295 SECPKG_ATTR_REMOTE_CERT_CONTEXT,
2296 &pCertContextServer);
2297
2298 if((sspi_status != SEC_E_OK) || (pCertContextServer == NULL)) {
2299 char buffer[STRERROR_LEN];
2300 failf(data, "schannel: Failed to read remote certificate context: %s",
2301 Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
2302 break; /* failed */
2303 }
2304
2305
2306 if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
2307 (pCertContextServer->cbCertEncoded > 0)))
2308 break;
2309
2310 x509_der = (const char *)pCertContextServer->pbCertEncoded;
2311 x509_der_len = pCertContextServer->cbCertEncoded;
2312 memset(&x509_parsed, 0, sizeof(x509_parsed));
2313 if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
2314 break;
2315
2316 pubkey = &x509_parsed.subjectPublicKeyInfo;
2317 if(!pubkey->header || pubkey->end <= pubkey->header) {
2318 failf(data, "SSL: failed retrieving public key from server certificate");
2319 break;
2320 }
2321
2322 result = Curl_pin_peer_pubkey(data,
2323 pinnedpubkey,
2324 (const unsigned char *)pubkey->header,
2325 (size_t)(pubkey->end - pubkey->header));
2326 if(result) {
2327 failf(data, "SSL: public key does not match pinned public key!");
2328 }
2329 } while(0);
2330
2331 if(pCertContextServer)
2332 CertFreeCertificateContext(pCertContextServer);
2333
2334 return result;
2335 }
2336
Curl_schannel_checksum(const unsigned char * input,size_t inputlen,unsigned char * checksum,size_t checksumlen,DWORD provType,const unsigned int algId)2337 static void Curl_schannel_checksum(const unsigned char *input,
2338 size_t inputlen,
2339 unsigned char *checksum,
2340 size_t checksumlen,
2341 DWORD provType,
2342 const unsigned int algId)
2343 {
2344 HCRYPTPROV hProv = 0;
2345 HCRYPTHASH hHash = 0;
2346 DWORD cbHashSize = 0;
2347 DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
2348 DWORD dwChecksumLen = (DWORD)checksumlen;
2349
2350 /* since this can fail in multiple ways, zero memory first so we never
2351 * return old data
2352 */
2353 memset(checksum, 0, checksumlen);
2354
2355 if(!CryptAcquireContext(&hProv, NULL, NULL, provType,
2356 CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
2357 return; /* failed */
2358
2359 do {
2360 if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
2361 break; /* failed */
2362
2363 /* workaround for original MinGW, should be (const BYTE*) */
2364 if(!CryptHashData(hHash, (BYTE*)input, (DWORD)inputlen, 0))
2365 break; /* failed */
2366
2367 /* get hash size */
2368 if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&cbHashSize,
2369 &dwHashSizeLen, 0))
2370 break; /* failed */
2371
2372 /* check hash size */
2373 if(checksumlen < cbHashSize)
2374 break; /* failed */
2375
2376 if(CryptGetHashParam(hHash, HP_HASHVAL, checksum, &dwChecksumLen, 0))
2377 break; /* failed */
2378 } while(0);
2379
2380 if(hHash)
2381 CryptDestroyHash(hHash);
2382
2383 if(hProv)
2384 CryptReleaseContext(hProv, 0);
2385 }
2386
Curl_schannel_md5sum(unsigned char * input,size_t inputlen,unsigned char * md5sum,size_t md5len)2387 static CURLcode Curl_schannel_md5sum(unsigned char *input,
2388 size_t inputlen,
2389 unsigned char *md5sum,
2390 size_t md5len)
2391 {
2392 Curl_schannel_checksum(input, inputlen, md5sum, md5len,
2393 PROV_RSA_FULL, CALG_MD5);
2394 return CURLE_OK;
2395 }
2396
Curl_schannel_sha256sum(const unsigned char * input,size_t inputlen,unsigned char * sha256sum,size_t sha256len)2397 static CURLcode Curl_schannel_sha256sum(const unsigned char *input,
2398 size_t inputlen,
2399 unsigned char *sha256sum,
2400 size_t sha256len)
2401 {
2402 Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
2403 PROV_RSA_AES, CALG_SHA_256);
2404 return CURLE_OK;
2405 }
2406
Curl_schannel_get_internals(struct ssl_connect_data * connssl,CURLINFO info UNUSED_PARAM)2407 static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
2408 CURLINFO info UNUSED_PARAM)
2409 {
2410 (void)info;
2411 return &BACKEND->ctxt->ctxt_handle;
2412 }
2413
2414 const struct Curl_ssl Curl_ssl_schannel = {
2415 { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
2416
2417 SSLSUPP_CERTINFO |
2418 SSLSUPP_PINNEDPUBKEY,
2419
2420 sizeof(struct ssl_backend_data),
2421
2422 Curl_schannel_init, /* init */
2423 Curl_schannel_cleanup, /* cleanup */
2424 Curl_schannel_version, /* version */
2425 Curl_none_check_cxn, /* check_cxn */
2426 Curl_schannel_shutdown, /* shutdown */
2427 Curl_schannel_data_pending, /* data_pending */
2428 Curl_schannel_random, /* random */
2429 Curl_none_cert_status_request, /* cert_status_request */
2430 Curl_schannel_connect, /* connect */
2431 Curl_schannel_connect_nonblocking, /* connect_nonblocking */
2432 Curl_schannel_get_internals, /* get_internals */
2433 Curl_schannel_close, /* close_one */
2434 Curl_none_close_all, /* close_all */
2435 Curl_schannel_session_free, /* session_free */
2436 Curl_none_set_engine, /* set_engine */
2437 Curl_none_set_engine_default, /* set_engine_default */
2438 Curl_none_engines_list, /* engines_list */
2439 Curl_none_false_start, /* false_start */
2440 Curl_schannel_md5sum, /* md5sum */
2441 Curl_schannel_sha256sum /* sha256sum */
2442 };
2443
2444 #endif /* USE_SCHANNEL */
2445