Xcode "Provisioning profile doesn't include signing certificate" after a certificate renewal
Our yearly Apple distribution certificate expired, we created a new one, and every archive failed: the provisioning profile doesn't include the signing certificate. Profiles embed the certificates they trust. How we regenerated profiles, cleaned keychains and verified signing identities.
Our iOS distribution certificate was about to expire. Following the reminder email, a developer created a new Apple Distribution certificate in the Apple Developer portal, installed it on the build Mac and revoked the old one to keep things tidy. The next archive for TestFlight failed in Xcode:
Provisioning profile "Shop App Store" doesn't include signing certificate "Apple Distribution:
Example Ltd (A1B2C3D4E5)".
On the CI machine, xcodebuild said the same thing in a longer form:
error: Provisioning profile "Shop App Store" doesn't include signing certificate "Apple Distribution:
Example Ltd (A1B2C3D4E5)". (in target 'Shop' from project 'Shop')
** ARCHIVE FAILED **
What is in the profile?
A provisioning profile is a signed plist. You can decode it and list the certificates it contains:
security cms -D -i ~/Library/MobileDevice/Provisioning\ Profiles/0f3c...mobileprovision > profile.plist
/usr/libexec/PlistBuddy -c 'Print :DeveloperCertificates' profile.plist | head -3
plutil -extract DeveloperCertificates.0 raw -o - profile.plist | base64 -d | \
openssl x509 -inform der -noout -subject -enddate -serial
subject=UID=A1B2C3D4E5, CN=Apple Distribution: Example Ltd (A1B2C3D4E5), OU=A1B2C3D4E5, O=Example Ltd, C=GB
notAfter=Nov 6 09:14:22 2024 GMT
serial=5F2A...
The profile contained the old certificate, with the old serial number. And the identities in the keychain:
security find-identity -v -p codesigning
1) 9A7F... "Apple Distribution: Example Ltd (A1B2C3D4E5)" <- new
2) 3C1D... "Apple Distribution: Example Ltd (A1B2C3D4E5)" (CSSMERR_TP_CERT_REVOKED)
2 valid identities found
Same name, different certificates. The new identity was valid; the profile did not include it.
What we ruled out
- The wrong team or bundle id. The profile's
TeamIdentifierandapplication-identifiermatched. - Missing private key.
find-identitylisted the new certificate as a valid identity, which requires the private key to be present. - An expired WWDR intermediate certificate. That produces "unable to build chain" errors, not this one.
Root cause
Each provisioning profile embeds the specific certificates allowed to sign with it. Creating a new distribution certificate does not update existing profiles, and revoking the old certificate made the profiles invalid. Xcode found the new identity in the keychain, matched it by name, then rejected it because the profile only trusted the old certificate.
Certificates, identities and profiles
| Item | Contains | Lives in |
|---|---|---|
| Signing certificate | Public key, issued by Apple, valid for a year | Developer portal and keychain |
| Signing identity | Certificate plus its private key | Keychain of the build machine |
| Provisioning profile | App id, team, entitlements, allowed certificates, devices (for development/ad hoc) | Portal, then ~/Library/MobileDevice/Provisioning Profiles |
Codesigning needs an identity whose certificate is listed in the profile. Profiles do not refer to "the current distribution certificate"; they list exact certificates. So renewing a certificate requires regenerating every profile that used the old one.
Revocation versus expiry
An expired certificate stops new signing but does not affect apps already on the App Store. Revoking a distribution certificate also does not affect App Store apps, but it invalidates profiles that include it, and for enterprise distribution it breaks installed apps. Revoking early, before new profiles exist, turns a routine renewal into a blocked release.
Who is affected
Teams renewing distribution or development certificates with manually managed profiles, teams sharing one build machine or CI where profiles are installed by hand, and anyone who revokes a certificate before regenerating the profiles that depend on it. Xcode's automatic signing handles this for local builds, but CI setups with manual profiles do not.
Environment
| Component | Version / value |
|---|---|
| Xcode | 16.1 |
| Signing | Manual signing for release builds, profiles installed on CI |
| Certificates | Apple Distribution, old one revoked after the new one was created |
| Profiles | App Store profiles for the app and its notification service extension |
Regenerate the profiles
In the Apple Developer portal, under Profiles, each App Store profile for the app and its extensions was edited to include the new certificate and saved, which produces a new profile with a new UUID. The same can be done through the App Store Connect API or fastlane:
fastlane sigh --app_identifier com.example.shop --force
fastlane sigh --app_identifier com.example.shop.NotificationService --force
Install the new profiles and remove the old ones
rm ~/Library/MobileDevice/Provisioning\ Profiles/0f3c*.mobileprovision # old UUIDs
open ShopAppStore.mobileprovision # installs the new one
Old profiles with the same name confuse Xcode's manual selection, so deleting them matters. On CI, the profiles directory is rebuilt from scratch in each job.
Clean the keychain
The revoked identity stayed in the keychain and appeared next to the new one with the same name, which can
make codesign pick the wrong one when identities are referenced by name. We deleted it:
security delete-certificate -Z 3C1D... # SHA-1 of the revoked certificate
And in the Xcode project, release signing now refers to the identity by its SHA-1 hash in the export options, not by name.
Archive again
xcodebuild -workspace Shop.xcworkspace -scheme Shop -configuration Release \
-archivePath build/Shop.xcarchive archive
xcodebuild -exportArchive -archivePath build/Shop.xcarchive \
-exportOptionsPlist ExportOptions.plist -exportPath build/export
Extensions and other targets
The app had a notification service extension with its own bundle id and its own App Store profile. We regenerated that profile too; forgetting an extension produces the same error, but naming the extension target, which is easy to misread as the main app failing again. List every target's bundle id before a renewal:
xcodebuild -workspace Shop.xcworkspace -scheme Shop -showBuildSettings \
| grep -E "PRODUCT_BUNDLE_IDENTIFIER|PROVISIONING_PROFILE_SPECIFIER"
Alternatives and trade-offs
- Automatic signing in Xcode. Handles regeneration for local builds; CI needs the same account access, which many teams avoid.
- fastlane match keeps certificates and profiles in an encrypted repository shared by the team and CI, and regenerates them together. We moved to it the following month; a separate post covers that pipeline.
How to test the fix
security cms -D -i build/export/Payload/Shop.app/embedded.mobileprovision | grep -A1 UUID
codesign -dvv build/export/Payload/Shop.app 2>&1 | grep -E "Authority|TeamIdentifier"
The authority chain should show the new Apple Distribution certificate, and the embedded profile should be the new UUID.
Confirming in production
The build uploaded to App Store Connect, passed processing and was distributed to TestFlight testers the same day. The app already in the App Store kept working throughout, as expected.
Updating CI
CI installed profiles from a shared drive. We replaced the files there, bumped the profile names in the export options, and ran a full archive and export on CI before telling the team the renewal was complete. A renewal is only done when CI can produce an uploadable build.
Regression guard
- A calendar reminder 30 days before certificate expiry, with a runbook: create the new certificate, regenerate all profiles, update CI, verify a build, and only then revoke the old certificate if needed.
- A CI step that prints the certificate serial in each profile and fails if it does not match the signing identity, with a readable message.
Security implications
Distribution certificates and their private keys let anyone sign builds as your team. Keep them out of personal keychains where possible, store them encrypted for CI, and limit who can create or revoke them in the developer account. Revoking is the right action after a key compromise; for routine renewal, it is usually unnecessary.
Prevention checklist
- Remember that profiles embed specific certificates; renewals require new profiles.
- Do not revoke the old certificate until new profiles are installed and tested.
- Remove old profiles and revoked identities from build machines.
- Reference signing identities by hash in CI.
- Consider fastlane match or automatic signing to keep certificates and profiles in sync.
References
- Apple Developer, Certificates overview: https://developer.apple.com/help/account/certificates/certificates-overview/
- Apple Developer, Create an App Store provisioning profile: https://developer.apple.com/help/account/manage-profiles/create-an-app-store-provisioning-profile/
- Apple, TN3125 Inside Code Signing: Provisioning Profiles: https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles
- fastlane sigh: https://docs.fastlane.tools/actions/sigh/
Add a label
Embed this post
<iframe src="https://www.hibug.me/ios-provisioning-profile-missing-signing-certificate" width="700" height="420" frameborder="0" loading="lazy"></iframe>
I have spent most of the last decade on mobile teams, first native iOS, then React Native and Flutter for companies that needed one team to ship to both stores. The work I enjoy most is the unglamorous part between "it runs on my phone" and "it is live for a million users": code signing, release builds, store review, crash triage and background behaviour that differs on every Android vendor. Most of the bugs I write about here cost a release day. Each post shows the exact error, what we ruled out, the fix and how we proved it in the next build, so you can get your own release out the door sooner.
Comments
0No comments yet. Be the first to comment!
Sign In to post a comment.