-
Notifications
You must be signed in to change notification settings - Fork 1.2k
[Networking] Search for CA roots if libcurl doesn't know where they are. #4877
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -182,17 +182,17 @@ extension _EasyHandle { | |
_config = config | ||
} | ||
|
||
/// Set allowed protocols | ||
/// Set the CA bundle path automatically if it isn't set | ||
/// | ||
/// - Note: This has security implications. Not limiting this, someone could | ||
/// redirect a HTTP request into one of the many other protocols that libcurl | ||
/// supports. | ||
/// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_PROTOCOLS.html | ||
/// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_REDIR_PROTOCOLS.html | ||
func setAllowedProtocolsToHTTPAndHTTPS() { | ||
let protocols = (CFURLSessionProtocolHTTP | CFURLSessionProtocolHTTPS) | ||
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionPROTOCOLS, protocols).asError() | ||
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionREDIR_PROTOCOLS, protocols).asError() | ||
/// Curl does not necessarily know where to find the CA root bundle, | ||
/// and in that case we need to specify where it is. There was a hack | ||
/// to do this automatically for Android but allowing an environment | ||
/// variable to control the location of the CA root bundle seems like | ||
/// a security issue in general. | ||
/// | ||
/// Rather than doing that, we have a list of places we might expect | ||
/// to find it, and search those until we locate a suitable file. | ||
func setCARootBundlePath() { | ||
#if os(Android) | ||
// See https://curl.haxx.se/docs/sslcerts.html | ||
// For SSL on Android you need a "cacert.pem" to be | ||
|
@@ -205,8 +205,58 @@ extension _EasyHandle { | |
else { | ||
try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionCAINFO, caInfo).asError() | ||
} | ||
return | ||
} | ||
#endif | ||
|
||
#if !NS_CURL_MISSING_CURLINFO_CAINFO | ||
#if !os(Windows) && !os(macOS) && !os(iOS) && !os(watchOS) && !os(tvOS) | ||
// Check if there is a default path; if there is, it will already | ||
// be set, so leave things alone | ||
var p: UnsafeMutablePointer<Int8>? = nil | ||
|
||
try! CFURLSession_easy_getinfo_charp(rawHandle, CFURLSessionInfoCAINFO, &p).asError() | ||
|
||
if p != nil { | ||
return | ||
} | ||
|
||
// Otherwise, search a list of known paths | ||
let paths = [ | ||
"/etc/ssl/certs/ca-certificates.crt", | ||
"/etc/pki/tls/certs/ca-bundle.crt", | ||
"/usr/share/ssl/certs/ca-bundle.crt", | ||
"/usr/local/share/certs/ca-root-nss.crt", | ||
"/etc/ssl/cert.pem" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of curiosity, is there reasoning or precedence for this search order? (I don't see any issue with it, I'm just not as familiar.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I took the list from curl's build system (I assumed that was a good place to look, because it already knows how to do this, just during configuration rather than at runtime). |
||
] | ||
|
||
for path in paths { | ||
var isDirectory: ObjCBool = false | ||
if FileManager.default.fileExists(atPath: path, | ||
isDirectory: &isDirectory) | ||
&& !isDirectory.boolValue { | ||
path.withCString { pathPtr in | ||
try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionCAINFO, UnsafeMutablePointer(mutating: pathPtr)).asError() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same idea as above making sure with don't get There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, the we failed in one of the previous iterations because of this, so yes, it's been tested. |
||
} | ||
return | ||
} | ||
} | ||
#endif // !os(Windows) && !os(macOS) && !os(iOS) && !os(watchOS) && !os(tvOS) | ||
#endif // !NS_CURL_MISSING_CURLINFO_CAINFO | ||
} | ||
|
||
/// Set allowed protocols | ||
/// | ||
/// - Note: This has security implications. Not limiting this, someone could | ||
/// redirect a HTTP request into one of the many other protocols that libcurl | ||
/// supports. | ||
/// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_PROTOCOLS.html | ||
/// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_REDIR_PROTOCOLS.html | ||
func setAllowedProtocolsToHTTPAndHTTPS() { | ||
let protocols = (CFURLSessionProtocolHTTP | CFURLSessionProtocolHTTPS) | ||
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionPROTOCOLS, protocols).asError() | ||
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionREDIR_PROTOCOLS, protocols).asError() | ||
setCARootBundlePath() | ||
//TODO: Added in libcurl 7.45.0 | ||
//TODO: Set default protocol for schemeless URLs | ||
//CURLOPT_DEFAULT_PROTOCOL available only in libcurl 7.45.0 | ||
|
@@ -217,6 +267,7 @@ extension _EasyHandle { | |
let redirectProtocols = (CFURLSessionProtocolHTTP | CFURLSessionProtocolHTTPS) | ||
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionPROTOCOLS, protocols).asError() | ||
try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionREDIR_PROTOCOLS, redirectProtocols).asError() | ||
setCARootBundlePath() | ||
} | ||
|
||
//TODO: Proxy setting, namely CFURLSessionOptionPROXY, CFURLSessionOptionPROXYPORT, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have we tested with
curl < 7.84.0
to make sure theNS_CURL_MISSING_CURLINFO_CAINFO
properly guards this code? I think it should, but I'd just want to make sure, otherwise I think this will alwaysfatalError
sincecurl
will returnCURLE_UNKNOWN_OPTION
. It might be good to just catch the error here and return instead of force trying.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. The original version of this PR actually failed because of this problem, so the guard definitely works.