Signing succeeds but validate fails with "Missing code-signing certificate"

We have a command line script that runs xcodebuild to make an archive, then runs xcodebuild again to export the archive to make an ipa, and then runs "altool --validate-app" to check that everything will be fine for a subsequent upload to the app store. This has been working fine for a few years but recently stopped working and we cannot figure out why.

The validation fails with this error:

ERROR: [altool.105912F20] Validation failed (409) Invalid Provisioning Profile. The provisioning profile included in the com.<redacted> bundle [Payload/<redacted>.app] is invalid. [Missing code-signing certificate]. A distribution provisioning profile should be used when uploading apps to App Store Connect. (ID: <redacted uuid looking thing>)

The project is configured with 'Automatically manage signing' unchecked, and the profile was created on developer.apple.com/account/resources/profiles and the matching profile magically appears in the "Provisioning Profile" drop down in Xcode.

The profile was created with two certificates checked, but examining the embedded.mobileprovision profile that ends up in the compiled ipa payload it appears to contain 19 certificates (probably all of them for this org?).

Is there a way to find out which certificate is missing exactly? And once identified is it a case of adding it to the profile used during compilation to fix this?

Ancillary question: why does the embedded.mobileprovision file contain so many certificates, and how does xcodebuild decide which ones it includes there?

Answered by DTS Engineer in 872540022
it appears to contain 19 certificates

I agree that that’s strange. A distribution profile should only contain distribution certificates, and most teams only have one or two of those active at any one time.

I recommend that you check the type of the profile and also look at the certificates embedded in the profile.

Is there a way to find out which certificate is missing exactly?

Yes. TN3125 Inside Code Signing: Provisioning Profiles explains how you can pull apart the profile to work out what it authorises. You combine that with the --extract-certificates option to codesign, which allows you to determine the certificate of the code-signing identity that was used to sign the code. I’ve got some info on how to do that somewhere…

Oh, right, here it is…

Have a look at the Check the Signing Certificate section of Resolving Code Signing Crashes on Launch. Its focus is on the Mac, but the bulk of our code-signing infrastructure works the same on all our platforms.

Share and Enjoy

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

it appears to contain 19 certificates

I agree that that’s strange. A distribution profile should only contain distribution certificates, and most teams only have one or two of those active at any one time.

I recommend that you check the type of the profile and also look at the certificates embedded in the profile.

Is there a way to find out which certificate is missing exactly?

Yes. TN3125 Inside Code Signing: Provisioning Profiles explains how you can pull apart the profile to work out what it authorises. You combine that with the --extract-certificates option to codesign, which allows you to determine the certificate of the code-signing identity that was used to sign the code. I’ve got some info on how to do that somewhere…

Oh, right, here it is…

Have a look at the Check the Signing Certificate section of Resolving Code Signing Crashes on Launch. Its focus is on the Mac, but the bulk of our code-signing infrastructure works the same on all our platforms.

Share and Enjoy

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

This is fantastic help, many thanks Mr Eskimo. We actually met once long long ago, your wisdom is much appreciated.

Now having done all of that this is what I found:

  1. the original profile has 2 certs, and the emitted binary has been signed with the second one of those. In that other thread under "Check the Signing Certificate" there is mention of "the first certificate is the one that matters" - why?
  2. Going back to the original error, it says that the profile included in the bundle is missing the code-signing certificate. Extracting and dumping the signature and dates of all 19 of those shows that the certifcate used for signing is in there, and is not expired.

Seems to me the error is kind of misleading and something else must be amiss, any ideas?

Accepted Answer
there is mention of "the first certificate is the one that matters" - why?

The context here really matters:

  • In a provisioning profile, the certificates act as an allowlist. So the profile holds a list of leaf certificates that it authorises.
  • In a code signature, the certificates act as a chain of trust [1]. The first certificate is the leaf, the next is the one that issued the leaf, and so on until you get to a root.

So when the trusted execution system evaluates code for execution, it checks whether the first certificate in the code signature is in the list of certificates in the profile.


Regarding your original issue, when you check certificates it’s critical that you look at the serial number. That’s what matters when it comes to matching.

If you double check that and the certificate that signed the code is in the profile then the next thing to check is whether this is the right type of profile. The easiest way to check that is to look at the certificates themselves. The Developer website won’t include development certificates in a distribution profile, so if the certificates are named Apple Distribution then you know you have a distribution profile.

Share and Enjoy

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

[1] TN3161 Inside Code Signing: Certificates has ane explanation of this and a bunch of other relevant terminology.

  • In a code signature, the certificates act as a chain of trust [1]. The first certificate is the leaf, the next is the one that issued the leaf, and so on until you get to a root.

Ah I see, did not realize this before but it makes perfect sense, thank you.

...the next thing to check is whether this is the right type of profile.

Turns out it is not a distribution profile and this was the problem all along. The error message "Missing code-signing certificate" was a red-herring this whole time.

What is interesting is that it appears that it used to work even though it shouldn't have, by virtue of the fact that these app builds are present in Testflight and the profile it was using dates from before those builds. Alas am unable to confirm that for certain as CI history is too shallow and we no longer have a copy of the app bundle to verify. At some point altool has stopped returning non-zero exit codes on failure so CI has been blind to the failures for some months now (probably since Xcode 26 I'm guessing).

Thanks again for your help it is invaluable. Have bookmarked these resources especially Resolving Code Signing Crashes on Launch which provides a ton of details missing from the technotes and official documentation.

Signing succeeds but validate fails with "Missing code-signing certificate"
 
 
Q