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