-34018 when using Secure Enclave

I'm trying to modify Chromium to generate a key pair in the Secure Enclave on MacOS, but I'm always getting the following error

OSStatus error -34018 - failed to generate asymmetric keypair

from the following code.

  CFErrorRef access_error = NULL;
  SecAccessControlRef access_control = SecAccessControlCreateWithFlags(
    kCFAllocatorDefault,
    kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
    kSecAccessControlPrivateKeyUsage,
    &access_error
  );

  NSDictionary *attributes = @{
    (__bridge id)kSecAttrKeyType: (__bridge id)kSecAttrKeyTypeECSECPrimeRandom,
    (__bridge id)kSecAttrKeySizeInBits: @256,
    (__bridge id)kSecAttrTokenID: (__bridge id)kSecAttrTokenIDSecureEnclave,
    (__bridge id)kSecPrivateKeyAttrs: @{
        (__bridge id)kSecAttrIsPermanent: @YES,
        (__bridge id)kSecAttrAccessControl: (__bridge id)access_control
    }
  };

  CFErrorRef creation_error = NULL;
  SecKeyRef key_ref = SecKeyCreateRandomKey((__bridge CFDictionaryRef)attributes, &creation_error);
  if (creation_error != NULL)
    LOG(ERROR) << "Failed to create key: " << CFErrorCopyDescription(creation_error);

-34018 seems to map to errSecMissingEntitlement, but I'm not sure what the missing entitlement is. Chromium comes with several entitlements configured, and I've signed and notarized the app, but it still does not work with the installed app from the notarized .dmg file.

Running

codesign -d --entitlements - Chromium.app

returns

[Dict]
    [Key] com.apple.application-identifier
    [Value]
        [String] <redacted-teamid>.<redacted-bundleid>
    [Key] keychain-access-groups
    [Value]
        [Array]
            [String] <redacted-teamid>.<redacted-bundleid>.devicetrust
            [String] <redacted-teamid>.<redacted-bundleid>.webauthn

Checking the embedded .provisionprofile (and the DER encoded profile) per these instructions also shows these entitlements in the notarized .app.

The same code works in a local Xcode project, so I figure it must be how I've configured Chromium, but I can't figure out what the missing piece is.

I am able to create keys in the keychain, in Chromium, if I remove the kSecAttrAccessControl and kSecAttrTokenID attributes. It's only when I'm trying to access the secure enclave, it seems.

I've tried multiple things to find the issue:

Does anyone see what the issue could be? This is all running on my M2 MacBook Pro on Ventura 13.3, if it matters.

Replies

-34018 seems to map to errSecMissingEntitlement, but I'm not sure what the missing entitlement is.

It’s com.apple.application-identifier. Using the Secure Enclave requires that your app have a registered App ID, which means it must be signed with this entitlement and that entitlement must be authorised by a provisioning profile.

If you put your code into a small test app, does it have the same problem?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for the response, Quinn. I believe my app has the com.apple.application-identifier entitlement, and so does the provisioning profile, but I could be wrong as the code works in a small test app in Xcode. Is there a way to check that this entitlement is present in the signed and notarized app? I've been running the following commands, which lead me to believe that we have the entitlement and proper authorization.

% codesign -d --entitlements - Browser.app

returns

Executable=/Applications/Browser.app/Contents/MacOS/Browser
[Dict]
	[Key] com.apple.application-identifier
	[Value]
		[String] TL6P21MQR.com.contoso.browser
	[Key] keychain-access-groups
	[Value]
		[Array]
			[String] TL6P21MQR.com.contoso.browser.devicetrust
			[String] TL6P21MQR.com.contoso.browser.webauthn

Inside of Browser.app I see the embedded.provisionprofile and looking in the DER encoded profile with these commands

% security cms -D -i embedded.provisionprofile -o Browser-payload.plist 
% plutil -extract DER-Encoded-Profile raw -o - Browser-payload.plist | base64 -D > Browser.der
% security cms -D -i Browser.der -o Browser-payload.der
% openssl asn1parse -in Browser-payload.der -inform der -i | cut -c 30-

Shows that the application-identifer entitlement is authorized by the provision profile, here are the seemingly relevant pieces of the output:

SET               
 SEQUENCE          
  UTF8STRING        :Version
  INTEGER           :01
...
SEQUENCE          
  UTF8STRING        :TeamIdentifier
  SEQUENCE          
   UTF8STRING        :TL6P21MQR
...
 SEQUENCE          
  UTF8STRING        :ApplicationIdentifierPrefix
  SEQUENCE          
   UTF8STRING        :TL6P21MQR
...
 SEQUENCE          
  UTF8STRING        :Entitlements
  appl [ 16 ]       
   INTEGER           :01
   cont [ 16 ]       
    SEQUENCE          
     UTF8STRING        :com.apple.application-identifier
     UTF8STRING        :TL6P21MQR.com.contoso.browser
    SEQUENCE          
     UTF8STRING        :com.apple.developer.team-identifier
     UTF8STRING        :TL6P21MQR
    SEQUENCE          
     UTF8STRING        :keychain-access-groups
     SEQUENCE          
      UTF8STRING        :TL6P21MQR.*

It seems to me like everything is in order, or am I missing something? Let me know if I left out any important details, and thanks again for your help.

I've been running the following commands, which lead me to believe that we have the entitlement and proper authorization.

Right.

The first command is the one that matters here. It shows that you claim com.apple.application-identifier. And if you claimed it and your profile wasn’t up to snuff, the system would block your app from launching.

You’re not claiming com.apple.developer.team-identifier, which is weird. When you sign with Xcode, it usually treats those as a pair.

the code works in a small test app in Xcode.

If you dump the entitlements of your small test app, do you see any other differences?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I'm signing using a modified version of a script that comes with Chromium which uses codesign for signing. Is there some configuration that was missed that should cause this entitlement to be included?

I tried to add the entitlement manually, but it didn't seem to have an effect (still seeing -34018).

As for the local test app, not much seems different, it does have the team-identifier entitlement you mentioned. This is from the exported, notarized archive of my test app, which shares the same name as the Browser app, so the same provisioning profile would work:

[Dict]
	[Key] com.apple.application-identifier
	[Value]
		[String] TL6P21MQR.com.contoso.browser

	[Key] com.apple.developer.team-identifier
	[Value]
		[String] TL6P21MQR

	[Key] keychain-access-groups
	[Value]
		[Array]
			[String] TL6P21MQR.keychain
  • The script is here, if you're interested: https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/mac/sign_chrome.py

  • While I don’t have a solution, I’m extremely interested in what you come up with. Secure Enclave-backed mTLS would be a game changer. If you are working somewhere public please share your code. I think we can potentially contact hmare (author of the Secure Enclave key helper code) at Google to share this work, get her opinion, and maybe even get it upstreamed.

  • I've spoken with hmare, and wile she was very kind and helpful, we weren't able to root cause the problem. She suggested I post to the chromium-dev Google group, but I didn't get any traction on this question there: https://groups.google.com/a/chromium.org/g/chromium-dev/c/xkx_AhcLZ8Q

    Unfortunately my project isn't open source right now :(

Add a Comment

Is there some configuration that was missed that should cause this entitlement to be included?

If you have questions about third-party tools or libraries, I recommend that you escalate them via the vendor’s support channel.

Are you sure that the code making the SecKeyCreateRandomKey call is in the main executable of your app? Browser frameworks often do networking in a secondary process, and their entitlements are controlled by their main executable, not by the main executable of the app itself.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thank you for your help Quinn, your most recent reply put me on the right path. While the code is in the main executable, something is going wrong during the signing process. I found this article which shares some Swift code that lets you query for entitlements at runtime: https://developer.apple.com/documentation/Xcode/signing-a-daemon-with-a-restricted-entitlement

Once converted to Obj-C, I could see that I didn't have any entitlements at all. Even in the main function of the app, there were no entitlements. It's odd to me that codesign reports the correct entitlements for the .app file, but they aren't present at runtime. I'm fiddling with our signing script now, and am finally seeing success.

Thanks again for your help!