Think I am misunderstanding keychain-access-groups, can anyone confirm how I should be handling it

I have a really simple profile, the entitlements are as follows.

<key>Entitlements</key>
<dict>
	<key>com.apple.application-identifier</key>
	<string>QXAFMEPH6X.com.ohanaware.aquaSwatch</string>
	<key>com.apple.developer.team-identifier</key>
	<string>QXAFMEPH6X</string>
	<key>keychain-access-groups</key>
	<array>
		<string>QXAFMEPH6X.*</string>
	</array>
</dict>

However when I add the keychain-access-groups to the code signing entitlements.

<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>keychain-access-groups</key>
<array>
	<string>QXAFMEPH6X.com.ohanaware.aquaSwatch</string>
</array>

The application crashes on launch.

Exception Type: EXC_CRASH (Code Signature Invalid) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Note: EXC_CORPSE_NOTIFY

Termination Reason: Namespace CODESIGNING, Code 0x1

I think I may have misunderstood Quinn's excellent article on Provision Profiles, because I assumed that the wildcard in the Profile, allowed me to use any identifier as long as the team id was correct.

https://developer.apple.com/forums/thread/685723

Thank you for any asssitance

Sam Rowlands

Replies

I assumed that the wildcard in the Profile, allowed me to use any identifier as long as the team id was correct.

That’s correct. I’m not sure what’s going on in your case. Notably, I was able to run this test myself and everything worked as expected:

  1. Using Xcode 13.1 on macOS 11.6, I created a new app from the macOS > App template.

  2. I configured code signing for my team.

  3. I added the Custom Network Protocol capability. I don’t actually need this capability; I added to solely force Xcode to assign my app a concrete App ID.

  4. I removed that capability.

  5. I added the Keychain Sharing capability but didn’t add any times to the list.

  6. I built the app.

  7. I dumped its profile and claimed entitlements:

    % security cms -D -i AquaSwatch.app/Contents/embedded.provisionprofile
    …
    <dict>
      …
      <key>Entitlements</key>
      <dict>
        <key>com.apple.application-identifier</key>
        <string>SKMME9E2Y8.com.example.apple-samplecode.AquaSwatch</string>
        <key>keychain-access-groups</key>
        <array>
            <string>SKMME9E2Y8.*</string>
        </array>
        <key>com.apple.developer.team-identifier</key>
        <string>SKMME9E2Y8</string>
            <key>com.apple.developer.networking.custom-protocol</key>
        <true/>
      </dict>
      …
    </dict>
    </plist>
    % codesign -d --entitlements :- AquaSwatch.app            
    …
    <dict>
      <key>com.apple.application-identifier</key>
      <string>SKMME9E2Y8.com.example.apple-samplecode.AquaSwatch</string>
      <key>com.apple.developer.team-identifier</key>
      <string>SKMME9E2Y8</string>
      <key>com.apple.security.app-sandbox</key>
      <true/>
      <key>com.apple.security.files.user-selected.read-only</key>
      <true/>
      <key>com.apple.security.get-task-allow</key>
      <true/>
      <key>keychain-access-groups</key>
      <array/>
    </dict>
    </plist>
    
  8. I added the app’s bundle ID to the Keychain Sharing list and rebuilt.

  9. I dumped its claimed entitlements again:

    % codesign -d --entitlements :- AquaSwatch.app
    …
    <dict>
      <key>com.apple.application-identifier</key>
      <string>SKMME9E2Y8.com.example.apple-samplecode.AquaSwatch</string>
      <key>com.apple.developer.team-identifier</key>
      <string>SKMME9E2Y8</string>
      <key>com.apple.security.app-sandbox</key>
      <true/>
      <key>com.apple.security.files.user-selected.read-only</key>
      <true/>
      <key>com.apple.security.get-task-allow</key>
      <true/>
      <key>keychain-access-groups</key>
      <array>
        <string>SKMME9E2Y8.com.example.apple-samplecode.AquaSwatch</string>
      </array>
    </dict>
    </plist>
    

    AFAICT this matches your setup.

  10. I ran the app:

    % ./AquaSwatch.app/Contents/MacOS/AquaSwatch ; echo $?                
    0
    

Share and Enjoy

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

Hi Quinn, Thank you for trying to help me.

There is something I must have fundamentally wrong. When trying to launch the application, console reports a load of information about the crash, but I can only see two things that appear to give any indication.

mac_vnode_check_signature: /Applications/Aqua Swatch.app/Contents/MacOS/Aqua Swatch: code signature validation failed fatally: When validating /Applications/Aqua Swatch.app/Contents/MacOS/Aqua Swatch: Code has restricted entitlements, but the validation of its code signature failed. Unsatisfied Entitlements:

But no entitlements are listed.

Console also lists the error "signature not valid: -67030". To which I can find no public information on.

Entitlements extracted from the application's code signature (via codesign -d --entitlements :- )

<dict>
	<key>com.apple.application-identifier</key>
	<string>QXAFMEPH6X.com.ohanaware.aquaSwatch</string>
	<key>com.apple.developer.team-identifier</key>
	<string>QXAFMEPH6X</string>
	<key>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.files.user-selected.read-write</key>
	<true/>
	<key>com.apple.security.network.client</key>
	<true/>
	<key>keychain-access-groups</key>
	<array>
		<string>QXAFMEPH6X.com.ohanaware.aquaSwatch</string>
	</array>
</dict>

Entitlements extracted from /Contents/embedded.provisionprofile (via security cms -D -i )

<key>Entitlements</key>
	<dict>

				<key>com.apple.application-identifier</key>
		<string>QXAFMEPH6X.com.ohanaware.aquaSwatch</string>

				<key>keychain-access-groups</key>
		<array>
				<string>QXAFMEPH6X.*</string>
		</array>

				<key>com.apple.developer.team-identifier</key>
		<string>QXAFMEPH6X</string>

	</dict>

The profile has weird spacing when listing the entitlements.

If I remove "keychain-access-groups", it still crashes. It only stops crashing when I have removed "com.apple.application-identifier" and "com.apple.developer.team-identifier" from the code sign entitlements (so the code sign entitlements only contain the com.apple.security elements).

Is there anything else I can check?

Does the profile need to be installed somewhere on the machine as well as within the application?

Console also lists the error "signature not valid: -67030". To which I can find no public information on.

Here’s a super handy tip: The security tool has an erorr subcommand that knows a lot of errors:

% security error -67030                 
Error: 0xFFFEFA2A -67030 invalid Info.plist (plist or signature have been modified)

Oh, and this is actually a public error, namely errSecCSInfoPlistFailed.

The profile has weird spacing when listing the entitlements.

That is normal.

Are you building your Info.plist and .entitlements file with Apple tools? Modern systems apply additional constraints on security-sensitive XML files. See Ensure Properly Formatted Entitlements for more on this.

Share and Enjoy

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

Morning Quinn,

Are you building your Info.plist and .entitlements file with Apple tools? Modern systems apply additional constraints on security-sensitive XML files. See Ensure Properly Formatted Entitlements for more on this.

I am not building either the info.plist or the entitlements file using Apple's tools. I am using [NSPropertyListSerialization dataWithPropertyList:format:options:error:] to create a NSData object of format kCFPropertyListXMLFormat_v1_0 which is then written to the file using a stream.

plutil -lint ~/mainEntitlementsAppStore.entitlements
~/mainEntitlementsAppStore.entitlements: OK
codesign -d --entitlements :- ~/Aqua\ Swatch.app 
Executable= ~/Aqua Swatch.app/Contents/MacOS/Aqua Swatch
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.application-identifier</key>
	<string>QXAFMEPH6X.com.ohanaware.aquaSwatch</string>
	<key>com.apple.developer.team-identifier</key>
	<string>QXAFMEPH6X</string>
	<key>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.network.client</key>
	<true/>
	<key>keychain-access-groups</key>
	<array>
		<string>QXAFMEPH6X.com.ohanaware.aquaSwatch</string>
	</array>
</dict>
</plist>

If the mainEntitlements only consists of com.apple.security keys, the application launches. Once "com.apple.application-identifier", "com.apple.developer.team-identifier" or "keychain-access-groups" is added to the entitlements the application crashes on launch.

Below is the console information from just this moment.

default	10:18:19.639377+0800	amfid	/Applications/Aqua Swatch.app/Contents/MacOS/Aqua Swatch signature not valid: -67671
default	10:18:19.639463+0800	kernel	mac_vnode_check_signature: /Applications/Aqua Swatch.app/Contents/MacOS/Aqua Swatch: code signature validation failed fatally: When validating /Applications/Aqua Swatch.app/Contents/MacOS/Aqua Swatch:
  Code has restricted entitlements, but the validation of its code signature failed.
Unsatisfied Entitlements:
default	10:18:19.639513+0800	kernel	proc 32652: load code signature error 4 for file "Aqua Swatch"
default	10:18:19.640376+0800	kernel	ASP: Security policy would not allow process: 32652, /Applications/Aqua Swatch.app/Contents/MacOS/Aqua Swatch
default	10:18:19.640408+0800	kernel	Aqua Swatch[32652] Corpse allowed 1 of 5
default	10:18:19.647641+0800	ReportCrash	Parsing corpse data for process Aqua Swatch [pid 32652]
error	10:18:19.704941+0800	CoreServicesUIAgent	handle LS launch error: {\n    Action = oapp;\n    AppMimimumSystemVersion = "10.11";\n    AppPath = "/Applications/Aqua Swatch.app";\n    ErrorCode = "-10826";\n}
default	10:18:19.808839+0800	***	Non-fatal error enumerating at <private>, continuing: Error Domain=NSCocoaErrorDomain Code=260 "The file “PlugIns” couldn’t be opened because there is no such file." UserInfo={NSURL=PlugIns/ -- file:///Applications/Aqua%20Swatch.app/Contents/, NSFilePath=/Applications/Aqua Swatch.app/Contents/PlugIns, NSUnderlyingError=0x7f9dfb91f9e0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
default	10:18:19.969116+0800	***	Non-fatal error enumerating at <private>, continuing: Error Domain=NSCocoaErrorDomain Code=260 "The file “PlugIns” couldn’t be opened because there is no such file." UserInfo={NSURL=PlugIns/ -- file:///Applications/Aqua%20Swatch.app/Contents/, NSFilePath=/Applications/Aqua Swatch.app/Contents/PlugIns, NSUnderlyingError=0x7f9dfb843d80 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
default	10:18:19.998976+0800	ReportCrash	Saved crash report for Aqua Swatch[32652] version ??? to Aqua Swatch_2021-10-26-101819_Mariposa.crash
default	10:18:20.008882+0800	analyticsd	Received event: com.apple.stability.crash {"appVersion":"???","exceptionType":13,"incidentID":"1B2F176A-1FCA-47CC-AE21-9A4EA88E0C81","logwritten":1,"process":"Aqua Swatch","responsibleApp":"Aqua Swatch"}
default	10:18:20.008759+0800	ReportCrash	Sending event: com.apple.stability.crash {"appVersion":"???","exceptionType":13,"incidentID":"1B2F176A-1FCA-47CC-AE21-9A4EA88E0C81","logwritten":1,"process":"Aqua Swatch","responsibleApp":"Aqua Swatch"}
default	10:18:20.014245+0800	analyticsd	Aggregated. Transform: StabilityCrashNumerator3WithIncidentID Dirty: 1 Event: com.apple.stability.crash {"appVersion":"???","exceptionType":13,"incidentID":"1B2F176A-1FCA-47CC-AE21-9A4EA88E0C81","logwritten":1,"process":"Aqua Swatch","responsibleApp":"Aqua Swatch","timestamp":1635214700008705}
default	10:18:20.014302+0800	analyticsd	Aggregated. Transform: StabilityCrashNumerator3 Dirty: 1 Event: com.apple.stability.crash {"appVersion":"???","exceptionType":13,"incidentID":"1B2F176A-1FCA-47CC-AE21-9A4EA88E0C81","logwritten":1,"process":"Aqua Swatch","responsibleApp":"Aqua Swatch","timestamp":1635214700008705}
default	10:18:20.014359+0800	analyticsd	Aggregated. Transform: StabilityCrashNumerator3WithBundleVersion Dirty: 1 Event: com.apple.stability.crash {"appVersion":"???","exceptionType":13,"incidentID":"1B2F176A-1FCA-47CC-AE21-9A4EA88E0C81","logwritten":1,"process":"Aqua Swatch","responsibleApp":"Aqua Swatch","timestamp":1635214700008705}
% security error -67671
Error: 0xFFFEF7A9 -67671 An internal error has occurred.

If I remove these keys, and rewrap the application, it launches with no error. "com.apple.application-identifier", "com.apple.developer.team-identifier" and "keychain-access-groups".

One final thing, clutching at staws, the permissions of the executables are all 755, while the provisionprofile is 666, I guess it should be 644.

Thank you for your patience and willingness to assist me.

One final thing, clutching at staws, the permissions of the executables are all 755, while the provisionprofile is 666, I guess it should be 644.

Tested this (the profiles permissions are 644), I also ensured that all the ACLs and xattrs are being stripped from the provisionprofile. However it made no change :(

The profile was created using Apple's web portal https://developer.apple.com/account/resources/profiles/list

If you'd like I can make the profile and the application available to download, it is signed with my App Store submission cert, which is the cert specified in the profile.

Earlier you wrote the following:

Does the profile need to be installed somewhere on the machine as well as within the application?

No. It only needs to be embedded within the app per the rules in Placing Content in a Bundle [1].


I am using -[NSPropertyListSerialization dataWithPropertyList:format:options:error:]

OK, that’s fine. That’ll create the file in Apple’s standard XML format, which is what you need. The error I’m referring to crops up when folks use various text processing tools to manipulate their property lists.

it is signed with my App Store submission cert, which is the cert specified in the profile.

Hmmm. If, just for the sake of debugging, you use an Apple Development or Developer ID Application signing identity, does that work?

The reason I ask is that, in general, Apple Development signed code is not intended to be run locally. Rather, it’s intended to be submitted to the store so that the store can then verify your signature before re-signing it for wider distribution.

On iOS this is an absolute requirement; there’s no way to run Apple Development signed code locally.

On macOS this is a lot fuzzier. I know that macOS will let you run Apple Development signed code normally, but it’s possible that your use of restricted entitlements is causing a problem.

So, it’d be better to test this with signing identities that are expected to work, which means Apple Development or Developer ID Application.

Share and Enjoy

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

[1] I finally got around to replacing the Nested Code section of TN2206!

Hi Quinn, It's been a while and I am sorry for the late response, I've had other things and I've also been trying to discuss this with other developers, it seems like it is something that I am doing wrong because no-one else appears to be running in to it :(

So in summary, adding a Provisioning Profile to the application doesn't cause a problem, until the keys from the Provisioning Profile are added to the applications entitlements, keys such as "com.apple.application-identifier" or "com.apple.developer.team-identifier".

I have tested it with both the "Apple Distribution" and "Apple Development" certificates.

I have also removed the Provisioning Profile from the application and I of course get the same crash, so my guess is that I'm not inserting it correctly into the application. It is added to the root of the "Contents" subfolder of the application bundle and is called "embedded.provisionprofile", which is done BEFORE any code signing.

So this raises two questions.

  1. Do I need to provide some extra information at signing time to notify code sign to use the profile?
  2. Is there a way that the Security framework can tell me that it knows the profile is there, some sort of validation?

Addendum: So for this time around I was able to actually figure out the crashing!

ProvisionedDevices - When using the "Apple Developer" certificate and provision profile, the machine being used for testing must be registered at Apple and included in the Provision Profile.

Am still not able to test with a Apple Distribution certificate and matching profile, it also does not include a ProvisionedDevices section.

I'll keep at it, nice to finally get somewhere.

  1. Do I need to provide some extra information at signing time to notify code sign to use the profile?

No.

  1. Is there a way that the Security framework can tell me that it knows the profile is there, some sort of validation?

Yes. I included code to do this in my Signing a Daemon with a Restricted Entitlement doc.

When using the "Apple Developer" certificate and provision profile, the machine being used for testing must be registered at Apple and included in the Provision Profile.

Correct.

Am still not able to test with a Apple Distribution certificate and matching profile, it also does not include a ProvisionedDevices section.

That’s not a huge surprise. In general, distribution signing is only useful for products that you’re uploading to the App Store. In some cases the system will let you run distribution-signed code but that’s not a standard use case.

Historically this was a pain on the Mac because there was no way to test your distribution-signed code. Nowadays you can test it using TestFlight, just like you do on iOS. Yay!

Share and Enjoy

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

Thank you Quinn,

The reason this creates some complication is that I and several others are used to wrapping for App Store Submission, and before we "Submit for Review", move the application to the Applications folder and launch it, just to give it a final check (including the receipt).

I've been trying to see if I can test the receipt verification code when using "Apple Development" but it doesn't work, I think there is a failure somewhere with testing receipts in general as I see others having problems testing receipts at the moment.

As for TestFlight, as a Mac only developer, I've never used it before and therefore I need to learn how to interact with it. However I'd feel more comfortable being able to test our apps locally before submitting it to a testing service, especially things like the receipt verification.

    let infoCF = try secCall { SecCodeCopySigningInformation(meStatic, [], $0) }
    let info = infoCF as NSDictionary
    let entitlements = info[kSecCodeInfoEntitlementsDict] as? NSDictionary

Thank you for this code snippet. I have been using the same API with SecStaticCode to read the application after it has been signed (a sort of code sign diagnostics tool), I am sorry to have to ask, but I don't currently see how this can tell me if the macOS knows this is signed with a profile or not as (in my tests) this API returns the apps Entitlements regardless.

I've looked through "SecCode.h" at the constants listed under "SecCodeCopySigningInformation" to see if there's a key, but it is not obvious to me.

However if the rule of thumb is that "Apple Distribution cert + provision profile + certain entitlements" == "can't be run locally", then I guess I don't really need to know at this point.

Thank you for taking your time to assist me. You must be getting tired of me asking questions and sometimes clearly not understanding things.