@@ -8,8 +8,7 @@ import Crypto
88import AsyncHTTPClient
99import NIOFoundationCompat
1010
11- class ChainVerifier {
12-
11+ actor ChainVerifier {
1312 private static let EXPECTED_CHAIN_LENGTH = 3
1413 private static let EXPECTED_JWT_SEGMENTS = 3
1514 private static let EXPECTED_ALGORITHM = " ES256 "
@@ -28,7 +27,7 @@ class ChainVerifier {
2827 self . verifiedPublicKeyCache = [ : ]
2928 }
3029
31- func verify< T: DecodedSignedData > ( signedData: String , type: T . Type , onlineVerification: Bool , environment: AppStoreEnvironment ) async -> VerificationResult < T > where T: Decodable {
30+ func verify< T: DecodedSignedData > ( signedData: String , type: T . Type , onlineVerification: Bool , environment: AppStoreEnvironment , currentTime : Date = . now ) async -> VerificationResult < T > where T: Decodable & Sendable {
3231 let header : JWTHeader
3332 let decodedBody : T
3433 do {
@@ -67,9 +66,9 @@ class ChainVerifier {
6766 do {
6867 let leafCertificate = try Certificate ( derEncoded: Array ( leaf_der_enocded) )
6968 let intermediateCertificate = try Certificate ( derEncoded: Array ( intermeidate_der_encoded) )
70- let validationTime = !onlineVerification && decodedBody. signedDateOptional != nil ? decodedBody. signedDateOptional! : getDate ( )
69+ let validationTime = !onlineVerification && decodedBody. signedDateOptional != nil ? decodedBody. signedDateOptional! : currentTime
7170
72- let verificationResult = await verifyChain ( leaf: leafCertificate, intermediate: intermediateCertificate, online: onlineVerification, validationTime: validationTime)
71+ let verificationResult = await verifyChain ( leaf: leafCertificate, intermediate: intermediateCertificate, online: onlineVerification, validationTime: validationTime, currentTime : currentTime )
7372 switch verificationResult {
7473 case . validCertificate( let chain) :
7574 let leafCertificate = chain. first!
@@ -90,22 +89,22 @@ class ChainVerifier {
9089 }
9190 }
9291
93- func verifyChain( leaf: Certificate , intermediate: Certificate , online: Bool , validationTime: Date ) async -> X509 . VerificationResult {
92+ func verifyChain( leaf: Certificate , intermediate: Certificate , online: Bool , validationTime: Date , currentTime : Date = . now ) async -> X509 . VerificationResult {
9493 if online {
9594 if let cachedResult = verifiedPublicKeyCache [ CacheKey ( leaf: leaf, intermediate: intermediate) ] {
96- if cachedResult. expirationTime > getDate ( ) {
95+ if cachedResult. expirationTime > currentTime {
9796 return cachedResult. publicKey
9897 }
9998 }
10099 }
101- let verificationResult = await verifyChainWithoutCaching ( leaf: leaf, intermediate: intermediate, online: online, validationTime: validationTime)
100+ let verificationResult = await verifyChainWithoutCaching ( leaf: leaf, intermediate: intermediate, online: online, validationTime: validationTime, currentTime : currentTime )
102101
103102 if online {
104103 if case . validCertificate = verificationResult {
105- verifiedPublicKeyCache [ CacheKey ( leaf: leaf, intermediate: intermediate) ] = CacheValue ( expirationTime: getDate ( ) . addingTimeInterval ( TimeInterval ( integerLiteral: ChainVerifier . CACHE_TIME_LIMIT) ) , publicKey: verificationResult)
104+ verifiedPublicKeyCache [ CacheKey ( leaf: leaf, intermediate: intermediate) ] = CacheValue ( expirationTime: currentTime . addingTimeInterval ( TimeInterval ( integerLiteral: ChainVerifier . CACHE_TIME_LIMIT) ) , publicKey: verificationResult)
106105 if verifiedPublicKeyCache. count > ChainVerifier . MAXIMUM_CACHE_SIZE {
107106 for kv in verifiedPublicKeyCache {
108- if kv. value. expirationTime < getDate ( ) {
107+ if kv. value. expirationTime < currentTime {
109108 verifiedPublicKeyCache. removeValue ( forKey: kv. key)
110109 }
111110 }
@@ -116,21 +115,17 @@ class ChainVerifier {
116115 return verificationResult
117116 }
118117
119- func verifyChainWithoutCaching( leaf: Certificate , intermediate: Certificate , online: Bool , validationTime: Date ) async -> X509 . VerificationResult {
118+ nonisolated func verifyChainWithoutCaching( leaf: Certificate , intermediate: Certificate , online: Bool , validationTime: Date , currentTime : Date = . now ) async -> X509 . VerificationResult {
120119 var verifier = Verifier ( rootCertificates: self . store) {
121120 RFC5280Policy ( validationTime: validationTime)
122121 AppStoreOIDPolicy ( )
123122 if online {
124- OCSPVerifierPolicy ( failureMode: . hard, requester: requester, validationTime: getDate ( ) )
123+ OCSPVerifierPolicy ( failureMode: . hard, requester: requester, validationTime: currentTime )
125124 }
126125 }
127126 let intermediateStore = CertificateStore ( [ intermediate] )
128127 return await verifier. validate ( leafCertificate: leaf, intermediates: intermediateStore)
129128 }
130-
131- func getDate( ) -> Date {
132- return Date ( )
133- }
134129}
135130
136131struct CacheKey : Hashable {
@@ -217,7 +212,7 @@ final class Requester: OCSPRequester {
217212 private struct OCSPFetchError : Error { }
218213}
219214
220- public enum VerificationResult < T> {
215+ public enum VerificationResult < T: Hashable & Sendable > : Hashable , Sendable {
221216 case valid( T )
222217 case invalid( VerificationError )
223218}
0 commit comments