@@ -22,6 +22,7 @@ final class SignedDataVerifierTests: XCTestCase {
2222 private var REAL_APPLE_SIGNING_CERTIFICATE_BASE64_ENCODED = " MIIEMDCCA7agAwIBAgIQaPoPldvpSoEH0lBrjDPv9jAKBggqhkjOPQQDAzB1MUQwQgYDVQQDDDtBcHBsZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9ucyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTELMAkGA1UECwwCRzYxEzARBgNVBAoMCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMB4XDTIxMDgyNTAyNTAzNFoXDTIzMDkyNDAyNTAzM1owgZIxQDA+BgNVBAMMN1Byb2QgRUNDIE1hYyBBcHAgU3RvcmUgYW5kIGlUdW5lcyBTdG9yZSBSZWNlaXB0IFNpZ25pbmcxLDAqBgNVBAsMI0FwcGxlIFdvcmxkd2lkZSBEZXZlbG9wZXIgUmVsYXRpb25zMRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOoTcaPcpeipNL9eQ06tCu7pUcwdCXdN8vGqaUjd58Z8tLxiUC0dBeA+euMYggh1/5iAk+FMxUFmA2a1r4aCZ8SjggIIMIICBDAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFD8vlCNR01DJmig97bB85c+lkGKZMHAGCCsGAQUFBwEBBGQwYjAtBggrBgEFBQcwAoYhaHR0cDovL2NlcnRzLmFwcGxlLmNvbS93d2RyZzYuZGVyMDEGCCsGAQUFBzABhiVodHRwOi8vb2NzcC5hcHBsZS5jb20vb2NzcDAzLXd3ZHJnNjAyMIIBHgYDVR0gBIIBFTCCAREwggENBgoqhkiG92NkBQYBMIH+MIHDBggrBgEFBQcCAjCBtgyBs1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMDYGCCsGAQUFBwIBFipodHRwOi8vd3d3LmFwcGxlLmNvbS9jZXJ0aWZpY2F0ZWF1dGhvcml0eS8wHQYDVR0OBBYEFCOCmMBq//1L5imvVmqX1oCYeqrMMA4GA1UdDwEB/wQEAwIHgDAQBgoqhkiG92NkBgsBBAIFADAKBggqhkjOPQQDAwNoADBlAjEAl4JB9GJHixP2nuibyU1k3wri5psGIxPME05sFKq7hQuzvbeyBu82FozzxmbzpogoAjBLSFl0dZWIYl2ejPV+Di5fBnKPu8mymBQtoE/H2bES0qAs8bNueU3CBjjh1lwnDsI= "
2323
2424 private var EFFECTIVE_DATE : Date = Date ( timeIntervalSince1970: TimeInterval ( 1681312846 ) ) ; // April 2023
25+ private let CLOCK_DATE : Int64 = 41231
2526
2627 func testValidChainWithoutOCSP( ) async throws {
2728 let verifier : ChainVerifier = getChainVerifier ( base64EncodedRootCertificate: ROOT_CA_BASE64_ENCODED)
@@ -85,6 +86,43 @@ final class SignedDataVerifierTests: XCTestCase {
8586 }
8687 }
8788
89+ func testOcspResponseCaching( ) async throws {
90+ let verifier : DateOverrideChainVerifier = DateOverrideChainVerifier ( expectedCalls: 1 , currentDate: CLOCK_DATE, base64EncodedRootCertificate: ROOT_CA_BASE64_ENCODED) !
91+ let leaf = try ! Certificate ( derEncoded: Array ( Data ( base64Encoded: LEAF_CERT_BASE64_ENCODED) !) )
92+ let intermediate = try ! Certificate ( derEncoded: Array ( Data ( base64Encoded: INTERMEDIATE_CA_BASE64_ENCODED) !) )
93+ let _ = await verifier. verifyChain ( leaf: leaf, intermediate: intermediate, online: true , validationTime: EFFECTIVE_DATE)
94+ verifier. setDate ( newDate: CLOCK_DATE + 1 ) // 1 second
95+ let _ = await verifier. verifyChain ( leaf: leaf, intermediate: intermediate, online: true , validationTime: EFFECTIVE_DATE)
96+ }
97+
98+ func testOcspResponseCachingHasExpiration( ) async throws {
99+ let verifier : DateOverrideChainVerifier = DateOverrideChainVerifier ( expectedCalls: 2 , currentDate: CLOCK_DATE, base64EncodedRootCertificate: ROOT_CA_BASE64_ENCODED) !
100+ let leaf = try ! Certificate ( derEncoded: Array ( Data ( base64Encoded: LEAF_CERT_BASE64_ENCODED) !) )
101+ let intermediate = try ! Certificate ( derEncoded: Array ( Data ( base64Encoded: INTERMEDIATE_CA_BASE64_ENCODED) !) )
102+ let _ = await verifier. verifyChain ( leaf: leaf, intermediate: intermediate, online: true , validationTime: EFFECTIVE_DATE)
103+ verifier. setDate ( newDate: CLOCK_DATE + 900 ) // 15 minutes
104+ let _ = await verifier. verifyChain ( leaf: leaf, intermediate: intermediate, online: true , validationTime: EFFECTIVE_DATE)
105+ }
106+
107+ func testOcspResponseCachingWithDifferentChains( ) async throws {
108+ let verifier : DateOverrideChainVerifier = DateOverrideChainVerifier ( expectedCalls: 2 , currentDate: CLOCK_DATE, base64EncodedRootCertificate: ROOT_CA_BASE64_ENCODED) !
109+ let leaf = try ! Certificate ( derEncoded: Array ( Data ( base64Encoded: LEAF_CERT_BASE64_ENCODED) !) )
110+ let intermediate = try ! Certificate ( derEncoded: Array ( Data ( base64Encoded: INTERMEDIATE_CA_BASE64_ENCODED) !) )
111+ let altLeaf = try ! Certificate ( derEncoded: Array ( Data ( base64Encoded: LEAF_CERT_BASE64_ENCODED) !) )
112+ let altIntermediate = try ! Certificate ( derEncoded: Array ( Data ( base64Encoded: REAL_APPLE_INTERMEDIATE_BASE64_ENCODED) !) )
113+ let _ = await verifier. verifyChain ( leaf: leaf, intermediate: intermediate, online: true , validationTime: EFFECTIVE_DATE)
114+ let _ = await verifier. verifyChain ( leaf: altLeaf, intermediate: altIntermediate, online: true , validationTime: EFFECTIVE_DATE)
115+ }
116+
117+ func testOcspResponseCachingWithSlightlyDifferentChains( ) async throws {
118+ let verifier : DateOverrideChainVerifier = DateOverrideChainVerifier ( expectedCalls: 2 , currentDate: CLOCK_DATE, base64EncodedRootCertificate: ROOT_CA_BASE64_ENCODED) !
119+ let leaf = try ! Certificate ( derEncoded: Array ( Data ( base64Encoded: LEAF_CERT_BASE64_ENCODED) !) )
120+ let intermediate = try ! Certificate ( derEncoded: Array ( Data ( base64Encoded: INTERMEDIATE_CA_BASE64_ENCODED) !) )
121+ let altIntermediate = try ! Certificate ( derEncoded: Array ( Data ( base64Encoded: REAL_APPLE_INTERMEDIATE_BASE64_ENCODED) !) )
122+ let _ = await verifier. verifyChain ( leaf: leaf, intermediate: intermediate, online: true , validationTime: EFFECTIVE_DATE)
123+ let _ = await verifier. verifyChain ( leaf: leaf, intermediate: altIntermediate, online: true , validationTime: EFFECTIVE_DATE)
124+ }
125+
88126 // The following test will communicate with Apple's OCSP servers, disable this test for offline testing
89127 func testAppleChainIsValidWithOCSP( ) async throws {
90128 let verifier : ChainVerifier = getChainVerifier ( base64EncodedRootCertificate: REAL_APPLE_ROOT_BASE64_ENCODED)
@@ -216,4 +254,30 @@ final class SignedDataVerifierTests: XCTestCase {
216254 private func getChainVerifier( base64EncodedRootCertificate: String ) -> ChainVerifier {
217255 return try ! ChainVerifier ( rootCertificates: [ Data ( base64Encoded: base64EncodedRootCertificate) !] )
218256 }
257+
258+ class DateOverrideChainVerifier : ChainVerifier {
259+ var currentDate : Int64
260+ var expectation : XCTestExpectation
261+
262+ init ? ( expectedCalls: Int , currentDate: Int64 , base64EncodedRootCertificate: String ) {
263+ self . currentDate = currentDate
264+ self . expectation = XCTestExpectation ( )
265+ self . expectation. assertForOverFulfill = true
266+ self . expectation. expectedFulfillmentCount = expectedCalls
267+ try ? super. init ( rootCertificates: [ Data ( base64Encoded: base64EncodedRootCertificate) !] )
268+ }
269+
270+ func setDate( newDate: Int64 ) {
271+ self . currentDate = newDate
272+ }
273+
274+ override func verifyChainWithoutCaching( leaf: Certificate , intermediate: Certificate , online: Bool , validationTime: Date ) async -> X509 . VerificationResult {
275+ expectation. fulfill ( )
276+ return . validCertificate( [ ] )
277+ }
278+
279+ override func getDate( ) -> Date {
280+ return Date ( timeIntervalSince1970: TimeInterval ( currentDate) )
281+ }
282+ }
219283}
0 commit comments