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