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