Skip to content

Commit dc8069d

Browse files
authored
Add swift-android-foundation-cacerts.patch (#18)
* Add swift-android-foundation-cacerts.patch * Update cache key for PR * Update swift-android-foundation-cacerts.patch * Update patch to use CFURLSessionOptionCAPATH instead of CFURLSessionOptionCAINFO * New cache key for github workflow * Fix check for isDirectory * Revert "Fix check for isDirectory" This reverts commit ff12e16. * Revert "Update patch to use CFURLSessionOptionCAPATH instead of CFURLSessionOptionCAINFO" This reverts commit 94e355e. * Go back to using CFURLSessionOptionCAINFO instead of CFURLSessionOptionCAPATH, since the latter does not work * Update patch to match swiftlang/swift-corelibs-foundation#5163
1 parent c3914d8 commit dc8069d

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

.github/workflows/sdks.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
SWIFT_TAG="swift-DEVELOPMENT-SNAPSHOT-${LATEST_TOOLCHAIN_VERSION}-a"
3232
fi
3333
echo "tag=$SWIFT_TAG" >> $GITHUB_OUTPUT
34-
echo "key=$SWIFT_TAG-ndk-${NDK_VERSION}-pic-bundle" >> $GITHUB_OUTPUT
34+
echo "key=$SWIFT_TAG-ndk-${NDK_VERSION}-url3-bundle" >> $GITHUB_OUTPUT
3535
- name: Get cached SDK bundle
3636
id: cache-bundle
3737
uses: actions/cache/restore@v4
@@ -126,7 +126,9 @@ jobs:
126126
ANDROID_ARCH=$arch BUILD_SWIFT_PM=1 ${TOOLCHAIN}/bin/swift get-packages-and-swift-source.swift
127127
done
128128
129+
git apply swift-android-foundation-cacerts.patch
129130
git apply swift-android.patch swift-android-ci.patch swift-crypto.patch swift-system.patch
131+
130132
if [ ${{ matrix.version }} = 'release' ]; then
131133
git apply swift-android-ci-release.patch swift-android-foundation-release.patch
132134
perl -pi -e 's%r26%ndk/27%' swift/stdlib/cmake/modules/AddSwiftStdlib.cmake
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
diff --git a/swift-corelibs-foundation/Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift b/swift-corelibs-foundation/Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift
2+
index cdf8875fce..b9b50a2361 100644
3+
--- a/swift-corelibs-foundation/Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift
4+
+++ b/swift-corelibs-foundation/Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift
5+
@@ -220,6 +220,66 @@ extension _EasyHandle {
6+
try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionCAINFO, caInfo).asError()
7+
}
8+
return
9+
+ } else {
10+
+ // When no certificate file has been specified, assemble all the certificate files
11+
+ // from the Android certificate store and writes them to a single `cacerts.pem` file
12+
+
13+
+ // See https://github.com/apple/swift-nio-ssl/blob/main/Sources/NIOSSL/AndroidCABundle.swift
14+
+ let certsFolders = [
15+
+ "/apex/com.android.conscrypt/cacerts", // >= Android14
16+
+ "/system/etc/security/cacerts" // < Android14
17+
+ ]
18+
+
19+
+ let aggregateCertPath = NSTemporaryDirectory() + "/cacerts-\(UUID().uuidString).pem"
20+
+
21+
+ if FileManager.default.createFile(atPath: aggregateCertPath, contents: nil) == false {
22+
+ return
23+
+ }
24+
+
25+
+ guard let fs = FileHandle(forWritingAtPath: aggregateCertPath) else {
26+
+ return
27+
+ }
28+
+
29+
+ // write a header
30+
+ fs.write("""
31+
+ ## Bundle of CA Root Certificates
32+
+ ## Auto-generated on \(Date())
33+
+ ## by aggregating certificates from: \(certsFolders)
34+
+
35+
+ """.data(using: .utf8)!)
36+
+
37+
+ // Go through each folder and load each certificate file (ending with ".0"),
38+
+ // and append them together into a single aggreagate file that curl can load.
39+
+ // The .0 files will contain some extra metadata, but libcurl only cares about the
40+
+ // -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- sections,
41+
+ // so we can naïvely concatenate them all and libcurl will understand the bundle.
42+
+ for certsFolder in certsFolders {
43+
+ let certsFolderURL = URL(fileURLWithPath: certsFolder)
44+
+ if (try? certsFolderURL.resourceValues(forKeys: [.isDirectoryKey]).isDirectory) != true { continue }
45+
+ let certURLs = try! FileManager.default.contentsOfDirectory(at: certsFolderURL, includingPropertiesForKeys: [.isRegularFileKey, .isReadableKey])
46+
+ for certURL in certURLs {
47+
+ // certificate files have names like "53a1b57a.0"
48+
+ if certURL.pathExtension != "0" { continue }
49+
+ do {
50+
+ if try certURL.resourceValues(forKeys: [.isRegularFileKey]).isRegularFile != true { continue }
51+
+ if try certURL.resourceValues(forKeys: [.isReadableKey]).isReadable != true { continue }
52+
+ try fs.write(contentsOf: try Data(contentsOf: certURL))
53+
+ } catch {
54+
+ // ignore individual errors and soldier on…
55+
+ continue
56+
+ }
57+
+ }
58+
+ }
59+
+
60+
+ try! fs.close()
61+
+
62+
+ aggregateCertPath.withCString { pathPtr in
63+
+ // note that it would be nice to use CFURLSessionOptionCAPATH instead
64+
+ // (see https://curl.se/libcurl/c/CURLOPT_CAPATH.html)
65+
+ // but it requires `c_rehash` to be run on the folder, which Android doesn't do
66+
+ try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionCAINFO, UnsafeMutablePointer(mutating: pathPtr)).asError()
67+
+ }
68+
+ return
69+
}
70+
#endif
71+

0 commit comments

Comments
 (0)