How to find if a pinned certificate is expired when iOS SSL is pinned with info.plist

I SSL pinned our app in info.plist by following this Apple.com's link.

I would like to show alert when certificate expired or handshaking expired.

Can someone please tell me how can I use this method for that?

func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void) {

}
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
        <key>NSPinnedDomains</key>
        <dict>
            <key>OurAppDomain.com</key>
            <dict>
                <key>NSIncludesSubdomains</key>
                <true/>
                <key>NSPinnedCAIdentities</key>
                <array>
                    <dict>
                        <key>SPKI-SHA256-BASE64</key>
                        <string>XYZXYZXYZXYZkdlkjs78YDIU787d9=</string>
                    </dict>
                </array>
            </dict>
        </dict>
    </dict>

Read here

  • https://www.raywenderlich.com/1484288-preventing-man-in-the-middle-attacks-in-ios-with-ssl-pinning
  • https://betterprogramming.pub/how-to-implement-ssl-pinning-in-swift-7c4e8f6ee821

Recommended

  • https://www.netguru.com/blog/certificate-pinning-in-ios

First: why do you want to show the user a message specifically for the case that your server certificate expired? There’s nothing a user can do about it, and worrying about certificate configuration is the job of your server admins, not users. I’d suggest that you just allow network operations to fail as designed and inform the user with a more appropriate level of detail. Your URL task already fails with an error that provides this message suitable for display: “An SSL error has occurred and a secure connection to the server cannot be made.”

Having said that, it appears cumbersome to do what you want. In the urlSession(_:didReceive:completionHandler:) delegate method, you would need to examine the certificate chain (challenge.protectionSpace.serverTrust) and essentially duplicate work that the system does by default when you subsequently tell it to performDefaultHandling. It gets messy.

BTW (if I’m reading it right) your question isn’t specific to certificate pinning, whether Info.plist-based or homebrew. An expired certificate will fail the handshake regardless of the pinning situation.

Still not sure I understand the objective. Your app is for tech-savvy insiders, and for that audience it’s fine to tell them to update to a newer app version if the server certificate gets changed and no longer matches the one pinned in the app? That’s fine I guess. Given this, a lower-effort solution can be simply to notify the user whenever an SSL failure happens (the -1200 code) and remind them to update to the newest app version if available.

You can check that error code in the Error object thrown (if using await) or passed to the completion handler of your URL session task call. The real type is NSError which has a code value you can check. It appears all SSL errors get reported as NSURLErrorSecureConnectionFailed (-1200). I just tried with https://expired.badssl.com and with a bad pinning setup and got the same -1200 for each. If this is sufficient for your needs, great.

Or if you really really need to differentiate between types of SSL errors, then implement that delegate method with your own custom logic to inspect the server certificate. You’ll see challenge.protectionSpace.serverTrust is of type SecTrust so you’ll use the trust API functions for this. That’s an old CoreFoundation-style C API which is less fun to use from Swift, but of course it works.

How to find if a pinned certificate is expired when iOS SSL is pinned with info.plist
 
 
Q