Skip to content

Commit d4a488b

Browse files
authored
Android: enable BoringSSL and other Package Collections support (#3393)
Also, disable FTS search through collections.
1 parent de60ad2 commit d4a488b

File tree

12 files changed

+47
-41
lines changed

12 files changed

+47
-41
lines changed

Sources/PackageCollections/PackageCollections.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import TSCBasic
1515
// TODO: is there a better name? this conflicts with the module name which is okay in this case but not ideal in Swift
1616
public struct PackageCollections: PackageCollectionsProtocol {
1717
// Check JSONPackageCollectionProvider.isSignatureCheckSupported before updating or removing this
18-
#if os(macOS) || os(Linux) || os(Windows)
18+
#if os(macOS) || os(Linux) || os(Windows) || os(Android)
1919
static let isSupportedPlatform = true
2020
#else
2121
static let isSupportedPlatform = false

Sources/PackageCollections/Providers/JSONPackageCollectionProvider.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ private typealias JSONModel = PackageCollectionModel.V1
2727
struct JSONPackageCollectionProvider: PackageCollectionProvider {
2828
// TODO: This can be removed when the `Security` framework APIs that the `PackageCollectionsSigning`
2929
// module depends on are available on all Apple platforms.
30-
#if os(macOS) || os(Linux) || os(Windows)
30+
#if os(macOS) || os(Linux) || os(Windows) || os(Android)
3131
static let isSignatureCheckSupported = true
3232
#else
3333
static let isSignatureCheckSupported = false

Sources/PackageCollections/Storage/SQLitePackageCollectionsStorage.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,11 @@ final class SQLitePackageCollectionsStorage: PackageCollectionsStorage, Closable
798798
"""
799799
try db.exec(query: table)
800800

801+
#if os(Android)
802+
// FTS queries for strings containing hyphens isn't working in SQLite on
803+
// Android, so disable for now.
804+
useSearchIndices.put(false)
805+
#else
801806
do {
802807
let ftsPackages = """
803808
CREATE VIRTUAL TABLE IF NOT EXISTS \(Self.packagesFTSName) USING fts4(
@@ -824,6 +829,7 @@ final class SQLitePackageCollectionsStorage: PackageCollectionsStorage, Closable
824829
// consistent results we will not fallback to FTS3 and just give up if FTS4 is not available.
825830
useSearchIndices.put(false)
826831
}
832+
#endif
827833

828834
try db.exec(query: "PRAGMA journal_mode=WAL;")
829835
}

Sources/PackageCollectionsSigning/Certificate/Certificate.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ import struct Foundation.Data
1212

1313
#if os(macOS)
1414
import Security
15-
#elseif os(Linux) || os(Windows)
15+
#elseif os(Linux) || os(Windows) || os(Android)
1616
@_implementationOnly import CCryptoBoringSSL
1717
#endif
1818

1919
#if os(macOS)
2020
typealias Certificate = CoreCertificate
21-
#elseif os(Linux) || os(Windows)
21+
#elseif os(Linux) || os(Windows) || os(Android)
2222
typealias Certificate = BoringSSLCertificate
2323
#else
2424
typealias Certificate = UnsupportedCertificate
@@ -109,7 +109,7 @@ struct CoreCertificate {
109109

110110
// MARK: - Certificate implementation using BoringSSL
111111

112-
#elseif os(Linux) || os(Windows)
112+
#elseif os(Linux) || os(Windows) || os(Android)
113113
final class BoringSSLCertificate {
114114
private let underlying: UnsafeMutablePointer<X509>
115115

Sources/PackageCollectionsSigning/Certificate/CertificatePolicy.swift

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import TSCBasic
1919

2020
#if os(macOS)
2121
import Security
22-
#elseif os(Linux) || os(Windows)
22+
#elseif os(Linux) || os(Windows) || os(Android)
2323
@_implementationOnly import CCryptoBoringSSL
2424
@_implementationOnly import PackageCollectionsSigningLibc
2525
#endif
@@ -29,7 +29,7 @@ let appleDistributionMacOSMarker = "1.2.840.113635.100.6.1.7"
2929
let appleIntermediateMarker = "1.2.840.113635.100.6.2.1"
3030

3131
// For BoringSSL only - the Security framework recognizes these marker extensions
32-
#if os(Linux) || os(Windows)
32+
#if os(Linux) || os(Windows) || os(Android)
3333
let supportedCriticalExtensions: Set<String> = [appleDistributionIOSMarker, appleDistributionMacOSMarker,
3434
// Support "Apple Development" cert markers--they are valid code signing certs after all and satisfy DefaultCertificatePolicy
3535
"1.2.840.113635.100.6.1.2", "1.2.840.113635.100.6.1.12"]
@@ -99,7 +99,7 @@ extension CertificatePolicy {
9999
}
100100
}
101101

102-
#elseif os(Linux) || os(Windows)
102+
#elseif os(Linux) || os(Windows) || os(Android)
103103
typealias BoringSSLVerifyCallback = @convention(c) (CInt, UnsafeMutablePointer<X509_STORE_CTX>?) -> CInt
104104

105105
/// Verifies a certificate chain.
@@ -232,7 +232,7 @@ extension CertificatePolicy {
232232
#endif
233233
}
234234

235-
#if os(Linux) || os(Windows)
235+
#if os(Linux) || os(Windows) || os(Android)
236236
private let ocspClient = BoringSSLOCSPClient()
237237

238238
private struct BoringSSLOCSPClient {
@@ -447,7 +447,7 @@ extension CertificatePolicy {
447447
throw CertificatePolicyError.extensionFailure
448448
}
449449
return !dict.isEmpty
450-
#elseif os(Linux) || os(Windows)
450+
#elseif os(Linux) || os(Windows) || os(Android)
451451
let nid = CCryptoBoringSSL_OBJ_create(oid, "ObjectShortName", "ObjectLongName")
452452
let index = certificate.withUnsafeMutablePointer { CCryptoBoringSSL_X509_get_ext_by_NID($0, nid, -1) }
453453
return index >= 0
@@ -466,7 +466,7 @@ extension CertificatePolicy {
466466
return false
467467
}
468468
return usages.first(where: { $0 == usage.data }) != nil
469-
#elseif os(Linux) || os(Windows)
469+
#elseif os(Linux) || os(Windows) || os(Android)
470470
let eku = certificate.withUnsafeMutablePointer { CCryptoBoringSSL_X509_get_extended_key_usage($0) }
471471
return eku & UInt32(usage.flag) > 0
472472
#else
@@ -488,7 +488,7 @@ extension CertificatePolicy {
488488
return false
489489
}
490490
return infoAccessValue.first(where: { valueDict in valueDict[kSecPropertyKeyValue] as? String == "1.3.6.1.5.5.7.48.1" }) != nil
491-
#elseif os(Linux) || os(Windows)
491+
#elseif os(Linux) || os(Windows) || os(Android)
492492
// Check that there is at least one OCSP responder URL, in which case OCSP check will take place in `verify`.
493493
let ocspURLs = certificate.withUnsafeMutablePointer { CCryptoBoringSSL_X509_get1_ocsp($0) }
494494
defer { CCryptoBoringSSL_sk_OPENSSL_STRING_free(ocspURLs) }
@@ -513,7 +513,7 @@ enum CertificateExtendedKeyUsage {
513513
}
514514
}
515515

516-
#elseif os(Linux) || os(Windows)
516+
#elseif os(Linux) || os(Windows) || os(Android)
517517
var flag: CInt {
518518
switch self {
519519
case .codeSigning:
@@ -581,7 +581,7 @@ struct DefaultCertificatePolicy: CertificatePolicy {
581581
private let callbackQueue: DispatchQueue
582582
private let diagnosticsEngine: DiagnosticsEngine
583583

584-
#if os(Linux) || os(Windows)
584+
#if os(Linux) || os(Windows) || os(Android)
585585
private let httpClient: HTTPClient
586586
#endif
587587

@@ -598,7 +598,7 @@ struct DefaultCertificatePolicy: CertificatePolicy {
598598
/// - callbackQueue: The `DispatchQueue` to use for callbacks
599599
/// - diagnosticsEngine: The `DiagnosticsEngine` for emitting warnings and errors.
600600
init(trustedRootCertsDir: URL?, additionalTrustedRootCerts: [Certificate]?, expectedSubjectUserID: String? = nil, callbackQueue: DispatchQueue, diagnosticsEngine: DiagnosticsEngine) {
601-
#if !(os(macOS) || os(Linux) || os(Windows))
601+
#if !(os(macOS) || os(Linux) || os(Windows) || os(Android))
602602
fatalError("Unsupported: \(#function)")
603603
#else
604604
var trustedRoots = [Certificate]()
@@ -613,14 +613,14 @@ struct DefaultCertificatePolicy: CertificatePolicy {
613613
self.callbackQueue = callbackQueue
614614
self.diagnosticsEngine = diagnosticsEngine
615615

616-
#if os(Linux) || os(Windows)
616+
#if os(Linux) || os(Windows) || os(Android)
617617
self.httpClient = HTTPClient.makeDefault(callbackQueue: callbackQueue)
618618
#endif
619619
#endif
620620
}
621621

622622
func validate(certChain: [Certificate], callback: @escaping (Result<Void, Error>) -> Void) {
623-
#if !(os(macOS) || os(Linux) || os(Windows))
623+
#if !(os(macOS) || os(Linux) || os(Windows) || os(Android))
624624
fatalError("Unsupported: \(#function)")
625625
#else
626626
let wrappedCallback: (Result<Void, Error>) -> Void = { result in self.callbackQueue.async { callback(result) } }
@@ -649,7 +649,7 @@ struct DefaultCertificatePolicy: CertificatePolicy {
649649
// Verify the cert chain - if it is trusted then cert chain is valid
650650
#if os(macOS)
651651
self.verify(certChain: certChain, anchorCerts: self.trustedRoots, diagnosticsEngine: self.diagnosticsEngine, callbackQueue: self.callbackQueue, callback: callback)
652-
#elseif os(Linux) || os(Windows)
652+
#elseif os(Linux) || os(Windows) || os(Android)
653653
self.verify(certChain: certChain, anchorCerts: self.trustedRoots, httpClient: self.httpClient, diagnosticsEngine: self.diagnosticsEngine, callbackQueue: self.callbackQueue, callback: callback)
654654
#endif
655655
} catch {
@@ -672,7 +672,7 @@ struct AppleDeveloperCertificatePolicy: CertificatePolicy {
672672
private let callbackQueue: DispatchQueue
673673
private let diagnosticsEngine: DiagnosticsEngine
674674

675-
#if os(Linux) || os(Windows)
675+
#if os(Linux) || os(Windows) || os(Android)
676676
private let httpClient: HTTPClient
677677
#endif
678678

@@ -689,7 +689,7 @@ struct AppleDeveloperCertificatePolicy: CertificatePolicy {
689689
/// - callbackQueue: The `DispatchQueue` to use for callbacks
690690
/// - diagnosticsEngine: The `DiagnosticsEngine` for emitting warnings and errors.
691691
init(trustedRootCertsDir: URL?, additionalTrustedRootCerts: [Certificate]?, expectedSubjectUserID: String? = nil, callbackQueue: DispatchQueue, diagnosticsEngine: DiagnosticsEngine) {
692-
#if !(os(macOS) || os(Linux) || os(Windows))
692+
#if !(os(macOS) || os(Linux) || os(Windows) || os(Android))
693693
fatalError("Unsupported: \(#function)")
694694
#else
695695
var trustedRoots = [Certificate]()
@@ -704,14 +704,14 @@ struct AppleDeveloperCertificatePolicy: CertificatePolicy {
704704
self.callbackQueue = callbackQueue
705705
self.diagnosticsEngine = diagnosticsEngine
706706

707-
#if os(Linux) || os(Windows)
707+
#if os(Linux) || os(Windows) || os(Android)
708708
self.httpClient = HTTPClient.makeDefault(callbackQueue: callbackQueue)
709709
#endif
710710
#endif
711711
}
712712

713713
func validate(certChain: [Certificate], callback: @escaping (Result<Void, Error>) -> Void) {
714-
#if !(os(macOS) || os(Linux) || os(Windows))
714+
#if !(os(macOS) || os(Linux) || os(Windows) || os(Android))
715715
fatalError("Unsupported: \(#function)")
716716
#else
717717
let wrappedCallback: (Result<Void, Error>) -> Void = { result in self.callbackQueue.async { callback(result) } }
@@ -752,7 +752,7 @@ struct AppleDeveloperCertificatePolicy: CertificatePolicy {
752752
// Verify the cert chain - if it is trusted then cert chain is valid
753753
#if os(macOS)
754754
self.verify(certChain: certChain, anchorCerts: self.trustedRoots, diagnosticsEngine: self.diagnosticsEngine, callbackQueue: self.callbackQueue, callback: callback)
755-
#elseif os(Linux) || os(Windows)
755+
#elseif os(Linux) || os(Windows) || os(Android)
756756
self.verify(certChain: certChain, anchorCerts: self.trustedRoots, httpClient: self.httpClient, diagnosticsEngine: self.diagnosticsEngine, callbackQueue: self.callbackQueue, callback: callback)
757757
#endif
758758
} catch {

Sources/PackageCollectionsSigning/Key/BoringSSLKey.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
//
2222
//===----------------------------------------------------------------------===//
2323

24-
#if os(Linux) || os(Windows)
24+
#if os(Linux) || os(Windows) || os(Android)
2525
import Foundation
2626

2727
@_implementationOnly import CCryptoBoringSSL

Sources/PackageCollectionsSigning/Key/Key+RSA.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ import Foundation
2525

2626
#if os(macOS)
2727
import Security
28-
#elseif os(Linux) || os(Windows)
28+
#elseif os(Linux) || os(Windows) || os(Android)
2929
@_implementationOnly import CCryptoBoringSSL
3030
#endif
3131

3232
#if os(macOS)
3333
typealias RSAPublicKey = CoreRSAPublicKey
3434
typealias RSAPrivateKey = CoreRSAPrivateKey
35-
#elseif os(Linux) || os(Windows)
35+
#elseif os(Linux) || os(Windows) || os(Android)
3636
typealias RSAPublicKey = BoringSSLRSAPublicKey
3737
typealias RSAPrivateKey = BoringSSLRSAPrivateKey
3838
#else
@@ -106,7 +106,7 @@ struct CoreRSAPublicKey: PublicKey {
106106

107107
// Reference: https://github.com/vapor/jwt-kit/blob/master/Sources/JWTKit/RSA/RSAKey.swift
108108

109-
#elseif os(Linux) || os(Windows)
109+
#elseif os(Linux) || os(Windows) || os(Android)
110110
final class BoringSSLRSAPrivateKey: PrivateKey, BoringSSLKey {
111111
let underlying: UnsafeMutablePointer<CCryptoBoringSSL.RSA>
112112

Sources/PackageCollectionsSigning/Signing/BoringSSLSigning.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
//
2222
//===----------------------------------------------------------------------===//
2323

24-
#if os(Linux) || os(Windows)
24+
#if os(Linux) || os(Windows) || os(Android)
2525
import Foundation
2626

2727
@_implementationOnly import CCryptoBoringSSL

Sources/PackageCollectionsSigning/Signing/Signing+RSAKey.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import struct Foundation.Data
2525

2626
#if os(macOS)
2727
import Security
28-
#elseif os(Linux) || os(Windows)
28+
#elseif os(Linux) || os(Windows) || os(Android)
2929
@_implementationOnly import CCryptoBoringSSL
3030
#endif
3131

@@ -59,7 +59,7 @@ extension CoreRSAPublicKey {
5959

6060
// MARK: - MessageSigner and MessageValidator conformance using BoringSSL
6161

62-
#elseif os(Linux) || os(Windows)
62+
#elseif os(Linux) || os(Windows) || os(Android)
6363
// Reference: https://github.com/vapor/jwt-kit/blob/master/Sources/JWTKit/RSA/RSASigner.swift
6464
extension BoringSSLRSAPrivateKey: BoringSSLSigning {
6565
private static let algorithm = BoringSSLEVP(type: .sha256)

Tests/PackageCollectionsSigningTests/CertificatePolicyTests.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class CertificatePolicyTests: XCTestCase {
7979
guard CertificatePolicyError.invalidCertChain == error as? CertificatePolicyError else {
8080
return XCTFail("Expected CertificatePolicyError.invalidCertChain")
8181
}
82-
#elseif os(Linux) || os(Windows)
82+
#elseif os(Linux) || os(Windows) || os(Android)
8383
guard CertificatePolicyError.noTrustedRootCertsConfigured == error as? CertificatePolicyError else {
8484
return XCTFail("Expected CertificatePolicyError.noTrustedRootCertsConfigured")
8585
}
@@ -142,7 +142,7 @@ class CertificatePolicyTests: XCTestCase {
142142
return XCTFail("Expected CertificatePolicyError.invalidCertChain")
143143
}
144144
}
145-
#elseif os(Linux) || os(Windows)
145+
#elseif os(Linux) || os(Windows) || os(Android)
146146
// On other platforms we have to specify `trustedRootCertsDir` so the Apple root cert is trusted
147147
try withTemporaryDirectory { tmp in
148148
try localFileSystem.copy(from: rootCAPath, to: tmp.appending(components: "AppleIncRoot.cer"))
@@ -192,7 +192,7 @@ class CertificatePolicyTests: XCTestCase {
192192
callbackQueue: callbackQueue, diagnosticsEngine: diagnosticsEngine)
193193
XCTAssertNoThrow(try tsc_await { callback in policy.validate(certChain: certChain, callback: callback) })
194194
}
195-
#elseif os(Linux) || os(Windows)
195+
#elseif os(Linux) || os(Windows) || os(Android)
196196
// On other platforms we have to specify `trustedRootCertsDir` so the Apple root cert is trusted
197197
try withTemporaryDirectory { tmp in
198198
try localFileSystem.copy(from: rootCAPath, to: tmp.appending(components: "AppleIncRoot.cer"))
@@ -257,7 +257,7 @@ class CertificatePolicyTests: XCTestCase {
257257
callbackQueue: callbackQueue, diagnosticsEngine: diagnosticsEngine)
258258
XCTAssertNoThrow(try tsc_await { callback in policy.validate(certChain: certChain, callback: callback) })
259259
}
260-
#elseif os(Linux) || os(Windows)
260+
#elseif os(Linux) || os(Windows) || os(Android)
261261
// On other platforms we have to specify `trustedRootCertsDir` so the Apple root cert is trusted
262262
try withTemporaryDirectory { tmp in
263263
try localFileSystem.copy(from: rootCAPath, to: tmp.appending(components: "AppleIncRoot.cer"))
@@ -327,7 +327,7 @@ class CertificatePolicyTests: XCTestCase {
327327
}
328328
}
329329
}
330-
#elseif os(Linux) || os(Windows)
330+
#elseif os(Linux) || os(Windows) || os(Android)
331331
// On other platforms we have to specify `trustedRootCertsDir` so the Apple root cert is trusted
332332
try withTemporaryDirectory { tmp in
333333
try localFileSystem.copy(from: rootCAPath, to: tmp.appending(components: "AppleIncRoot.cer"))
@@ -395,7 +395,7 @@ class CertificatePolicyTests: XCTestCase {
395395
}
396396
}
397397
}
398-
#elseif os(Linux) || os(Windows)
398+
#elseif os(Linux) || os(Windows) || os(Android)
399399
// On other platforms we have to specify `trustedRootCertsDir` so the Apple root cert is trusted
400400
try withTemporaryDirectory { tmp in
401401
try localFileSystem.copy(from: rootCAPath, to: tmp.appending(components: "AppleIncRoot.cer"))

Tests/PackageCollectionsSigningTests/PackageCollectionSigningTest.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ class PackageCollectionSigningTests: XCTestCase {
247247
signing.validate(signedCollection: signedCollection, certPolicyKey: certPolicyKey, callback: callback)
248248
})
249249
}
250-
#elseif os(Linux) || os(Windows)
250+
#elseif os(Linux) || os(Windows) || os(Android)
251251
// On other platforms we have to specify `trustedRootCertsDir` so the Apple root cert is trusted
252252
try withTemporaryDirectory { tmp in
253253
try localFileSystem.copy(from: rootCAPath, to: tmp.appending(components: "AppleIncRoot.cer"))
@@ -339,7 +339,7 @@ class PackageCollectionSigningTests: XCTestCase {
339339
signing.validate(signedCollection: signedCollection, certPolicyKey: certPolicyKey, callback: callback)
340340
})
341341
}
342-
#elseif os(Linux) || os(Windows)
342+
#elseif os(Linux) || os(Windows) || os(Android)
343343
// On other platforms we have to specify `trustedRootCertsDir` so the Apple root cert is trusted
344344
try withTemporaryDirectory { tmp in
345345
try localFileSystem.copy(from: rootCAPath, to: tmp.appending(components: "AppleIncRoot.cer"))
@@ -412,7 +412,7 @@ class PackageCollectionSigningTests: XCTestCase {
412412
XCTAssertNoThrow(try tsc_await { callback in
413413
signing.validate(signedCollection: signedCollection, certPolicyKey: certPolicyKey, callback: callback)
414414
})
415-
#elseif os(Linux) || os(Windows)
415+
#elseif os(Linux) || os(Windows) || os(Android)
416416
// On other platforms we have to specify `trustedRootCertsDir` so the Apple root cert is trusted
417417
try withTemporaryDirectory { tmp in
418418
try localFileSystem.copy(from: rootCAPath, to: tmp.appending(components: "AppleIncRoot.cer"))
@@ -467,7 +467,7 @@ class PackageCollectionSigningTests: XCTestCase {
467467
XCTAssertNoThrow(try tsc_await { callback in
468468
signing.validate(signedCollection: signedCollection, certPolicyKey: certPolicyKey, callback: callback)
469469
})
470-
#elseif os(Linux) || os(Windows)
470+
#elseif os(Linux) || os(Windows) || os(Android)
471471
// On other platforms we have to specify `trustedRootCertsDir` so the Apple root cert is trusted
472472
try withTemporaryDirectory { tmp in
473473
try localFileSystem.copy(from: rootCAPath, to: tmp.appending(components: "AppleIncRoot.cer"))

Tests/PackageCollectionsSigningTests/Utilities.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ extension String {
178178

179179
extension XCTestCase {
180180
func skipIfUnsupportedPlatform() throws {
181-
#if os(macOS) || os(Linux) || os(Windows)
181+
#if os(macOS) || os(Linux) || os(Windows) || os(Android)
182182
#else
183183
throw XCTSkip("Skipping test on unsupported platform")
184184
#endif

0 commit comments

Comments
 (0)