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