How to fetch a certificate chain from keychain

I am able to retrieve individual certificates (end-user cert issues by root CA) present on the device using SecItemCopyMatching. But, how do I retrieve all the certificates that are part of a certificate chain i.e. end-user certificate issues by an intermediate CA which in turn is signed by another intermediate CA and so on and which is eventually signed by root CA? IS there a way to associate all these certificates as part of a single chain certificate?

To do this you have to search for a path from the leaf to the root, and you can do that using a trust object (

SecTrust
). Specifically, evaluating a trust object (
SecTrustEvaluate
) will first build a chain of trust and then evaluate various policies against that chain. Regardless of whether the policies succeed or fail — that is, regardless of the
SecTrustResultType
you get back — if a valid chain was found then it’ll be available via
SecTrustGetCertificateCount
and
SecTrustGetCertificateAtIndex
.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for the reply Eskimo!


Could you elaborate a bit more? Currently, I am deploying a configuration profile on the device via MDM that contains a certificate payload as well as a vpn payload. I am fetching the identity using SecItemCopyMatching. Then, I am using SecIdentityCopyCertificate and SecIdentityCopyPrivateKey to fetch certificate and the private key from the identity and use the private key to create a signature using SecKeyCreateSignature. Where does SecTrust object fit into this picture and how to I even know if the cert is part of a certificate chain by looking at the result of SecItemCopyMatching?

I’m still not clear on your goals here: Once you build this certificate chain what do you plan to do with it?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

The certificate chain will already be built and deployed on the device by an mdm provider alongwith the vpn configuration. I plan to fetch these certs and send to a service that can validate the certs and the user.

4-party validation seems a bit much, and not just because every added check is another opportunity to spoof...who validates the validator?


What happens if a new cert is put in place on the device while your server is making it's check? At some point, you need to let the as-designed process do it's job. Check-re-checks have their limits. Why not just validate the chain and be done...

The certificate chain will already be built and deployed on the device by an mdm provider alongwith the vpn configuration.

In this context “certificate” is quite ambiguous. What sort of payloads are we looking at?

com.apple.security.pkcs12
?
com.apple.security.pem
?
com.apple.security.pkcs1
?
com.apple.security.root
?

Note You can learn more about these payloads in the Configuration Profile Reference.

Also, is this VPN configuration for one of the built-in VPN transport? Or for a custom VPN transport (that is, a Network Extension packet tunnel provider or app proxy provider) that you’re creating?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

It is a com.apple.security.pkcs12 payload along with a custom VPN payload. Is it not possible to install a certificate chain using a com.apple.security.pkcs12 payload?


I will be more specific with my question-

Is there a way to get the Private Key (SecKeyRef object) of the leaf cert once the trust chain has been established? I see that the Public Key can be retrieved with SecTrustCopyPublicKey and specific certificates can be retrieved with SecTrustGetCertificateAtIndex but I also need the private key to create a signature using SecKeyCreateSignature.

Is there a way to get the Private Key (

SecKeyRef
object) of the leaf cert once the trust chain has been established?

Certificates don’t contain private keys. For that you need a digital identity (

SecIdentity
), which is the combination of a certificate and the private key that matches the public key in that certificate.

If you have an identity you can get the private key using

SecIdentityCopyPrivateKey
.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Is it not possible to install a certificate chain using a com.apple.security.pkcs12 payload?


> Certificates don’t contain private keys.

Yes, but the SecTrust object doesn't return an identity as far as I can see. It only has SecTrustCopyPublicKey and SecTrustGetCertificateAtIndex. So how do I retrieve a private key for a leaf cert in the cert chain?

I’m sorry this is taking so long. I think the source of my confusion is that you’re asking a very simple question (how to get the private key for a VPN configuration) using terminology from some other platform (certificate chains) that does not apply on iOS.

Is it not possible to install a certificate chain using a

com.apple.security.pkcs12
payload?

A PKCS#12 contains a digital identity, that is, the leaf certificate and its associated private key. It can also contain intermediate certificates (which creates a certificate chain, I guess) but it’s hard to access those on iOS.

So, anyway, let’s assume you’ve created a VPN configuration profile with a

com.apple.security.pkcs12
payload. How do you access that private key? Here’s how to do that:
  1. When the system installs the configuration profile the

    com.apple.vpn.managed
    payload creates a VPN configuration and the
    com.apple.security.pkcs12
    payload is unpacked and the resulting digital identity is put in the keychain with its access group set to
    com.apple.managed.vpn.shared
    .
  2. If you’re an enterprise-focused VPN app you can apply for the entitlement necessary to access that keychain access group (if you don’t already have that entitlement, see Network Extension Framework Entitlements).

  3. The resulting VPN configuration will have its

    identityReference
    property set to point to the imported digital identity. You need to follow that reference to get a digital identity object (
    SecIdentity
    ). I just posted code to do that in your other thread.
  4. From there you can get the private key using

    SecIdentityCopyPrivateKey
    .

What else do you need?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi Eskimo. Sorry for the confusion and thanks for responding!


> I think the source of my confusion is that you’re asking a very simple question (how to get the private key for a VPN configuration) using terminology from some other platform (certificate chains) that does not apply on iOS.


I am not asking how to get a private key from a VPN configuration. Why do you say certificate chains do not apply on iOS? What is the correct terminology that is used for certificate chain equivalents on iOS?


>A PKCS#12 contains a digital identity, that is, the leaf certificate and its associated private key. It can also contain intermediate certificates (which creates a certificate chain, I guess) but it’s hard to access those on iOS.


This is precisely my question. How do I access these intermediate certificates (or certificate chain) if they are deployed using a com.apple.security.pkcs12 payload? Is there a way to get the entire chain from the leaf cert to the root cert? Is using SecTrust object a way to do that?

I am not asking how to get a private key from a VPN configuration.

But but but… that’s exactly what you asked in your 4 Dec post:

So how do I retrieve a private key for a leaf cert in the cert chain?

How do I access these intermediate certificates (or certificate chain) if they are deployed using a

com.apple.security.pkcs12
payload?

I don’t think that’s possible. Last I checked iOS’s PKCS#12 importer will only return the main digital identity. It will not return any intermediates that happen to be packaged in the PKCS#12.

You may be able to make this work by putting those intermediates in a

com.apple.security.pem
or
com.apple.security.pkcs1
payload. However, I’m not sure that’ll work because I think that those certificates will end up in the wrong keychain access group.

You might also try getting the leaf certificate from the digital identity and evaluating trust on it. If the system can find the intermediates anywhere, it should fill them in during the trust evaluation process. I suspect, however, that this will also fail because the intermediates simply aren’t available.

There’s a lot of educated (guesswork) in the above. If you’d like me to look into this in detail, I recommend that you open a DTS tech support incident and we can take things from there.

If you do this, please reference this DevForums thread for context.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

But but but… that’s exactly what you asked in your 4 Dec post:

So how do I retrieve a private key for a leaf cert in the cert chain?

That was about how to retrieve a private key for a leaf cert from SecTrust as I thought from your previous replies that cert chain would be stored in SecTrust object to evaluate Trust which had SecTrustCopyPublicKey and SecTrustGetCertificateAtIndex methods to retrieve Public key and certificates.


Anyway, thanks for your answer. It gives me a good overview of some of the possibilities and issues with implementing those options. I will open a DTS tech support incident if I need more information. This was a good discussion!

How to fetch a certificate chain from keychain
 
 
Q