Can a Developer ID Packet Tunnel System Extension access a hardware-bound ACME identity from a managed VPN profile?

I’m developing a macOS VPN app distributed directly with Developer ID. Its NEPacketTunnelProvider is packaged as a System Extension (packet-tunnel-provider-systemextension). On macOS 15.6 (24G84), I installed a configuration profile containing:

  • A com.apple.security.acme payload with HardwareBound=true, Attest=true, and a P-256 key.
  • A com.apple.vpn.managed payload whose PayloadCertificateUUID references that ACME payload. VPNSubType and ProviderBundleIdentifier identify my app and provider.

macOS issued the certificate, and the managed VPN starts the provider. In startTunnel, protocolConfiguration.identityReference is non-nil (20 bytes). However, resolving it in the provider returns -25291 (errSecNotAvailable): `let query: [CFString: Any] = [ kSecClass: kSecClassIdentity, kSecValuePersistentRef: identityReference, kSecUseDataProtectionKeychain: true, kSecReturnRef: true, kSecMatchLimit: kSecMatchLimitOne ] var result: CFTypeRef? let status = SecItemCopyMatching(query as CFDictionary, &result)

The containing app receives the same non-nil reference, but its identity query returns -25306. Neither binary currently has the com.apple.managed.vpn.shared keychain access group; I understand that this group requires a separate managed capability. An Apple Device Management Engineer states that third-party processes cannot access hardware-bound ACME identities in the Data Protection Keychain, with an exception for VPN extensions. The NETunnelProviderManager documentation says that apps and Packet Tunnel Providers need com.apple.managed.vpn.shared to use credentials supplied by configuration profiles. Is com.apple.managed.vpn.shared the supported way for a Developer ID Packet Tunnel System Extension to resolve this specific hardware-bound ACME identity? If granted, should the provider use the query above, or another public API? Does the VPN-extension exception apply when the System Extension runs outside the logged-in user’s keychain context? If this is unsupported for a System Extension, what is the supported approach for a directly distributed Developer ID VPN app to perform client authentication with this non-exportable key? I need a usable SecIdentity or signing operation, not the private-key bytes.

Answered by Device Management Engineer in 907481022

This will not work.

On iOS, iPadOS, visionOS, and tvOS, the PayloadCertificateUUID can reference any identity type, including an ACME payload with HardwareBound set to true. The operating system copies that identity into the com.apple.managed.vpn.shared keychain access group. Developers of VPN extensions can apply for the entitlement for this keychain access group, and then their extension is able to access the identity.

On macOS we three additional complications that overlap: File-based vs data protection keychains, system vs user keychains, and app extensions vs system extensions.

The legacy file-based keychain system does not support hardware-bound keys at all. When the ACME client creates a hardware-bound key it must put it in a data protection keychain.

When the MDM server installs the profile containing an ACME payload and VPN payload, it installs it on either the system or user MDM channel. When the Mac installs the ACME payload, it puts the resulting identity in the corresponding system or user data protection keychain.

Third party code cannot access the system keychain; only OS components can. Your VPN extension is packaged as a system extension. This makes it able to run at all times, even when no user is logged in. However this also means it cannot access the user keychain.

ManagedApp framework does not solve this problem either. Although it can deliver hardware-bound keys, it only delivers them to managed apps and those apps' app extensions. Since your VPN extension is a system extension, it cannot use ManagedApp framework.

I suggest filling feedback explaining how your VPN extension is affected.

    kSecClass: kSecClassIdentity,
    kSecValuePersistentRef: identityReference,
    kSecUseDataProtectionKeychain: true,
    kSecReturnRef: true,
    kSecMatchLimit: kSecMatchLimitOne
]
var result: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &result)

This will not work.

On iOS, iPadOS, visionOS, and tvOS, the PayloadCertificateUUID can reference any identity type, including an ACME payload with HardwareBound set to true. The operating system copies that identity into the com.apple.managed.vpn.shared keychain access group. Developers of VPN extensions can apply for the entitlement for this keychain access group, and then their extension is able to access the identity.

On macOS we three additional complications that overlap: File-based vs data protection keychains, system vs user keychains, and app extensions vs system extensions.

The legacy file-based keychain system does not support hardware-bound keys at all. When the ACME client creates a hardware-bound key it must put it in a data protection keychain.

When the MDM server installs the profile containing an ACME payload and VPN payload, it installs it on either the system or user MDM channel. When the Mac installs the ACME payload, it puts the resulting identity in the corresponding system or user data protection keychain.

Third party code cannot access the system keychain; only OS components can. Your VPN extension is packaged as a system extension. This makes it able to run at all times, even when no user is logged in. However this also means it cannot access the user keychain.

ManagedApp framework does not solve this problem either. Although it can deliver hardware-bound keys, it only delivers them to managed apps and those apps' app extensions. Since your VPN extension is a system extension, it cannot use ManagedApp framework.

I suggest filling feedback explaining how your VPN extension is affected.