Is there a way to associate a certificate with a vpn profile?

I deployed a custom VPN configuration on the device alongwith a MDM certificate. The field "Identifier" of the VPN configuration has the value same as that of my app's bundle identifier so that my app uses that VPN profile for network extension. While establishing a vpn connection, I want to verify the MDM certificate that is deployed along with my vpn configuration. But, SecItemCopyMatching returns all the certificates present on the device and not just the one associated with my vpn configuration. Is there a way to filter the certificates based on the vpn profile that contains them?

Accepted Reply

Yes I do get the

identityReference
but it is in the
NSData
format.

That’s expected. The data is a persistent reference to an item in the keychain, and you can find the underlying item with code like this:

let persistentRef: Data = …
var copyResult: CFTypeRef? = nil
let err = SecItemCopyMatching([
    kSecValuePersistentRef: persistentRef,
    kSecReturnRef: true
] as NSDictionary, &copyResult)
guard err == errSecSuccess else {
    … handle the error …
}
let identity = copyResult! as! SecIdentity
print(identity)

Share and Enjoy

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

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

Replies

There’s four steps to make this work:

  1. Your app must have access to the

    com.apple.managed.vpn.shared
    keychain access group, as described in FAQ#9 in the Network Extension Framework Entitlements.
  2. Your certificate payload (

    com.apple.security.pkcs12
    ) must be in the same configuration profile as the VPN payload (
    com.apple.vpn.managed
    or
    com.apple.vpn.managed.applayer
    ).
  3. Your VPN payload must have

    AuthenticationMethod
    set to
    Certificate
    .
  4. Your VPN payload must explicitly reference the certificate payload via the

    PayloadCertificateUUID
    property.

With regards the last two points, the best way to make sure your VPN payload is set up correctly is to use Apple Configurator to create the profile, setting the VPN type to Custom SSL.

Share and Enjoy

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

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

Thanks for the answer Eskimo. I can confirm that I have all of these setup correctly. Still, when I call SecItemCopyMatching, it returns all the certificates in the keychain. Is there any specific filter that I should add to the dictionary that I am passing in SecItemCopyMatching? Or is there a different method to fetch just the certificate associated with vpn profile?

Still, when I call SecItemCopyMatching, it returns all the certificates in the keychain.

Indeed. Sorry, I misread your original email.

Do you not get a reference to the right digital identity via the

identityReference
property of the
NETunnelProviderProtocol
object?

Share and Enjoy

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

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

> Do you not get a reference to the right digital identity via the

identityReference
property of the
NETunnelProviderProtocol
object?


Yes I do get the identityReference but it is in the NSData format. What I need is a SecIdentityRef so that I can use all the apple-provided functions like SecIdentityCopyPrivateKey, SecIdentityCopyCertificate, SecKeyCreateSignature etc. Is there a way to get is in the SecIdentityRef format or convert what I get in NSData format into SecIdentityRef?

Yes I do get the

identityReference
but it is in the
NSData
format.

That’s expected. The data is a persistent reference to an item in the keychain, and you can find the underlying item with code like this:

let persistentRef: Data = …
var copyResult: CFTypeRef? = nil
let err = SecItemCopyMatching([
    kSecValuePersistentRef: persistentRef,
    kSecReturnRef: true
] as NSDictionary, &copyResult)
guard err == errSecSuccess else {
    … handle the error …
}
let identity = copyResult! as! SecIdentity
print(identity)

Share and Enjoy

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

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

Thanks Eskimo! This solved my issue.