@@ -24,6 +24,15 @@ import Security
24
24
@_implementationOnly import PackageCollectionsSigningLibc
25
25
#endif
26
26
27
+ let appleDistributionIOSMarker = " 1.2.840.113635.100.6.1.4 "
28
+ let appleDistributionMacOSMarker = " 1.2.840.113635.100.6.1.7 "
29
+ let appleIntermediateMarker = " 1.2.840.113635.100.6.2.1 "
30
+
31
+ // For BoringSSL only - the Security framework recognizes these marker extensions
32
+ #if os(Linux) || os(Windows)
33
+ let supportedCriticalExtensions : Set < String > = [ appleDistributionIOSMarker, appleDistributionMacOSMarker]
34
+ #endif
35
+
27
36
protocol CertificatePolicy {
28
37
/// Validates the given certificate chain.
29
38
///
@@ -162,9 +171,29 @@ extension CertificatePolicy {
162
171
// Custom error handling
163
172
let errorCode = CCryptoBoringSSL_X509_STORE_CTX_get_error ( ctx)
164
173
// Certs could have unknown critical extensions and cause them to be rejected.
165
- // Instead of disabling all critical extension checks with X509_V_FLAG_IGNORE_CRITICAL
166
- // we will just ignore this specific error.
174
+ // Check if they are tolerable.
167
175
if errorCode == X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION {
176
+ guard let cert = ctx? . pointee. current_cert else {
177
+ return result
178
+ }
179
+ for i in 0 ..< CCryptoBoringSSL_X509_get_ext_count ( cert) {
180
+ let ext = CCryptoBoringSSL_X509_get_ext ( cert, numericCast ( i) )
181
+ // Skip if extension is not critical or it is supported by BoringSSL
182
+ if CCryptoBoringSSL_X509_EXTENSION_get_critical ( ext) <= 0 || CCryptoBoringSSL_X509_supported_extension ( ext) > 0 { continue }
183
+
184
+ // Extract OID of the critical extension
185
+ let capacity = 100
186
+ let oidBuffer = UnsafeMutablePointer< Int8> . allocate( capacity: capacity)
187
+ defer { oidBuffer. deallocate ( ) }
188
+
189
+ let extObj = CCryptoBoringSSL_X509_EXTENSION_get_object ( ext)
190
+ guard CCryptoBoringSSL_OBJ_obj2txt ( oidBuffer, numericCast ( capacity) , extObj, numericCast ( 1 ) ) > 0 ,
191
+ let oid = String ( cString: oidBuffer, encoding: . utf8) ,
192
+ supportedCriticalExtensions. contains ( oid) else {
193
+ return result
194
+ }
195
+ }
196
+ // No actual unhandled critical extension found, so trust the cert chain
168
197
return 1
169
198
}
170
199
return result
@@ -173,7 +202,7 @@ extension CertificatePolicy {
173
202
174
203
guard CCryptoBoringSSL_X509_verify_cert ( x509StoreCtx) == 1 else {
175
204
let error = CCryptoBoringSSL_X509_verify_cert_error_string ( numericCast ( CCryptoBoringSSL_X509_STORE_CTX_get_error ( x509StoreCtx) ) )
176
- diagnosticsEngine. emit ( warning: " The certificate is invalid: \( String ( describing: error) ) " )
205
+ diagnosticsEngine. emit ( warning: " The certificate is invalid: \( String ( describing: error. flatMap { String ( cString : $0 , encoding : . utf8 ) } ) ) " )
177
206
return wrappedCallback ( . failure( CertificatePolicyError . invalidCertChain) )
178
207
}
179
208
@@ -481,6 +510,7 @@ enum CertificatePolicyError: Error, Equatable {
481
510
case unexpectedCertChainLength
482
511
case missingRequiredExtension
483
512
case extensionFailure
513
+ case unhandledCriticalException
484
514
case noTrustedRootCertsConfigured
485
515
case ocspSetupFailure
486
516
case ocspFailure
@@ -595,9 +625,6 @@ struct DefaultCertificatePolicy: CertificatePolicy {
595
625
/// marker extensions for Apple Distribution certifiications.
596
626
struct AppleDeveloperCertificatePolicy : CertificatePolicy {
597
627
private static let expectedCertChainLength = 3
598
- private static let appleDistributionIOSMarker = " 1.2.840.113635.100.6.1.4 "
599
- private static let appleDistributionMacOSMarker = " 1.2.840.113635.100.6.1.7 "
600
- private static let appleIntermediateMarker = " 1.2.840.113635.100.6.2.1 "
601
628
602
629
let trustedRoots : [ Certificate ] ?
603
630
let expectedSubjectUserID : String ?
@@ -666,10 +693,10 @@ struct AppleDeveloperCertificatePolicy: CertificatePolicy {
666
693
}
667
694
668
695
// Check marker extensions (certificates issued post WWDC 2019 have both extensions but earlier ones have just one depending on platform)
669
- guard try ( self . hasExtension ( oid: Self . appleDistributionIOSMarker, in: certChain [ 0 ] ) || self . hasExtension ( oid: Self . appleDistributionMacOSMarker, in: certChain [ 0 ] ) ) else {
696
+ guard try ( self . hasExtension ( oid: appleDistributionIOSMarker, in: certChain [ 0 ] ) || self . hasExtension ( oid: appleDistributionMacOSMarker, in: certChain [ 0 ] ) ) else {
670
697
return wrappedCallback ( . failure( CertificatePolicyError . missingRequiredExtension) )
671
698
}
672
- guard try self . hasExtension ( oid: Self . appleIntermediateMarker, in: certChain [ 1 ] ) else {
699
+ guard try self . hasExtension ( oid: appleIntermediateMarker, in: certChain [ 1 ] ) else {
673
700
return wrappedCallback ( . failure( CertificatePolicyError . missingRequiredExtension) )
674
701
}
675
702
0 commit comments