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