Skip to content

Commit ac1af64

Browse files
authored
Merge pull request swiftlang#4947 from al45tair/eng/PR-123434144-6.0
[6.0][Networking] Search for CA roots if libcurl doesn't know where they are.
2 parents 77af9c5 + 04f89f9 commit ac1af64

File tree

5 files changed

+73
-10
lines changed

5 files changed

+73
-10
lines changed

CoreFoundation/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,10 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin)
441441
if((NS_CURL_ASSUME_FEATURES_MISSING) OR (CURL_VERSION_STRING VERSION_LESS "7.30.0"))
442442
add_compile_definitions($<$<COMPILE_LANGUAGE:C>:NS_CURL_MISSING_MAX_HOST_CONNECTIONS>)
443443
endif()
444+
445+
if((NS_CURL_ASSUME_FEATURES_MISSING) OR (CURL_VERSION_STRING VERSION_LESS "7.84.0"))
446+
add_compile_definitions($<$<COMPILE_LANGUAGE:C>:NS_CURL_MISSING_CURLINFO_CAINFO>)
447+
endif()
444448
endif()
445449

446450
add_framework(CFURLSessionInterface

CoreFoundation/URL.subproj/CFURLSessionInterface.c

+3
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,9 @@ 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+
#if !NS_CURL_MISSING_CURLINFO_CAINFO
590+
CFURLSessionInfo const CFURLSessionInfoCAINFO = { CURLINFO_CAINFO };
591+
#endif
589592
CFURLSessionInfo const CFURLSessionInfoCERTINFO = { CURLINFO_CERTINFO };
590593
CFURLSessionInfo const CFURLSessionInfoCONDITION_UNMET = { CURLINFO_CONDITION_UNMET };
591594
CFURLSessionInfo const CFURLSessionInfoRTSP_SESSION_ID = { CURLINFO_RTSP_SESSION_ID };

CoreFoundation/URL.subproj/CFURLSessionInterface.h

+1
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/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin)
1515
if((NS_CURL_ASSUME_FEATURES_MISSING) OR (CURL_VERSION_STRING VERSION_LESS "7.30.0"))
1616
add_compile_definitions(NS_CURL_MISSING_MAX_HOST_CONNECTIONS)
1717
endif()
18+
19+
if((NS_CURL_ASSUME_FEATURES_MISSING) OR (CURL_VERSION_STRING VERSION_LESS "7.84.0"))
20+
add_compile_definitions(NS_CURL_MISSING_CURLINFO_CAINFO)
21+
endif()
1822
endif()
1923

2024
add_library(FoundationNetworking

Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift

+61-10
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,58 @@ extension _EasyHandle {
205205
else {
206206
try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionCAINFO, caInfo).asError()
207207
}
208+
return
208209
}
209210
#endif
211+
212+
#if !NS_CURL_MISSING_CURLINFO_CAINFO
213+
#if !os(Windows) && !os(macOS) && !os(iOS) && !os(watchOS) && !os(tvOS)
214+
// Check if there is a default path; if there is, it will already
215+
// be set, so leave things alone
216+
var p: UnsafeMutablePointer<Int8>? = nil
217+
218+
try! CFURLSession_easy_getinfo_charp(rawHandle, CFURLSessionInfoCAINFO, &p).asError()
219+
220+
if p != nil {
221+
return
222+
}
223+
224+
// Otherwise, search a list of known paths
225+
let paths = [
226+
"/etc/ssl/certs/ca-certificates.crt",
227+
"/etc/pki/tls/certs/ca-bundle.crt",
228+
"/usr/share/ssl/certs/ca-bundle.crt",
229+
"/usr/local/share/certs/ca-root-nss.crt",
230+
"/etc/ssl/cert.pem"
231+
]
232+
233+
for path in paths {
234+
var isDirectory: ObjCBool = false
235+
if FileManager.default.fileExists(atPath: path,
236+
isDirectory: &isDirectory)
237+
&& !isDirectory.boolValue {
238+
path.withCString { pathPtr in
239+
try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionCAINFO, UnsafeMutablePointer(mutating: pathPtr)).asError()
240+
}
241+
return
242+
}
243+
}
244+
#endif // !os(Windows) && !os(macOS) && !os(iOS) && !os(watchOS) && !os(tvOS)
245+
#endif // !NS_CURL_MISSING_CURLINFO_CAINFO
246+
}
247+
248+
/// Set allowed protocols
249+
///
250+
/// - Note: This has security implications. Not limiting this, someone could
251+
/// redirect a HTTP request into one of the many other protocols that libcurl
252+
/// supports.
253+
/// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_PROTOCOLS.html
254+
/// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_REDIR_PROTOCOLS.html
255+
func setAllowedProtocolsToHTTPAndHTTPS() {
256+
let protocols = (CFURLSessionProtocolHTTP | CFURLSessionProtocolHTTPS)
257+
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionPROTOCOLS, protocols).asError()
258+
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionREDIR_PROTOCOLS, protocols).asError()
259+
setCARootBundlePath()
210260
//TODO: Added in libcurl 7.45.0
211261
//TODO: Set default protocol for schemeless URLs
212262
//CURLOPT_DEFAULT_PROTOCOL available only in libcurl 7.45.0
@@ -217,6 +267,7 @@ extension _EasyHandle {
217267
let redirectProtocols = (CFURLSessionProtocolHTTP | CFURLSessionProtocolHTTPS)
218268
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionPROTOCOLS, protocols).asError()
219269
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionREDIR_PROTOCOLS, redirectProtocols).asError()
270+
setCARootBundlePath()
220271
}
221272

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

0 commit comments

Comments
 (0)