Skip to content

Commit f075048

Browse files
authored
Revert "Update to swift-certificates 0.4.0 (#6316)"
This reverts commit c49480c.
1 parent aa0670b commit f075048

15 files changed

+161
-451
lines changed
Binary file not shown.
-57 Bytes
Binary file not shown.
-95 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.
Binary file not shown.
Binary file not shown.
-95 Bytes
Binary file not shown.
1 Byte
Binary file not shown.
Binary file not shown.
Binary file not shown.

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -751,10 +751,10 @@ if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
751751
// dependency version changes here with those projects.
752752
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.2.2")),
753753
.package(url: "https://github.com/apple/swift-driver.git", branch: relatedDependenciesBranch),
754-
.package(url: "https://github.com/apple/swift-crypto.git", .upToNextMinor(from: "2.5.0")),
754+
.package(url: "https://github.com/apple/swift-crypto.git", .upToNextMinor(from: "2.4.1")),
755755
.package(url: "https://github.com/apple/swift-system.git", .upToNextMinor(from: "1.1.1")),
756756
.package(url: "https://github.com/apple/swift-collections.git", .upToNextMinor(from: "1.0.1")),
757-
.package(url: "https://github.com/apple/swift-certificates.git", .upToNextMinor(from: "0.4.0")),
757+
.package(url: "https://github.com/apple/swift-certificates.git", .upToNextMinor(from: "0.1.0")),
758758
]
759759
} else {
760760
package.dependencies += [

Sources/PackageSigning/SignatureProvider.swift

Lines changed: 7 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ public enum SignatureProvider {
6464
let provider = format.provider
6565
return try await provider.extractSigningEntity(
6666
signature: signature,
67-
format: format,
6867
verifierConfiguration: verifierConfiguration
6968
)
7069
}
@@ -120,9 +119,6 @@ public enum SigningError: Error {
120119
case keyDoesNotSupportSignatureAlgorithm
121120
case signingIdentityNotSupported
122121
case unableToValidateSignature(String)
123-
case invalidSignature(String)
124-
case certificateInvalid(String)
125-
case certificateNotTrusted(SigningEntity)
126122
}
127123

128124
// MARK: - Signature formats and providers
@@ -181,7 +177,6 @@ protocol SignatureProviderProtocol {
181177

182178
func extractSigningEntity(
183179
signature: [UInt8],
184-
format: SignatureFormat,
185180
verifierConfiguration: VerifierConfiguration
186181
) async throws -> SigningEntity
187182
}
@@ -254,6 +249,13 @@ struct CMSSignatureProvider: SignatureProviderProtocol {
254249
}
255250
}
256251

252+
func extractSigningEntity(
253+
signature: [UInt8],
254+
verifierConfiguration: VerifierConfiguration
255+
) async throws -> SigningEntity {
256+
throw StringError("not implemented")
257+
}
258+
257259
func status(
258260
signature: [UInt8],
259261
content: [UInt8],
@@ -308,66 +310,6 @@ struct CMSSignatureProvider: SignatureProviderProtocol {
308310
throw SigningError.unableToValidateSignature("\(error)")
309311
}
310312
}
311-
312-
func extractSigningEntity(
313-
signature: [UInt8],
314-
format: SignatureFormat,
315-
verifierConfiguration: VerifierConfiguration
316-
) async throws -> SigningEntity {
317-
switch format {
318-
case .cms_1_0_0:
319-
do {
320-
let cmsSignature = try CMSSignature(derEncoded: signature)
321-
let signers = try cmsSignature.signers
322-
guard signers.count == 1, let signer = signers.first else {
323-
throw SigningError.invalidSignature("expected 1 signer but got \(signers.count)")
324-
}
325-
326-
let signingCertificate = signer.certificate
327-
328-
var trustRoots: [Certificate] = []
329-
if verifierConfiguration.includeDefaultTrustStore {
330-
trustRoots.append(contentsOf: CertificateStores.defaultTrustRoots)
331-
}
332-
trustRoots.append(contentsOf: try verifierConfiguration.trustedRoots.map { try Certificate($0) })
333-
334-
// Verifier uses these to build cert chain for validation
335-
// (see also notes in `status` method)
336-
var untrustedIntermediates: [Certificate] = []
337-
// WWDR intermediates are not required when signing with ADP certs,
338-
// (i.e., these intermediates may not be in the signature), hence
339-
// we include them here to ensure Verifier can build cert chain.
340-
untrustedIntermediates.append(contentsOf: Certificates.wwdrIntermediates)
341-
// For self-signed certificate, the signature should include intermediate(s).
342-
untrustedIntermediates.append(contentsOf: cmsSignature.certificates)
343-
344-
let policySet = self.buildPolicySet(configuration: verifierConfiguration, httpClient: self.httpClient)
345-
346-
var verifier = Verifier(rootCertificates: CertificateStore(trustRoots), policy: policySet)
347-
let result = await verifier.validate(
348-
leafCertificate: signingCertificate,
349-
intermediates: CertificateStore(untrustedIntermediates)
350-
)
351-
352-
switch result {
353-
case .validCertificate:
354-
return SigningEntity.from(certificate: signingCertificate)
355-
case .couldNotValidate(let validationFailures):
356-
if validationFailures.isEmpty {
357-
let signingEntity = SigningEntity.from(certificate: signingCertificate)
358-
throw SigningError.certificateNotTrusted(signingEntity)
359-
} else {
360-
throw SigningError
361-
.certificateInvalid("failures: \(validationFailures.map(\.policyFailureReason))")
362-
}
363-
}
364-
} catch let error as SigningError {
365-
throw error
366-
} catch {
367-
throw SigningError.invalidSignature("\(error)")
368-
}
369-
}
370-
}
371313
}
372314

373315
#if canImport(Security)

Sources/PackageSigning/VerifierPolicies.swift

Lines changed: 62 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -16,149 +16,99 @@ import struct Foundation.Date
1616
import struct Foundation.URL
1717

1818
import Basics
19-
@_implementationOnly import SwiftASN1
20-
@_implementationOnly @_spi(DisableValidityCheck) import X509
19+
@_implementationOnly import X509
2120

2221
extension SignatureProviderProtocol {
2322
func buildPolicySet(configuration: VerifierConfiguration, httpClient: HTTPClient) -> PolicySet {
24-
var policies: [VerifierPolicy] = [
25-
_CodeSigningPolicy(),
26-
_ADPCertificatePolicy(),
27-
]
28-
29-
let now = Date()
30-
switch (configuration.certificateExpiration, configuration.certificateRevocation) {
31-
case (.enabled(let expiryValidationTime), .strict(let revocationValidationTime)):
32-
policies.append(RFC5280Policy(validationTime: expiryValidationTime ?? now))
33-
policies
34-
.append(_OCSPVerifierPolicy(
35-
failureMode: .hard,
36-
httpClient: httpClient,
37-
validationTime: revocationValidationTime ?? now
38-
))
39-
case (.enabled(let expiryValidationTime), .allowSoftFail(let revocationValidationTime)):
40-
policies.append(RFC5280Policy(validationTime: expiryValidationTime ?? now))
41-
policies
42-
.append(_OCSPVerifierPolicy(
43-
failureMode: .soft,
44-
httpClient: httpClient,
45-
validationTime: revocationValidationTime ?? now
46-
))
47-
case (.enabled(let expiryValidationTime), .disabled):
48-
policies.append(RFC5280Policy(validationTime: expiryValidationTime ?? now))
49-
case (.disabled, .strict(let revocationValidationTime)):
50-
// Always do expiry check (and before) if revocation check is enabled
51-
policies.append(RFC5280Policy(validationTime: revocationValidationTime ?? now))
52-
policies
53-
.append(_OCSPVerifierPolicy(
54-
failureMode: .hard,
55-
httpClient: httpClient,
56-
validationTime: revocationValidationTime ?? now
57-
))
58-
case (.disabled, .allowSoftFail(let revocationValidationTime)):
59-
// Always do expiry check (and before) if revocation check is enabled
60-
policies.append(RFC5280Policy(validationTime: revocationValidationTime ?? now))
23+
var policies = [VerifierPolicy]()
24+
25+
if case .enabled(let validationTime) = configuration.certificateExpiration {
26+
policies.append(RFC5280Policy(validationTime: validationTime ?? Date()))
27+
}
28+
29+
switch configuration.certificateRevocation {
30+
case .strict(let validationTime):
31+
policies.append(_OCSPVerifierPolicy(httpClient: httpClient, mode: .strict, validationTime: validationTime))
32+
case .allowSoftFail(let validationTime):
6133
policies
6234
.append(_OCSPVerifierPolicy(
63-
failureMode: .soft,
6435
httpClient: httpClient,
65-
validationTime: revocationValidationTime ?? now
36+
mode: .allowSoftFail,
37+
validationTime: validationTime
6638
))
67-
case (.disabled, .disabled):
68-
// We should still do basic certificate validations even if expiry check is disabled
69-
policies.append(RFC5280Policy.withValidityCheckDisabled())
39+
case .disabled:
40+
()
7041
}
7142

7243
return PolicySet(policies: policies)
7344
}
7445
}
7546

76-
/// Policy for code signing certificates.
77-
struct _CodeSigningPolicy: VerifierPolicy {
78-
let verifyingCriticalExtensions: [ASN1ObjectIdentifier] = [
79-
ASN1ObjectIdentifier.X509ExtensionID.keyUsage,
80-
ASN1ObjectIdentifier.X509ExtensionID.extendedKeyUsage,
81-
]
82-
83-
func chainMeetsPolicyRequirements(chain: UnverifiedCertificateChain) async -> PolicyEvaluationResult {
84-
let isCodeSigning = (
85-
try? chain.leaf.extensions.extendedKeyUsage?.contains(ExtendedKeyUsage.Usage.codeSigning)
86-
) ??
87-
false
88-
guard isCodeSigning else {
89-
return .failsToMeetPolicy(reason: "Certificate \(chain.leaf) does not have code signing extended key usage")
90-
}
91-
return .meetsPolicy
92-
}
93-
}
94-
95-
/// Policy for ADP certificates.
96-
struct _ADPCertificatePolicy: VerifierPolicy {
97-
/// Include custom marker extensions (which can be critical) so they would not
98-
/// be considered unhandled and cause certificate chain validation to fail.
99-
let verifyingCriticalExtensions: [ASN1ObjectIdentifier] = Self.swiftPackageMarkers
100-
+ Self.developmentMarkers
101-
102-
// Marker extensions for Swift Package certificate
103-
private static let swiftPackageMarkers: [ASN1ObjectIdentifier] = [
104-
// This is not a critical extension but including it just in case
105-
ASN1ObjectIdentifier.NameAttributes.adpSwiftPackageMarker,
106-
]
107-
108-
// Marker extensions for Development certificate (included for testing)
109-
private static let developmentMarkers: [ASN1ObjectIdentifier] = [
110-
[1, 2, 840, 113_635, 100, 6, 1, 2],
111-
[1, 2, 840, 113_635, 100, 6, 1, 12],
112-
]
113-
114-
func chainMeetsPolicyRequirements(chain: UnverifiedCertificateChain) async -> PolicyEvaluationResult {
115-
// Not policing anything here. This policy is mainly for
116-
// listing marker extensions to prevent chain validation
117-
// from failing prematurely.
118-
.meetsPolicy
119-
}
120-
}
121-
12247
struct _OCSPVerifierPolicy: VerifierPolicy {
12348
private static let cacheTTL: DispatchTimeInterval = .seconds(5 * 60)
12449
private let cache = ThreadSafeKeyValueStore<
12550
UnverifiedCertificateChain,
12651
(result: PolicyEvaluationResult, expires: DispatchTime)
12752
>()
12853

129-
private var underlying: OCSPVerifierPolicy<_OCSPRequester>
130-
131-
let verifyingCriticalExtensions: [ASN1ObjectIdentifier] = []
132-
133-
/// Initializes an `_OCSPVerifierPolicy` that caches its results.
134-
///
135-
/// - Parameters:
136-
/// - failureMode: `OCSPFailureMode` that defines policy failure in event of failure.
137-
/// Possible values are `hard` (OCSP request failure and unknown status
138-
/// not allowed) or `soft` (OCSP request failure and unknown status allowed).
139-
/// - httpClient: `HTTPClient` that backs`_OCSPRequester` for making OCSP requests.
140-
/// - validationTime: The time used to decide if the OCSP request is relatively recent. It is
141-
/// considered a failure if the request is too old.
142-
init(failureMode: OCSPFailureMode, httpClient: HTTPClient, validationTime: Date) {
143-
self.underlying = OCSPVerifierPolicy(
144-
failureMode: failureMode,
145-
requester: _OCSPRequester(httpClient: httpClient),
146-
validationTime: validationTime
147-
)
54+
private let underlying: OCSPVerifierPolicy<_OCSPRequester>
55+
private let mode: Mode
56+
private let validationTime: Date
57+
58+
init(httpClient: HTTPClient, mode: Mode, validationTime: Date?) {
59+
self.underlying = OCSPVerifierPolicy(requester: _OCSPRequester(httpClient: httpClient))
60+
self.mode = mode
61+
self.validationTime = validationTime ?? Date()
14862
}
14963

150-
mutating func chainMeetsPolicyRequirements(chain: UnverifiedCertificateChain) async -> PolicyEvaluationResult {
64+
func chainMeetsPolicyRequirements(chain: UnverifiedCertificateChain) async -> PolicyEvaluationResult {
65+
// Check for expiration of the leaf before revocation
66+
let leaf = chain.leaf
67+
if leaf.notValidBefore > leaf.notValidAfter {
68+
return .failsToMeetPolicy(
69+
reason: "OCSPVerifierPolicy: leaf certificate \(leaf) has invalid expiry, notValidAfter is earlier than notValidBefore"
70+
)
71+
}
72+
if self.validationTime < leaf.notValidBefore {
73+
return .failsToMeetPolicy(reason: "OCSPVerifierPolicy: leaf certificate \(leaf) is not yet valid")
74+
}
75+
if self.validationTime > leaf.notValidAfter {
76+
return .failsToMeetPolicy(reason: "OCSPVerifierPolicy: leaf certificate \(leaf) has expired")
77+
}
78+
15179
// Look for cached result
15280
if let cached = self.cache[chain], cached.expires < .now() {
15381
return cached.result
15482
}
15583

15684
// This makes HTTP requests
15785
let result = await self.underlying.chainMeetsPolicyRequirements(chain: chain)
86+
let actualResult: PolicyEvaluationResult
87+
switch result {
88+
case .meetsPolicy:
89+
actualResult = result
90+
case .failsToMeetPolicy(let reason):
91+
switch self.mode {
92+
case .strict:
93+
actualResult = result
94+
case .allowSoftFail:
95+
// Allow 'unknown' status and failed OCSP request in this mode
96+
if reason.lowercased().contains("revoked through ocsp") {
97+
actualResult = result
98+
} else {
99+
actualResult = .meetsPolicy
100+
}
101+
}
102+
}
158103

159104
// Save result to cache
160-
self.cache[chain] = (result: result, expires: .now() + Self.cacheTTL)
161-
return result
105+
self.cache[chain] = (result: actualResult, expires: .now() + Self.cacheTTL)
106+
return actualResult
107+
}
108+
109+
enum Mode {
110+
case strict
111+
case allowSoftFail
162112
}
163113
}
164114

Tests/PackageSigningTests/SigningIdentityTests.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ final class SigningIdentityTests: XCTestCase {
3030
let certificate = try Certificate(certificateBytes)
3131

3232
let subject = certificate.subject
33-
XCTAssertEqual("Test (EC) leaf", subject.commonName)
34-
XCTAssertEqual("Test (EC) org unit", subject.organizationalUnitName)
35-
XCTAssertEqual("Test (EC) org", subject.organizationName)
33+
XCTAssertEqual("Test (EC)", subject.commonName)
34+
XCTAssertEqual("Test (EC)", subject.organizationalUnitName)
35+
XCTAssertEqual("Test (EC)", subject.organizationName)
3636

3737
let privateKeyBytes = try readFileContents(
3838
in: fixturePath,
@@ -63,9 +63,9 @@ final class SigningIdentityTests: XCTestCase {
6363
let certificate = try Certificate(certificateBytes)
6464

6565
let subject = certificate.subject
66-
XCTAssertEqual("Test (RSA) leaf", subject.commonName)
67-
XCTAssertEqual("Test (RSA) org unit", subject.organizationalUnitName)
68-
XCTAssertEqual("Test (RSA) org", subject.organizationName)
66+
XCTAssertEqual("Test (RSA)", subject.commonName)
67+
XCTAssertEqual("Test (RSA)", subject.organizationalUnitName)
68+
XCTAssertEqual("Test (RSA)", subject.organizationName)
6969

7070
let privateKeyBytes = try readFileContents(
7171
in: fixturePath,

0 commit comments

Comments
 (0)