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