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