"Signing certificate" and post-installation assignment fail due to IOPCIPrimaryMatch

I'm having trouble configuring the "IOPCIPrimaryMatch" entitlement.

I'm currently developing using "sign to run locally" and have been able to confirm the expected behavior. I was considering signing with "Developer ID Application" for future distribution to customers, but after finding the following forum, I'm now aiming to sign with "Apple Development." https://developer.apple.com/forums/thread/743021

I'm currently having trouble with the IOPCIPrimaryMatch value. The "signing certificate" status in Xcode changes depending on the value, as follows:

Successful if the value is as follows: <key>IOPCIPrimaryMatch</key> <string>0xFFFFFFFF&0x00161916</string>

An error occurs if the value is as follows: <key>IOPCIPrimaryMatch</key> <string>0xFFFFFFFF&amp;0x00161916</string>

So I tried building and installing using "0xFFFFFFFF&0x00161916", but this time the driver was not assigned to the PCI device.

By the way, when I used "sign to run locally", both the installation and assignment were successful with the following: <key>IOPCIPrimaryMatch</key> <string>0xFFFFFFFF&amp;0x00161916</string>

Could you please tell me the correct way to write this?

I'm currently developing using "sign to run locally" and have been able to confirm the expected behavior. I was considering signing with "Developer ID Application" for future distribution to customers, but after finding the following forum, I'm now aiming to sign with "Apple Development." https://developer.apple.com/forums/thread/743021

I've already replied on that post and my advice to you is going to be the same ("Switch everything to automatic"!) with one addition. Looking at you account, you entitlement.plist configuration should be:

<key>com.apple.developer.driverkit.transport.pci</key>
<array>
	<dict>
		<key>IOPCIPrimaryMatch</key>
		<string>0x00001916&amp;0x0000FFFF</string>
	</dict>
</array>

...which matches what you were approved for. That value will display in Xcode as:

0x00001916&0x0000FFFF

By the way, when I used "sign to run locally", both the installation and assignment were successful with the following: <key>IOPCIPrimaryMatch</key> <string>0xFFFFFFFF&amp;0x00161916</string>

Unfortunately, signing locally can be deeply misleading, as it basically works by disabling exactly the validation that's failing here. There's a similar issue when you switch from "Automatic" to "Manual" code-signing. It's possible using "Manual" to get Xcode to sign configurations it wouldn't sign with "Automatic"... and, in most cases, all you've done there is convert a build time error into a runtime failure. That's not progress.

On the topic of those errors, quoting myself:

"...One thing to be aware of here is that Xcode has a "bias" in the way it presents codesign errors where it assumes the Entitlement.plist is "correct" and the profile is "wrong". However, in practice that's basically "never" the case with DriverKit entitlements and tends to lead to a lot of "flailing" trying to somehow "fix" the provisioning profile...."

The rest of that post has more details on this process, but the key idea here is that you fix code signing issues by changing the configuration of the "data" (either your entitlement.plist or your portal configuration), NOT by changing the configuration of your project.

Finally, for reference, I have two posts on describing how to validate the entitlement configuration of a DEXT build. This post outlines the "theory", while the following post has a detailed example from an actual DEXT.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Your answer is helpful. My previous question was strange because I didn't consider posting it in HTML. As a result, I wasn't able to properly communicate what I wanted to say.

The symptoms I'm experiencing are as follows:

  1. With the following settings, the "signing certificate" status in Xcode shows as failed.
<key>IOPCIPrimaryMatch</key> <string>0x00001916&amp;0x0000FFFF</string>

The error message is as follows: doesn't include the com.apple.developer.driverkit.allow-any-userclient-access entitlement and doesn't match the entitlements file's value for the com.apple.developer.driverkit.transport.pci entitlement.

  1. With the following settings, the "signing certificate" status error in Xcode disappears, and building and driver installation succeed. However, the driver cannot be assigned to the device.
<key>IOPCIPrimaryMatch</key> <string>0x00001916&0x0000FFFF</string>

To check for any minor errors in my work, I reverted to a "sign to run locally" environment and tried the following values. All errors disappeared, and my drivers and software worked correctly.

<key>IOPCIPrimaryMatch</key> <string>0x00001916&amp;0x0000FFFF</string>

What I wanted to convey in my previous post was that I think I should include this "amp;", but when I do, the "signing certificate" status in Xcode shows as failed. Why is that?

I tried the values ​​you provided, and the problem was exactly the same as before, so I'd really appreciate an answer.

So, let me start with the causes of these failures:

But when I do, the "signing certificate" status in Xcode shows as failed. Why is that?

This post has more detail, but in basic terms, your app’s "signing" is created from two components:

  1. Your Entitlement.plist -> This is used to create the actual code-signature "attached" to your app bundle.

  2. The provisioning profile -> This is a file that we've signed and which is then embedded inside your app’s bundle. (Note: not all signed apps have/need one of these, but all DEXT do).

The system "validates" the entitlement by comparing the entitlement values contained in those two files (your app’s code signature and its embedded provisioning profile). That's why the profile (#2) is signed by us - it "proves" we want your app to have the entitlement. Xcode checks that your app is properly signed by comparing the data in those values to ensure that they "match", creating this failure when they "don't match".

What I wanted to convey in my previous post was that I think I should include this "amp;",

So, the confusion around "&" vs "&amp;" happens because the "right" answer depends on how you're looking at the file.

  1. If you open a plist file as plain text, you'll see the value "&amp;". That's because the standalone character "&" is a reserved XML character, and "&amp;" is its escaped variant.

  2. If you open the plist file in any sort of plist editor, it will show you "&". That's because that's the character you actually "wanted" to enter/display.

Making this concrete, here is the raw text of one entire entitlement.plist:

<?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.developer.driverkit</key>
	<true/>
	<key>com.apple.developer.driverkit.allow-any-userclient-access</key>
	<true/>
	<key>com.apple.developer.driverkit.allow-third-party-userclients</key>
	<true/>
	<key>com.apple.developer.driverkit.transport.pci</key>
	<array>
		<dict>
			<key>IOPCIPrimaryMatch</key>
			<string>0xFFFFFFFF&amp;0x00000000</string>
		</dict>
	</array>
	<key>com.apple.security.app-sandbox</key>
	<true/>
</dict>
</plist>

And here is a screenshot of exactly the same file in Xcode:

Again, that's exactly the same data shown two different ways.

That leads to here:

With the following settings, the "signing certificate" status error in Xcode disappears, and building and driver installation succeed.

Going back to the two files above, only one of those (the entitlement plist) is directly editable by "you". So, from that perspective, an app is "properly signed" when you've configured your entitlement plist to match your provisioning profile. FYI, TN3125: Inside Code Signing: Provisioning Profiles has directions for viewing what's actually inside a provisioning profile file. However, the basic "game" here is pretty simple— if Xcode works with one plist configuration and errors with a slightly different plist configuration, then the first configuration is "right" and the second is "wrong"...

However, the driver cannot be assigned to the device.

...but all that means is that your DEXT has a valid signature configuration. That doesn't mean it will actually "work". DEXT matching basically relies on a two-stage process which works something like this:

  1. The IOKitPersonalities dictionary is used as a standard KEXT loading dictionary by the kernel. That loads the driver specified by "IOClass" into the kernel in EXACTLY the way a standard IOKit KEXT would load.

  2. After that initial match, the kernel then compares the entitlement configuration of your DEXT against the data that's in the provider you're matching against*. If configuration matches, then loading will continue. If it doesn't, then the match will be failed and your driver will be unloaded.

*One small detail here is that this matching process is actually handled by the specific family driver using its own implementation. For example, IOPCIFamily has a specific limitation around matching with "built-in" hardware that's independent of direct hardware matching. If you're curious, you can actually see the code for IOPCIFamily checks here.

Note that everything above occurs in the kernel BEFORE any of your code actually "runs" or your DEXT process actually "exists". Indeed, the next step AFTER this is when your DEXT actually starts loading.

Making that concrete, nothing prevents you from creating a DEXT with an IOKitPersonalities dictionary that matches a USB device and a signing configuration that matches PCI. The DEXT will build fine and is fully installable. However, that DEXT... won't actually "do" anything. That is, stage #1 will occur and stage #2 will always fail.

Similarly, this works:

To check for any minor errors in my work, I reverted to a "sign to run locally" environment and tried the following values.

...because it basically just skips #2 above.

In terms of next steps, a few different points:

  • IOPCIFamily does have the "Dev Only" entitlement (see the configuration above). That works by defining a match criteria that covers "any" PCI device. If you just want something to work "now" and/or you're working with development hardware (which doesn't match your final hardware config), then this is the best option.

  • Given that the local signing driver is working, it sounds like the underlying problem here is that the entitlement you've been granted doesn't have the right configuration. Fixing that is going to require applying for the entitlement again with the right values. If you go that route, please include my name ("Kevin Elliott") in the request and mention that you're correcting an incorrect grant, along with the entitlement values you actually need.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thank you for your reply. I'm sorry for the late response, as I was working on another issue.

I understand that I need to resubmit.

I would like some advice on how to submit the application before resubmitting.

Based on my current understanding, since it's XML, I believe the following value is correct:

<string>0x00001916&amp;0x0000FFFF</string>

However, currently, if I enter "&amp;", the "Signing Certificate" status displays "Failed." Based on the current situation, does this mean that when resubmitting, I'm required to enter the following value, including "&amp;"?

<string>0x00001916&amp;0x0000FFFF</string>

There's one thing that concerns me. I checked the contents of the provisioning file I downloaded from the URL you provided. I thought the current issue was occurring because it didn't contain "&amp;". However, when I actually looked at the file, I found that it did contain "&amp;".

$ security cms -D -i mep_DeveloperID_2030_DextPCIe2.provisionprofile -o test.plist
$ cat test.plist
<dict>
<key>IOPCIPrimaryMatch</key>
<string>0x00001916&amp;0x0000FFFF</string>
</dict>

The provisioning file appears to me to have the correct value. If you could tell me the correct value for IOPCIPrimaryMatch in this situation, I will resubmit my authorization request.

However, currently, if I enter "&amp;", the "Signing Certificate" status displays "Failed." Based on the current situation, does this mean that when resubmitting, I'm required to enter the following value, including "&amp;"?

I don't think it actually matters. More specifically, if you submitted with a value of:

<string>0x00001916&0x0000FFFF</string>

We'd HAVE to modify that to:

<string>0x00001916&amp;0x0000FFFF</string>

That is, we CANNOT create a provisioning profile that directly contained that first configuration. That configuration is invalid XML. I don't think any of our tooling will allow it to be created, and I do know that none of our validators will accept it.

Now, theoretically, we could construct an entitlement which displayed as:

<string>0x00001916&amp;0x0000FFFF</string>

Because its raw text value was:

<string>0x00001916&amp;amp;0x0000FFFF</string>

However:

  • I believe our internal tooling is set up to prevent that.

  • Even if it didn't, our tooling actually shows the "raw" value when we create entitlements, and the approvers know enough about all this to recognize that the second version is broken.

Finally, just to make this clear, these two values aren't actually "different". This is what our high-level tools show and what the "value" actually is:

<string>0x00001916&0x0000FFFF</string>

While this:

<string>0x00001916&amp;0x0000FFFF</string>

...is what was actually written in the text file. The value "&amp;" is simply the escaped version of "&", since "&" is a reserved XML character. This isn't even about your provisioning profile itself. Exactly the same thing is happening in the IOKitPersonalities dictionary of your Info.plist. All of this is just the way XML works.

Returning to here with specific advice:

Based on the current situation, does this mean that when resubmitting, I'm required to enter the following value, including "&amp;"?

I’d use:

<string>0x00001916&0x0000FFFF</string>

And then try this:

<string>0x00001916&amp;0x0000FFFF</string>

…if the form complains.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thank you for your reply. I understand that the following is a reserved character in XML:

"&amp;"

Below are the current expected and actual values.

Driverkit expected value

<string>0x00001916&amp;0x0000FFFF</string>

Provisioning file contents

<string>0x00001916&amp;0x0000FFFF</string>

Entitlements file contents

<string>0x00001916&amp;0x0000FFFF</string>

I'm not sure why Xcode "Signing Certificate" status is "Failed" with the above configuration. It doesn't seem to me that Driverkit and the provisioning file expect "&" as the expected value. Based on the above, isn't it Xcode that expects "&"? I'm suspicious of Xcode's behavior.

I'm worried that resubmitting the authorization request won't improve the situation. Is my understanding incorrect?

I'm not sure why Xcode "Signing Certificate" status is "Failed" with the above configuration. It doesn't seem to me that DriverKit and the provisioning file expect "&" as the expected value. Based on the above, isn't it Xcode that expects "&"? I'm suspicious of Xcode's behavior.

I was able to get a look at your account configuration this morning, and I think I can explain what's going on. For reference, I looked at the bundle with this structure:

com.<redact>0.DextPCIe

**Short answer: **

Change your Entitlement.plist configuration to "Development Only" entitlement configuration:

<key>com.apple.developer.driverkit.transport.pci</key>
<array>
	<dict>
		<key>IOPCIPrimaryMatch</key>
		<string>0xFFFFFFFF&amp;0x00000000</string>
	</dict>
</array>

...and I think you'll find that your build will suddenly work fine. Note that it's perfectly fine to use the configuration above for normal testing and development. The entitlement above does match "all" devices, but your IOKitPersonalities dictionary controls what you ACTUALLY match against, so having an "broad" entitlement doesn't mean you'll match against anything new/different.

**Long Answer: ** Looking at your account configuration, you have enabled the entitlement on that bundle ID, but you've never actually generated a provisioning profile that includes that particular one. If you track down the provisioning profile you're signing with and view its contents using these instructions in TN3125: Inside Code Signing: Provisioning Profiles, I believe you'll find that it includes the value I listed above, NOT the custom entitlement configuration you're expecting.

What you're actually hitting here is a longstanding (this started in Xcode 15) issue caused by Xcode not properly handling the way DriverKit has "overlapping" entitlements with different values. You can actually see the issue in Xcode when you add capabilities. That is, if you specifically add your custom capability:

DriverKit PCI (PrimaryMatch)

Xcode will update its UI and add two:

DriverKit PCI (development)
DriverKit PCI (PrimaryMatch)

And if you try and fix that problem by deleting:

DriverKit PCI (development)

...Xcode will delete both.

Here is what I would recommend you do about this:

  • Right "now" and for development purposes, switch to the development-only entitlement (the configuration above) and ignore the problem. That's the simplest configuration for basic development and you're better off sidestepping the problem so you can get work done instead of fighting with the system over this.

Once you’re ready to ship or need to distribute non-development builds, then you'll do one of two things:

  1. If you're lucky, it's possible Xcode will have finally resolved these issues and it will just "work". I can't comment on how likely that is to happen, but I will say that the situation has improved (Xcode 16/26 actually handles most of DriverKit, just not PCI or USB) and that this issue is something we're working to address.

  2. Use the process I describe in this post to manually generate a provisioning profile and sign your DEXT with that profile.

One side note on #2. One of the reasons I recommend using the development-only entitlement is that development signing works by embedding the machine identifier of every machine the build will run on inside the signing profile. If you’re using automatic, that's mostly invisible, but using manual signing means generating a new profile every time you change something.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

My current goal is to ship the PCIe DriverKit. I want my customers to be able to install our DriverKit without having to disable SIP or anything like that.

I tried the following value as suggested, and the build did indeed pass.

<string>0xFFFFFFFF&amp;0x00000000</string>

After checking the contents of the downloaded provisioning file again, I was able to clarify the problem. The value in the file created in App Development wasn't set properly.

Created a provisioning file with DriverKit App Development and checked the value of IOPCIPrimaryMatch.

<string>0xFFFFFFFF&amp;0x00000000</string>

Created a provisioning file with the Distribution Developer ID and checked the value of IOPCIPrimaryMatch.

<string>0x00001916&amp;0x0000FFFF</string>

Why is there a difference between the Apple Development value and the Developer ID value? My account belongs to a corporate account. Is this related?

Also, when I check your post, it seems like I've never created a provisioning file. That's strange. Is the local file on my PC invalid?

As I mentioned at the beginning, I found the following article and was aiming to sign using Apple Development. https://developer.apple.com/forums/thread/743021

However, according to the URL you provided, would manual signing using a provisioning file created with a Distribution Developer ID be better? Actually, I was having trouble with manual signing, and that's when I found the above article.

My current goal is to ship the PCIe DriverKit. I want my customers to be able to install our DriverKit without having to disable SIP or anything like that.

Absolutely.

Why is there a difference between the Apple Development value and the Developer ID value?

The two different values happen because of the "development only" variant that's added to all accounts.

(a) This is the "development only" configuration (which all accounts have):

<string>0xFFFFFFFF&amp;0x00000000</string>

(b) And this is the specific configuration you were approved for, which is unique to your account:

<string>0x00001916&amp;0x0000FFFF</string>

Unfortunately, the portal and Xcode handling of these overlapping configurations doesn't work all that well. You can find a description of what's actually going on here. However, note that I don't think the flow described at the end of that post actually works today.

However, according to the URL you provided, would manual signing using a provisioning file created with a Distribution Developer ID be better?

First off, please file a bug on this and post the bug number back here. While there are multiple bugs on this issue (r.165921470), more developer bugs would help document the impact to help get these issues resolved.

Next, in terms of solutions, I don't currently have a direct guide I can provide. The basic issue here is this:

  1. When archiving builds, Xcode is requiring a "DriverKit development profile" in order to archive the build.

"Xcode 14 and later requires a DriverKit development profile enabled for iOS and macOS. Visit the developer website to create or download a DriverKit profile."

  1. Issues in the portal mean that any development profile you create will configure "a" above, forcing your DEXT to use that entitlement configuration.

  2. Correctly exporting a distribution build requires signing with configuration "b“, but the export will fail because #1 means your archive build is signed with configuration "a".

All of that means that resolving this requires one of two solutions:

  • Creating an archive signed with configuration "b". I've been unable to find any way to do this.

  • Manually resigning the DEXT such that you're able to provide the correct entitlement.plist configuration AND the corresponding provisioning profile. I believe this approach will work, but I don't know what command for that would actually "be".

I’m actively working to find a solution to this, but I don’t have one at the moment.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

I built Dext with a development ID and successfully re-signed and notarized it. This time, I only notarized the Driverkit, and plan to do the installer app later.

Here are the steps I tried:

  1. Signed the build using Apple Development in Xcode
  2. Re-signed the build product
  3. Zipped the build product
  4. Notarized using xcrun notarytool submit, which returned Accept.

Below is a sample re-signing command.

codesign \
--sign $CODE_SIGN_IDENTITY \
--entitlements <entitlement-file> \
--options runtime \
--verbose \
--force \
build/Release/<my-driver>.app

I'll probably need to eventually create an installer app and notarize it, but I think I've temporarily resolved the recent issue of not being able to sign with a Developer ID in Xcode. If you have any issues from an engineering perspective, please let me know.

I built Dext with a development ID and successfully re-signed and notarized it. This time, I only notarized the Driverkit, and plan to do the installer app later.

The flow you've described below won't give you a working build. The build will have the development provisioning profile and entitlement configuration in a Developer ID signed build, which means one of two things will happen:

  1. (more likely, best case) The DEXT will not load on any device, since the provisioning profile configuration (development) doesn't match the apps signing configuration.

  2. (less likely, worst case) The system will allow the DEXT to load, relying on the development provisioning configuration. That means it will work... but ONLY on the limited set of machines that were embedded in the provisioning profile (this is how development signing works).

Note that #2 is particularly dangerous, since you can end up shipping a DEXT that works on "your" machines but none of your customers.

I just put up a "How to sign a DEXT" post which describes how to make this work. See the second post for instructions on signing USB and PCI DEXTs.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

"Signing certificate" and post-installation assignment fail due to IOPCIPrimaryMatch
 
 
Q