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