Skip to content

Commit c62fb45

Browse files
committed
[Networking] Search for CA roots if libcurl doesn't know where they are.
Normally, distro maintainers will tell libcurl where to look when they build it, and up to now we've been relying on that. That doesn't work for the fully static Linux build, where we're building our own libcurl, and where the idea is that we'll run on any old Linux system. To make TLS work under that circumstance, we'll need to look in a few likely places for CA root files. We only do this if libcurl doesn't already know where to look. rdar://123434144
1 parent 1b514e4 commit c62fb45

File tree

3 files changed

+61
-10
lines changed

3 files changed

+61
-10
lines changed

CoreFoundation/URL.subproj/CFURLSessionInterface.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,7 @@ CFURLSessionInfo const CFURLSessionInfoFTP_ENTRY_PATH = { CURLINFO_FTP_ENTRY_PAT
586586
CFURLSessionInfo const CFURLSessionInfoREDIRECT_URL = { CURLINFO_REDIRECT_URL };
587587
CFURLSessionInfo const CFURLSessionInfoPRIMARY_IP = { CURLINFO_PRIMARY_IP };
588588
CFURLSessionInfo const CFURLSessionInfoAPPCONNECT_TIME = { CURLINFO_APPCONNECT_TIME };
589+
CFURLSessionInfo const CFURLSessionInfoCAINFO = { CURLINFO_CAINFO };
589590
CFURLSessionInfo const CFURLSessionInfoCERTINFO = { CURLINFO_CERTINFO };
590591
CFURLSessionInfo const CFURLSessionInfoCONDITION_UNMET = { CURLINFO_CONDITION_UNMET };
591592
CFURLSessionInfo const CFURLSessionInfoRTSP_SESSION_ID = { CURLINFO_RTSP_SESSION_ID };

CoreFoundation/URL.subproj/CFURLSessionInterface.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ CF_EXPORT CFURLSessionInfo const CFURLSessionInfoFTP_ENTRY_PATH; // CURLINFO_FTP
445445
CF_EXPORT CFURLSessionInfo const CFURLSessionInfoREDIRECT_URL; // CURLINFO_REDIRECT_URL
446446
CF_EXPORT CFURLSessionInfo const CFURLSessionInfoPRIMARY_IP; // CURLINFO_PRIMARY_IP
447447
CF_EXPORT CFURLSessionInfo const CFURLSessionInfoAPPCONNECT_TIME; // CURLINFO_APPCONNECT_TIME
448+
CF_EXPORT CFURLSessionInfo const CFURLSessionInfoCAINFO; // CURLINFO_CAINFO
448449
CF_EXPORT CFURLSessionInfo const CFURLSessionInfoCERTINFO; // CURLINFO_CERTINFO
449450
CF_EXPORT CFURLSessionInfo const CFURLSessionInfoCONDITION_UNMET; // CURLINFO_CONDITION_UNMET
450451
CF_EXPORT CFURLSessionInfo const CFURLSessionInfoRTSP_SESSION_ID; // CURLINFO_RTSP_SESSION_ID

Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -182,17 +182,17 @@ extension _EasyHandle {
182182
_config = config
183183
}
184184

185-
/// Set allowed protocols
185+
/// Set the CA bundle path automatically if it isn't set
186186
///
187-
/// - Note: This has security implications. Not limiting this, someone could
188-
/// redirect a HTTP request into one of the many other protocols that libcurl
189-
/// supports.
190-
/// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_PROTOCOLS.html
191-
/// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_REDIR_PROTOCOLS.html
192-
func setAllowedProtocolsToHTTPAndHTTPS() {
193-
let protocols = (CFURLSessionProtocolHTTP | CFURLSessionProtocolHTTPS)
194-
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionPROTOCOLS, protocols).asError()
195-
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionREDIR_PROTOCOLS, protocols).asError()
187+
/// Curl does not necessarily know where to find the CA root bundle,
188+
/// and in that case we need to specify where it is. There was a hack
189+
/// to do this automatically for Android but allowing an environment
190+
/// variable to control the location of the CA root bundle seems like
191+
/// a security issue in general.
192+
///
193+
/// Rather than doing that, we have a list of places we might expect
194+
/// to find it, and search those until we locate a suitable file.
195+
func setCARootBundlePath() {
196196
#if os(Android)
197197
// See https://curl.haxx.se/docs/sslcerts.html
198198
// For SSL on Android you need a "cacert.pem" to be
@@ -205,8 +205,56 @@ extension _EasyHandle {
205205
else {
206206
try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionCAINFO, caInfo).asError()
207207
}
208+
return
209+
}
210+
#endif
211+
212+
#if !os(Windows) && !os(macOS) && !os(iOS) && !os(watchOS) && !os(tvOS)
213+
// Check if there is a default path; if there is, it will already
214+
// be set, so leave things alone
215+
var p: UnsafeMutablePointer<Int8>? = nil
216+
217+
try! CFURLSession_easy_getinfo_charp(rawHandle, CFURLSessionInfoCAINFO, &p).asError()
218+
219+
if p != nil {
220+
return
221+
}
222+
223+
// Otherwise, search a list of known paths
224+
let paths = [
225+
"/etc/ssl/certs/ca-certificates.crt",
226+
"/etc/pki/tls/certs/ca-bundle.crt",
227+
"/usr/share/ssl/certs/ca-bundle.crt",
228+
"/usr/local/share/certs/ca-root-nss.crt",
229+
"/etc/ssl/cert.pem"
230+
]
231+
232+
for path in paths {
233+
var isDirectory: ObjCBool = false
234+
if FileManager.default.fileExists(atPath: path,
235+
isDirectory: &isDirectory)
236+
&& !isDirectory.boolValue {
237+
path.withCString { pathPtr in
238+
try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionCAINFO, UnsafeMutablePointer(mutating: pathPtr)).asError()
239+
}
240+
return
241+
}
208242
}
209243
#endif
244+
}
245+
246+
/// Set allowed protocols
247+
///
248+
/// - Note: This has security implications. Not limiting this, someone could
249+
/// redirect a HTTP request into one of the many other protocols that libcurl
250+
/// supports.
251+
/// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_PROTOCOLS.html
252+
/// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_REDIR_PROTOCOLS.html
253+
func setAllowedProtocolsToHTTPAndHTTPS() {
254+
let protocols = (CFURLSessionProtocolHTTP | CFURLSessionProtocolHTTPS)
255+
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionPROTOCOLS, protocols).asError()
256+
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionREDIR_PROTOCOLS, protocols).asError()
257+
setCARootBundlePath()
210258
//TODO: Added in libcurl 7.45.0
211259
//TODO: Set default protocol for schemeless URLs
212260
//CURLOPT_DEFAULT_PROTOCOL available only in libcurl 7.45.0
@@ -217,6 +265,7 @@ extension _EasyHandle {
217265
let redirectProtocols = (CFURLSessionProtocolHTTP | CFURLSessionProtocolHTTPS)
218266
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionPROTOCOLS, protocols).asError()
219267
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionREDIR_PROTOCOLS, redirectProtocols).asError()
268+
setCARootBundlePath()
220269
}
221270

222271
//TODO: Proxy setting, namely CFURLSessionOptionPROXY, CFURLSessionOptionPROXYPORT,

0 commit comments

Comments
 (0)