iosswiftsslios15

Replace deprecated `SecTrustGetCertificateAtIndex` in iOS 15?


I'm getting a deprecation warning in iOS 15 SDK, but the suggested replacement is not a one-to-one replacement. This is what I have for evaluating the SSL trust chain:

func valid(_ trust: SecTrust, forHost host: String) -> Bool {
    guard valid(trust, for: [SecPolicyCreateSSL(true, nil)]),
        valid(trust, for: [SecPolicyCreateSSL(true, host as CFString)]) else {
            return false
    }

    let serverCertificatesData = Set(
        (0..<SecTrustGetCertificateCount(trust))
            .compactMap { SecTrustGetCertificateAtIndex(trust, $0) }
            .map { SecCertificateCopyData($0) as Data }
    )

    let pinnedCertificatesData = Set(
        certificates.map { SecCertificateCopyData($0) as Data }
    )

    return !serverCertificatesData.isDisjoint(with: pinnedCertificatesData)
}

The warning I get in Xcode 13 beta is:

'SecTrustGetCertificateAtIndex' was deprecated in iOS 15.0: renamed to 'SecTrustCopyCertificateChain(_:)'. 
Use 'SecTrustCopyCertificateChain(_:)' instead.

However, SecTrustGetCertificateAtIndex (docs) returns SecCertificate where SecTrustCopyCertificateChain (docs) returns a CFArray. How can this properly be updated in the usage I provided?


Solution

  • iOS 14.5 => iOS 15 SDK Diff indicates that the only additions are these (as of Xcode 13 Beta 1)

    SecBase.h
    Added errSecInvalidCRLAuthority
    Added errSecInvalidTupleCredentials
    Added errSecCertificateDuplicateExtension
    
    SecTrust.h
    Added SecTrustCopyCertificateChain()
    

    They didn't add any new sibling type to SecCertificate. As you already noted that it returns a CFArray.

    func SecTrustCopyCertificateChain(_ trust: SecTrust) -> CFArray?
    

    So for this part of your code -

    let serverCertificatesData = Set(
        (0..<SecTrustGetCertificateCount(trust))
            .compactMap { SecTrustGetCertificateAtIndex(trust, $0) }
            .map { SecCertificateCopyData($0) as Data }
    )
    

    It seems worth a try that SecTrustCopyCertificateChain might return a CFArray of SecCertificate instances? Unfortunately I can't debug this right now.

    Maybe try something like this -

    if let certificates = SecTrustCopyCertificateChain(trust) as? [SecCertificate] {
        let serverCertificatesData = Set(
            certificates.map { SecCertificateCopyData($0) as Data }
        )
    }