xref: /curl/lib/vtls/sectransp.c (revision fa0ccd9f)
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