1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 * Copyright (C) Nick Zitzmann, <nickzman@gmail.com>.
10 *
11 * This software is licensed as described in the file COPYING, which
12 * you should have received as part of this distribution. The terms
13 * are also available at https://curl.se/docs/copyright.html.
14 *
15 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
16 * copies of the Software, and permit persons to whom the Software is
17 * furnished to do so, under the terms of the COPYING file.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 * SPDX-License-Identifier: curl
23 *
24 ***************************************************************************/
25
26 /*
27 * Source file for all iOS and macOS Secure Transport-specific code for the
28 * TLS/SSL layer. No code but vtls.c should ever call or use these functions.
29 */
30
31 #include "curl_setup.h"
32
33 #ifdef USE_SECTRANSP
34
35 #include "urldata.h" /* for the Curl_easy definition */
36 #include "curl_base64.h"
37 #include "strtok.h"
38 #include "multiif.h"
39 #include "strcase.h"
40 #include "x509asn1.h"
41 #include "strerror.h"
42 #include "cipher_suite.h"
43
44 #ifdef __clang__
45 #pragma clang diagnostic push
46 #pragma clang diagnostic ignored "-Wunreachable-code"
47 #endif /* __clang__ */
48
49 #ifdef __GNUC__
50 #pragma GCC diagnostic push
51 #pragma GCC diagnostic ignored "-Waddress"
52 #endif
53
54 #include <limits.h>
55
56 #include <Security/Security.h>
57 /* For some reason, when building for iOS, the omnibus header above does
58 * not include SecureTransport.h as of iOS SDK 5.1. */
59 #include <Security/SecureTransport.h>
60 #include <CoreFoundation/CoreFoundation.h>
61 #include <CommonCrypto/CommonDigest.h>
62
63 /* The Security framework has changed greatly between iOS and different macOS
64 versions, and we will try to support as many of them as we can (back to
65 Leopard and iOS 5) by using macros and weak-linking.
66
67 In general, you want to build this using the most recent OS SDK, since some
68 features require curl to be built against the latest SDK. TLS 1.1 and 1.2
69 support, for instance, require the macOS 10.8 SDK or later. TLS 1.3
70 requires the macOS 10.13 or iOS 11 SDK or later. */
71 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
72
73 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
74 #error "The Secure Transport backend requires Leopard or later."
75 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */
76
77 #define CURL_BUILD_IOS 0
78 #define CURL_BUILD_IOS_7 0
79 #define CURL_BUILD_IOS_9 0
80 #define CURL_BUILD_IOS_11 0
81 #define CURL_BUILD_IOS_13 0
82 #define CURL_BUILD_MAC 1
83 /* This is the maximum API level we are allowed to use when building: */
84 #define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
85 #define CURL_BUILD_MAC_10_6 MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
86 #define CURL_BUILD_MAC_10_7 MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
87 #define CURL_BUILD_MAC_10_8 MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
88 #define CURL_BUILD_MAC_10_9 MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
89 #define CURL_BUILD_MAC_10_11 MAC_OS_X_VERSION_MAX_ALLOWED >= 101100
90 #define CURL_BUILD_MAC_10_13 MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
91 #define CURL_BUILD_MAC_10_15 MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
92 /* These macros mean "the following code is present to allow runtime backward
93 compatibility with at least this cat or earlier":
94 (You set this at build-time using the compiler command line option
95 "-mmacosx-version-min.") */
96 #define CURL_SUPPORT_MAC_10_5 MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
97 #define CURL_SUPPORT_MAC_10_6 MAC_OS_X_VERSION_MIN_REQUIRED <= 1060
98 #define CURL_SUPPORT_MAC_10_7 MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
99 #define CURL_SUPPORT_MAC_10_8 MAC_OS_X_VERSION_MIN_REQUIRED <= 1080
100 #define CURL_SUPPORT_MAC_10_9 MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
101
102 #elif TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
103 #define CURL_BUILD_IOS 1
104 #define CURL_BUILD_IOS_7 __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
105 #define CURL_BUILD_IOS_9 __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
106 #define CURL_BUILD_IOS_11 __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
107 #define CURL_BUILD_IOS_13 __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
108 #define CURL_BUILD_MAC 0
109 #define CURL_BUILD_MAC_10_5 0
110 #define CURL_BUILD_MAC_10_6 0
111 #define CURL_BUILD_MAC_10_7 0
112 #define CURL_BUILD_MAC_10_8 0
113 #define CURL_BUILD_MAC_10_9 0
114 #define CURL_BUILD_MAC_10_11 0
115 #define CURL_BUILD_MAC_10_13 0
116 #define CURL_BUILD_MAC_10_15 0
117 #define CURL_SUPPORT_MAC_10_5 0
118 #define CURL_SUPPORT_MAC_10_6 0
119 #define CURL_SUPPORT_MAC_10_7 0
120 #define CURL_SUPPORT_MAC_10_8 0
121 #define CURL_SUPPORT_MAC_10_9 0
122
123 #else
124 #error "The Secure Transport backend requires iOS or macOS."
125 #endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
126
127 #if CURL_BUILD_MAC
128 #include <sys/sysctl.h>
129 #endif /* CURL_BUILD_MAC */
130
131 #include "sendf.h"
132 #include "inet_pton.h"
133 #include "connect.h"
134 #include "select.h"
135 #include "vtls.h"
136 #include "vtls_int.h"
137 #include "sectransp.h"
138 #include "curl_printf.h"
139 #include "strdup.h"
140
141 #include "curl_memory.h"
142 /* The last #include file should be: */
143 #include "memdebug.h"
144
145
146 /* From MacTypes.h (which we cannot include because it is not present in
147 iOS: */
148 #define ioErr -36
149 #define paramErr -50
150
151 struct st_ssl_backend_data {
152 SSLContextRef ssl_ctx;
153 bool ssl_direction; /* true if writing, false if reading */
154 size_t ssl_write_buffered_length;
155 BIT(sent_shutdown);
156 };
157
158 /* Create the list of default ciphers to use by making an intersection of the
159 * ciphers supported by Secure Transport and the list below, using the order
160 * of the former.
161 * This list is based on TLS recommendations by Mozilla, balancing between
162 * security and wide compatibility: "Most ciphers that are not clearly broken
163 * and dangerous to use are supported"
164 */
165 static const uint16_t default_ciphers[] = {
166 TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */
167 TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */
168 TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */
169
170 #if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
171 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */
172 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */
173 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */
174 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */
175 #endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
176
177 #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
178 TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */
179 TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */
180 TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, /* 0x0067 */
181 TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, /* 0x006B */
182 TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */
183 TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */
184 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, /* 0x009E */
185 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, /* 0x009F */
186 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */
187 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */
188 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */
189 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */
190 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */
191 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */
192 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */
193 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */
194 #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
195
196 #if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
197 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
198 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
199
200 /* TLSv1.3 is not supported by Secure Transport, but there is also other
201 * code referencing TLSv1.3, like: kTLSProtocol13 ? */
202 TLS_AES_128_GCM_SHA256, /* 0x1301 */
203 TLS_AES_256_GCM_SHA384, /* 0x1302 */
204 TLS_CHACHA20_POLY1305_SHA256, /* 0x1303 */
205 #endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
206 };
207
208 #define DEFAULT_CIPHERS_LEN sizeof(default_ciphers)/sizeof(default_ciphers[0])
209
210
211 /* pinned public key support tests */
212
213 /* version 1 supports macOS 10.12+ and iOS 10+ */
214 #if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \
215 (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200))
216 #define SECTRANSP_PINNEDPUBKEY_V1 1
217 #endif
218
219 /* version 2 supports macOS 10.7+ */
220 #if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)
221 #define SECTRANSP_PINNEDPUBKEY_V2 1
222 #endif
223
224 #if defined(SECTRANSP_PINNEDPUBKEY_V1) || defined(SECTRANSP_PINNEDPUBKEY_V2)
225 /* this backend supports CURLOPT_PINNEDPUBLICKEY */
226 #define SECTRANSP_PINNEDPUBKEY 1
227 #endif /* SECTRANSP_PINNEDPUBKEY */
228
229 #ifdef SECTRANSP_PINNEDPUBKEY
230 /* both new and old APIs return rsa keys missing the spki header (not DER) */
231 static const unsigned char rsa4096SpkiHeader[] = {
232 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d,
233 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
234 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
235 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00};
236
237 static const unsigned char rsa2048SpkiHeader[] = {
238 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
239 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
240 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
241 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00};
242 #ifdef SECTRANSP_PINNEDPUBKEY_V1
243 /* the *new* version does not return DER encoded ecdsa certs like the old... */
244 static const unsigned char ecDsaSecp256r1SpkiHeader[] = {
245 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
246 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
247 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
248 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
249 0x42, 0x00};
250
251 static const unsigned char ecDsaSecp384r1SpkiHeader[] = {
252 0x30, 0x76, 0x30, 0x10, 0x06, 0x07,
253 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
254 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04,
255 0x00, 0x22, 0x03, 0x62, 0x00};
256 #endif /* SECTRANSP_PINNEDPUBKEY_V1 */
257 #endif /* SECTRANSP_PINNEDPUBKEY */
258
sectransp_bio_cf_in_read(SSLConnectionRef connection,void * buf,size_t * dataLength)259 static OSStatus sectransp_bio_cf_in_read(SSLConnectionRef connection,
260 void *buf,
261 size_t *dataLength) /* IN/OUT */
262 {
263 struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
264 struct ssl_connect_data *connssl = cf->ctx;
265 struct st_ssl_backend_data *backend =
266 (struct st_ssl_backend_data *)connssl->backend;
267 struct Curl_easy *data = CF_DATA_CURRENT(cf);
268 ssize_t nread;
269 CURLcode result;
270 OSStatus rtn = noErr;
271
272 DEBUGASSERT(data);
273 nread = Curl_conn_cf_recv(cf->next, data, buf, *dataLength, &result);
274 CURL_TRC_CF(data, cf, "bio_read(len=%zu) -> %zd, result=%d",
275 *dataLength, nread, result);
276 if(nread < 0) {
277 switch(result) {
278 case CURLE_OK:
279 case CURLE_AGAIN:
280 rtn = errSSLWouldBlock;
281 backend->ssl_direction = FALSE;
282 break;
283 default:
284 rtn = ioErr;
285 break;
286 }
287 nread = 0;
288 }
289 else if(nread == 0) {
290 rtn = errSSLClosedGraceful;
291 }
292 else if((size_t)nread < *dataLength) {
293 rtn = errSSLWouldBlock;
294 }
295 *dataLength = nread;
296 return rtn;
297 }
298
sectransp_bio_cf_out_write(SSLConnectionRef connection,const void * buf,size_t * dataLength)299 static OSStatus sectransp_bio_cf_out_write(SSLConnectionRef connection,
300 const void *buf,
301 size_t *dataLength) /* IN/OUT */
302 {
303 struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
304 struct ssl_connect_data *connssl = cf->ctx;
305 struct st_ssl_backend_data *backend =
306 (struct st_ssl_backend_data *)connssl->backend;
307 struct Curl_easy *data = CF_DATA_CURRENT(cf);
308 ssize_t nwritten;
309 CURLcode result;
310 OSStatus rtn = noErr;
311
312 DEBUGASSERT(data);
313 nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, FALSE,
314 &result);
315 CURL_TRC_CF(data, cf, "bio_send(len=%zu) -> %zd, result=%d",
316 *dataLength, nwritten, result);
317 if(nwritten <= 0) {
318 if(result == CURLE_AGAIN) {
319 rtn = errSSLWouldBlock;
320 backend->ssl_direction = TRUE;
321 }
322 else {
323 rtn = ioErr;
324 }
325 nwritten = 0;
326 }
327 else if((size_t)nwritten < *dataLength) {
328 rtn = errSSLWouldBlock;
329 }
330 *dataLength = nwritten;
331 return rtn;
332 }
333
334 #if CURL_BUILD_MAC
GetDarwinVersionNumber(int * major,int * minor)335 CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
336 {
337 int mib[2];
338 char *os_version;
339 size_t os_version_len;
340 char *os_version_major, *os_version_minor;
341 char *tok_buf;
342
343 /* Get the Darwin kernel version from the kernel using sysctl(): */
344 mib[0] = CTL_KERN;
345 mib[1] = KERN_OSRELEASE;
346 if(sysctl(mib, 2, NULL, &os_version_len, NULL, 0) == -1)
347 return;
348 os_version = malloc(os_version_len*sizeof(char));
349 if(!os_version)
350 return;
351 if(sysctl(mib, 2, os_version, &os_version_len, NULL, 0) == -1) {
352 free(os_version);
353 return;
354 }
355
356 /* Parse the version: */
357 os_version_major = Curl_strtok_r(os_version, ".", &tok_buf);
358 os_version_minor = Curl_strtok_r(NULL, ".", &tok_buf);
359 *major = atoi(os_version_major);
360 *minor = atoi(os_version_minor);
361 free(os_version);
362 }
363 #endif /* CURL_BUILD_MAC */
364
365 /* Apple provides a myriad of ways of getting information about a certificate
366 into a string. Some are not available under iOS or newer cats. Here's a
367 unified function for getting a string describing the certificate that ought
368 to work in all cats starting with Leopard. */
getsubject(SecCertificateRef cert)369 CF_INLINE CFStringRef getsubject(SecCertificateRef cert)
370 {
371 CFStringRef server_cert_summary = CFSTR("(null)");
372
373 #if CURL_BUILD_IOS
374 /* iOS: There is only one way to do this. */
375 server_cert_summary = SecCertificateCopySubjectSummary(cert);
376 #else
377 #if CURL_BUILD_MAC_10_7
378 /* Lion & later: Get the long description if we can. */
379 if(&SecCertificateCopyLongDescription)
380 server_cert_summary =
381 SecCertificateCopyLongDescription(NULL, cert, NULL);
382 else
383 #endif /* CURL_BUILD_MAC_10_7 */
384 #if CURL_BUILD_MAC_10_6
385 /* Snow Leopard: Get the certificate summary. */
386 if(&SecCertificateCopySubjectSummary)
387 server_cert_summary = SecCertificateCopySubjectSummary(cert);
388 else
389 #endif /* CURL_BUILD_MAC_10_6 */
390 /* Leopard is as far back as we go... */
391 (void)SecCertificateCopyCommonName(cert, &server_cert_summary);
392 #endif /* CURL_BUILD_IOS */
393 return server_cert_summary;
394 }
395
CopyCertSubject(struct Curl_easy * data,SecCertificateRef cert,char ** certp)396 static CURLcode CopyCertSubject(struct Curl_easy *data,
397 SecCertificateRef cert, char **certp)
398 {
399 CFStringRef c = getsubject(cert);
400 CURLcode result = CURLE_OK;
401 const char *direct;
402 char *cbuf = NULL;
403 *certp = NULL;
404
405 if(!c) {
406 failf(data, "SSL: invalid CA certificate subject");
407 return CURLE_PEER_FAILED_VERIFICATION;
408 }
409
410 /* If the subject is already available as UTF-8 encoded (ie 'direct') then
411 use that, else convert it. */
412 direct = CFStringGetCStringPtr(c, kCFStringEncodingUTF8);
413 if(direct) {
414 *certp = strdup(direct);
415 if(!*certp) {
416 failf(data, "SSL: out of memory");
417 result = CURLE_OUT_OF_MEMORY;
418 }
419 }
420 else {
421 size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1;
422 cbuf = calloc(1, cbuf_size);
423 if(cbuf) {
424 if(!CFStringGetCString(c, cbuf, (CFIndex)cbuf_size,
425 kCFStringEncodingUTF8)) {
426 failf(data, "SSL: invalid CA certificate subject");
427 result = CURLE_PEER_FAILED_VERIFICATION;
428 }
429 else
430 /* pass back the buffer */
431 *certp = cbuf;
432 }
433 else {
434 failf(data, "SSL: could not allocate %zu bytes of memory", cbuf_size);
435 result = CURLE_OUT_OF_MEMORY;
436 }
437 }
438 if(result)
439 free(cbuf);
440 CFRelease(c);
441 return result;
442 }
443
444 #if CURL_SUPPORT_MAC_10_6
445 /* The SecKeychainSearch API was deprecated in Lion, and using it will raise
446 deprecation warnings, so let's not compile this unless it is necessary: */
CopyIdentityWithLabelOldSchool(char * label,SecIdentityRef * out_c_a_k)447 static OSStatus CopyIdentityWithLabelOldSchool(char *label,
448 SecIdentityRef *out_c_a_k)
449 {
450 OSStatus status = errSecItemNotFound;
451 SecKeychainAttributeList attr_list;
452 SecKeychainAttribute attr;
453 SecKeychainSearchRef search = NULL;
454 SecCertificateRef cert = NULL;
455
456 /* Set up the attribute list: */
457 attr_list.count = 1L;
458 attr_list.attr = &attr;
459
460 /* Set up our lone search criterion: */
461 attr.tag = kSecLabelItemAttr;
462 attr.data = label;
463 attr.length = (UInt32)strlen(label);
464
465 /* Start searching: */
466 status = SecKeychainSearchCreateFromAttributes(NULL,
467 kSecCertificateItemClass,
468 &attr_list,
469 &search);
470 if(status == noErr) {
471 status = SecKeychainSearchCopyNext(search,
472 (SecKeychainItemRef *)&cert);
473 if(status == noErr && cert) {
474 /* If we found a certificate, does it have a private key? */
475 status = SecIdentityCreateWithCertificate(NULL, cert, out_c_a_k);
476 CFRelease(cert);
477 }
478 }
479
480 if(search)
481 CFRelease(search);
482 return status;
483 }
484 #endif /* CURL_SUPPORT_MAC_10_6 */
485
CopyIdentityWithLabel(char * label,SecIdentityRef * out_cert_and_key)486 static OSStatus CopyIdentityWithLabel(char *label,
487 SecIdentityRef *out_cert_and_key)
488 {
489 OSStatus status = errSecItemNotFound;
490
491 #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
492 CFArrayRef keys_list;
493 CFIndex keys_list_count;
494 CFIndex i;
495
496 /* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
497 kSecClassIdentity was introduced in Lion. If both exist, let's use them
498 to find the certificate. */
499 if(&SecItemCopyMatching && kSecClassIdentity) {
500 CFTypeRef keys[5];
501 CFTypeRef values[5];
502 CFDictionaryRef query_dict;
503 CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
504 kCFStringEncodingUTF8);
505
506 /* Set up our search criteria and expected results: */
507 values[0] = kSecClassIdentity; /* we want a certificate and a key */
508 keys[0] = kSecClass;
509 values[1] = kCFBooleanTrue; /* we want a reference */
510 keys[1] = kSecReturnRef;
511 values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the
512 * label matching below worked correctly */
513 keys[2] = kSecMatchLimit;
514 /* identity searches need a SecPolicyRef in order to work */
515 values[3] = SecPolicyCreateSSL(FALSE, NULL);
516 keys[3] = kSecMatchPolicy;
517 /* match the name of the certificate (does not work in macOS 10.12.1) */
518 values[4] = label_cf;
519 keys[4] = kSecAttrLabel;
520 query_dict = CFDictionaryCreate(NULL, (const void **)keys,
521 (const void **)values, 5L,
522 &kCFCopyStringDictionaryKeyCallBacks,
523 &kCFTypeDictionaryValueCallBacks);
524 CFRelease(values[3]);
525
526 /* Do we have a match? */
527 status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list);
528
529 /* Because kSecAttrLabel matching does not work with kSecClassIdentity,
530 * we need to find the correct identity ourselves */
531 if(status == noErr) {
532 keys_list_count = CFArrayGetCount(keys_list);
533 *out_cert_and_key = NULL;
534 status = 1;
535 for(i = 0; i < keys_list_count; i++) {
536 OSStatus err = noErr;
537 SecCertificateRef cert = NULL;
538 SecIdentityRef identity =
539 (SecIdentityRef) CFArrayGetValueAtIndex(keys_list, i);
540 err = SecIdentityCopyCertificate(identity, &cert);
541 if(err == noErr) {
542 CFStringRef common_name = NULL;
543 OSStatus copy_status = noErr;
544 #if CURL_BUILD_IOS
545 common_name = SecCertificateCopySubjectSummary(cert);
546 #elif CURL_BUILD_MAC_10_7
547 copy_status = SecCertificateCopyCommonName(cert, &common_name);
548 #endif
549 if(copy_status == noErr &&
550 CFStringCompare(common_name, label_cf, 0) == kCFCompareEqualTo) {
551 CFRelease(cert);
552 CFRelease(common_name);
553 CFRetain(identity);
554 *out_cert_and_key = identity;
555 status = noErr;
556 break;
557 }
558 if(common_name)
559 CFRelease(common_name);
560 }
561 CFRelease(cert);
562 }
563 }
564
565 if(keys_list)
566 CFRelease(keys_list);
567 CFRelease(query_dict);
568 CFRelease(label_cf);
569 }
570 else {
571 #if CURL_SUPPORT_MAC_10_6
572 /* On Leopard and Snow Leopard, fall back to SecKeychainSearch. */
573 status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
574 #endif /* CURL_SUPPORT_MAC_10_6 */
575 }
576 #elif CURL_SUPPORT_MAC_10_6
577 /* For developers building on older cats, we have no choice but to fall back
578 to SecKeychainSearch. */
579 status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
580 #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
581 return status;
582 }
583
CopyIdentityFromPKCS12File(const char * cPath,const struct curl_blob * blob,const char * cPassword,SecIdentityRef * out_cert_and_key)584 static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
585 const struct curl_blob *blob,
586 const char *cPassword,
587 SecIdentityRef *out_cert_and_key)
588 {
589 OSStatus status = errSecItemNotFound;
590 CFURLRef pkcs_url = NULL;
591 CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
592 cPassword, kCFStringEncodingUTF8) : NULL;
593 CFDataRef pkcs_data = NULL;
594
595 /* We can import P12 files on iOS or macOS 10.7 or later: */
596 /* These constants are documented as having first appeared in 10.6 but they
597 raise linker errors when used on that cat for some reason. */
598 #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
599 bool resource_imported;
600
601 if(blob) {
602 pkcs_data = CFDataCreate(kCFAllocatorDefault,
603 (const unsigned char *)blob->data,
604 (CFIndex)blob->len);
605 status = (pkcs_data != NULL) ? errSecSuccess : errSecAllocate;
606 resource_imported = (pkcs_data != NULL);
607 }
608 else {
609 pkcs_url =
610 CFURLCreateFromFileSystemRepresentation(NULL,
611 (const UInt8 *)cPath,
612 (CFIndex)strlen(cPath), FALSE);
613 resource_imported =
614 CFURLCreateDataAndPropertiesFromResource(NULL,
615 pkcs_url, &pkcs_data,
616 NULL, NULL, &status);
617 }
618
619 if(resource_imported) {
620 CFArrayRef items = NULL;
621
622 /* On iOS SecPKCS12Import will never add the client certificate to the
623 * Keychain.
624 *
625 * It gives us back a SecIdentityRef that we can use directly. */
626 #if CURL_BUILD_IOS
627 const void *cKeys[] = {kSecImportExportPassphrase};
628 const void *cValues[] = {password};
629 CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
630 password ? 1L : 0L, NULL, NULL);
631
632 if(options) {
633 status = SecPKCS12Import(pkcs_data, options, &items);
634 CFRelease(options);
635 }
636
637
638 /* On macOS SecPKCS12Import will always add the client certificate to
639 * the Keychain.
640 *
641 * As this does not match iOS, and apps may not want to see their client
642 * certificate saved in the user's keychain, we use SecItemImport
643 * with a NULL keychain to avoid importing it.
644 *
645 * This returns a SecCertificateRef from which we can construct a
646 * SecIdentityRef.
647 */
648 #elif CURL_BUILD_MAC_10_7
649 SecItemImportExportKeyParameters keyParams;
650 SecExternalFormat inputFormat = kSecFormatPKCS12;
651 SecExternalItemType inputType = kSecItemTypeCertificate;
652
653 memset(&keyParams, 0x00, sizeof(keyParams));
654 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
655 keyParams.passphrase = password;
656
657 status = SecItemImport(pkcs_data, NULL, &inputFormat, &inputType,
658 0, &keyParams, NULL, &items);
659 #endif
660
661
662 /* Extract the SecIdentityRef */
663 if(status == errSecSuccess && items && CFArrayGetCount(items)) {
664 CFIndex i, count;
665 count = CFArrayGetCount(items);
666
667 for(i = 0; i < count; i++) {
668 CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(items, i);
669 CFTypeID itemID = CFGetTypeID(item);
670
671 if(itemID == CFDictionaryGetTypeID()) {
672 CFTypeRef identity = (CFTypeRef) CFDictionaryGetValue(
673 (CFDictionaryRef) item,
674 kSecImportItemIdentity);
675 CFRetain(identity);
676 *out_cert_and_key = (SecIdentityRef) identity;
677 break;
678 }
679 #if CURL_BUILD_MAC_10_7
680 else if(itemID == SecCertificateGetTypeID()) {
681 status = SecIdentityCreateWithCertificate(NULL,
682 (SecCertificateRef) item,
683 out_cert_and_key);
684 break;
685 }
686 #endif
687 }
688 }
689
690 if(items)
691 CFRelease(items);
692 CFRelease(pkcs_data);
693 }
694 #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
695 if(password)
696 CFRelease(password);
697 if(pkcs_url)
698 CFRelease(pkcs_url);
699 return status;
700 }
701
702 /* This code was borrowed from nss.c, with some modifications:
703 * Determine whether the nickname passed in is a filename that needs to
704 * be loaded as a PEM or a nickname.
705 *
706 * returns 1 for a file
707 * returns 0 for not a file
708 */
is_file(const char * filename)709 CF_INLINE bool is_file(const char *filename)
710 {
711 struct_stat st;
712
713 if(!filename)
714 return FALSE;
715
716 if(stat(filename, &st) == 0)
717 return S_ISREG(st.st_mode);
718 return FALSE;
719 }
720
721 static CURLcode
sectransp_set_ssl_version_min_max(struct Curl_easy * data,struct st_ssl_backend_data * backend,struct ssl_primary_config * conn_config)722 sectransp_set_ssl_version_min_max(struct Curl_easy *data,
723 struct st_ssl_backend_data *backend,
724 struct ssl_primary_config *conn_config)
725 {
726 #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
727 OSStatus err;
728 SSLProtocol ver_min;
729 SSLProtocol ver_max;
730
731 #if CURL_SUPPORT_MAC_10_7
732 if(!&SSLSetProtocolVersionMax)
733 goto legacy;
734 #endif
735
736 switch(conn_config->version) {
737 case CURL_SSLVERSION_DEFAULT:
738 case CURL_SSLVERSION_TLSv1:
739 case CURL_SSLVERSION_TLSv1_0:
740 ver_min = kTLSProtocol1;
741 break;
742 case CURL_SSLVERSION_TLSv1_1:
743 ver_min = kTLSProtocol11;
744 break;
745 case CURL_SSLVERSION_TLSv1_2:
746 ver_min = kTLSProtocol12;
747 break;
748 case CURL_SSLVERSION_TLSv1_3:
749 default:
750 failf(data, "SSL: unsupported minimum TLS version value");
751 return CURLE_SSL_CONNECT_ERROR;
752 }
753
754 switch(conn_config->version_max) {
755 case CURL_SSLVERSION_MAX_DEFAULT:
756 case CURL_SSLVERSION_MAX_NONE:
757 case CURL_SSLVERSION_MAX_TLSv1_3:
758 case CURL_SSLVERSION_MAX_TLSv1_2:
759 ver_max = kTLSProtocol12;
760 break;
761 case CURL_SSLVERSION_MAX_TLSv1_1:
762 ver_max = kTLSProtocol11;
763 break;
764 case CURL_SSLVERSION_MAX_TLSv1_0:
765 ver_max = kTLSProtocol1;
766 break;
767 default:
768 failf(data, "SSL: unsupported maximum TLS version value");
769 return CURLE_SSL_CONNECT_ERROR;
770 }
771
772 err = SSLSetProtocolVersionMin(backend->ssl_ctx, ver_min);
773 if(err != noErr) {
774 failf(data, "SSL: failed to set minimum TLS version");
775 return CURLE_SSL_CONNECT_ERROR;
776 }
777 err = SSLSetProtocolVersionMax(backend->ssl_ctx, ver_max);
778 if(err != noErr) {
779 failf(data, "SSL: failed to set maximum TLS version");
780 return CURLE_SSL_CONNECT_ERROR;
781 }
782
783 return CURLE_OK;
784 #endif
785 #if CURL_SUPPORT_MAC_10_7
786 goto legacy;
787 legacy:
788 switch(conn_config->version) {
789 case CURL_SSLVERSION_DEFAULT:
790 case CURL_SSLVERSION_TLSv1:
791 case CURL_SSLVERSION_TLSv1_0:
792 break;
793 default:
794 failf(data, "SSL: unsupported minimum TLS version value");
795 return CURLE_SSL_CONNECT_ERROR;
796 }
797
798 /* only TLS 1.0 is supported, disable SSL 3.0 and SSL 2.0 */
799 SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, FALSE);
800 SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, TRUE);
801
802 return CURLE_OK;
803 #endif
804 }
805
sectransp_cipher_suite_get_str(uint16_t id,char * buf,size_t buf_size,bool prefer_rfc)806 static int sectransp_cipher_suite_get_str(uint16_t id, char *buf,
807 size_t buf_size, bool prefer_rfc)
808 {
809 /* are these fortezza suites even supported ? */
810 if(id == SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA)
811 msnprintf(buf, buf_size, "%s", "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA");
812 else if(id == SSL_FORTEZZA_DMS_WITH_NULL_SHA)
813 msnprintf(buf, buf_size, "%s", "SSL_FORTEZZA_DMS_WITH_NULL_SHA");
814 /* can TLS_EMPTY_RENEGOTIATION_INFO_SCSV even be set ? */
815 else if(id == TLS_EMPTY_RENEGOTIATION_INFO_SCSV)
816 msnprintf(buf, buf_size, "%s", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV");
817 /* do we still need to support these SSL2-only ciphers ? */
818 else if(id == SSL_RSA_WITH_RC2_CBC_MD5)
819 msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_RC2_CBC_MD5");
820 else if(id == SSL_RSA_WITH_IDEA_CBC_MD5)
821 msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_IDEA_CBC_MD5");
822 else if(id == SSL_RSA_WITH_DES_CBC_MD5)
823 msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_DES_CBC_MD5");
824 else if(id == SSL_RSA_WITH_3DES_EDE_CBC_MD5)
825 msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_3DES_EDE_CBC_MD5");
826 else
827 return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc);
828 return 0;
829 }
830
sectransp_cipher_suite_walk_str(const char ** str,const char ** end)831 static uint16_t sectransp_cipher_suite_walk_str(const char **str,
832 const char **end)
833 {
834 uint16_t id = Curl_cipher_suite_walk_str(str, end);
835 size_t len = *end - *str;
836
837 if(!id) {
838 /* are these fortezza suites even supported ? */
839 if(strncasecompare("SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA", *str, len))
840 id = SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA;
841 else if(strncasecompare("SSL_FORTEZZA_DMS_WITH_NULL_SHA", *str, len))
842 id = SSL_FORTEZZA_DMS_WITH_NULL_SHA;
843 /* can TLS_EMPTY_RENEGOTIATION_INFO_SCSV even be set ? */
844 else if(strncasecompare("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", *str, len))
845 id = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
846 /* do we still need to support these SSL2-only ciphers ? */
847 else if(strncasecompare("SSL_RSA_WITH_RC2_CBC_MD5", *str, len))
848 id = SSL_RSA_WITH_RC2_CBC_MD5;
849 else if(strncasecompare("SSL_RSA_WITH_IDEA_CBC_MD5", *str, len))
850 id = SSL_RSA_WITH_IDEA_CBC_MD5;
851 else if(strncasecompare("SSL_RSA_WITH_DES_CBC_MD5", *str, len))
852 id = SSL_RSA_WITH_DES_CBC_MD5;
853 else if(strncasecompare("SSL_RSA_WITH_3DES_EDE_CBC_MD5", *str, len))
854 id = SSL_RSA_WITH_3DES_EDE_CBC_MD5;
855 }
856 return id;
857 }
858
859 /* allocated memory must be freed */
sectransp_get_supported_ciphers(SSLContextRef ssl_ctx,size_t * len)860 static SSLCipherSuite * sectransp_get_supported_ciphers(SSLContextRef ssl_ctx,
861 size_t *len)
862 {
863 SSLCipherSuite *ciphers = NULL;
864 OSStatus err = noErr;
865 *len = 0;
866
867 err = SSLGetNumberSupportedCiphers(ssl_ctx, len);
868 if(err != noErr)
869 goto failed;
870
871 ciphers = malloc(*len * sizeof(SSLCipherSuite));
872 if(!ciphers)
873 goto failed;
874
875 err = SSLGetSupportedCiphers(ssl_ctx, ciphers, len);
876 if(err != noErr)
877 goto failed;
878
879 #if CURL_BUILD_MAC
880 {
881 int maj = 0, min = 0;
882 GetDarwinVersionNumber(&maj, &min);
883 /* There is a known bug in early versions of Mountain Lion where ST's ECC
884 ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
885 Work around the problem here by disabling those ciphers if we are
886 running in an affected version of macOS. */
887 if(maj == 12 && min <= 3) {
888 size_t i = 0, j = 0;
889 for(; i < *len; i++) {
890 if(ciphers[i] >= 0xC001 && ciphers[i] <= 0xC032)
891 continue;
892 ciphers[j++] = ciphers[i];
893 }
894 *len = j;
895 }
896 }
897 #endif
898
899 return ciphers;
900 failed:
901 *len = 0;
902 Curl_safefree(ciphers);
903 return NULL;
904 }
905
sectransp_set_default_ciphers(struct Curl_easy * data,SSLContextRef ssl_ctx)906 static CURLcode sectransp_set_default_ciphers(struct Curl_easy *data,
907 SSLContextRef ssl_ctx)
908 {
909 CURLcode ret = CURLE_SSL_CIPHER;
910 size_t count = 0, i, j;
911 OSStatus err;
912 size_t supported_len;
913 SSLCipherSuite *ciphers = NULL;
914
915 ciphers = sectransp_get_supported_ciphers(ssl_ctx, &supported_len);
916 if(!ciphers) {
917 failf(data, "SSL: Failed to get supported ciphers");
918 goto failed;
919 }
920
921 /* Intersect the ciphers supported by Secure Transport with the default
922 * ciphers, using the order of the former. */
923 for(i = 0; i < supported_len; i++) {
924 for(j = 0; j < DEFAULT_CIPHERS_LEN; j++) {
925 if(default_ciphers[j] == ciphers[i]) {
926 ciphers[count++] = ciphers[i];
927 break;
928 }
929 }
930 }
931
932 if(count == 0) {
933 failf(data, "SSL: no supported default ciphers");
934 goto failed;
935 }
936
937 err = SSLSetEnabledCiphers(ssl_ctx, ciphers, count);
938 if(err != noErr) {
939 failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
940 goto failed;
941 }
942
943 ret = CURLE_OK;
944 failed:
945 Curl_safefree(ciphers);
946 return ret;
947 }
948
sectransp_set_selected_ciphers(struct Curl_easy * data,SSLContextRef ssl_ctx,const char * ciphers)949 static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
950 SSLContextRef ssl_ctx,
951 const char *ciphers)
952 {
953 CURLcode ret = CURLE_SSL_CIPHER;
954 size_t count = 0, i;
955 const char *ptr, *end;
956 OSStatus err;
957 size_t supported_len;
958 SSLCipherSuite *supported = NULL;
959 SSLCipherSuite *selected = NULL;
960
961 supported = sectransp_get_supported_ciphers(ssl_ctx, &supported_len);
962 if(!supported) {
963 failf(data, "SSL: Failed to get supported ciphers");
964 goto failed;
965 }
966
967 selected = malloc(supported_len * sizeof(SSLCipherSuite));
968 if(!selected) {
969 failf(data, "SSL: Failed to allocate memory");
970 goto failed;
971 }
972
973 for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) {
974 uint16_t id = sectransp_cipher_suite_walk_str(&ptr, &end);
975
976 /* Check if cipher is supported */
977 if(id) {
978 for(i = 0; i < supported_len && supported[i] != id; i++);
979 if(i == supported_len)
980 id = 0;
981 }
982 if(!id) {
983 if(ptr[0] != '\0')
984 infof(data, "SSL: unknown cipher in list: \"%.*s\"", (int) (end - ptr),
985 ptr);
986 continue;
987 }
988
989 /* No duplicates allowed (so selected cannot overflow) */
990 for(i = 0; i < count && selected[i] != id; i++);
991 if(i < count) {
992 infof(data, "SSL: duplicate cipher in list: \"%.*s\"", (int) (end - ptr),
993 ptr);
994 continue;
995 }
996
997 selected[count++] = id;
998 }
999
1000 if(count == 0) {
1001 failf(data, "SSL: no supported cipher in list");
1002 goto failed;
1003 }
1004
1005 err = SSLSetEnabledCiphers(ssl_ctx, selected, count);
1006 if(err != noErr) {
1007 failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
1008 goto failed;
1009 }
1010
1011 ret = CURLE_OK;
1012 failed:
1013 Curl_safefree(supported);
1014 Curl_safefree(selected);
1015 return ret;
1016 }
1017
sectransp_session_free(void * sessionid,size_t idsize)1018 static void sectransp_session_free(void *sessionid, size_t idsize)
1019 {
1020 /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
1021 cached session ID inside the Security framework. There is a private
1022 function that does this, but I do not want to have to explain to you why I
1023 got your application rejected from the App Store due to the use of a
1024 private API, so the best we can do is free up our own char array that we
1025 created way back in sectransp_connect_step1... */
1026 (void)idsize;
1027 Curl_safefree(sessionid);
1028 }
1029
sectransp_connect_step1(struct Curl_cfilter * cf,struct Curl_easy * data)1030 static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
1031 struct Curl_easy *data)
1032 {
1033 struct ssl_connect_data *connssl = cf->ctx;
1034 struct st_ssl_backend_data *backend =
1035 (struct st_ssl_backend_data *)connssl->backend;
1036 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
1037 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
1038 const struct curl_blob *ssl_cablob = conn_config->ca_info_blob;
1039 const char * const ssl_cafile =
1040 /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
1041 (ssl_cablob ? NULL : conn_config->CAfile);
1042 const bool verifypeer = conn_config->verifypeer;
1043 char * const ssl_cert = ssl_config->primary.clientcert;
1044 const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
1045 char *ciphers;
1046 OSStatus err = noErr;
1047 CURLcode result;
1048 #if CURL_BUILD_MAC
1049 int darwinver_maj = 0, darwinver_min = 0;
1050
1051 DEBUGASSERT(backend);
1052
1053 CURL_TRC_CF(data, cf, "connect_step1");
1054 GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
1055 #endif /* CURL_BUILD_MAC */
1056
1057 #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
1058 if(&SSLCreateContext) { /* use the newer API if available */
1059 if(backend->ssl_ctx)
1060 CFRelease(backend->ssl_ctx);
1061 backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
1062 if(!backend->ssl_ctx) {
1063 failf(data, "SSL: could not create a context");
1064 return CURLE_OUT_OF_MEMORY;
1065 }
1066 }
1067 else {
1068 /* The old ST API does not exist under iOS, so do not compile it: */
1069 #if CURL_SUPPORT_MAC_10_8
1070 if(backend->ssl_ctx)
1071 (void)SSLDisposeContext(backend->ssl_ctx);
1072 err = SSLNewContext(FALSE, &(backend->ssl_ctx));
1073 if(err != noErr) {
1074 failf(data, "SSL: could not create a context: OSStatus %d", err);
1075 return CURLE_OUT_OF_MEMORY;
1076 }
1077 #endif /* CURL_SUPPORT_MAC_10_8 */
1078 }
1079 #else
1080 if(backend->ssl_ctx)
1081 (void)SSLDisposeContext(backend->ssl_ctx);
1082 err = SSLNewContext(FALSE, &(backend->ssl_ctx));
1083 if(err != noErr) {
1084 failf(data, "SSL: could not create a context: OSStatus %d", err);
1085 return CURLE_OUT_OF_MEMORY;
1086 }
1087 #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
1088 backend->ssl_write_buffered_length = 0UL; /* reset buffered write length */
1089
1090 result = sectransp_set_ssl_version_min_max(data, backend, conn_config);
1091 if(result != CURLE_OK)
1092 return result;
1093
1094 #if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
1095 defined(HAVE_BUILTIN_AVAILABLE)
1096 if(connssl->alpn) {
1097 if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
1098 struct alpn_proto_buf proto;
1099 size_t i;
1100 CFStringRef cstr;
1101 CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0,
1102 &kCFTypeArrayCallBacks);
1103 for(i = 0; i < connssl->alpn->count; ++i) {
1104 cstr = CFStringCreateWithCString(NULL, connssl->alpn->entries[i],
1105 kCFStringEncodingUTF8);
1106 if(!cstr)
1107 return CURLE_OUT_OF_MEMORY;
1108 CFArrayAppendValue(alpnArr, cstr);
1109 CFRelease(cstr);
1110 }
1111 err = SSLSetALPNProtocols(backend->ssl_ctx, alpnArr);
1112 if(err != noErr)
1113 infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d",
1114 err);
1115 CFRelease(alpnArr);
1116 Curl_alpn_to_proto_str(&proto, connssl->alpn);
1117 infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
1118 }
1119 }
1120 #endif
1121
1122 if(ssl_config->key) {
1123 infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure "
1124 "Transport. The private key must be in the Keychain.");
1125 }
1126
1127 if(ssl_cert || ssl_cert_blob) {
1128 bool is_cert_data = ssl_cert_blob != NULL;
1129 bool is_cert_file = (!is_cert_data) && is_file(ssl_cert);
1130 SecIdentityRef cert_and_key = NULL;
1131
1132 /* User wants to authenticate with a client cert. Look for it. Assume that
1133 the user wants to use an identity loaded from the Keychain. If not, try
1134 it as a file on disk */
1135
1136 if(!is_cert_data)
1137 err = CopyIdentityWithLabel(ssl_cert, &cert_and_key);
1138 else
1139 err = !noErr;
1140 if((err != noErr) && (is_cert_file || is_cert_data)) {
1141 if(!ssl_config->cert_type)
1142 infof(data, "SSL: Certificate type not set, assuming "
1143 "PKCS#12 format.");
1144 else if(!strcasecompare(ssl_config->cert_type, "P12")) {
1145 failf(data, "SSL: The Security framework only supports "
1146 "loading identities that are in PKCS#12 format.");
1147 return CURLE_SSL_CERTPROBLEM;
1148 }
1149
1150 err = CopyIdentityFromPKCS12File(ssl_cert, ssl_cert_blob,
1151 ssl_config->key_passwd,
1152 &cert_and_key);
1153 }
1154
1155 if(err == noErr && cert_and_key) {
1156 SecCertificateRef cert = NULL;
1157 CFTypeRef certs_c[1];
1158 CFArrayRef certs;
1159
1160 /* If we found one, print it out: */
1161 err = SecIdentityCopyCertificate(cert_and_key, &cert);
1162 if(err == noErr) {
1163 char *certp;
1164 result = CopyCertSubject(data, cert, &certp);
1165 if(!result) {
1166 infof(data, "Client certificate: %s", certp);
1167 free(certp);
1168 }
1169
1170 CFRelease(cert);
1171 if(result == CURLE_PEER_FAILED_VERIFICATION)
1172 return CURLE_SSL_CERTPROBLEM;
1173 if(result)
1174 return result;
1175 }
1176 certs_c[0] = cert_and_key;
1177 certs = CFArrayCreate(NULL, (const void **)certs_c, 1L,
1178 &kCFTypeArrayCallBacks);
1179 err = SSLSetCertificate(backend->ssl_ctx, certs);
1180 if(certs)
1181 CFRelease(certs);
1182 if(err != noErr) {
1183 failf(data, "SSL: SSLSetCertificate() failed: OSStatus %d", err);
1184 return CURLE_SSL_CERTPROBLEM;
1185 }
1186 CFRelease(cert_and_key);
1187 }
1188 else {
1189 const char *cert_showfilename_error =
1190 is_cert_data ? "(memory blob)" : ssl_cert;
1191
1192 switch(err) {
1193 case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */
1194 failf(data, "SSL: Incorrect password for the certificate \"%s\" "
1195 "and its private key.", cert_showfilename_error);
1196 break;
1197 case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */
1198 failf(data, "SSL: Couldn't make sense of the data in the "
1199 "certificate \"%s\" and its private key.",
1200 cert_showfilename_error);
1201 break;
1202 case -25260: /* errSecPassphraseRequired */
1203 failf(data, "SSL The certificate \"%s\" requires a password.",
1204 cert_showfilename_error);
1205 break;
1206 case errSecItemNotFound:
1207 failf(data, "SSL: cannot find the certificate \"%s\" and its private "
1208 "key in the Keychain.", cert_showfilename_error);
1209 break;
1210 default:
1211 failf(data, "SSL: cannot load the certificate \"%s\" and its private "
1212 "key: OSStatus %d", cert_showfilename_error, err);
1213 break;
1214 }
1215 return CURLE_SSL_CERTPROBLEM;
1216 }
1217 }
1218
1219 /* SSL always tries to verify the peer, this only says whether it should
1220 * fail to connect if the verification fails, or if it should continue
1221 * anyway. In the latter case the result of the verification is checked with
1222 * SSL_get_verify_result() below. */
1223 #if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
1224 /* Snow Leopard introduced the SSLSetSessionOption() function, but due to
1225 a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag
1226 works, it does not work as expected under Snow Leopard, Lion or
1227 Mountain Lion.
1228 So we need to call SSLSetEnableCertVerify() on those older cats in order
1229 to disable certificate validation if the user turned that off.
1230 (Secure Transport always validates the certificate chain by default.)
1231 Note:
1232 Darwin 11.x.x is Lion (10.7)
1233 Darwin 12.x.x is Mountain Lion (10.8)
1234 Darwin 13.x.x is Mavericks (10.9)
1235 Darwin 14.x.x is Yosemite (10.10)
1236 Darwin 15.x.x is El Capitan (10.11)
1237 */
1238 #if CURL_BUILD_MAC
1239 if(&SSLSetSessionOption && darwinver_maj >= 13) {
1240 #else
1241 if(&SSLSetSessionOption) {
1242 #endif /* CURL_BUILD_MAC */
1243 bool break_on_auth = !conn_config->verifypeer ||
1244 ssl_cafile || ssl_cablob;
1245 err = SSLSetSessionOption(backend->ssl_ctx,
1246 kSSLSessionOptionBreakOnServerAuth,
1247 break_on_auth);
1248 if(err != noErr) {
1249 failf(data, "SSL: SSLSetSessionOption() failed: OSStatus %d", err);
1250 return CURLE_SSL_CONNECT_ERROR;
1251 }
1252 }
1253 else {
1254 #if CURL_SUPPORT_MAC_10_8
1255 err = SSLSetEnableCertVerify(backend->ssl_ctx,
1256 conn_config->verifypeer ? true : FALSE);
1257 if(err != noErr) {
1258 failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
1259 return CURLE_SSL_CONNECT_ERROR;
1260 }
1261 #endif /* CURL_SUPPORT_MAC_10_8 */
1262 }
1263 #else
1264 err = SSLSetEnableCertVerify(backend->ssl_ctx,
1265 conn_config->verifypeer ? true : FALSE);
1266 if(err != noErr) {
1267 failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
1268 return CURLE_SSL_CONNECT_ERROR;
1269 }
1270 #endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
1271
1272 if((ssl_cafile || ssl_cablob) && verifypeer) {
1273 bool is_cert_data = ssl_cablob != NULL;
1274 bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile);
1275
1276 if(!(is_cert_file || is_cert_data)) {
1277 failf(data, "SSL: cannot load CA certificate file %s",
1278 ssl_cafile ? ssl_cafile : "(blob memory)");
1279 return CURLE_SSL_CACERT_BADFILE;
1280 }
1281 }
1282
1283 /* Configure hostname check. SNI is used if available.
1284 * Both hostname check and SNI require SSLSetPeerDomainName().
1285 * Also: the verifyhost setting influences SNI usage */
1286 if(conn_config->verifyhost) {
1287 char *server = connssl->peer.sni ?
1288 connssl->peer.sni : connssl->peer.hostname;
1289 err = SSLSetPeerDomainName(backend->ssl_ctx, server, strlen(server));
1290
1291 if(err != noErr) {
1292 failf(data, "SSL: SSLSetPeerDomainName() failed: OSStatus %d",
1293 err);
1294 return CURLE_SSL_CONNECT_ERROR;
1295 }
1296
1297 if(connssl->peer.type != CURL_SSL_PEER_DNS) {
1298 infof(data, "WARNING: using IP address, SNI is being disabled by "
1299 "the OS.");
1300 }
1301 }
1302 else {
1303 infof(data, "WARNING: disabling hostname validation also disables SNI.");
1304 }
1305
1306 ciphers = conn_config->cipher_list;
1307 if(ciphers) {
1308 result = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers);
1309 }
1310 else {
1311 result = sectransp_set_default_ciphers(data, backend->ssl_ctx);
1312 }
1313 if(result != CURLE_OK) {
1314 failf(data, "SSL: Unable to set ciphers for SSL/TLS handshake. "
1315 "Error code: %d", (int)result);
1316 return CURLE_SSL_CIPHER;
1317 }
1318
1319 #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
1320 /* We want to enable 1/n-1 when using a CBC cipher unless the user
1321 specifically does not want us doing that: */
1322 if(&SSLSetSessionOption) {
1323 SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
1324 !ssl_config->enable_beast);
1325 SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart,
1326 ssl_config->falsestart); /* false start support */
1327 }
1328 #endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
1329
1330 /* Check if there is a cached ID we can/should use here! */
1331 if(ssl_config->primary.cache_session) {
1332 char *ssl_sessionid;
1333 size_t ssl_sessionid_len;
1334
1335 Curl_ssl_sessionid_lock(data);
1336 if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
1337 (void **)&ssl_sessionid, &ssl_sessionid_len,
1338 NULL)) {
1339 /* we got a session id, use it! */
1340 err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
1341 Curl_ssl_sessionid_unlock(data);
1342 if(err != noErr) {
1343 failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
1344 return CURLE_SSL_CONNECT_ERROR;
1345 }
1346 /* Informational message */
1347 infof(data, "SSL reusing session ID");
1348 }
1349 /* If there is not one, then let's make one up! This has to be done prior
1350 to starting the handshake. */
1351 else {
1352 ssl_sessionid =
1353 aprintf("%s:%d:%d:%s:%d",
1354 ssl_cafile ? ssl_cafile : "(blob memory)",
1355 verifypeer, conn_config->verifyhost, connssl->peer.hostname,
1356 connssl->peer.port);
1357 ssl_sessionid_len = strlen(ssl_sessionid);
1358
1359 err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
1360 if(err != noErr) {
1361 Curl_ssl_sessionid_unlock(data);
1362 failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
1363 return CURLE_SSL_CONNECT_ERROR;
1364 }
1365
1366 result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, NULL,
1367 ssl_sessionid, ssl_sessionid_len,
1368 sectransp_session_free);
1369 Curl_ssl_sessionid_unlock(data);
1370 if(result)
1371 return result;
1372 }
1373 }
1374
1375 err = SSLSetIOFuncs(backend->ssl_ctx,
1376 sectransp_bio_cf_in_read,
1377 sectransp_bio_cf_out_write);
1378 if(err != noErr) {
1379 failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err);
1380 return CURLE_SSL_CONNECT_ERROR;
1381 }
1382
1383 err = SSLSetConnection(backend->ssl_ctx, cf);
1384 if(err != noErr) {
1385 failf(data, "SSL: SSLSetConnection() failed: %d", err);
1386 return CURLE_SSL_CONNECT_ERROR;
1387 }
1388
1389 connssl->connecting_state = ssl_connect_2;
1390 return CURLE_OK;
1391 }
1392
1393 static long pem_to_der(const char *in, unsigned char **out, size_t *outlen)
1394 {
1395 char *sep_start, *sep_end, *cert_start, *cert_end;
1396 size_t i, j, err;
1397 size_t len;
1398 char *b64;
1399
1400 /* Jump through the separators at the beginning of the certificate. */
1401 sep_start = strstr(in, "-----");
1402 if(!sep_start)
1403 return 0;
1404 cert_start = strstr(sep_start + 1, "-----");
1405 if(!cert_start)
1406 return -1;
1407
1408 cert_start += 5;
1409
1410 /* Find separator after the end of the certificate. */
1411 cert_end = strstr(cert_start, "-----");
1412 if(!cert_end)
1413 return -1;
1414
1415 sep_end = strstr(cert_end + 1, "-----");
1416 if(!sep_end)
1417 return -1;
1418 sep_end += 5;
1419
1420 len = cert_end - cert_start;
1421 b64 = malloc(len + 1);
1422 if(!b64)
1423 return -1;
1424
1425 /* Create base64 string without linefeeds. */
1426 for(i = 0, j = 0; i < len; i++) {
1427 if(cert_start[i] != '\r' && cert_start[i] != '\n')
1428 b64[j++] = cert_start[i];
1429 }
1430 b64[j] = '\0';
1431
1432 err = Curl_base64_decode((const char *)b64, out, outlen);
1433 free(b64);
1434 if(err) {
1435 free(*out);
1436 return -1;
1437 }
1438
1439 return sep_end - in;
1440 }
1441
1442 #define MAX_CERTS_SIZE (50*1024*1024) /* arbitrary - to catch mistakes */
1443
1444 static int read_cert(const char *file, unsigned char **out, size_t *outlen)
1445 {
1446 int fd;
1447 ssize_t n;
1448 unsigned char buf[512];
1449 struct dynbuf certs;
1450
1451 Curl_dyn_init(&certs, MAX_CERTS_SIZE);
1452
1453 fd = open(file, 0);
1454 if(fd < 0)
1455 return -1;
1456
1457 for(;;) {
1458 n = read(fd, buf, sizeof(buf));
1459 if(!n)
1460 break;
1461 if(n < 0) {
1462 close(fd);
1463 Curl_dyn_free(&certs);
1464 return -1;
1465 }
1466 if(Curl_dyn_addn(&certs, buf, n)) {
1467 close(fd);
1468 return -1;
1469 }
1470 }
1471 close(fd);
1472
1473 *out = Curl_dyn_uptr(&certs);
1474 *outlen = Curl_dyn_len(&certs);
1475
1476 return 0;
1477 }
1478
1479 static CURLcode append_cert_to_array(struct Curl_easy *data,
1480 const unsigned char *buf, size_t buflen,
1481 CFMutableArrayRef array)
1482 {
1483 char *certp;
1484 CURLcode result;
1485 SecCertificateRef cacert;
1486 CFDataRef certdata;
1487
1488 certdata = CFDataCreate(kCFAllocatorDefault, buf, (CFIndex)buflen);
1489 if(!certdata) {
1490 failf(data, "SSL: failed to allocate array for CA certificate");
1491 return CURLE_OUT_OF_MEMORY;
1492 }
1493
1494 cacert = SecCertificateCreateWithData(kCFAllocatorDefault, certdata);
1495 CFRelease(certdata);
1496 if(!cacert) {
1497 failf(data, "SSL: failed to create SecCertificate from CA certificate");
1498 return CURLE_SSL_CACERT_BADFILE;
1499 }
1500
1501 /* Check if cacert is valid. */
1502 result = CopyCertSubject(data, cacert, &certp);
1503 switch(result) {
1504 case CURLE_OK:
1505 break;
1506 case CURLE_PEER_FAILED_VERIFICATION:
1507 return CURLE_SSL_CACERT_BADFILE;
1508 case CURLE_OUT_OF_MEMORY:
1509 default:
1510 return result;
1511 }
1512 free(certp);
1513
1514 CFArrayAppendValue(array, cacert);
1515 CFRelease(cacert);
1516
1517 return CURLE_OK;
1518 }
1519
1520 static CURLcode verify_cert_buf(struct Curl_cfilter *cf,
1521 struct Curl_easy *data,
1522 const unsigned char *certbuf, size_t buflen,
1523 SSLContextRef ctx)
1524 {
1525 int n = 0;
1526 CURLcode rc;
1527 long res;
1528 unsigned char *der;
1529 size_t derlen, offset = 0;
1530 OSStatus ret;
1531 SecTrustResultType trust_eval;
1532 CFMutableArrayRef array = NULL;
1533 SecTrustRef trust = NULL;
1534 CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
1535 (void)cf;
1536 /*
1537 * Certbuf now contains the contents of the certificate file, which can be
1538 * - a single DER certificate,
1539 * - a single PEM certificate or
1540 * - a bunch of PEM certificates (certificate bundle).
1541 *
1542 * Go through certbuf, and convert any PEM certificate in it into DER
1543 * format.
1544 */
1545 array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1546 if(!array) {
1547 failf(data, "SSL: out of memory creating CA certificate array");
1548 result = CURLE_OUT_OF_MEMORY;
1549 goto out;
1550 }
1551
1552 while(offset < buflen) {
1553 n++;
1554
1555 /*
1556 * Check if the certificate is in PEM format, and convert it to DER. If
1557 * this fails, we assume the certificate is in DER format.
1558 */
1559 res = pem_to_der((const char *)certbuf + offset, &der, &derlen);
1560 if(res < 0) {
1561 failf(data, "SSL: invalid CA certificate #%d (offset %zu) in bundle",
1562 n, offset);
1563 result = CURLE_SSL_CACERT_BADFILE;
1564 goto out;
1565 }
1566 offset += res;
1567
1568 if(res == 0 && offset == 0) {
1569 /* This is not a PEM file, probably a certificate in DER format. */
1570 rc = append_cert_to_array(data, certbuf, buflen, array);
1571 if(rc != CURLE_OK) {
1572 CURL_TRC_CF(data, cf, "append_cert for CA failed");
1573 result = rc;
1574 goto out;
1575 }
1576 break;
1577 }
1578 else if(res == 0) {
1579 /* No more certificates in the bundle. */
1580 break;
1581 }
1582
1583 rc = append_cert_to_array(data, der, derlen, array);
1584 free(der);
1585 if(rc != CURLE_OK) {
1586 CURL_TRC_CF(data, cf, "append_cert for CA failed");
1587 result = rc;
1588 goto out;
1589 }
1590 }
1591
1592 ret = SSLCopyPeerTrust(ctx, &trust);
1593 if(!trust) {
1594 failf(data, "SSL: error getting certificate chain");
1595 goto out;
1596 }
1597 else if(ret != noErr) {
1598 failf(data, "SSLCopyPeerTrust() returned error %d", ret);
1599 goto out;
1600 }
1601
1602 CURL_TRC_CF(data, cf, "setting %d trust anchors", n);
1603 ret = SecTrustSetAnchorCertificates(trust, array);
1604 if(ret != noErr) {
1605 failf(data, "SecTrustSetAnchorCertificates() returned error %d", ret);
1606 goto out;
1607 }
1608 ret = SecTrustSetAnchorCertificatesOnly(trust, TRUE);
1609 if(ret != noErr) {
1610 failf(data, "SecTrustSetAnchorCertificatesOnly() returned error %d", ret);
1611 goto out;
1612 }
1613
1614 trust_eval = 0;
1615 ret = SecTrustEvaluate(trust, &trust_eval);
1616 if(ret != noErr) {
1617 failf(data, "SecTrustEvaluate() returned error %d", ret);
1618 goto out;
1619 }
1620
1621 switch(trust_eval) {
1622 case kSecTrustResultUnspecified:
1623 /* what does this really mean? */
1624 CURL_TRC_CF(data, cf, "trust result: Unspecified");
1625 result = CURLE_OK;
1626 goto out;
1627 case kSecTrustResultProceed:
1628 CURL_TRC_CF(data, cf, "trust result: Proceed");
1629 result = CURLE_OK;
1630 goto out;
1631
1632 case kSecTrustResultRecoverableTrustFailure:
1633 failf(data, "SSL: peer not verified: RecoverableTrustFailure");
1634 goto out;
1635 case kSecTrustResultDeny:
1636 failf(data, "SSL: peer not verified: Deny");
1637 goto out;
1638 default:
1639 failf(data, "SSL: perr not verified: result=%d", trust_eval);
1640 goto out;
1641 }
1642
1643 out:
1644 if(trust)
1645 CFRelease(trust);
1646 if(array)
1647 CFRelease(array);
1648 return result;
1649 }
1650
1651 static CURLcode verify_cert(struct Curl_cfilter *cf,
1652 struct Curl_easy *data, const char *cafile,
1653 const struct curl_blob *ca_info_blob,
1654 SSLContextRef ctx)
1655 {
1656 CURLcode result;
1657 unsigned char *certbuf;
1658 size_t buflen;
1659 bool free_certbuf = FALSE;
1660
1661 if(ca_info_blob) {
1662 CURL_TRC_CF(data, cf, "verify_peer, CA from config blob");
1663 certbuf = ca_info_blob->data;
1664 buflen = ca_info_blob->len;
1665 }
1666 else if(cafile) {
1667 CURL_TRC_CF(data, cf, "verify_peer, CA from file '%s'", cafile);
1668 if(read_cert(cafile, &certbuf, &buflen) < 0) {
1669 failf(data, "SSL: failed to read or invalid CA certificate");
1670 return CURLE_SSL_CACERT_BADFILE;
1671 }
1672 free_certbuf = TRUE;
1673 }
1674 else
1675 return CURLE_SSL_CACERT_BADFILE;
1676
1677 result = verify_cert_buf(cf, data, certbuf, buflen, ctx);
1678 if(free_certbuf)
1679 free(certbuf);
1680 return result;
1681 }
1682
1683
1684 #ifdef SECTRANSP_PINNEDPUBKEY
1685 static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
1686 SSLContextRef ctx,
1687 const char *pinnedpubkey)
1688 { /* Scratch */
1689 size_t pubkeylen, realpubkeylen, spkiHeaderLength = 24;
1690 unsigned char *pubkey = NULL, *realpubkey = NULL;
1691 const unsigned char *spkiHeader = NULL;
1692 CFDataRef publicKeyBits = NULL;
1693
1694 /* Result is returned to caller */
1695 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
1696
1697 /* if a path was not specified, do not pin */
1698 if(!pinnedpubkey)
1699 return CURLE_OK;
1700
1701
1702 if(!ctx)
1703 return result;
1704
1705 do {
1706 SecTrustRef trust;
1707 OSStatus ret;
1708 SecKeyRef keyRef;
1709
1710 ret = SSLCopyPeerTrust(ctx, &trust);
1711 if(ret != noErr || !trust)
1712 break;
1713
1714 keyRef = SecTrustCopyPublicKey(trust);
1715 CFRelease(trust);
1716 if(!keyRef)
1717 break;
1718
1719 #ifdef SECTRANSP_PINNEDPUBKEY_V1
1720
1721 publicKeyBits = SecKeyCopyExternalRepresentation(keyRef, NULL);
1722 CFRelease(keyRef);
1723 if(!publicKeyBits)
1724 break;
1725
1726 #elif SECTRANSP_PINNEDPUBKEY_V2
1727
1728 {
1729 OSStatus success;
1730 success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
1731 &publicKeyBits);
1732 CFRelease(keyRef);
1733 if(success != errSecSuccess || !publicKeyBits)
1734 break;
1735 }
1736
1737 #endif /* SECTRANSP_PINNEDPUBKEY_V2 */
1738
1739 pubkeylen = (size_t)CFDataGetLength(publicKeyBits);
1740 pubkey = (unsigned char *)CFDataGetBytePtr(publicKeyBits);
1741
1742 switch(pubkeylen) {
1743 case 526:
1744 /* 4096 bit RSA pubkeylen == 526 */
1745 spkiHeader = rsa4096SpkiHeader;
1746 break;
1747 case 270:
1748 /* 2048 bit RSA pubkeylen == 270 */
1749 spkiHeader = rsa2048SpkiHeader;
1750 break;
1751 #ifdef SECTRANSP_PINNEDPUBKEY_V1
1752 case 65:
1753 /* ecDSA secp256r1 pubkeylen == 65 */
1754 spkiHeader = ecDsaSecp256r1SpkiHeader;
1755 spkiHeaderLength = 26;
1756 break;
1757 case 97:
1758 /* ecDSA secp384r1 pubkeylen == 97 */
1759 spkiHeader = ecDsaSecp384r1SpkiHeader;
1760 spkiHeaderLength = 23;
1761 break;
1762 default:
1763 infof(data, "SSL: unhandled public key length: %zu", pubkeylen);
1764 #elif SECTRANSP_PINNEDPUBKEY_V2
1765 default:
1766 /* ecDSA secp256r1 pubkeylen == 91 header already included?
1767 * ecDSA secp384r1 header already included too
1768 * we assume rest of algorithms do same, so do nothing
1769 */
1770 result = Curl_pin_peer_pubkey(data, pinnedpubkey, pubkey,
1771 pubkeylen);
1772 #endif /* SECTRANSP_PINNEDPUBKEY_V2 */
1773 continue; /* break from loop */
1774 }
1775
1776 realpubkeylen = pubkeylen + spkiHeaderLength;
1777 realpubkey = malloc(realpubkeylen);
1778 if(!realpubkey)
1779 break;
1780
1781 memcpy(realpubkey, spkiHeader, spkiHeaderLength);
1782 memcpy(realpubkey + spkiHeaderLength, pubkey, pubkeylen);
1783
1784 result = Curl_pin_peer_pubkey(data, pinnedpubkey, realpubkey,
1785 realpubkeylen);
1786
1787 } while(0);
1788
1789 Curl_safefree(realpubkey);
1790 if(publicKeyBits)
1791 CFRelease(publicKeyBits);
1792
1793 return result;
1794 }
1795 #endif /* SECTRANSP_PINNEDPUBKEY */
1796
1797 static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf,
1798 struct Curl_easy *data)
1799 {
1800 struct ssl_connect_data *connssl = cf->ctx;
1801 struct st_ssl_backend_data *backend =
1802 (struct st_ssl_backend_data *)connssl->backend;
1803 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
1804 OSStatus err;
1805 SSLCipherSuite cipher;
1806 SSLProtocol protocol = 0;
1807
1808 DEBUGASSERT(ssl_connect_2 == connssl->connecting_state);
1809 DEBUGASSERT(backend);
1810 CURL_TRC_CF(data, cf, "connect_step2");
1811
1812 /* Here goes nothing: */
1813 check_handshake:
1814 connssl->io_need = CURL_SSL_IO_NEED_NONE;
1815 err = SSLHandshake(backend->ssl_ctx);
1816
1817 if(err != noErr) {
1818 switch(err) {
1819 case errSSLWouldBlock: /* they are not done with us yet */
1820 connssl->io_need = backend->ssl_direction ?
1821 CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
1822 return CURLE_OK;
1823
1824 /* The below is errSSLServerAuthCompleted; it is not defined in
1825 Leopard's headers */
1826 case -9841:
1827 if((conn_config->CAfile || conn_config->ca_info_blob) &&
1828 conn_config->verifypeer) {
1829 CURLcode result = verify_cert(cf, data, conn_config->CAfile,
1830 conn_config->ca_info_blob,
1831 backend->ssl_ctx);
1832 if(result)
1833 return result;
1834 }
1835 /* the documentation says we need to call SSLHandshake() again */
1836 goto check_handshake;
1837
1838 /* Problem with encrypt / decrypt */
1839 case errSSLPeerDecodeError:
1840 failf(data, "Decode failed");
1841 break;
1842 case errSSLDecryptionFail:
1843 case errSSLPeerDecryptionFail:
1844 failf(data, "Decryption failed");
1845 break;
1846 case errSSLPeerDecryptError:
1847 failf(data, "A decryption error occurred");
1848 break;
1849 case errSSLBadCipherSuite:
1850 failf(data, "A bad SSL cipher suite was encountered");
1851 break;
1852 case errSSLCrypto:
1853 failf(data, "An underlying cryptographic error was encountered");
1854 break;
1855 #if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9
1856 case errSSLWeakPeerEphemeralDHKey:
1857 failf(data, "Indicates a weak ephemeral Diffie-Hellman key");
1858 break;
1859 #endif
1860
1861 /* Problem with the message record validation */
1862 case errSSLBadRecordMac:
1863 case errSSLPeerBadRecordMac:
1864 failf(data, "A record with a bad message authentication code (MAC) "
1865 "was encountered");
1866 break;
1867 case errSSLRecordOverflow:
1868 case errSSLPeerRecordOverflow:
1869 failf(data, "A record overflow occurred");
1870 break;
1871
1872 /* Problem with zlib decompression */
1873 case errSSLPeerDecompressFail:
1874 failf(data, "Decompression failed");
1875 break;
1876
1877 /* Problem with access */
1878 case errSSLPeerAccessDenied:
1879 failf(data, "Access was denied");
1880 break;
1881 case errSSLPeerInsufficientSecurity:
1882 failf(data, "There is insufficient security for this operation");
1883 break;
1884
1885 /* These are all certificate problems with the server: */
1886 case errSSLXCertChainInvalid:
1887 failf(data, "SSL certificate problem: Invalid certificate chain");
1888 return CURLE_PEER_FAILED_VERIFICATION;
1889 case errSSLUnknownRootCert:
1890 failf(data, "SSL certificate problem: Untrusted root certificate");
1891 return CURLE_PEER_FAILED_VERIFICATION;
1892 case errSSLNoRootCert:
1893 failf(data, "SSL certificate problem: No root certificate");
1894 return CURLE_PEER_FAILED_VERIFICATION;
1895 case errSSLCertNotYetValid:
1896 failf(data, "SSL certificate problem: The certificate chain had a "
1897 "certificate that is not yet valid");
1898 return CURLE_PEER_FAILED_VERIFICATION;
1899 case errSSLCertExpired:
1900 case errSSLPeerCertExpired:
1901 failf(data, "SSL certificate problem: Certificate chain had an "
1902 "expired certificate");
1903 return CURLE_PEER_FAILED_VERIFICATION;
1904 case errSSLBadCert:
1905 case errSSLPeerBadCert:
1906 failf(data, "SSL certificate problem: Couldn't understand the server "
1907 "certificate format");
1908 return CURLE_PEER_FAILED_VERIFICATION;
1909 case errSSLPeerUnsupportedCert:
1910 failf(data, "SSL certificate problem: An unsupported certificate "
1911 "format was encountered");
1912 return CURLE_PEER_FAILED_VERIFICATION;
1913 case errSSLPeerCertRevoked:
1914 failf(data, "SSL certificate problem: The certificate was revoked");
1915 return CURLE_PEER_FAILED_VERIFICATION;
1916 case errSSLPeerCertUnknown:
1917 failf(data, "SSL certificate problem: The certificate is unknown");
1918 return CURLE_PEER_FAILED_VERIFICATION;
1919
1920 /* These are all certificate problems with the client: */
1921 case errSecAuthFailed:
1922 failf(data, "SSL authentication failed");
1923 break;
1924 case errSSLPeerHandshakeFail:
1925 failf(data, "SSL peer handshake failed, the server most likely "
1926 "requires a client certificate to connect");
1927 break;
1928 case errSSLPeerUnknownCA:
1929 failf(data, "SSL server rejected the client certificate due to "
1930 "the certificate being signed by an unknown certificate "
1931 "authority");
1932 break;
1933
1934 /* This error is raised if the server's cert did not match the server's
1935 hostname: */
1936 case errSSLHostNameMismatch:
1937 failf(data, "SSL certificate peer verification failed, the "
1938 "certificate did not match \"%s\"\n", connssl->peer.dispname);
1939 return CURLE_PEER_FAILED_VERIFICATION;
1940
1941 /* Problem with SSL / TLS negotiation */
1942 case errSSLNegotiation:
1943 failf(data, "Could not negotiate an SSL cipher suite with the server");
1944 break;
1945 case errSSLBadConfiguration:
1946 failf(data, "A configuration error occurred");
1947 break;
1948 case errSSLProtocol:
1949 failf(data, "SSL protocol error");
1950 break;
1951 case errSSLPeerProtocolVersion:
1952 failf(data, "A bad protocol version was encountered");
1953 break;
1954 case errSSLPeerNoRenegotiation:
1955 failf(data, "No renegotiation is allowed");
1956 break;
1957
1958 /* Generic handshake errors: */
1959 case errSSLConnectionRefused:
1960 failf(data, "Server dropped the connection during the SSL handshake");
1961 break;
1962 case errSSLClosedAbort:
1963 failf(data, "Server aborted the SSL handshake");
1964 break;
1965 case errSSLClosedGraceful:
1966 failf(data, "The connection closed gracefully");
1967 break;
1968 case errSSLClosedNoNotify:
1969 failf(data, "The server closed the session with no notification");
1970 break;
1971 /* Sometimes paramErr happens with buggy ciphers: */
1972 case paramErr:
1973 case errSSLInternal:
1974 case errSSLPeerInternalError:
1975 failf(data, "Internal SSL engine error encountered during the "
1976 "SSL handshake");
1977 break;
1978 case errSSLFatalAlert:
1979 failf(data, "Fatal SSL engine error encountered during the SSL "
1980 "handshake");
1981 break;
1982 /* Unclassified error */
1983 case errSSLBufferOverflow:
1984 failf(data, "An insufficient buffer was provided");
1985 break;
1986 case errSSLIllegalParam:
1987 failf(data, "An illegal parameter was encountered");
1988 break;
1989 case errSSLModuleAttach:
1990 failf(data, "Module attach failure");
1991 break;
1992 case errSSLSessionNotFound:
1993 failf(data, "An attempt to restore an unknown session failed");
1994 break;
1995 case errSSLPeerExportRestriction:
1996 failf(data, "An export restriction occurred");
1997 break;
1998 case errSSLPeerUserCancelled:
1999 failf(data, "The user canceled the operation");
2000 break;
2001 case errSSLPeerUnexpectedMsg:
2002 failf(data, "Peer rejected unexpected message");
2003 break;
2004 #if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9
2005 /* Treating non-fatal error as fatal like before */
2006 case errSSLClientHelloReceived:
2007 failf(data, "A non-fatal result for providing a server name "
2008 "indication");
2009 break;
2010 #endif
2011
2012 /* Error codes defined in the enum but should never be returned.
2013 We list them here just in case. */
2014 #if CURL_BUILD_MAC_10_6
2015 /* Only returned when kSSLSessionOptionBreakOnCertRequested is set */
2016 case errSSLClientCertRequested:
2017 failf(data, "Server requested a client certificate during the "
2018 "handshake");
2019 return CURLE_SSL_CLIENTCERT;
2020 #endif
2021 #if CURL_BUILD_MAC_10_9
2022 /* Alias for errSSLLast, end of error range */
2023 case errSSLUnexpectedRecord:
2024 failf(data, "Unexpected (skipped) record in DTLS");
2025 break;
2026 #endif
2027 default:
2028 /* May also return codes listed in Security Framework Result Codes */
2029 failf(data, "Unknown SSL protocol error in connection to %s:%d",
2030 connssl->peer.hostname, err);
2031 break;
2032 }
2033 return CURLE_SSL_CONNECT_ERROR;
2034 }
2035 else {
2036 char cipher_str[64];
2037 /* we have been connected fine, we are not waiting for anything else. */
2038 connssl->connecting_state = ssl_connect_3;
2039
2040 #ifdef SECTRANSP_PINNEDPUBKEY
2041 if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
2042 CURLcode result =
2043 pkp_pin_peer_pubkey(data, backend->ssl_ctx,
2044 data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
2045 if(result) {
2046 failf(data, "SSL: public key does not match pinned public key");
2047 return result;
2048 }
2049 }
2050 #endif /* SECTRANSP_PINNEDPUBKEY */
2051
2052 /* Informational message */
2053 (void)SSLGetNegotiatedCipher(backend->ssl_ctx, &cipher);
2054 (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol);
2055
2056 sectransp_cipher_suite_get_str((uint16_t) cipher, cipher_str,
2057 sizeof(cipher_str), TRUE);
2058 switch(protocol) {
2059 case kSSLProtocol2:
2060 infof(data, "SSL 2.0 connection using %s", cipher_str);
2061 break;
2062 case kSSLProtocol3:
2063 infof(data, "SSL 3.0 connection using %s", cipher_str);
2064 break;
2065 case kTLSProtocol1:
2066 infof(data, "TLS 1.0 connection using %s", cipher_str);
2067 break;
2068 #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
2069 case kTLSProtocol11:
2070 infof(data, "TLS 1.1 connection using %s", cipher_str);
2071 break;
2072 case kTLSProtocol12:
2073 infof(data, "TLS 1.2 connection using %s", cipher_str);
2074 break;
2075 #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
2076 #if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
2077 case kTLSProtocol13:
2078 infof(data, "TLS 1.3 connection using %s", cipher_str);
2079 break;
2080 #endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
2081 default:
2082 infof(data, "Unknown protocol connection");
2083 break;
2084 }
2085
2086 #if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
2087 defined(HAVE_BUILTIN_AVAILABLE)
2088 if(connssl->alpn) {
2089 if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
2090 CFArrayRef alpnArr = NULL;
2091 CFStringRef chosenProtocol = NULL;
2092 err = SSLCopyALPNProtocols(backend->ssl_ctx, &alpnArr);
2093
2094 if(err == noErr && alpnArr && CFArrayGetCount(alpnArr) >= 1)
2095 chosenProtocol = CFArrayGetValueAtIndex(alpnArr, 0);
2096
2097 #ifdef USE_HTTP2
2098 if(chosenProtocol &&
2099 !CFStringCompare(chosenProtocol, CFSTR(ALPN_H2), 0)) {
2100 cf->conn->alpn = CURL_HTTP_VERSION_2;
2101 }
2102 else
2103 #endif
2104 if(chosenProtocol &&
2105 !CFStringCompare(chosenProtocol, CFSTR(ALPN_HTTP_1_1), 0)) {
2106 cf->conn->alpn = CURL_HTTP_VERSION_1_1;
2107 }
2108 else
2109 infof(data, VTLS_INFOF_NO_ALPN);
2110
2111 /* chosenProtocol is a reference to the string within alpnArr
2112 and does not need to be freed separately */
2113 if(alpnArr)
2114 CFRelease(alpnArr);
2115 }
2116 }
2117 #endif
2118
2119 return CURLE_OK;
2120 }
2121 }
2122
2123 static CURLcode
2124 add_cert_to_certinfo(struct Curl_easy *data,
2125 SecCertificateRef server_cert,
2126 int idx)
2127 {
2128 CURLcode result = CURLE_OK;
2129 const char *beg;
2130 const char *end;
2131 CFDataRef cert_data = SecCertificateCopyData(server_cert);
2132
2133 if(!cert_data)
2134 return CURLE_PEER_FAILED_VERIFICATION;
2135
2136 beg = (const char *)CFDataGetBytePtr(cert_data);
2137 end = beg + CFDataGetLength(cert_data);
2138 result = Curl_extract_certinfo(data, idx, beg, end);
2139 CFRelease(cert_data);
2140 return result;
2141 }
2142
2143 static CURLcode
2144 collect_server_cert_single(struct Curl_cfilter *cf, struct Curl_easy *data,
2145 SecCertificateRef server_cert,
2146 CFIndex idx)
2147 {
2148 CURLcode result = CURLE_OK;
2149 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
2150 #ifndef CURL_DISABLE_VERBOSE_STRINGS
2151 if(data->set.verbose) {
2152 char *certp;
2153 result = CopyCertSubject(data, server_cert, &certp);
2154 if(!result) {
2155 infof(data, "Server certificate: %s", certp);
2156 free(certp);
2157 }
2158 }
2159 #endif
2160 if(ssl_config->certinfo)
2161 result = add_cert_to_certinfo(data, server_cert, (int)idx);
2162 return result;
2163 }
2164
2165 /* This should be called during step3 of the connection at the earliest */
2166 static CURLcode collect_server_cert(struct Curl_cfilter *cf,
2167 struct Curl_easy *data)
2168 {
2169 #ifndef CURL_DISABLE_VERBOSE_STRINGS
2170 const bool show_verbose_server_cert = data->set.verbose;
2171 #else
2172 const bool show_verbose_server_cert = FALSE;
2173 #endif
2174 struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
2175 CURLcode result = ssl_config->certinfo ?
2176 CURLE_PEER_FAILED_VERIFICATION : CURLE_OK;
2177 struct ssl_connect_data *connssl = cf->ctx;
2178 struct st_ssl_backend_data *backend =
2179 (struct st_ssl_backend_data *)connssl->backend;
2180 CFArrayRef server_certs = NULL;
2181 SecCertificateRef server_cert;
2182 OSStatus err;
2183 CFIndex i, count;
2184 SecTrustRef trust = NULL;
2185
2186 DEBUGASSERT(backend);
2187
2188 if(!show_verbose_server_cert && !ssl_config->certinfo)
2189 return CURLE_OK;
2190
2191 if(!backend->ssl_ctx)
2192 return result;
2193
2194 #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
2195 #if CURL_BUILD_IOS
2196 #pragma unused(server_certs)
2197 err = SSLCopyPeerTrust(backend->ssl_ctx, &trust);
2198 /* For some reason, SSLCopyPeerTrust() can return noErr and yet return
2199 a null trust, so be on guard for that: */
2200 if(err == noErr && trust) {
2201 count = SecTrustGetCertificateCount(trust);
2202 if(ssl_config->certinfo)
2203 result = Curl_ssl_init_certinfo(data, (int)count);
2204 for(i = 0L ; !result && (i < count) ; i++) {
2205 server_cert = SecTrustGetCertificateAtIndex(trust, i);
2206 result = collect_server_cert_single(cf, data, server_cert, i);
2207 }
2208 CFRelease(trust);
2209 }
2210 #else
2211 /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion.
2212 The function SecTrustGetCertificateAtIndex() is officially present
2213 in Lion, but it is unfortunately also present in Snow Leopard as
2214 private API and does not work as expected. So we have to look for
2215 a different symbol to make sure this code is only executed under
2216 Lion or later. */
2217 if(&SecTrustCopyPublicKey) {
2218 #pragma unused(server_certs)
2219 err = SSLCopyPeerTrust(backend->ssl_ctx, &trust);
2220 /* For some reason, SSLCopyPeerTrust() can return noErr and yet return
2221 a null trust, so be on guard for that: */
2222 if(err == noErr && trust) {
2223 count = SecTrustGetCertificateCount(trust);
2224 if(ssl_config->certinfo)
2225 result = Curl_ssl_init_certinfo(data, (int)count);
2226 for(i = 0L ; !result && (i < count) ; i++) {
2227 server_cert = SecTrustGetCertificateAtIndex(trust, i);
2228 result = collect_server_cert_single(cf, data, server_cert, i);
2229 }
2230 CFRelease(trust);
2231 }
2232 }
2233 else {
2234 #if CURL_SUPPORT_MAC_10_8
2235 err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs);
2236 /* Just in case SSLCopyPeerCertificates() returns null too... */
2237 if(err == noErr && server_certs) {
2238 count = CFArrayGetCount(server_certs);
2239 if(ssl_config->certinfo)
2240 result = Curl_ssl_init_certinfo(data, (int)count);
2241 for(i = 0L ; !result && (i < count) ; i++) {
2242 server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs,
2243 i);
2244 result = collect_server_cert_single(cf, data, server_cert, i);
2245 }
2246 CFRelease(server_certs);
2247 }
2248 #endif /* CURL_SUPPORT_MAC_10_8 */
2249 }
2250 #endif /* CURL_BUILD_IOS */
2251 #else
2252 #pragma unused(trust)
2253 err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs);
2254 if(err == noErr) {
2255 count = CFArrayGetCount(server_certs);
2256 if(ssl_config->certinfo)
2257 result = Curl_ssl_init_certinfo(data, (int)count);
2258 for(i = 0L ; !result && (i < count) ; i++) {
2259 server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i);
2260 result = collect_server_cert_single(cf, data, server_cert, i);
2261 }
2262 CFRelease(server_certs);
2263 }
2264 #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
2265 return result;
2266 }
2267
2268 static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf,
2269 struct Curl_easy *data)
2270 {
2271 struct ssl_connect_data *connssl = cf->ctx;
2272 CURLcode result;
2273
2274 CURL_TRC_CF(data, cf, "connect_step3");
2275 /* There is no step 3!
2276 * Well, okay, let's collect server certificates, and if verbose mode is on,
2277 * let's print the details of the server certificates. */
2278 result = collect_server_cert(cf, data);
2279 if(result)
2280 return result;
2281
2282 connssl->connecting_state = ssl_connect_done;
2283 return CURLE_OK;
2284 }
2285
2286 static CURLcode
2287 sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
2288 bool nonblocking,
2289 bool *done)
2290 {
2291 CURLcode result;
2292 struct ssl_connect_data *connssl = cf->ctx;
2293 curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
2294 int what;
2295
2296 /* check if the connection has already been established */
2297 if(ssl_connection_complete == connssl->state) {
2298 *done = TRUE;
2299 return CURLE_OK;
2300 }
2301
2302 if(ssl_connect_1 == connssl->connecting_state) {
2303 /* Find out how much more time we are allowed */
2304 const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
2305
2306 if(timeout_ms < 0) {
2307 /* no need to continue if time already is up */
2308 failf(data, "SSL connection timeout");
2309 return CURLE_OPERATION_TIMEDOUT;
2310 }
2311
2312 result = sectransp_connect_step1(cf, data);
2313 if(result)
2314 return result;
2315 }
2316
2317 while(ssl_connect_2 == connssl->connecting_state) {
2318
2319 /* check allowed time left */
2320 const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
2321
2322 if(timeout_ms < 0) {
2323 /* no need to continue if time already is up */
2324 failf(data, "SSL connection timeout");
2325 return CURLE_OPERATION_TIMEDOUT;
2326 }
2327
2328 /* if ssl is expecting something, check if it is available. */
2329 if(connssl->io_need) {
2330
2331 curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
2332 sockfd : CURL_SOCKET_BAD;
2333 curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
2334 sockfd : CURL_SOCKET_BAD;
2335
2336 what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
2337 nonblocking ? 0 : timeout_ms);
2338 if(what < 0) {
2339 /* fatal error */
2340 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
2341 return CURLE_SSL_CONNECT_ERROR;
2342 }
2343 else if(0 == what) {
2344 if(nonblocking) {
2345 *done = FALSE;
2346 return CURLE_OK;
2347 }
2348 else {
2349 /* timeout */
2350 failf(data, "SSL connection timeout");
2351 return CURLE_OPERATION_TIMEDOUT;
2352 }
2353 }
2354 /* socket is readable or writable */
2355 }
2356
2357 /* Run transaction, and return to the caller if it failed or if this
2358 * connection is done nonblocking and this loop would execute again. This
2359 * permits the owner of a multi handle to abort a connection attempt
2360 * before step2 has completed while ensuring that a client using select()
2361 * or epoll() will always have a valid fdset to wait on.
2362 */
2363 result = sectransp_connect_step2(cf, data);
2364 if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
2365 return result;
2366
2367 } /* repeat step2 until all transactions are done. */
2368
2369
2370 if(ssl_connect_3 == connssl->connecting_state) {
2371 result = sectransp_connect_step3(cf, data);
2372 if(result)
2373 return result;
2374 }
2375
2376 if(ssl_connect_done == connssl->connecting_state) {
2377 CURL_TRC_CF(data, cf, "connected");
2378 connssl->state = ssl_connection_complete;
2379 *done = TRUE;
2380 }
2381 else
2382 *done = FALSE;
2383
2384 /* Reset our connect state machine */
2385 connssl->connecting_state = ssl_connect_1;
2386
2387 return CURLE_OK;
2388 }
2389
2390 static CURLcode sectransp_connect_nonblocking(struct Curl_cfilter *cf,
2391 struct Curl_easy *data,
2392 bool *done)
2393 {
2394 return sectransp_connect_common(cf, data, TRUE, done);
2395 }
2396
2397 static CURLcode sectransp_connect(struct Curl_cfilter *cf,
2398 struct Curl_easy *data)
2399 {
2400 CURLcode result;
2401 bool done = FALSE;
2402
2403 result = sectransp_connect_common(cf, data, FALSE, &done);
2404
2405 if(result)
2406 return result;
2407
2408 DEBUGASSERT(done);
2409
2410 return CURLE_OK;
2411 }
2412
2413 static ssize_t sectransp_recv(struct Curl_cfilter *cf,
2414 struct Curl_easy *data,
2415 char *buf,
2416 size_t buffersize,
2417 CURLcode *curlcode);
2418
2419 static CURLcode sectransp_shutdown(struct Curl_cfilter *cf,
2420 struct Curl_easy *data,
2421 bool send_shutdown, bool *done)
2422 {
2423 struct ssl_connect_data *connssl = cf->ctx;
2424 struct st_ssl_backend_data *backend =
2425 (struct st_ssl_backend_data *)connssl->backend;
2426 CURLcode result = CURLE_OK;
2427 ssize_t nread;
2428 char buf[1024];
2429 size_t i;
2430
2431 DEBUGASSERT(backend);
2432 if(!backend->ssl_ctx || cf->shutdown) {
2433 *done = TRUE;
2434 goto out;
2435 }
2436
2437 connssl->io_need = CURL_SSL_IO_NEED_NONE;
2438 *done = FALSE;
2439
2440 if(send_shutdown && !backend->sent_shutdown) {
2441 OSStatus err;
2442
2443 CURL_TRC_CF(data, cf, "shutdown, send close notify");
2444 err = SSLClose(backend->ssl_ctx);
2445 switch(err) {
2446 case noErr:
2447 backend->sent_shutdown = TRUE;
2448 break;
2449 case errSSLWouldBlock:
2450 connssl->io_need = CURL_SSL_IO_NEED_SEND;
2451 result = CURLE_OK;
2452 goto out;
2453 default:
2454 CURL_TRC_CF(data, cf, "shutdown, error: %d", (int)err);
2455 result = CURLE_SEND_ERROR;
2456 goto out;
2457 }
2458 }
2459
2460 for(i = 0; i < 10; ++i) {
2461 if(!backend->sent_shutdown) {
2462 nread = sectransp_recv(cf, data, buf, (int)sizeof(buf), &result);
2463 }
2464 else {
2465 /* We would like to read the close notify from the server using
2466 * Secure Transport, however SSLRead() no longer works after we
2467 * sent the notify from our side. So, we just read from the
2468 * underlying filter and hope it will end. */
2469 nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);
2470 }
2471 CURL_TRC_CF(data, cf, "shutdown read -> %zd, %d", nread, result);
2472 if(nread <= 0)
2473 break;
2474 }
2475
2476 if(nread > 0) {
2477 /* still data coming in? */
2478 connssl->io_need = CURL_SSL_IO_NEED_RECV;
2479 }
2480 else if(nread == 0) {
2481 /* We got the close notify alert and are done. */
2482 CURL_TRC_CF(data, cf, "shutdown done");
2483 *done = TRUE;
2484 }
2485 else if(result == CURLE_AGAIN) {
2486 connssl->io_need = CURL_SSL_IO_NEED_RECV;
2487 result = CURLE_OK;
2488 }
2489 else {
2490 DEBUGASSERT(result);
2491 CURL_TRC_CF(data, cf, "shutdown, error: %d", result);
2492 }
2493
2494 out:
2495 cf->shutdown = (result || *done);
2496 return result;
2497 }
2498
2499 static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
2500 {
2501 struct ssl_connect_data *connssl = cf->ctx;
2502 struct st_ssl_backend_data *backend =
2503 (struct st_ssl_backend_data *)connssl->backend;
2504
2505 (void) data;
2506
2507 DEBUGASSERT(backend);
2508
2509 if(backend->ssl_ctx) {
2510 CURL_TRC_CF(data, cf, "close");
2511 #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
2512 if(&SSLCreateContext)
2513 CFRelease(backend->ssl_ctx);
2514 #if CURL_SUPPORT_MAC_10_8
2515 else
2516 (void)SSLDisposeContext(backend->ssl_ctx);
2517 #endif /* CURL_SUPPORT_MAC_10_8 */
2518 #else
2519 (void)SSLDisposeContext(backend->ssl_ctx);
2520 #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
2521 backend->ssl_ctx = NULL;
2522 }
2523 }
2524
2525 static size_t sectransp_version(char *buffer, size_t size)
2526 {
2527 return msnprintf(buffer, size, "SecureTransport");
2528 }
2529
2530 static bool sectransp_data_pending(struct Curl_cfilter *cf,
2531 const struct Curl_easy *data)
2532 {
2533 const struct ssl_connect_data *connssl = cf->ctx;
2534 struct st_ssl_backend_data *backend =
2535 (struct st_ssl_backend_data *)connssl->backend;
2536 OSStatus err;
2537 size_t buffer;
2538
2539 (void)data;
2540 DEBUGASSERT(backend);
2541
2542 if(backend->ssl_ctx) { /* SSL is in use */
2543 CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending");
2544 err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer);
2545 if(err == noErr)
2546 return buffer > 0UL;
2547 return FALSE;
2548 }
2549 else
2550 return FALSE;
2551 }
2552
2553 static CURLcode sectransp_random(struct Curl_easy *data UNUSED_PARAM,
2554 unsigned char *entropy, size_t length)
2555 {
2556 /* arc4random_buf() is not available on cats older than Lion, so let's
2557 do this manually for the benefit of the older cats. */
2558 size_t i;
2559 u_int32_t random_number = 0;
2560
2561 (void)data;
2562
2563 for(i = 0 ; i < length ; i++) {
2564 if(i % sizeof(u_int32_t) == 0)
2565 random_number = arc4random();
2566 entropy[i] = random_number & 0xFF;
2567 random_number >>= 8;
2568 }
2569 i = random_number = 0;
2570 return CURLE_OK;
2571 }
2572
2573 static CURLcode sectransp_sha256sum(const unsigned char *tmp, /* input */
2574 size_t tmplen,
2575 unsigned char *sha256sum, /* output */
2576 size_t sha256len)
2577 {
2578 (void)sha256len;
2579 assert(sha256len >= CURL_SHA256_DIGEST_LENGTH);
2580 (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum);
2581 return CURLE_OK;
2582 }
2583
2584 static bool sectransp_false_start(void)
2585 {
2586 #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
2587 if(&SSLSetSessionOption)
2588 return TRUE;
2589 #endif
2590 return FALSE;
2591 }
2592
2593 static ssize_t sectransp_send(struct Curl_cfilter *cf,
2594 struct Curl_easy *data,
2595 const void *mem,
2596 size_t len,
2597 CURLcode *curlcode)
2598 {
2599 struct ssl_connect_data *connssl = cf->ctx;
2600 struct st_ssl_backend_data *backend =
2601 (struct st_ssl_backend_data *)connssl->backend;
2602 size_t processed = 0UL;
2603 OSStatus err;
2604
2605 DEBUGASSERT(backend);
2606
2607 /* The SSLWrite() function works a little differently than expected. The
2608 fourth argument (processed) is currently documented in Apple's
2609 documentation as: "On return, the length, in bytes, of the data actually
2610 written."
2611
2612 Now, one could interpret that as "written to the socket," but actually,
2613 it returns the amount of data that was written to a buffer internal to
2614 the SSLContextRef instead. So it is possible for SSLWrite() to return
2615 errSSLWouldBlock and a number of bytes "written" because those bytes were
2616 encrypted and written to a buffer, not to the socket.
2617
2618 So if this happens, then we need to keep calling SSLWrite() over and
2619 over again with no new data until it quits returning errSSLWouldBlock. */
2620
2621 /* Do we have buffered data to write from the last time we were called? */
2622 if(backend->ssl_write_buffered_length) {
2623 /* Write the buffered data: */
2624 err = SSLWrite(backend->ssl_ctx, NULL, 0UL, &processed);
2625 switch(err) {
2626 case noErr:
2627 /* processed is always going to be 0 because we did not write to
2628 the buffer, so return how much was written to the socket */
2629 processed = backend->ssl_write_buffered_length;
2630 backend->ssl_write_buffered_length = 0UL;
2631 break;
2632 case errSSLWouldBlock: /* argh, try again */
2633 *curlcode = CURLE_AGAIN;
2634 return -1L;
2635 default:
2636 failf(data, "SSLWrite() returned error %d", err);
2637 *curlcode = CURLE_SEND_ERROR;
2638 return -1L;
2639 }
2640 }
2641 else {
2642 /* We have got new data to write: */
2643 err = SSLWrite(backend->ssl_ctx, mem, len, &processed);
2644 if(err != noErr) {
2645 switch(err) {
2646 case errSSLWouldBlock:
2647 /* Data was buffered but not sent, we have to tell the caller
2648 to try sending again, and remember how much was buffered */
2649 backend->ssl_write_buffered_length = len;
2650 *curlcode = CURLE_AGAIN;
2651 return -1L;
2652 default:
2653 failf(data, "SSLWrite() returned error %d", err);
2654 *curlcode = CURLE_SEND_ERROR;
2655 return -1L;
2656 }
2657 }
2658 }
2659 return (ssize_t)processed;
2660 }
2661
2662 static ssize_t sectransp_recv(struct Curl_cfilter *cf,
2663 struct Curl_easy *data,
2664 char *buf,
2665 size_t buffersize,
2666 CURLcode *curlcode)
2667 {
2668 struct ssl_connect_data *connssl = cf->ctx;
2669 struct st_ssl_backend_data *backend =
2670 (struct st_ssl_backend_data *)connssl->backend;
2671 struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
2672 size_t processed = 0UL;
2673 OSStatus err;
2674
2675 DEBUGASSERT(backend);
2676
2677 again:
2678 *curlcode = CURLE_OK;
2679 err = SSLRead(backend->ssl_ctx, buf, buffersize, &processed);
2680
2681 if(err != noErr) {
2682 switch(err) {
2683 case errSSLWouldBlock: /* return how much we read (if anything) */
2684 if(processed) {
2685 return (ssize_t)processed;
2686 }
2687 *curlcode = CURLE_AGAIN;
2688 return -1L;
2689
2690 /* errSSLClosedGraceful - server gracefully shut down the SSL session
2691 errSSLClosedNoNotify - server hung up on us instead of sending a
2692 closure alert notice, read() is returning 0
2693 Either way, inform the caller that the server disconnected. */
2694 case errSSLClosedGraceful:
2695 case errSSLClosedNoNotify:
2696 *curlcode = CURLE_OK;
2697 return 0;
2698
2699 /* The below is errSSLPeerAuthCompleted; it is not defined in
2700 Leopard's headers */
2701 case -9841:
2702 if((conn_config->CAfile || conn_config->ca_info_blob) &&
2703 conn_config->verifypeer) {
2704 CURLcode result = verify_cert(cf, data, conn_config->CAfile,
2705 conn_config->ca_info_blob,
2706 backend->ssl_ctx);
2707 if(result) {
2708 *curlcode = result;
2709 return -1;
2710 }
2711 }
2712 goto again;
2713 default:
2714 failf(data, "SSLRead() return error %d", err);
2715 *curlcode = CURLE_RECV_ERROR;
2716 return -1L;
2717 }
2718 }
2719 return (ssize_t)processed;
2720 }
2721
2722 static void *sectransp_get_internals(struct ssl_connect_data *connssl,
2723 CURLINFO info UNUSED_PARAM)
2724 {
2725 struct st_ssl_backend_data *backend =
2726 (struct st_ssl_backend_data *)connssl->backend;
2727 (void)info;
2728 DEBUGASSERT(backend);
2729 return backend->ssl_ctx;
2730 }
2731
2732 const struct Curl_ssl Curl_ssl_sectransp = {
2733 { CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */
2734
2735 SSLSUPP_CAINFO_BLOB |
2736 SSLSUPP_CERTINFO |
2737 #ifdef SECTRANSP_PINNEDPUBKEY
2738 SSLSUPP_PINNEDPUBKEY |
2739 #endif /* SECTRANSP_PINNEDPUBKEY */
2740 SSLSUPP_HTTPS_PROXY |
2741 SSLSUPP_CIPHER_LIST,
2742
2743 sizeof(struct st_ssl_backend_data),
2744
2745 Curl_none_init, /* init */
2746 Curl_none_cleanup, /* cleanup */
2747 sectransp_version, /* version */
2748 Curl_none_check_cxn, /* check_cxn */
2749 sectransp_shutdown, /* shutdown */
2750 sectransp_data_pending, /* data_pending */
2751 sectransp_random, /* random */
2752 Curl_none_cert_status_request, /* cert_status_request */
2753 sectransp_connect, /* connect */
2754 sectransp_connect_nonblocking, /* connect_nonblocking */
2755 Curl_ssl_adjust_pollset, /* adjust_pollset */
2756 sectransp_get_internals, /* get_internals */
2757 sectransp_close, /* close_one */
2758 Curl_none_close_all, /* close_all */
2759 Curl_none_set_engine, /* set_engine */
2760 Curl_none_set_engine_default, /* set_engine_default */
2761 Curl_none_engines_list, /* engines_list */
2762 sectransp_false_start, /* false_start */
2763 sectransp_sha256sum, /* sha256sum */
2764 NULL, /* associate_connection */
2765 NULL, /* disassociate_connection */
2766 sectransp_recv, /* recv decrypted data */
2767 sectransp_send, /* send data to encrypt */
2768 NULL, /* get_channel_binding */
2769 };
2770
2771 #ifdef __GNUC__
2772 #pragma GCC diagnostic pop
2773 #endif
2774
2775 #ifdef __clang__
2776 #pragma clang diagnostic pop
2777 #endif
2778
2779 #endif /* USE_SECTRANSP */
2780