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