Expiry Date and other meta data of SecIdentity and attached certificates parsed through SecPKCS12Import on iOS

TLDR; Is there a way (on iOS 11 upwards) to get the expiry date of a SecIdentity's certificate imported with SecPKCS12Import?


In order to support client certificates for NSStream based TLS TCP connections in an iOS app we're importing the certificates with SecPKCS12Import, extracting the common name and related emails of the certificate for displaying information to the user, generating our own UUID to re-identify this identity later and store it in the keychain. The UUID is packed into the label, which does not help in directly looking the identity up later, but together with equality on SecIdentity helps to identitfy already imported certificates and link them to our own DB.


Now a typical use case for a client certificate is to let it expire every now and then, send out new ones to the users and let them handle the update. Knowing the expiry date of identities (which really means the expiry dates of their related certificates) is needed in this case, otherwise I don't see any other data that could let the user easily differentiate between the old, no longer valid identity and the new one.

Answered by Systems Engineer in 408821022

Yeah, this is difficult as there is no API for accessing the Not Valid After property of the certificate embedded in the P12. One option that may help is by creating a SecTrust object from your PKCS12 data and examining the kSecTrustResultValue to see if this value still returns a 1. If you can examine kSecTrustResultValue and return a 1 you can assume you still have a valid identity.


let password = "password"
let options = [ kSecImportExportPassphrase as String: password ]
var rawItems: CFArray?
let status = SecPKCS12Import(data as CFData,
                             options as CFDictionary,
                             &rawItems)


guard status == errSecSuccess else {
    os_log("status was not errSecSuccess: %{public}@", status)
    return
}
let items = rawItems! as! Array<Dictionary<String, Any>>


let item = items[0]
let secTrust: SecTrust = item[kSecImportItemTrust as String] as! SecTrust
if let secTrustResults = SecTrustCopyResult(secTrust) as? [String: AnyObject],
    let trustEvaluationDate = secTrustResults[kSecTrustEvaluationDate as String], // CFDateRef representing when the evaluation for this trust object took place.
    let trustResult = secTrustResults[kSecTrustResultValue as String] // CFNumberRef representing the SecTrustResultType result for the evaluation.
{
    os_log("Trust Evaluation Date: %{public}@", String(describing: trustEvaluationDate))
    os_log("Trust Evaluation Result: %{public}@", String(describing:trustResult))
}


Matt Eaton

DTS Engineering, CoreOS

meaton3 at apple.com

Accepted Answer

Yeah, this is difficult as there is no API for accessing the Not Valid After property of the certificate embedded in the P12. One option that may help is by creating a SecTrust object from your PKCS12 data and examining the kSecTrustResultValue to see if this value still returns a 1. If you can examine kSecTrustResultValue and return a 1 you can assume you still have a valid identity.


let password = "password"
let options = [ kSecImportExportPassphrase as String: password ]
var rawItems: CFArray?
let status = SecPKCS12Import(data as CFData,
                             options as CFDictionary,
                             &rawItems)


guard status == errSecSuccess else {
    os_log("status was not errSecSuccess: %{public}@", status)
    return
}
let items = rawItems! as! Array<Dictionary<String, Any>>


let item = items[0]
let secTrust: SecTrust = item[kSecImportItemTrust as String] as! SecTrust
if let secTrustResults = SecTrustCopyResult(secTrust) as? [String: AnyObject],
    let trustEvaluationDate = secTrustResults[kSecTrustEvaluationDate as String], // CFDateRef representing when the evaluation for this trust object took place.
    let trustResult = secTrustResults[kSecTrustResultValue as String] // CFNumberRef representing the SecTrustResultType result for the evaluation.
{
    os_log("Trust Evaluation Date: %{public}@", String(describing: trustEvaluationDate))
    os_log("Trust Evaluation Result: %{public}@", String(describing:trustResult))
}


Matt Eaton

DTS Engineering, CoreOS

meaton3 at apple.com

Expiry Date and other meta data of SecIdentity and attached certificates parsed through SecPKCS12Import on iOS
 
 
Q