Code Signing

RSS for tag

Certify that an app was created by you using Code signing, a macOS security technology.

Posts under Code Signing tag

20 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

"Unable to Verify App" message started to appear for an already existing app
I have an app being deployed to QA ad hoc. All the builds have always been signed with the same provisioning profile under the same developer account. In the last two weeks, I built two different versions (e.g. 0.0.2 and 0.0.3). So, QA has been working with version 0.0.2 until last Wednesday when 0.0.3 was ready. The new build was signed in exactly the same way as before. However, on a test device with iOS 16.3.1, it did not start, showing the following message: . (Note: Everything was OK with Internet connection there, as QA tried to run the app immediately after downloading it and also tried it dozens of times.) NB1: After the problem appeared, QA checked the previous version 0.0.2, and it still ran fine on the target device. However, the issue persisted when returning to 0.0.3. NB2: The app does not appear in Settings/General/VPN&Device management section, so there is no way to actually verify it NB3: The same IPA file runs on iOS 12 and 14 without any issues all the time. I would greatly appreciate it if somebody could clarify the reasons of such behaviour or at least point out how to avoid it in future.
3
1
841
Feb ’24
Code Sign using Azure Key Vault
I need an OV certificate to code sign an Electron application. I was used to build in Jenkins the application oth for Windows and macOS using Electron-Forge (https://www.electronforge.io/guides/code-signing/code-signing-macos). To be more specific use XCode and Keychain to store the certificate. Sadly, new certificate industry requirements will force me to use Azure Key Vaults (or other cloud HSM alternatives) to store the certificate. I need to find a way to code-sign it for macOS from Azure Key Vaults or equivalent solutions. Thank you
5
0
2.1k
Sep ’24
Mystified by certificate renewal process
I got an email from Apple, "Your Developer ID Installer Certificate will no longer be valid in 30 days". So I went to my certificates page on developer.apple.com, and I see the attached photo. Basically, yes, I have a Developer ID Installer Certificate that expires 2023/07/01; but I also have one that expires 2025/12/08, and one that expires 2026/01/09, and one that expires 2026/12/15, and another that expires 2026/12/16! Why do I have all these certificates? I have no idea. There is a "+" button to add a new one; but given that I already seem to have ones that won't expire for several more years, do I need to? There does not seem to be a "-" button, or any way to clear out this cruft. I then recalled that perhaps I have managed my certificates in Xcode in the past, not on this page (or maybe I have done both, at different times?). So I went to Xcode, and things seem to be rather a mess there too, but in a different way (second image attached). Here, I seem to have lots of stale certificates that are in gray and say "Not in Keychain" – how do I clear those out? Again there does not seem to be a "-" button. And the newer ones that I saw on developer.apple.com do not seem to be listed here, maybe – it's hard to compare, though, because on developer.apple.com it shows the expiration date but not creation date, whereas in Xcode it shows creation date but not expiration date. What should I do? Note that I am not a member of multiple different teams, or anything like that; I'm a solo developer. This stuff is really confusing and does not seem to be well-documented anywhere that I have found. Am I just being dense?
8
1
2k
Mar ’24
Code Signing an app including a binary Metallib
Hi! I am currently trying to upload my iOS app to App Store Connect. Unfortunately, code signing fails with the following error: "Code object is not signed at all.", referencing a binary Metallib (created with metal-tt and an mtlp-json script). I am using Xcode's automatically managed signing and the binary metallib is located inside the "Resources" directory of a framework that I am including with "Embed and sign" in the app. Could anyone give some guidance on what I need to change to make code signing work? Thank you.
4
0
885
Jul ’24
App Groups: macOS vs iOS: Fight!
I regularly see folks confused by the difference in behaviour of app groups between macOS and iOS. One day I’ll have time to write this up for the official docs (r. 92322409) but, in the meantime, here’s a quick overview. [Well, it was a quick overview. Things have got considerably more complicated in recent years.] If you have questions or comments, start a new thread with the details. Put it in the Privacy & Security > General topic area and tag it with Code Signing and Entitlements. Oh, and if this is about app group container protection, also include Files and Storage. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" App Groups: macOS vs iOS: Fight! The app groups mechanism works differently on macOS and iOS. On iOS: App group IDs start with the group. prefix. To use an app group ID, first allocate it on the Developer website. This associates the app group ID with your team. Then claim the app group ID in your app’s App Groups entitlement (com.apple.security.application-groups) entitlement. Like all entitlements on iOS, that claim must be authorised by a provisioning profile. A profile will only authorise an app group ID that’s allocated by your team. For more background on provisioning profiles, see TN3125 Inside Code Signing: Provisioning Profiles. In contrast, on macOS: App group IDs typically start with your Team ID. They can’t be explicitly allocated on the Developer website. Code that isn’t sandboxed doesn’t need to claim the app group ID in the App Groups entitlement. [1] To use an app group, claim the app group ID in the App Groups entitlement. The App Groups entitlement is not restricted, meaning that this claim doesn’t need to be authorised by a provisioning profile. The App Store submission process checks that your app group IDs make sense. IMPORTANT In this context I’m using macOS to refer to a standard macOS app. In Mac Catalyst things behave as they do on iOS. Likewise for iOS Apps on Mac. Also, anything I say about iOS also applies to tvOS, watchOS, and visionOS. This difference is a product of the way that each platform protects app group content. On iOS the Developer website enforces group uniqueness, that is, the site prevents team B from using an app group ID that’s assigned to team A. In contrast, on macOS: App group IDs are prefixed with the Team ID solely to prevent collisions. The Mac App Store prevents you from publishing an app that uses an app group ID that’s used by another team. In macOS 15 and later, all apps are subject to app group container protection. [1] This was true prior to macOS 15. It may still technically be true in macOS 15 and later, but the most important thing, access to the app group container, requires the entitlement because of app group container protection. Crossing the Streams [… and mixing my pop culture metaphors!] In some circumstances you might need to share an app group between iOS and macOS code. For example, you might have a Mac app that needs to share an app group with: A Mac Catalyst app An iOS app that runs on macOS via iOS Apps on Mac The solution is to use an iOS-style app group ID in your Mac app. To do this: Confirm that the app group ID is registered to your team on the Developer website. Claim the app group ID in the App Groups entitlement. If you submit that app to the Mac App Store, the submission process checks that your app group ID claims make sense, that is, they either follow the macOS convention (use a prefix of the Team ID) or the iOS convention (allocate a group ID, with the group. prefix, on the Developer website). IMPORTANT Due to app group container protection, this approach is only viable for Mac App Store apps. For more details, see App Group Container Protection, below. App Groups and the Keychain The differences described above explain an oddity associated with keychain access. Consider this quote from Sharing Access to Keychain Items Among a Collection of Apps: Application groups When you collect related apps into an application group using the App Groups entitlement, they share access to a group container, and gain the ability to message each other in certain ways. Starting in iOS 8, the array of strings given by this entitlement also extends the list of keychain access groups. There are three things to note here: Using an app group ID as a keychain access group only works on iOS; it’s not supported on macOS [1] because doing so would be insecure. The App Groups entitlement must be authorised by a provisioning profile on iOS, and that process is what protects the keychain from unauthorised access. The required group. prefix means that these keychain access groups can’t collide with other keychain access groups, which all start with an App ID prefix (there’s also Apple-only keychain access groups that start with other prefixes, like apple). In contrast, standard keychain access groups are protected the same way on both platforms, using the Keychain Access Groups entitlement (keychain-access-groups). [1] Except for iOS Apps on Mac. Not Entirely Unsatisfied When you launch a Mac app that uses app groups you might see this log entry: type: error time: 10:41:35.858009+0000 process: taskgated-helper subsystem: com.apple.ManagedClient category: ProvisioningProfiles message: com.example.apple-samplecode.Test92322409: Unsatisfied entitlements: com.apple.security.application-groups Note The exact format of that log entry, and the circumstances under which it’s generated, varies by platform. On macOS 13.0.1 I was able to generate it by running a sandboxed app that claims the App Group entitlement and also claims some other restricted entitlement. This looks kinda worrying and can be the source of problems. You see this error when you have a sandboxed app that uses an app group. In a sandboxed app your use of the app group must be authorised by the App Groups entitlement. This message is telling you that your use of the App Groups entitlement is not authorised by your provisioning profile. On iOS this would be a show stopper. The trusted execution system would prevent your app from launching at all. On macOS that’s not the case. The trusted execution system knows that there’s no way to get a Mac provisioning profile that authorises the App Groups entitlement, and thus it allows the app to launch anyway. However, that’s not the end of the story. You might run into problems with: macOS 15’s app group container protection The entitlements validated flag App Group Container Protection macOS 15 introduced app group container protection. To access an app group container without user intervention: Claim access to the app group by listing its ID in the App Groups entitlement. Locate the container by calling the containerURL(forSecurityApplicationGroupIdentifier:) method. Ensure that at least one of the following criteria are met: Your app is deployed via the Mac App Store (A). Or via TestFlight when running on macOS 15.1 or later (B). Or the app group ID starts with your app’s Team ID (C). Or your app’s claim to the app group is authorised by a provisioning profile embedded in the app (D) [1]. If your app doesn’t follow these rules, the system prompts the user to approve its access to the container. If granted, that consent applies only for the duration of that app instance. For more on this, see: The System Integrity Protection section of the macOS Sequoia 15 Release Notes The System Integrity Protection section of the macOS Sequoia 15.1 Release Notes WWDC 2024 Session 10123 What’s new in privacy, starting at 12:23 The above criteria mean that you rarely run into the app group authorisation prompt when your app is deployed. If you encounter a case where that happens, feel free to start a thread here on DevForums. See the top of this post for info on the topic and tags to use. However, you might run into some issues during development: If you have a multiplatform app built from a single target — for example, if you created the project from the Multiplatform > App template — Xcode’s Signing & Capabilities editor doesn’t understand all of these app group nuances. To work around this, conditionalise the entitlements file build setting. See this thread for more. If you use an iOS-style app group ID in a macOS app, you might run into the authorisation prompt during day-to-day development. One way around this is to use a macOS-style app group ID during development and switch to the iOS-style app group ID for production. [1] This is what allows Mac Catalyst and iOS Apps on Mac to work. Entitlements Validated Flag If your app claims the app group entitlement but that claim isn’t authorised by a provisioning profile, the trusted execution system allows the app to launch but it clears its entitlements validated flag. Some subsystems that rely on entitlements will fail in this case. The most notable example of this is the data protection keychain. Note If you’re curious about this flag, use the procinfo subcommand of launchctl to view it. For example: % sudo launchctl procinfo `pgrep Test20230126` … code signing info = valid … entitlements validated … If the flag has been cleared, this line will be missing from the code signing info section. The practical impact of this is that, for a sandboxed app on macOS, you can either use app groups or use the data protection keychain, but not both. Needless to say, this is less than ideal (r. 104859788). IMPORTANT This doesn’t stop you using the keychain in general. You can still use the file-based keychain. For more information about these terms, see TN3137 On Mac keychain APIs and implementations. One place this often crops up is with Network Extension (NE) framework system extensions. These must be sandboxed and often use an app group as part of their IPC story. Specifically, they might want to publish an XPC named endpoint and, when doing that, the name listed in NEMachServiceName must be a ‘child’ of an app group. Fortunately, system extensions are effectively daemons and so can’t use the data protection keychain anyway. So, if you’re building an NE system extension, this message is probably nothing to be worried about. If you’re building some other program that’s affected by this, open a thread here on DevForums and let’s talk. See the top of this post for info on the topic and tags to use. Revision History 2024-11-05 Further clarified app group container protection. Reworked some other sections to account for this new reality. 2024-10-29 Clarified the points in App Group Container Protection. 2024-10-23 Fleshed out the discussion of app group container protection on macOS 15. 2024-09-04 Added information about app group container protection on macOS 15. 2023-01-31 Renamed the Not Entirely Unsatisfactory section to Not Entirely Unsatisfied. Updated it to describe the real impact of that log message. 2022-12-12 First posted.
0
0
2.2k
2w
JPackage : mac-signing-key-user-name?
I am trying to sign a Java application, packaged in a disk image, via jpackage, invoked via Ant (so no XCode anywhere). The packaging itself works fine, but I am having trouble figuring out the signing parameters. In particular, it seems I will have to provide a parameter --mac-signing-key-user-name What value should I give to this parameter? I have an Apple Developer Account (well, obviously...), I have generated a certificate and quite a few other things, but I am confused as to what the "signing-key-user-name" should be. The error message I currently get from jpackage is: No certificate found matching [...] using keychain [] I am on MAC OS 12.6 and JDK 17. Any help would be greatly appreciated.
3
0
1.4k
Dec ’23
Resolving errSecInternalComponent errors during code signing
One code signing issue I commonly see, both here on DevForums and in my Day Job™ with DTS, is that the codesign command fails with errSecInternalComponent. This issue crops up in a wide variety of circumstances and the correct fix depends on the specific problem. This post is my attempt to clarify the potential causes of this error and help folks resolve it. If you have any questions or comments about this, please start a new thread, tagging it with Code Signing so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Resolving errSecInternalComponent errors during code signing In some circumstances the codesign command might fail with the error errSecInternalComponent. For example: % codesign -s "Apple Development" "MyTrue" MyTrue: errSecInternalComponent This typically affects folks who are signing code in a nonstandard environment, for example, when logged into a Mac via SSH or when signing code on a continuous integration (CI) server. This post explains how to resolve such issues, starting in the simplest case, signing from Terminal app, and then going on to discuss SSH and other contexts. IMPORTANT Before going further, make sure you understand the difference between a digital identity and a certificate. See TN3161 Inside Code Signing: Certificates for the details. Test from Terminal Code signing makes extensive use of the keychain, and that’s sensitive to the execution context in which it’s running. So, the first step in resolving this problem is to test your code signing from Terminal. To start, log in to the Mac using the GUI. Note If you don’t have access to the GUI, see Working without the GUI, below. Check that Keychain Access shows that your code signing identity’s certificate is trusted. Select the certificate and look for a green checkmark with the text “This certificate is valid”. If you see a red cross with an explanatory text like “… certificate is not trusted”, follow the instructions in Fixing an untrusted code signing certificate. Note macOS 15 moved Keychain Access out of the Utilities folder. The easiest way to find and launch Keychain Access is to use Spotlight. In Terminal, run the security tool to check that your code signing identity is available: % security find-identity -p codesigning Policy: Code Signing Matching identities 1) 4E587951B705280CBB8086325CD134D4CDA04977 "Apple Development: …" 1 identities found Valid identities only 1) 4E587951B705280CBB8086325CD134D4CDA04977 "Apple Development: …" 1 valid identities found If the identity is missing from the Matching identities list, you don’t have a code signing identity to sign with. If you see your code signing identity’s certificate in the keychain, it’s possible that you’re missing its private key. See Certificate Signing Requests Explained for more about that issue. If the identity is shown in the Matching identities list but not in the Valid identities only list, see Fixing an untrusted code signing certificate. This example assumes that you’re testing with an Apple Development signing identity. If you’re using something else, you’ll see a different identity name in this list. Use that identity name in the codesign command below. Still in Terminal, make a copy of the true tool to use for this test: % cp "/usr/bin/true" "MyTrue" Try to sign it: % codesign -s "Apple Development" -f "MyTrue" MyTrue: replacing existing signature The -f flag tells codesign to replace the existing signature. This command may display one or more keychain dialogs but, once you respond to those, it should correctly sign MyTrue. If it doesn’t, skip down to the Terminal failure section at the end of this post. Eliminate keychain alerts When you signed your code in the previous section, you may have seen one of two different types of keychain alerts: Keychain unlock dialog Access control list (ACL) dialog The keychain unlock dialog looks like this: codesign wants to use the … keychain. Please enter the keychain password. Password: [ ] [Cancel] [[OK]] The keychain containing your code signing identity is locked, and you must enter the keychain password to unlock it. You rarely see this dialog when logged in via the GUI because the system automatically unlocks the login keychain when you log in. However, the underlying cause of this alert will become relevant in the next section, when you log in via SSH. The ACL dialog looks like this: codesign wants to sign using key … in your keychain. To allow this, enter the … keychain password. Password: [ ] [Always Allow] [Deny] [[Allow]] The ACL for the your code signing identity’s private key prevents codesign from using the private key without your explicit approval. If you enter your password and click Allow, codesign can use the private key once. If you click Always Allow, the system adds codesign to the private key’s ACL so that it doesn’t have to ask again. To avoid this alert in the future, enter your keychain password and click Always Allow. Now repeat the codesign command from the previous section. It will sign the code without presenting any dialogs. Test over SSH Once you can sign your code in Terminal without seeing any dialogs, it’s time to repeat that process over SSH. To start, log out of the GUI and then log in via SSH. If you’re testing on a CI system, log in to that system by running ssh from Terminal on your Mac. If you want to test on your local Mac, choose one of these options If you have a second Mac, log in to that second Mac using the GUI, launch Terminal, and then run ssh to log in to your main Mac from there. If you have an iPad, use a third-party iPad SSH app to log in to your main Mac over SSH. Use a virtualisation app to run a macOS guest that you can treat like your CI system. Once you’re logged in over SSH, repeat the signing command from the earlier section: % codesign -s "Apple Development" -f "MyTrue" MyTrue: replacing existing signature MyTrue: errSecInternalComponent This fails because: The system locked the keychain when you logged out of the GUI. Logging in via SSH does not unlock the keychain. When codesign tries to use your code signing identity, the system attempts to present the keychain unlock dialog. That fails because you’re logged in via SSH and thus don’t have access to the GUI. The system returns the errSecInternalComponent error to codesign, which reports it to you. To fix this, unlock your keychain using the security tool: % security unlock-keychain password to unlock default: KEYCHAIN_PASSWORD % codesign -s "Apple Development" -f "MyTrue" MyTrue: replacing existing signature IMPORTANT This assumes that your code signing identity is in your login keychain. If it’s in some other keychain, read the security man page to learn how to unlock a specific keychain. Best practice is to store both parts of your code signing identity (the certificate and the private key) in the same keychain. If you split the identity across two keychains, unlock the keychain that contains the private key. Test your CI job Once you have everything working on your CI system over SSH, try running exactly the same commands in your CI job. If your CI system manages user contexts correctly, those commands should just work. If they don’t, discuss this with your CI vendor. Note macOS has a complex execution context model. For background on this, see the Execution Contexts section of Technote 2083 Daemons and Agents. Some CI systems don’t correctly establish a user context when running jobs. For example, they might switch the traditional Unix execution context — the EUID, RUID, and so on — but not the security context. This mixed execution context causes problems for the keychain, which relies on the security context. Avoid doing code signing work as root. Some folks run everything as root because they think it’ll avoid problems. When working with the keychain the opposite is true: Running as root often causes more problems than it solves. These problems are most likely to show up when you use sudo, which creates a mixed execution context. Working without the GUI The instructions above assume you have access to the GUI so that you can test and resolve issues using GUI tools like Keychain Access. However, many CI systems don’t give you access to the GUI; at best you might have interactive access using SSH. Note If you CI system allows remote access using a screen sharing protocol, use that rather than messing around with the instructions here. If you don’t have access to the GUI of the machine on which you’re signing code, there are three issues to deal with: Avoiding the keychain unlock dialog Avoiding the ACL dialog Investigating an untrusted code signing certificate issue To unlock the keychain, use the unlock-keychain subcommand of the security tool, discussed in the Test over SSH section earlier. When logged in with the GUI, you can respond to ACL dialog by clicking Always Allow. This prevents that dialog showing up again. However, if you don’t have GUI access there’s no way to click that button. To get around this, import your signing identity and set its ACL to allow codesign to use it without extra authorisation. To do this, first unlock the keychain: % security unlock-keychain password to unlock default: KEYCHAIN_PASSWORD Then use the security tool to import the PKCS#12 file: % security import IDENTITY.p12 -T /usr/bin/codesign -P P12_PASSWORD 1 identity imported. Note the -T option, which adds codesign to the private key’s ACL. Finally, modify the partition list to allow access by Apple code: % security set-key-partition-list -S "apple:" -l "Apple Development: …" This example assumes you’re using an Apple Development signing identity to test with. If you’re using something else, replace Apple Development: … with that identity name. Finally, investigating an untrusted code signing certificate issue remotely is quite challenging. Your best option here is to set up a local test environment, run your investigation in that environment, and then apply the results to your CI environment. There are two good choices for your local test environment: Use a virtualisation app to create a ‘clean’ macOS guest, one that’s never seen your code signing setup before. Use System Settings > Users & Groups to create a new local user account and do your testing there. The first option is best because you can easily restore your VM to a clean state between tests. When running through the process described in Fixing an untrusted code signing certificate, you might end up performing two different remedial actions: Importing an intermediate Reseting trust settings. Once you understand these remediations, you need to apply them to your CI system. The first one is easy: To import an intermediate, run security with the import subcommand: % security import INTERMEDIATE.cer 1 certificate imported. Resetting trust settings is more of a challenge. It’s probably possible to do this with the security tool but, honestly, if you think that your CI system has messed up trust settings it’s easiest to throw it away and start again from scratch. Terminal failure The bulk of this post assumes that the process described in the Test from Terminal section works. If it doesn’t, something weird is happening and you should apply the following diagnostic suggestions. The first is to create a new local user account on your Mac — using System Settings > Users & Groups — and then retry there. The goal of this test is to isolate: A problem that affects your Mac as a whole From a problem that’s tied to your user account If the problem is with your user account, switch back to your original account and run: % security dump-trust-settings SecTrustSettingsCopyCertificates: No Trust Settings were found. In most cases this should report that no trust settings were found. If it report trust setting overrides, remove them. See Check for a trust settings override in Fixing an untrusted code signing certificate. If that doesn’t resolve the issue, something else is afoot and I recommend that you seek dedicated help per the start of this post. Revision History 2024-10-05 Added the Terminal failure section. Made other minor editorial changes. 2022-08-12 Extended the unlock-keychain explanation to cover the split identity issue. 2022-08-11 First posted.
0
0
8.5k
2w
Cannot add provisioning profile to any devices with Xcode
Hello. I have an iOS app written in Xamarin, but this issue is not related to Xamarin or Visual Studio. I am trying to deploy my xamarin app onto an iOS device, but I am unable to get the iOS device to install the provisioning profile via Xcode. I work at a company with a decent variety of test devices and the result seems to be the same from iPads to iPods to iPhones of various ages. I have created a certificate and a provisioning profile. The certificate is associated with the provisioning profile on the developer portal. I have imported the certificate (including private keys) into my login keychain on MacOS. I have the .mobileprovision file downloaded to the machine. I am signed into Xcode with my apple developer account. In Xcode, i went to Window > Devices and Simulators and selected my device. I right clicked my device and selected "Show Provisioning Profiles". I clicked the plus and chose my .mobileprovision file. I get the same error on every device: Failed to install one or more provisioning profiles on the device. Please ensure the provisioning profile is configured for this device. If not, please try to generate a new profile.| this is an incredibly vague and unhelpful error. I'm not really sure what it means by "configured for this device". Not sure where to go from here
7
5
14k
Jun ’24
CoreMedia I/O Camera Extension Installation Error (Invalid Signature)
Hi! I'm trying to move from CoreMedio I/O DAL Plug-In to CoreMedia I/O camera extensions, announced in macOS 12.3. I created a test extension, placed it inside my app bundle into Contents/Library/SystemExtensions and signed with codesigning certificate. But when I try to install my extension from inside my app, using this code (Swift): func requestActivation() { guard case .idle = status else { fatalError("Invalid state") } print("Requesting activation of extension \"\(extensionIdentifier)\"") let req = OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: extensionIdentifier, queue: DispatchQueue.main) req.delegate = self OSSystemExtensionManager.shared.submitRequest(req) status = .requested } I'm getting an error: OSSystemExtensionErrorDomain error 8: Code Signature Invalid which is rather generic. Can anybody tell me what I am doing wrong? Or at least propose some steps to find it out? I'm posting here entitlements and codesign output for my extension and containing application for further information. kdg@admins-Mac-mini SystemExtensions % codesign -d --entitlements - ./com.visicom.VirtualCamera.avextension.systemextension Executable=/Applications/VirtualCamera.app/Contents/Library/SystemExtensions/com.visicom.VirtualCamera.avextension.systemextension/Contents/MacOS/com.visicom.VirtualCamera.avextension [Dict] [Key] com.apple.security.app-sandbox [Value] [Bool] true [Key] com.apple.security.application-groups [Value] [Array] [String] 6SUWV7QQBJ.com.visicom.VirtualCamera kdg@admins-Mac-mini /Applications % codesign -d --entitlements - ./VirtualCamera.app Executable=/Applications/VirtualCamera.app/Contents/MacOS/VirtualCamera [Dict] [Key] com.apple.developer.system-extension.install [Value] [Bool] true [Key] com.apple.security.app-sandbox [Value] [Bool] true [Key] com.apple.security.application-groups [Value] [Array] [String] 6SUWV7QQBJ.com.visicom.VirtualCamera [Key] com.apple.security.files.user-selected.read-only [Value] [Bool] true kdg@admins-Mac-mini SystemExtensions % codesign -dvvv ./com.visicom.VirtualCamera.avextension.systemextension Executable=/Applications/VirtualCamera.app/Contents/Library/SystemExtensions/com.visicom.VirtualCamera.avextension.systemextension/Contents/MacOS/com.visicom.VirtualCamera.avextension Identifier=com.visicom.VirtualCamera.avextension Format=bundle with Mach-O universal (x86_64 arm64) CodeDirectory v=20500 size=1553 flags=0x10700(hard,kill,expires,runtime) hashes=37+7 location=embedded Hash type=sha256 size=32 CandidateCDHash sha256=25bd80657bfd6e0ab95467146c7b532817e9e520 CandidateCDHashFull sha256=25bd80657bfd6e0ab95467146c7b532817e9e5209fd50b0cb7ceef40dcfb40e8 Hash choices=sha256 CMSDigest=25bd80657bfd6e0ab95467146c7b532817e9e5209fd50b0cb7ceef40dcfb40e8 CMSDigestType=2 CDHash=25bd80657bfd6e0ab95467146c7b532817e9e520 Signature size=9006 Authority=Developer ID Application: Visicom Media Inc. (6SUWV7QQBJ) Authority=Developer ID Certification Authority Authority=Apple Root CA Timestamp=7 Jul 2022, 21:49:32 Info.plist entries=23 TeamIdentifier=6SUWV7QQBJ Runtime Version=12.3.0 Sealed Resources version=2 rules=13 files=0 Internal requirements count=1 size=200 kdg@admins-Mac-mini /Applications % codesign -dvvv ./VirtualCamera.app Executable=/Applications/VirtualCamera.app/Contents/MacOS/VirtualCamera Identifier=com.visicom.VirtualCamera Format=app bundle with Mach-O universal (x86_64 arm64) CodeDirectory v=20500 size=1989 flags=0x10700(hard,kill,expires,runtime) hashes=51+7 location=embedded Hash type=sha256 size=32 CandidateCDHash sha256=31e15fbbd436a67a20c5b58c597d8a4796a67720 CandidateCDHashFull sha256=31e15fbbd436a67a20c5b58c597d8a4796a6772020308fb69f4ee80b4e32788b Hash choices=sha256 CMSDigest=31e15fbbd436a67a20c5b58c597d8a4796a6772020308fb69f4ee80b4e32788b CMSDigestType=2 CDHash=31e15fbbd436a67a20c5b58c597d8a4796a67720 Signature size=9006 Authority=Developer ID Application: Visicom Media Inc. (6SUWV7QQBJ) Authority=Developer ID Certification Authority Authority=Apple Root CA Timestamp=7 Jul 2022, 21:58:09 Info.plist entries=20 TeamIdentifier=6SUWV7QQBJ Runtime Version=12.3.0 Sealed Resources version=2 rules=13 files=4 Internal requirements count=1 size=188 Thanks in advance!
8
0
2.4k
Aug ’24
Code Signing Resources
General: DevForums tags: Code Signing, Signing Certificates, Provisioning Profiles, Entitlements Developer Account Help — This document is good in general but, in particular, the Reference section is chock-full of useful information, including the names and purposes of all certificate types issued by Apple Developer web site, tables of which capabilities are supported by which distribution models on iOS and macOS, and information on how to use managed capabilities. Developer > Support > Certificates covers some important policy issues Entitlements documentation TN3125 Inside Code Signing: Provisioning Profiles — This includes links to other technotes in the Inside Code Signing series. WWDC 2021 Session 10204 Distribute apps in Xcode with cloud signing Certificate Signing Requests Explained DevForums post --deep Considered Harmful DevForums post Don’t Run App Store Distribution-Signed Code DevForums post Resolving errSecInternalComponent errors during code signing DevForums post Finding a Capability’s Distribution Restrictions DevForums post Signing code with a hardware-based code-signing identity DevForums post Mac code signing: DevForums tag: Developer ID Creating distribution-signed code for macOS documentation Packaging Mac software for distribution documentation Placing Content in a Bundle documentation Embedding Nonstandard Code Structures in a Bundle documentation Embedding a Command-Line Tool in a Sandboxed App documentation Signing a Daemon with a Restricted Entitlement documentation Defining launch environment and library constraints documentation WWDC 2023 Session 10266 Protect your Mac app with environment constraints TN2206 macOS Code Signing In Depth archived technote — This doc has mostly been replaced by the other resources linked to here but it still contains a few unique tidbits and it’s a great historical reference. Manual Code Signing Example DevForums post The Care and Feeding of Developer ID DevForums post TestFlight, Provisioning Profiles, and the Mac App Store DevForums post For problems with notarisation, see Notarisation Resources. For problems with the trusted execution system, including Gatekeeper, see Trusted Execution Resources. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com"
0
0
13k
Feb ’24
Resolving Gatekeeper Problems
This post is part of a cluster of posts related to the trusted execution system. If you found your way here directly, I recommend that you start at the top. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Resolving Gatekeeper Problems Gatekeeper strives to ensure that only trusted software runs on a user’s Mac. It’s important that your code pass Gatekeeper. If not, you’re likely to lose a lot of customers, and your users’ hard-won trust. There are four common Gatekeeper problems: App blocked by a dangling load command path Broken code signature Lack of notarisation Command-line tool blocked by Gatekeeper The first problem is by far the most common. For the details, see Resolving Gatekeeper Problems Caused by Dangling Load Command Paths. For general information about Gatekeeper, read Apple > Developer > Signing Mac Software with Developer ID and Apple > Support > Safely open apps on your Mac. IMPORTANT This post focuses on Developer ID-signed code. Gatekeeper should not block App Store apps. If an app downloaded from the App Store fails to run, it’s likely to be some other trusted execution issue. For more about this, read Resolving Trusted Execution Problems. macOS 14 introduced gktool, a very minimal interface to Gatekeeper. Run the tool with the help argument to learn more: % gktool help Verify Your Signature A good first step in any Gatekeeper investigation is to verify that your code is signed correctly. Use the codesign tool for this: % codesign -v -vvv --strict --deep MyApp.app The -vvv options increase verbosity to the point where codesign will give you useful diagnostics. For example: % codesign -v -vvv --strict --deep "Munged.app" Munged.app: a sealed resource is missing or invalid file added: …/Munged.app/Contents/Resources/names/Adam.txt file modified: …/Munged.app/Contents/Resources/names/Morgan.txt file missing: …/Munged.app/Contents/Resources/names/Rhonda.txt This app was changed after it was signed in three different ways: Adam.txt was added. Morgan.txt was modified. Rhonda.txt was removed. You might see some results that make no sense. For example: Start with an app with a valid code signature: % codesign -v -vvv --strict --deep "NotNormal.app" NotNormal.app: valid on disk NotNormal.app: satisfies its Designated Requirement Use the Finder to create a zip archive (File > Compress). Use the Finder to unpack that archive. Check the code signature of the unpacked file: % codesign -v -vvv --strict --deep "NotNormal 2.app" NotNormal 2.app: a sealed resource is missing or invalid file added: …/NotNormal 2.app/Contents/Resources/names/Zoë Schrödinger.txt file missing: …/NotNormal 2.app/Contents/Resources/names/Zoë Schrödinger.txt There are two things to note here. First, just compressing and decompressing the app broke its code signature. Weird! Second, look at the error messages. It seems that the Zoë Schrödinger.txt file is was both added and removed. Weirder! To see what’s going on here you have to look at a hex dump of the file name: % ls "NotNormal.app/Contents/Resources/names" | xxd 00000000: 5a6f c3ab 2053 6368 726f cc88 6469 6e67 Zo.. Schro..ding 00000010: 6572 2e74 7874 0a er.txt. % ls "NotNormal 2.app/Contents/Resources/names" | xxd 00000000: 5a6f 65cc 8820 5363 6872 6fcc 8864 696e Zoe.. Schro..din 00000010: 6765 722e 7478 740a ger.txt. The names are not the same! The app started out with the ë in precomposed form and the ö in decomposed form. Compressing and decompressing the app converted the ë to its decomposed form, and that change broke the code signature. Programs that deal with Unicode are expected to ignore differences in normalisation. Sadly, Apple’s code signing implementation missed that memo (r. 68829319). For more details see this post but the executive summary is that it’s best to stick to ASCII when naming files in a bundle. Identify a Notarisation Problem Gatekeeper requires that your app be notarised. If not, it will block the execution of your app with a generic, user-level message. If you find your app blocked by Gatekeeper, check if this is a notarisation issue by looking in the system log for an entry like this: type: info time: 2022-05-11 14:57:21.812176 -0700 process: syspolicyd subsystem: com.apple.syspolicy category: default message: ticket not available: 2/2/8b7410713591e6c79ea98f0132136f0faa55d22a Note If the ticket details show as <private>, enable private data in the system log. For information on how to do that, see Recording Private Data in the System Log. For general information about the system log, see Your Friend the System Log. The long hex number is the code directory hash, or cdhash, of the offending code. In this example, it’s the cdhash of the app itself: % codesign -d -vvv /Applications/NotNotarised.app … CDHash=8b7410713591e6c79ea98f0132136f0faa55d22a … However, in some cases it may be the cdhash of some library referenced by the app. For more information about cdhashes, see TN3126 Inside Code Signing: Hashes. Resolve a Notarisation Problem The obvious cause of this problem is that you haven’t notarised your app. For information on how to do that, see Notarizing macOS Software Before Distribution. If you have notarised your app and yet you still see this problem, something more subtle is happening. For example, your app might reference a dynamic library that wasn’t seen by the notary service. To investigate this: Fetch the notary log for your app. For advice on that, see Fetching the Notary Log. Confirm that the notary log matches the app you installed. Look in the notary log for the sha256 property. Its value is a SHA-256 hash of the file received by the notary service. Check that this matches the SHA-256 hash of the file you used to install your app. If not, see Hash Mismatch, below. Search the notary log for the cdhash value from the Gatekeeper log message. If the notary log doesn’t contain that cdhash, that code wasn’t included in the notarised ticket. It’s possible that you failed to submit the code to the notary service, that it was switched out with a different version after you notarised your app, that it was package in some way that the notary service couldn’t see it, or that something went wrong within the notary service. Hash Mismatch If you stapled your notarised ticket to the file used to install your app then the hashes in step 2 of the previous section won’t match. What to do depends on the file type: If the file used to install your app was a zip archive (.zip), you definitely have the wrong file. Zip archives don’t support stapling. If the file used to install your app was a signed disk image (.dmg), compare the disk image’s cdhash with the cdhash for the disk image in the notary log. If those match, you know you’re working with the same disk image. To dump a disk image’s cdhash, run the codesign tool as follows: % codesign -d -vvv DISK_IMAGE … CDHash=d963af703ac2e54af6609e9ad309abee7b66fae2 … Replace DISK_IMAGE with the path to your disk image. If the file used to install your app was a disk image but it wasn’t signed, switch to a signed disk image. It’s generally a better option. If the file used to install your app was an installer package (.pkg), there’s no good way to know if this is the correct package. In this case, modify your notarisation workflow to retain a copy of the file before it was modified by stapler. Tool Blocked by Gatekeeper If your product includes a command-line tool, you might notice this behaviour: When you double click the tool in Finder, it’s blocked by Gatekeeper. When you run the tool from within Terminal, it works. This is a known bug in macOS (r. 58097824). The issue is that, when you double click a tool in the Finder, it doesn’t run Gatekeeper’s standard execution logic. Rather, the Finder passes the tool to Terminal as a document and that opens a window (and associated shell) in which to run that document. This triggers Gatekeeper’s document logic, and that logic always blocks the tool. There are two ways around this: Embed your tool in an application. If the user runs the application first, Gatekeeper runs its normal application check. If the user allows the app to run, Gatekeeper records that decision and applies it to the app and any code within the app, including your tool. Install your tool using an installer package. When the user goes to install the package, Gatekeeper checks it. Assuming that check passes, Gatekeeper does no further checks on the content it installed. Revision History 2024-11-11 Added a mention of gktool. 2022-05-20 Added the Verify Your Signature section. Made other minor editorial changes.
0
0
3.7k
Oct ’24
Resolving Code Signing Crashes on Launch
This post is part of a cluster of posts related to the trusted execution system. If you found your way here directly, I recommend that you start at the top. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Resolving Code Signing Crashes on Launch A code signing crash has the following exception information: Exception Type: EXC_CRASH (SIGKILL (Code Signature Invalid)) IMPORTANT Most developers never see a code signing crash because they use Xcode to build and sign their product. Xcode’s code signing infrastructure detects problems that could cause a code signing crash, and its automatic code signing fixes them for you! If you’re having problems with code signing crashes and you can use Xcode but aren’t, consider making the switch Xcode. The most common code signing crash is a crash on launch. To confirm that, look at the thread backtraces: Backtrace not available If you see valid thread backtraces this is not a crash on launch. Go back to Resolving Trusted Execution Problems and read through the Code Signing Crashes After Launch section. If you see no thread backtraces, your code didn’t run at all. The trusted execution system has blocked it. In most cases there is some evidence of the problem in the system log. For example: type: error time: 2022-05-19 06:29:17.640331 -0700 process: taskgated-helper subsystem: com.apple.ManagedClient category: ProvisioningProfiles message: com.example.apple-samplecode.OverClaim: Unsatisfied entitlements: com.apple.overclaim This indicates that the OverClaim app, with bundle ID com.example.apple-samplecode.OverClaim, claimed a restricted entitlement, com.apple.overclaim, that wasn’t authorised by a provisioning profile. For more information about provisioning profiles, see TN3125 Inside Code Signing: Provisioning Profiles. Specifically, the Entitlements on macOS section discusses the concept of restricted entitlements. For general information about the system log, see Your Friend the System Log. Normalise the Entitlements Property List Entitlement property list files look like text and so it’s tempting to edit them with a text editor. This can lead to all sorts of problems. If you have code whose entitlements property list contains comments, non-Unix line endings, or other weird formatting, the trusted execution system may block it. To avoid such problems, normalise your entitlements property list before passing it to codesign. For example: % plutil -convert xml1 MyApp.plist % codesign -s III --entitlements MyApp.plist MyApp.app Problems like this typically show up on older systems. Modern systems use DER-encoded entitlements, as discussed in The future is DER section of TN3125. A related gotcha is line breaks. Consider this entitlements property list file: % cat MyApp.plist … <plist version="1.0"> <dict> <key> com.apple.security.cs.disable-library-validation</key> <true/> </dict> </plist> This is a valid property list but it doesn’t do what you think it does. It looks like it claims the com.apple.security.cs.disable-library-validation entitlement but in reality it claims \ncom.apple.security.cs.disable-library-validation. The system treats the latter as a restricted entitlement and thus requires it to be authorised by a profile. Of course no such profile will authorise that entitlement, and so the app is blocked by the trusted execution system. Similarly, consider this: % cat MyApp.plist … <plist version="1.0"> <dict> <key> com.apple.security.cs.disable-library-validation</key> <true/> </dict> </plist> This claims com.apple.security.cs.disable-library-validation, note the leading space, and that’s also blocked by the trusted execution system. Check for Unauthorised Entitlements Sometimes the system log may not make it obvious what’s gone wrong. It may be easier to work this out by looking at the built program. The most common cause of problems like this is the app claiming a restricted entitlement that’s not authorised by a provisioning profile. To start your investigation, dump the entitlements to check for restricted entitlements: % codesign -d --entitlements - "OverClaim.app" …/OverClaim.app/Contents/MacOS/OverClaim [Dict] [Key] com.apple.application-identifier [Value] [String] SKMME9E2Y8.com.example.apple-samplecode.OverClaim [Key] com.apple.developer.team-identifier [Value] [String] SKMME9E2Y8 [Key] com.apple.overclaim [Value] [Bool] true [Key] com.apple.security.get-task-allow [Value] [Bool] true In this case all the entitlements except com.apple.security.get-task-allow are restricted. Note If there are no restricted entitlements, something else has gone wrong. Go back to Resolving Trusted Execution Problems and look for other potential causes. Now check that the provisioning profile was embedded correctly and extract its payload: % ls -l "OverClaim.app/Contents/embedded.provisionprofile" … OverClaim.app/Contents/embedded.provisionprofile % security cms -D -i "OverClaim.app/Contents/embedded.provisionprofile" -o "OverClaim-payload.plist" Check that the profile applies to this app by dumping the com.apple.application-identifier entitlement authorised by the profile: % /usr/libexec/PlistBuddy -c "print :Entitlements:com.apple.application-identifier" OverClaim-payload.plist SKMME9E2Y8.com.example.apple-samplecode.* This should match the com.apple.application-identifier entitlement claimed by the app. Repeat this for all the remaining restricted entitlements: % /usr/libexec/PlistBuddy -c "print :Entitlements:com.apple.developer.team-identifier" OverClaim-payload.plist SKMME9E2Y8 % /usr/libexec/PlistBuddy -c "print :Entitlements:com.apple.overclaim" OverClaim-payload.plist Print: Entry, ":Entitlements:com.apple.overclaim", Does Not Exist In this example the problem is the com.apple.overclaim entitlement, which is claimed by the app but not authorised by the profile. If that’s the case for your program, you have two choices: If you program doesn’t need this entitlement, update your code signing to not claim it. If you program relies on this entitlement, update your profile to authorise it. The entitlement allowlist in the profile is built by the Apple Developer website based on the capabilities enabled on your App ID. To change this allowlist, modify your App ID capabilities and rebuild your profile. Some capabilities are only available on some platforms and, within that platform, for some distribution channels. For these details for macOS, see Developer Account Help > Reference > Supported capabilities (macOS). Some capabilities require review and approval by Apple. For more on this, see Developer Account Help > Reference > Provisioning with capabilities. Check for Required Entitlements If your app claims any restricted entitlements, it must also claim the com.apple.application-identifier entitlement, with its value being your app’s App ID. macOS uses this value to confirm that the embedded provisioning profile is appropriate for your app. Without this, macOS might not use this profile, which means there’s nothing to authorise your app’s use of restricted entitlements, which prevents your app from launching. IMPORTANT macOS 12 and later will use an embedded provisioning profile even if the app doesn’t claim the com.apple.application-identifier entitlement. So, if your app works on macOS 12 and later but fails on macOS 11, this is likely the cause. If you claim the com.apple.application-identifier entitlement then I recommend that you also claim the com.apple.developer.team-identifier entitlement. That’s what Xcode does, and my experience is that it’s best to stay on that well-trodden path. Check the Signing Certificate If your program’s entitlements look good, the next most likely problem is that your program was signed by a signing identity whose certificate is not authorised by the profile. To debug this, first extract the certificate chain from your program: % codesign -d --extract-certificates=signed-with- "OverClaim.app" … % for i in signed-with-* ; do mv "${i}" "${i}.cer" ; done The first certificate is the one that matters: % certtool d "signed-with-0.cer" Serial Number : 53 DB 60 CC 85 32 83 DE 72 D9 6A C9 8F 84 78 25 … Subject Name : Other name : UT376R4K29 Common Name : Apple Development: Quinn Quinn (7XFU7D52S4) OrgUnit : SKMME9E2Y8 Org : Quinn Quinn Country : US … Now check this against each of the certificates authorised by the profile. Start by extracting the first one: % plutil -extract DeveloperCertificates.0 raw -o - OverClaim-payload.plist | base64 -D > "authorised0.cer" % certtool d "authorised0.cer" Serial Number : 46 A8 EF 2C 52 54 DE FD D1 76 9D 3A 41 7C 9E 43 … Subject Name : Other name : UT376R4K29 Common Name : Mac Developer: Quinn Quinn (7XFU7D52S4) OrgUnit : SKMME9E2Y8 Org : Quinn Quinn Country : US … That’s not a match. So try the next one: % plutil -extract DeveloperCertificates.1 raw -o - OverClaim-payload.plist | base64 -D > authorised1.cer % certtool d "authorised1.cer" Serial Number : 53 DB 60 CC 85 32 83 DE 72 D9 6A C9 8F 84 78 25 … Subject Name : Other name : UT376R4K29 Common Name : Apple Development: Quinn Quinn (7XFU7D52S4) OrgUnit : SKMME9E2Y8 Org : Quinn Quinn Country : US … This matches, which means the profile applies to this code. IMPORTANT When checking for a match, look at the Serial Number field. Don’t just rely on the Common Name field. A common mistake is to have two signing identities whose certificates have identical common names but the profile only lists one of them. If you get to the end of the list of certificate list in the profile and don’t find the certificate that the program was signed with, you know what the problem is: Your program is signed with a signing identity whose certificate is not listed in its profile. To fix this, either: Reconfigure your code signing to use a signing identity whose certificate is listed. Or update the profile to include the certificate of the signing identity you’re using. Check for Expiration If your certificates aren’t the problem, check that nothing has expired. Start with the certificate from the app’s signature: % certtool d "signed-with-0.cer" Serial Number : 53 DB 60 CC 85 32 83 DE 72 D9 6A C9 8F 84 78 25 … Not Before : 10:52:56 Apr 21, 2022 Not After : 10:52:55 Apr 21, 2023 … Also check the expiry date on the profile: % plutil -extract ExpirationDate raw -o - OverClaim-payload.plist 2023-04-21T11:02:58Z If either has expired, update it and re-sign your product. IMPORTANT Developer ID-signed code and installers include a secure timestamp. When the system checks the expiry date on a Developer ID certificate, it only checks that the certificate was valid at the time that the code was signed, base on that secure timestamp. Thus, an old Developer ID-signed app will continue to run after it’s certificate has expired. To learn more about secure timestamps, see TN3161 Inside Code Signing: Certificates. Check the Supported Devices If everything else checks out, the last thing to check is that the profile authorises the code to run on this machine. There are two cases here: Developer ID profiles authorise the code on all machines. Other profiles authorise the code on a specific list of machines. If you think you have a Developer ID profile, confirm that by looking for the ProvisionsAllDevices property: % plutil -extract "ProvisionsAllDevices" xml1 -o - "OverClaim-payload.plist" … No value at that key path or invalid key path: ProvisionsAllDevices If that’s not the case, get the ProvisionedDevices property and verify that the current machine’s provisioning UDID is listed there: % plutil -extract "ProvisionedDevices" xml1 -o - "OverClaim-payload.plist" … <array> … <string>A545CA26-80D7-5B38-A98C-530A798BE342</string> … </array> </plist> % system_profiler SPHardwareDataType … Provisioning UDID: A545CA26-80D7-5B38-A98C-530A798BE342 … If you get to the end any everything looks OK, your provisioning profile is not the cause of this crash. Return to Resolving Trusted Execution Problems for more suggestions. Revision History 2024-02-20 Added the Check for Required Entitlements section. Added a link to TN3161. Fixed the Developer Account Help links. 2022-06-08 Added the Normalise the Entitlements Property List section. 2022-05-20 First posted.
0
0
4.4k
Feb ’24
Resolving Trusted Execution Problems
I help a lot of developers with macOS trusted execution problems. For example, they might have an app being blocked by Gatekeeper, or an app that crashes on launch with a code signing error. If you encounter a problem that’s not explained here, start a new thread with the details. Make sure to add relevant tags — like Gatekeeper, Code Signing, and Notarization — so that I see your post. IMPORTANT macOS 14 has a new tool, syspolicy_check, that was specifically designed to help diagnose problems like this. I plan to update this post once I have more experience with it. In the meantime, however, if you hit a trusted execution problem and it reproduces on macOS 14, please try out syspolicy_check and let us know how that pans out. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Resolving Trusted Execution Problems macOS supports three software distribution channels: The user downloads an app from the App Store. The user gets a Developer ID-signed program directly from its developer. The user builds programs locally using Apple or third-party developer tools. The trusted execution system aims to protect users from malicious code. It’s comprised of a number of different subsystems. For example, Gatekeeper strives to ensure that only trusted software runs on a user’s Mac, while XProtect is the platform’s built-in anti-malware technology. Note To learn more about these technologies, see Apple Platform Security. If you’re developing software for macOS your goal is to avoid trusted execution entanglements. You want users to install and use your product without taking any special steps. If, for example, you ship an app that’s blocked by Gatekeeper, you’re likely to lose a lot of customers, and your users’ hard-won trust. Trusted execution problems are rare with Mac App Store apps because the Mac App Store validation process tends to catch things early. This post is primarily focused on Developer ID-signed programs. Developers who use Xcode encounter fewer trusted execution problems because Xcode takes care of many code signing and packaging chores. If you’re not using Xcode, consider making the switch. If you can’t, consult the following for information on how to structure, sign, and package your code: Placing Content in a Bundle Embedding Nonstandard Code Structures in a Bundle Embedding a Command-Line Tool in a Sandboxed App Creating distribution-signed code for macOS Packaging Mac software for distribution Gatekeeper Basics User-level apps on macOS implement a quarantine system for new downloads. For example, if Safari downloads a zip archive, it quarantines that archive. This involves setting the com.apple.quarantine extended attribute on the file. Note The com.apple.quarantine extended attribute is not documented as API. If you need to add, check, or remove quarantine from a file programmatically, use the quarantinePropertiesKey property. User-level unarchiving tools preserve quarantine. To continue the above example, if you double click the quarantined zip archive in the Finder, Archive Utility will unpack the archive and quarantine the resulting files. If you launch a quarantined app, the system invokes Gatekeeper. Gatekeeper checks the app for problems. If it finds no problems, it asks the user to confirm the launch, just to be sure. If it finds a problem, it displays an alert to the user and prevents them from launching it. The exact wording of this alert varies depending on the specific problem, and from release to release of macOS, but it generally looks like the ones shown in Apple > Support > Safely open apps on your Mac. The system may run Gatekeeper at other times as well. The exact circumstances under which it runs Gatekeeper is not documented and changes over time. However, running a quarantined app always invokes Gatekeeper. Unix-y networking tools, like curl and scp, don’t quarantine the files they download. Unix-y unarchiving tools, like tar and unzip, don’t propagate quarantine to the unarchived files. Confirm the Problem Trusted execution problems can be tricky to reproduce: You may encounter false negatives, that is, you have a trusted execution problem but you don’t see it during development. You may also encounter false positives, that is, things fail on one specific Mac but otherwise work. To avoid chasing your own tail, test your product on a fresh Mac, one that’s never seen your product before. The best way to do this is using a VM, restoring to a snapshot between runs. For a concrete example of this, see Testing a Notarised Product. The most common cause of problems is a Gatekeeper alert saying that it’s blocked your product from running. However, that’s not the only possibility. Before going further, confirm that Gatekeeper is the problem by running your product without quarantine. That is, repeat the steps in Testing a Notarised Product except, in step 2, download your product in a way that doesn’t set quarantine. Then try launching your app. If that launch fails then Gatekeeper is not the problem, or it’s not the only problem! Note The easiest way to download your app to your test environment without setting quarantine is curl or scp. Alternatively, use xattr to remove the com.apple.quarantine extended attribute from the download before you unpack it. For more information about the xattr tool, see the xattr man page. Trusted execution problems come in all shapes and sizes. The remaining sections address the most common ones. App Blocked by Gatekeeper If your product is an app and it works correctly when not quarantined but is blocked by Gatekeeper when it is, you have a Gatekeeper problem. For advice on how to investigate such issues, see Resolving Gatekeeper Problems. App Can’t Be Opened Not all failures to launch are Gatekeeper errors. In some cases the app is just broken. For example: The app’s executable might be missing the x bit set in its file permissions. The app’s executable might be subtly incompatible with the current system. A classic example of this is trying to run a third-party app that contains arm64e code. macOS requires that third-party kernel extensions use the arm64e architecture. In other circumstances, stick to arm64 for your shipping products. If you want to test arm64e code locally, see Preparing Your App to Work with Pointer Authentication. The app’s executable might claim restricted entitlements that aren’t authorised by a provisioning profile. Or the app might have some other code signing problem. Note For more information about provisioning profiles, see TN3125 Inside Code Signing: Provisioning Profiles. In such cases the system displays an alert saying: The application “NoExec” can’t be opened. [[OK]] Note In macOS 11 this alert was: You do not have permission to open the application “NoExec”. Contact your computer or network administrator for assistance. [[OK]] which was much more confusing. A good diagnostic here is to run the app’s executable from Terminal. For example, an app with a missing x bit will fail to run like so: % NoExec.app/Contents/MacOS/NoExec zsh: permission denied: NoExec.app/Contents/MacOS/NoExec And an app with unauthorised entitlements will be killed by the trusted execution system: % OverClaim.app/Contents/MacOS/OverClaim zsh: killed OverClaim.app/Contents/MacOS/OverClaim In some cases running the executable from Terminal will reveal useful diagnostics. For example, if the app references a library that’s not available, the dynamic linker will print a helpful diagnostic: % MissingLibrary.app/Contents/MacOS/MissingLibrary dyld[88394]: Library not loaded: @rpath/CoreWaffleVarnishing.framework/Versions/A/CoreWaffleVarnishing … zsh: abort MissingLibrary.app/Contents/MacOS/MissingLibrary Code Signing Crashes on Launch A code signing crash has the following exception information: Exception Type: EXC_CRASH (SIGKILL (Code Signature Invalid)) The most common such crash is a crash on launch. To confirm that, look at the thread backtraces: Backtrace not available For steps to debug this, see Resolving Code Signing Crashes on Launch. One common cause of this problem is running distribution-signed code. Don’t do that! For details on why that’s a bad idea, see Don’t Run App Store Distribution-Signed Code. Code Signing Crashes After Launch If your program crashes due to a code signing problem after launch, you might have encountered the issue discussed in Updating Mac Software. Non-Code Signing Failures After Launch The hardened runtime enables a number of security checks within a process. Some coding techniques are incompatible with the hardened runtime. If you suspect that your code is incompatible with the hardened runtime, see Resolving Hardened Runtime Incompatibilities. App Sandbox Inheritance If you’re creating a product with the App Sandbox enabled and it crashes with a trap within _libsecinit_appsandbox, it’s likely that you’re having App Sandbox inheritance problems. For the details, see Resolving App Sandbox Inheritance Problems. Library Loading Problem Most library loading problems have an obvious cause. For example, the library might not be where you expect it, or it might be built with the wrong platform or architecture. However, some library loading problems are caused by the trusted execution system. For the details, see Resolving Library Loading Problems. Explore the System Log If none of the above resolves your issue, look in the system log for clues as to what’s gone wrong. Some good keywords to search for include: gk, for Gatekeeper xprotect syspolicy, per the syspolicyd man page cmd, for Mach-O load command oddities amfi, for Apple mobile file integrity, per the amfid man page taskgated, see its taskgated man page yara, discussed in Apple Platform Security ProvisioningProfiles You may be able to get more useful logging with this command: % sudo sysctl -w security.mac.amfi.verbose_logging=1 Here’s a log command that I often use when I’m investigating a trusted execution problem and I don’t know here to start: % log stream --predicate "sender == 'AppleMobileFileIntegrity' or sender == 'AppleSystemPolicy' or process == 'amfid' or process == 'taskgated-helper' or process == 'syspolicyd'" For general information the system log, see Your Friend the System Log. Revision History 2024-10-11 Added info about the security.mac.amfi.verbose_logging option. Updated some links to point to official documentation that replaces some older DevForums posts. 2024-01-12 Added a specific command to the Explore the System Log section. Change the syspolicy_check callout to reflect that macOS 14 is no longer in beta. Made minor editorial changes. 2023-06-14 Added a quick call-out to the new syspolicy_check tool. 2022-06-09 Added the Non-Code Signing Failures After Launch section. 2022-06-03 Added a link to Don’t Run App Store Distribution-Signed Code. Fixed the link to TN3125. 2022-05-20 First posted.
0
0
7.7k
Oct ’24
Packaging Mac Software for Distribution
IMPORTANT I’m very pleased to report that, due to the hard work of a number of folks at Apple, this DevForums post has been replaced by official documentation: Packaging Mac software for distribution. I’m leaving this post in place as a historical curiosity, but please consult the official documentation going forward. This post is one of a pair of posts, the other one being Creating Distribution-Signed Code for Mac, that replaces my earlier Signing a Mac Product For Distribution post. For more background on this, see the notes at the top of Creating Distribution-Signed Code for Mac. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Packaging Mac Software for Distribution Build a zip archive, disk image, or installer package for distributing your Mac software. Overview Xcode is a great tool for creating and distributing Mac apps. Once you’ve written your code you can upload it to the App Store with just a few clicks. However, Xcode cannot do everything. For example: Some Mac software products are not apps. You might, for example, be creating a product that includes a daemon. Some Mac products include multiple components. Your daemon might include an app to configure it. Some Mac products ship outside of the App Store, and so need to be packaged for distribution. For example, you might choose to distribute your daemon and its configuration app in an installer package. Some Mac products are built with third-party developer tools. If your product cannot be built and distributed using Xcode alone, follow these instructions to package it for distribution. Note If you use a third-party developer tool to build your app, consult its documentation for advice specific to that tool. To start this process you need distribution-signed code. For detailed advice on how to create distribution-signed code, see Creating Distribution-Signed Code for Mac. If you ship your product frequently, create a script to automate the distribution process. Decide on a Container Format To get started, decide on your container format. Mac products support two distribution channels: The Mac App Store, for apps Independent distribution, for apps and non-apps, using Developer ID signing A Mac App Store app must be submitted as an installer package. In contrast, products distributed outside of the Mac App Store use a variety of different container formats, the most common being: Zip archive (.zip) Disk image (.dmg) Installer package (.pkg) You may choose to nest these containers. For example, you might ship an app inside an installer package on a disk image. Nesting containers is straightforward: Just work from the inside out, following the instructions for each container at each step. IMPORTANT Sign your code and each nested container (if the container supports signing). For example, if you ship an app inside an installer package on a disk image, sign the app, then create the installer package, then sign that package, then create the disk image, then sign the disk image. Each container format has its own pros and cons, so choose an approach based on the requirements of your product. Build a Zip Archive If you choose to distribute your product in a zip archive, use the ditto tool to create that archive: Create a directory that holds everything you want to distribute. Run the ditto tool as shown below, where DDD is the path to the directory from step 1 and ZZZ is the path where ditto creates the zip archive. % ditto -c -k --keepParent DDD ZZZ Zip archives cannot be signed, although their contents can be. Build an Installer Package If you choose to distribute your product in an installer package, start by determining your installer signing identity. Choose the right identity for your distribution channel: If you’re distributing an app on the Mac App Store, use a Mac Installer Distribution signing identity. This is named 3rd Party Mac Developer Installer: TTT, where TTT identifies your team. If you’re distributing a product independently, use a Developer ID Installer signing identity. This is named Developer ID Installer: TTT, where TTT identifies your team. For information on how to set up these installer signing identities, see Developer Account Help. Run the following command to confirm that your installer signing identity is present and correct: % security find-identity -v 1) 6210ECCC616B6A72F238DE6FDDFDA1A06DEFF9FB "3rd Party Mac Developer Installer: …" 2) C32E0E68CE92936D5532E21BAAD8CFF4A6D9BAA1 "Developer ID Installer: …" 2 valid identities found The -v argument filters for valid identities only. If the installer signing identity you need is not listed, see Developer Account Help. IMPORTANT Do not use the -p codesigning option to filter for code signing identities. Installer signing identities are different from code signing identities and the -p codesigning option filters them out. If your product consists of a single app, use the productbuild tool to create a simple installer package for it: % productbuild --sign III --component AAA /Applications PPP In this command: III is your installer signing identity. AAA is the path to your app. PPP is the path where productbuild creates the installer package. The above is the simplest possible use of productbuild. If you’re submitting an app to the Mac App Store, that’s all you need. If you have a more complex product, you’ll need a more complex installer package. For more details on how to work with installer packages, see the man pages for productbuild, productsign, pkgbuild, and pkgutil. For instructions on how to read a man page, see Reading UNIX Manual Pages. Build a Disk Image If you choose to distribute your product in a disk image: Create a directory to act as the source for the root directory of your disk image’s volume. Populate that directory with the items you want to distribute. If you’re automating this, use ditto rather than cp because ditto preserves symlinks. Use hdiutil command shown below to create the disk image, where SSS is the directory from step 1 and DDD is the path where hdiutil creates the disk image. Decide on a code signing identifier for this disk image. If you were signing bundled code, you’d use the bundle ID as the code signing identifier. However, disk images have no bundle ID and thus you must choose a code signing identifier for your image. For advice on how to do this, see the Sign Each Code section in Creating Distribution-Signed Code for Mac. Use the codesign command shown below to sign the disk image, where III is your Developer ID Application code signing identity (named Developer ID Application: TTT, where TTT identifies your team), BBB is the code signing identifier you chose in the previous step, and DDD is the path to the disk image from step 3. % hdiutil create -srcFolder SSS -o DDD % codesign -s III --timestamp -i BBB DDD For more information on code signing identities, see the Confirm Your Code Signing section in Creating Distribution-Signed Code for Mac. IMPORTANT Sign your disk image with a code signing identity, not an installer signing identity. There are various third-party tools that configure a disk image for distribution. For example, the tool might arrange the icons nicely, set a background image, and add a symlink to the Applications folder. If you use such a tool, or create your own tool for this, make sure that the resulting disk image: Is signed with your Developer ID Application code signing identity Is a UDIF-format read-only zip-compressed disk image (type UDZO) Submit Your App to the Mac App Store If you’re creating an app for the Mac App Store, submit your signed installer package using either the altool command-line tool or the Transporter app. For detailed instructions, see App Store Connect Help > Reference > Upload tools. Notarize Your Product If you’re distributing outside of the Mac App Store, notarize the file you intend to distribute to your users. For detailed instructions, see Customizing the Notarization Workflow. Skip the Export a Package for Notarization section because you already have the file that you want to submit. If you’re using nested containers, only notarize the outermost container. For example, if you have an app inside an installer package on a disk image, sign the app, sign the installer package, and sign the disk image, but only notarize the disk image. The exception to this rule is if you have a custom third-party installer. In that case, see the discussion in Customizing the Notarization Workflow. Staple Your Product Once you’ve notarized your product, staple the resulting ticket to the file you intend to distribute. Staple the Ticket to Your Distribution discusses how to do this for an app within a zip archive. The other common container formats, installer packages and disk images, support stapling directly. For example, to staple a tick to a disk image: % xcrun stapler staple FlyingAnimals.dmg Stapling is recommended but not mandatory. However, if you don’t staple a user might find that your product is blocked by Gatekeeper if they try to install or use it while the Mac is offline. Revision History 2024-02-19 Added a preamble that links to the official documentation, Packaging Mac software for distribution. 2022-03-01 First posted.
0
0
8.8k
Feb ’24
Creating Distribution-Signed Code for Mac
IMPORTANT I’m very pleased to report that, due to the hard work of a number of folks at Apple, this DevForums post has been replaced by official documentation: Creating distribution-signed code for macOS. I’m leaving this post in place as a historical curiosity, but please consult the official documentation going forward. This post is one of a pair of posts, the other one being Packaging Mac Software for Distribution, that replaces my earlier Signing a Mac Product For Distribution post. Over the past year I’ve been trying to convert my most useful code signing posts here on DevForums to official documentation, namely: Placing Content in a Bundle Updating Mac Software Signing a Daemon with a Restricted Entitlement Embedding a Command-Line Tool in a Sandboxed App Embedding Nonstandard Code Structures in a Bundle Unfortunately in the past month or so my Day Job™, answering developer questions for DTS, has become super busy, and so I’ve not had chance to complete this work by publish a replacement for Signing a Mac Product For Distribution. This post, and Packaging Mac Software for Distribution, represent the current state of that effort. I think these are sufficiently better than Packaging Mac Software for Distribution to warrant posting them here on DevForums while I wait for the quiet time needed to finish the official work. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Creating Distribution-Signed Code for Mac Sign Mac code for distribution using either Xcode or command-line tools. Overview Before shipping a software product for the Mac, you must first create distribution-signed code, that is, code that you can package up and then submit to either the Mac App Store or the notary service. The way you do this depends on the nature of your product and how it was built: If your product is a standalone app, possibly with nested code such as an app extension, that you build using Xcode, use Xcode to export a distribution-signed app. If your product isn't a standalone app, but you build it using Xcode, create an Xcode archive, and then manually export distribution-signed code from that archive. If you build your product using an external build system, such as make, add a manual signing step to your build system. Once you have distribution-signed code, package it for distribution. For more information, see Packaging Mac Software for Distribution. Note If you use a third-party developer tool to build your app, consult its documentation for advice specific to that tool. Export an App from Xcode If your product is a standalone app that you build with Xcode, follow these steps to export a distribution-signed app: Build an Xcode archive from your project. Export a distribution-signed app from that Xcode archive. You can complete each step from the Xcode app or automate the steps using xcodebuild. To build an Xcode archive using the Xcode app, select your app’s scheme and choose Product > Archive. This creates the Xcode archive and selects it in the organizer. To create a distribution-sign app from that archive, select the archive in the organizer, click Distribute App, and follow the workflow from there. Note If the button says Distribute Content rather than Distribute App, your archive has multiple items in its Products directory. Make sure that every target whose output is embedded in your app has the Skip Install (SKIP_INSTALL) build setting set; this prevents the output from also being copied into the Xcode archive’s Products directory. For more on this, see TN3110 Resolving generic Xcode archive issue. For more information about the Xcode archives and the organizer, see Distributing Your App for Beta Testing and Releases. To build an Xcode archive from the command line, run xcodebuild with the archive action. Once you have an Xcode archive, export a distribution-signed app by running xcodebuild with the -exportArchive option. For more information about xcodebuild, see its man page. For instructions on how to read a man page, see Reading UNIX Manual Pages. For information about the keys supported by the export options property list, run xcodebuild with the -help argument. Export a Non-App Product Built with Xcode If you build your product with Xcode but it’s not a standalone app, you can build an Xcode archive using the techniques described in the previous section but you cannot export distribution-signed code from that archive. The Xcode organizer and the -exportArchive option only work for standalone apps. To export a distribution-signed product from the Xcode archive: Copy the relevant components from the archive. Sign those components manually. The exact commands for doing this vary depending on how your product is structured, so let’s consider a specific example. Imagine your product is a daemon but it also has an associated configuration app. Moreover, the configuration app has a share extension, and an embedded framework to share code between the app and the extension. When you build an Xcode archive from this project it has this structure: DaemonWithApp.xcarchive/ Info.plist Products/ usr/ local/ bin/ Daemon Applications/ ConfigApp.app/ Contents/ embedded.provisionprofile Frameworks/ Core.framework/ … PlugIns/ Share.appex/ Contents/ embedded.provisionprofile … … … The Products directory contains two items: the daemon itself (Daemon) and the configuration app (ConfigApp.app). To sign this product, first copy these items out of the archive: % mkdir "to-be-signed" % ditto "DaemonWithApp.xcarchive/Products/usr/local/bin/Daemon" "to-be-signed/Daemon" % ditto "DaemonWithApp.xcarchive/Products/Applications/ConfigApp.app" "to-be-signed/ConfigApp.app" IMPORTANT When you copy code, use ditto rather than cp. ditto preserves symlinks, which are critical to the structure of Mac frameworks. For more information on this structure, see Placing Content in a Bundle. Symlinks are also useful when dealing with nonstandard code structures. For more details, see Embedding Nonstandard Code Structures in a Bundle. The code you copy from the Xcode archive is typically development-signed: % codesign -d -vv to-be-signed/Daemon … Authority=Apple Development: … … To ship this code, you need to re-sign it for distribution. Confirm Your Code Signing Identity To sign code for distribution you need a code signing identity. Choose the right identity for your distribution channel: If you’re distributing an app on the Mac App Store, use an Apple Distribution code signing identity. This is named Apple Distribution: TTT, where TTT identifies your team. Alternatively, you can use the old school Mac App Distribution code signing identity. This is named 3rd Party Mac Developer Application: TTT, where TTT identifies your team. If you’re distributing a product independently, use a Developer ID Application code signing identity. This is named Developer ID Application: TTT, where TTT identifies your team. For information on how to set up these code signing identities, see Developer Account Help. To confirm that your code-signing identity is present and correct, run the following command: % security find-identity -p codesigning -v 1) A06E7F3F8237330EE15CB91BE1A511C00B853358 "Apple Distribution: …" 2) ADC03B244F4C1018384DCAFFC920F26136F6B59B "Developer ID Application: …" 2 valid identities found The -p codesigning argument filters for code-signing identities. The -v argument filters for valid identities only. If the code-signing identity that you need isn't listed, see Developer Account Help. Each output line includes a SHA-1 hash that uniquely identifies the identity. If you have multiple identities with the same name, sign your code using this hash rather than the identity name. Identify the Code to Sign To sign your product, first identify each code item that you need to sign. For example, in the DaemonWithApp product, there are four code items: ConfigApp.app, Core.framework, Share.appex, and Daemon. For each code item, determine the following: Is it bundled code? Is it a main executable? IMPORTANT For a code item to be considered bundled code it must be the main code within a bundle. If, for example, you have an app with a nested helper tool, there are two code items: the app and the helper tool. The app is considered bundle code but the helper tool is not. In some cases, it might not be obvious whether the code item is a main executable. To confirm, run the file command. A main executable says Mach-O … executable. For example: % file "to-be-signed/ConfigApp.app/Contents/Frameworks/Core.framework/Versions/A/Core" … … Mach-O 64-bit dynamically linked shared library x86_64 … % file "to-be-signed/ConfigApp.app/Contents/PlugIns/Share.appex/Contents/MacOS/Share" … … Mach-O 64-bit executable x86_64 … The Core.framework is not a main executable but Share.appex is. To continue the DaemonWithApp example, here’s a summary of this info for each of its code items: | Code Item | Bundled Code? | Main Executable | | --------- | ------------- | --------------- | | ConfigApp.app | yes | yes | | Core.framework | yes | no | | Share.appex | yes | yes | | Daemon | no | yes | Determine the Signing Order Sign code from the inside out. That is, if A depends on B, sign B before you sign A. For the DaemonWithApp example, the signing order for the app is: Core.framework Share.appex ConfigApp.app The app and daemon are independent, so you can sign them in either order. Configure Your Entitlements A code signature may include entitlements. These key-value pairs grant an executable permission to use a service or technology. For more information about this, see Entitlements. Entitlements only make sense on a main executable. When a process runs an executable, the system grants the process the entitlements claimed by its code signature. Do not apply entitlements to library code. It doesn’t do anything useful and can prevent your code from running. When signing a main executable, decide whether it needs entitlements. If so, create an entitlements file to use when signing that executable. This entitlements file is a property list containing the key-value pairs for the entitlements that the executable claims. If you build your product with Xcode, you might be able to use the .entitlements file that Xcode manages in your source code. If not, create the .entitlements file yourself. IMPORTANT The entitlements file must be a property list in the standard XML format with LF line endings, no comments, and no BOM. If you’re not sure of the file’s provenance, use plutil to convert it to the standard format. For specific instructions, see Ensure Properly Formatted Entitlements. If you have a development-signed version of your program you can get a head start on this by dumping its entitlements. For example: % codesign -d --entitlements - --xml "to-be-signed/ConfigApp.app" | plutil -convert xml1 -o - - … <dict> <key>com.apple.application-identifier</key> <string>SKMME9E2Y8.com.example.apple-samplecode.DaemonWithApp.App</string> <key>com.apple.developer.team-identifier</key> <string>SKMME9E2Y8</string> <key>com.apple.security.app-sandbox</key> <true/> <key>keychain-access-groups</key> <array> <string>SKMME9E2Y8.com.example.apple-samplecode.DaemonWithApp.SharedKeychain</string> </array> </dict> </plist> Keep in mind that some entitlements vary between development and distribution builds. For example: The value of the APS Environment (macOS) Entitlement changes from development to production. The com.apple.security.get-task-allow entitlement allows the debugger to attach to your program, so you rarely apply it to a distribution-signed program. To check whether an entitlement varies in distribution builds, see the documentation for that specific entitlement in Entitlements. For information about when it makes sense to distribute a program signed with the get-task-allow entitlement, see Avoid the Get-Task-Allow Entitlement section in Resolving Common Notarization Issues). Embed Distribution Provisioning Profiles In general, all entitlement claims must be authorized by a provisioning profile. This is an important security feature. For example, the fact that the keychain-access-groups entitlement must be authorized by a profile prevents other developers from shipping an app that impersonates your app in order to steal its keychain items. However, macOS allows programs to claim some entitlements without such authorization. These unrestricted entitlements include: com.apple.security.get-task-allow com.apple.security.application-groups Those used to enable and configure the App Sandbox Those used to configure the Hardened Runtime If your program claims a restricted entitlement, include a distribution provisioning profile to authorize that claim: Create the profile on the developer web site. Copy that profile into your program’s bundle. Note If your product includes a non-bundled executable that uses a restricted entitlement, package that executable in an app-like structure. For details on this technique, see Signing a Daemon with a Restricted Entitlement. To create a distribution provisioning profile, follow the instructions in Developer Account Help. Make sure to choose a profile type that matches your distribution channel (Mac App Store or Developer ID). Once you have a distribution provisioning profile, copy it into your program’s bundle. For information about where to copy it, see Placing Content in a Bundle. To continue the DaemonWithApp example, the configuration app and its share extension use a keychain access group to share secrets. The system grants the programs access to that group based on their keychain-access-groups entitlement claim, and such claims must be authorized by a provisioning profile. The app and the share extension each have their own profile. To distribute the app, update the app and share extension bundles with the corresponding distribution provisioning profile: % cp "ConfigApp-Dist.provisionprofile" "to-be-signed/ConfigApp.app/Contents/embedded.provisionprofile" % cp "Share-Dist.provisionprofile" "to-be-signed/ConfigApp.app/Contents/PlugIns/Share.appex/Contents/embedded.provisionprofile" Modifying the app in this way will break the seal on its code signature. This is fine because you are going to re-sign the app before distributing it. IMPORTANT If you’re building your product with Xcode then you might find that Xcode has embedded a provisioning profile within your bundle. This is a development provisioning profile. You must replace it with a distribution provisioning profile. Sign Each Code Item For all code types, the basic codesign command looks like this: % codesign -s III PPP Here III is the name of the code signing identity to use and PPP is the path to the code to sign. The specific identity you use for III varies depending on your distribution channel, as discussed in Confirm Your Code Signing, above. Note If you have multiple identities with the same name, supply the identity’s SHA-1 hash to specify it unambiguously. For information on how to get this hash, see Confirm Your Code Signing, above. When signing bundled code, as defined in Identify the Code to Sign, above, use the path to the bundle for PPP, not the path to the bundle’s main code. If you’re re-signing code — that is, the code you’re signing is already signed — add the -f option. If you’re signing a main executable that needs entitlements, add the --entitlements EEE option, where EEE is the path to the entitlements file for that executable. For information on how to create this file, see Configure Your Entitlements, above. If you’re signing for Developer ID distribution, add the --timestamp option to include a secure timestamp. If you’re signing a main executable for Developer ID distribution, add the -o runtime option to enable the Hardened Runtime. For more information about the Hardened Runtime, see Hardened Runtime. If you’re signing non-bundled code, add the -i BBB option to set the code signing identifier. Here BBB is the bundle ID the code would have if it had a bundle ID. For example, if you have an app whose bundle ID is com.example.flying-animals that has a nested command-line tool called pig-jato, the bundle ID for that tool would logically be com.example.flying-animals.pig-jato, and that’s a perfectly fine value to use for BBB. Note For bundled code, you don’t need to supply a code signing identifier because codesign defaults to using the bundle ID. Repeat this signing step for every code item in your product, in the order you established in Determine the Signing Order, above. If you have a complex product with many code items to sign, create a script to automate this process. Here's the complete sequence of commands to sign the DaemonWithApp example for Developer ID distribution: % codesign -s "Developer ID Application" -f --timestamp "to-be-signed/ConfigApp.app/Contents/Frameworks/Core.framework" to-be-signed/ConfigApp.app/Contents/Frameworks/Core.framework: replacing existing signature % codesign -s "Developer ID Application" -f --timestamp -o runtime --entitlements "Share.entitlements" "to-be-signed/ConfigApp.app/Contents/PlugIns/Share.appex" to-be-signed/ConfigApp.app/Contents/PlugIns/Share.appex: replacing existing signature % codesign -s "Developer ID Application" -f --timestamp -o runtime --entitlements "ConfigApp.entitlements" "to-be-signed/ConfigApp.app" to-be-signed/ConfigApp.app: replacing existing signature % codesign -s "Developer ID Application" -f --timestamp -o runtime -i "com.example.apple-samplecode.DaemonWithApp.Daemon" "to-be-signed/Daemon" to-be-signed/Daemon: replacing existing signature Consider Deep Harmful When signing code, do not pass the --deep option to codesign. This option is helpful in some specific circumstances but it will cause problems when signing a complex product. Specifically: It applies the same code signing options to every code item that it signs, something that’s not appropriate. For example, you might have an app with an embedded command-line tool, where the app and the tool need different entitlements. The --deep option will apply the same entitlements to both, which is a serious mistake. It only signs code that it can find, and it only finds code in nested code sites. If you put code in a place where the system is expecting to find data, --deep won’t sign it. The first issue is fundamental to how --deep works, and is the main reason you should avoid it. The second issue is only a problem if you don’t follow the rules for nesting code and data within a bundle, as documented in Placing Content in a Bundle. Revision History 2024-02-19 Added a preamble that links to the official documentation, Creating distribution-signed code for macOS. 2022-08-17 Updated the Confirm Your Code Signing Identity section to cover Apple Distribution code signing identities. Added a link to TN3110. 2022-03-01 First posted.
0
0
9.3k
Feb ’24
Certificate Signing Requests Explained
I regularly help developers with code signing problems and I find that a lot of those problems stem from a fundamental misunderstanding of how code signing requests work. This post is my attempt at explaining that. Note After posting this I then went on to write TN3161 Inside Code Signing: Certificates, which covers similar ground in a much more comprehensive way. I think this post still has value, but you should definitely start by reading TN3161. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Certificate Signing Requests Explained I see a lot of folks confused by how code signing requests (CSRs) work, and that causes problems down the line. This is my attempt to explain the process and head off those problems. IMPORTANT This post covers the ‘classic’ certificate creation process described in Developer Account Help > Create certificates > Create a certificate signing request. Things work differently if you use Xcode to create your certificates, and very differently if you use cloud-managed certificates. Here’s a basic outline of the CSR process: You run Keychain Access and choose Certificate Assistant > Request a Certificate from a Certificate Authority. You run through the workflow as described in Developer Account Help > Create certificates > Create a certificate signing request. This does two things: It generates a public / private key pair in your keychain. To see these, run Keychain Access and select “login” on the left and Keys at the top. Look for keys whose names match the Common Name you entered in step 2. It prompts you to save a .certSigningRequest file (CSR). This contains a copy of the public key. You upload the CSR file to the developer web site. The developer web site issues you a certificate. In human terms this certificate says “Apple certifies that the subject of this certificate holds the private key that matches the public key embedded in this certificate.” Note The developer web site sets the subject information in the certificate based on your developer account. It ignores the subject information in the CSR. So, you can enter any information you want in step 2. This is a good way to distinguish between different keys in your keychain. For example, you might set the Common Name field in step 2 to include a unique identifier that allows you to easily identify the public / private key pair generated in step 3. You download the certificate and add it to your keychain. At this point your keychain contains a digital identity, that is, a certificate and the private key that matches the public key embedded in that certificate. To see this in Keychain Access, select “login” on the left and My Certificates at the top. What’s This My Certificates Thing? There’s an industry-wide terminology problem here. Folks use the term certificate to mean two different things: A digital identity, that is, a certificate and its matching private key An actual certificate This industry-wide confusion extends into the Apple ecosystem. For example: The Security framework gets this right, drawing a clear distinction between a digital identity (SecIdentity) and a certificate (SecCertificate). Keychain Access uses My Certificates for digital identities. Other user-facing apps use different terms. For example, Apple Configurator uses signing identity (yay for them!). OTOH, the help for Apple Mail uses the term personal certificate. Xcode and its documentation uses the term signing certificate to denote a digital identity that can be used for code signing. This terminological inexactitude causes all sorts of problems. For example, imagine you’re setting up a new Mac. You download your certificate from the developer web site and then wonder why you can’t sign your code. That’s because the developer web site gives you a certificate, not a digital identity. Indeed, the developer web site can’t give you a digital identity because it never got a copy of your private key [1]. [1] Again, we’re talking about the classic certificate creation process here; this statement is not true for cloud-managed certificates. Digital Identity Formation Apple platforms form a digital identity by: Extracting the public key from the certificate. Calculating a SHA-1 digest of that. Looking for a private key whose kSecAttrApplicationLabel attribute matches that SHA-1 hash. For more background on this, see my SecItem attributes for keys post. Note that it’s perfectly valid for multiple certificates to match against the same private key, yielding a digital identity for each certificate. You regularly see this when you renew a certificate. Looking Inside a CSR A CSR is a PEM file (PEM is short for Privacy-Enhanced Mail) with the CERTIFICATE REQUEST label: % cat CertificateSigningRequest.certSigningRequest -----BEGIN CERTIFICATE REQUEST----- MIICgjCCAWoCAQAwPTEcMBoGCSqGSIb3DQEJARYNZnJvZ0Bmcm9nLmNvbTEQMA4G … Ur9x5voYb6CafUBZMMiYw6aFXcgnsx4ZXxe8VEqNCarrQi+9tqitDD/bCuymT5Da 2+t64DGjpVM2lwtwqvH6Qh6QdPjkUw== -----END CERTIFICATE REQUEST----- To see inside, run the openssl tool as shown below: % openssl req -in CertificateSigningRequest.certSigningRequest -text -noout Certificate Request: Data: Version: 0 (0x0) Subject: emailAddress=mrgumby@opendoor.com, CN=Mr Gumby, C=US Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:b1:b4:a0:15:4d:4a:d7:29:1d:ed:d6:b7:c2:7c: … 28:b9:8a:58:a4:04:63:fe:45:b2:4f:db:bd:93:20: 4e:8b Exponent: 65537 (0x10001) Attributes: a0:00 Signature Algorithm: sha256WithRSAEncryption 80:f9:0e:73:8e:42:d8:3c:e3:e0:06:54:13:d7:48:ef:a8:71: … 2f:74:e1:2e:cf:e7:ed:3e:64:b4:78:85:f4:ac:38:07:b1:15: 6b:3c:39:f9 For even more details, convert the file to DER form and then dump that as ASN.1: % openssl req -in CertificateSigningRequest.certSigningRequest -out CertificateSigningRequest.der -outform der % dumpasn1 -p -a CertificateSigningRequest.der SEQUENCE { SEQUENCE { INTEGER 0 SEQUENCE { SET { SEQUENCE { OBJECT IDENTIFIER emailAddress (1 2 840 113549 1 9 1) IA5String 'mrgumby@opendoor.com' } } SET { SEQUENCE { OBJECT IDENTIFIER commonName (2 5 4 3) UTF8String 'Mr Gumby' } } SET { SEQUENCE { OBJECT IDENTIFIER countryName (2 5 4 6) PrintableString 'US' } } } SEQUENCE { SEQUENCE { OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) NULL } BIT STRING, encapsulates { SEQUENCE { INTEGER 00 B1 B4 A0 15 4D 4A D7 29 1D ED D6 B7 C2 7C 74 … 28 B9 8A 58 A4 04 63 FE 45 B2 4F DB BD 93 20 4E 8B INTEGER 65537 } } } [0] Error: Object has zero length. } SEQUENCE { OBJECT IDENTIFIER sha256WithRSAEncryption (1 2 840 113549 1 1 11) NULL } BIT STRING 80 F9 0E 73 8E 42 D8 3C E3 E0 06 54 13 D7 48 EF … ED 3E 64 B4 78 85 F4 AC 38 07 B1 15 6B 3C 39 F9 } I’m using the dumpasn1 tool, available here. To extract the public key from the CSR, run this command: % openssl req -in CertificateSigningRequest.certSigningRequest -noout -pubkey -out public.pem % cat public.pem -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsbSgFU1K1ykd7da3wnx0 … FymGqUEcwfIISlG1C9VXyMRPzDcMrzjHm4i9qI9NliYouYpYpARj/kWyT9u9kyBO iwIDAQAB -----END PUBLIC KEY----- To further explore that key, use the techniques in my On Cryptographic Key Formats post. Revision History 2024-07-23 Updated to include a link to TN3161 Inside Code Signing: Certificates. 2022-11-03 First posted.
0
0
24k
Jul ’24
Command CodeSign failed with a nonzero exit code
After Upgrading to Xcode 13 my Builds are failing with Command CodeSign failed with a nonzero exit code. My app is in version 3.4.4. While trying to build version 3.4.5 for Mac we have started to get this error: Command CodeSign failed with a nonzero exit code Have tried everything people have said in this and other forums: Clean build folder; Restart Xcode Add --deep to Other Code Signing Flags Revalidate all Certificates Manual and Auto Signing The unsigned executable works fine. I am Evan able to Sign it manually and distribute locally. For Store Submission we need this step to succeed. Will appreciate help from Apple Technical Support This started happening with Xcode 13.
5
0
25k
Aug ’24
Transfer developer account to a new computer?
Hello, I've just got a new computer and now I want to transfer my developer account (certificates, keys etc.) to the new computer. Right now my developer membership has expired since I'm not doing any apps right now, but I might start again in the future. I'm not sure if I need to transfer anything, or if I will just get new certificates and keys when (if) I restart my membership? What do I need do, before I reset my old computer? I have developed apps for both for iOS and macOS.
4
1
3.7k
Jun ’24
launchApplicationAtURL - Launched Application "Verifying" since Catalina
We have a test tool our engineers use to launch various versions of our application during development and verification. Each daily build of our application is stored on a server. As well, each push of a change generates a new build of our application that is stored on a server. These are added to a database and the developer application accesses the server via REST to find the desired version to run, retrieves a server path and launches the application. This tool is valuable in finding pushes that introduced regressions. The developer application (Runner) is using the launchApplicationAtURL:options:configuration:error: (deprecated I know) to launch the app. Prior to Catalina, this was working great. However, as of Catalina, this process is taking a VERY long time due to the app needing to be "verified". the app seems to need to be copied to the users machine and verified. It only occurs the first launch, but as most of the time the users are running new push or daily builds, it has made the app useless. With the new remote work environment it is even worse as VPN copy can take forever. I have switched to using NSTask with a shell script to open the executable in the bundle. If I add the developer tool (Runner) to the Developer Tools in Privacy this seems to launch the application without the need for verification. However this just seems wrong. It also provides little feedback to know when the application is up and running, which makes my user experience poor. As well many of the systems we use this tool on for verification do not have Developer Tools installed. They are VMs. Is there a way for me to use the launchApplicationAtURL:options:configuration:error: (or the new openApplicationAtURL:configuration:completionHandler:) to launch these versions of the application without the need for the lengthy verification process? Adding our application to the Developer Tools did not seem to help.
2
0
997
Jun ’24
`--deep` Considered Harmful
Many of the trusted execution problems I see are caused by folks signing their product using the --deep option. While that can work in some circumstances, I generally recommend against it. There are two issues with --deep: It applies the same code signing options to every code item that it signs, something that’s not appropriate in general. For example, you might have an app containing a nested command-line tool, where the app and the tool need different entitlements. The --deep option will apply the same entitlements to both, which is a serious mistake. It only signs code that it can find, and it only finds code in nested code sites. If you put code in a place where the system is expecting to find data, --deep won’t sign it. The first issue is fundamental to how --deep works, and is the main reason you should not use it. Indeed, on macOS it may cause the trusted execution system to block your program from running. For the details, see the Check for Entitlements on Library Code section of Resolving Library Loading Problems. The second issue is only a problem if you don’t follow the rules for nesting code and data within a bundle, as documented in Placing Content in a Bundle. However, my experience is that the products that don’t follow those rules are exactly the same sort of products that try to use --deep. The alternative to --deep is to sign each code item separately, from the inside out. If your product has lots of nested code, automate this using a script. Note One exception to the prohibition on --deep is Automator apps. If you’re signing an Automator app, see this DevForums post. For detailed information on how to correctly sign and package Mac software, see Creating distribution-signed code for macOS and Packaging Mac software for distribution. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Revision history: 2024-05-06 Update some links to reference the Real Documentation™ rather than my legacy DevForums posts. 2022-06-14 Added a link to Resolving Library Loading Problems. Replaced the link to Signing a Mac Product For Distribution with a link to Creating Distribution-Signed Code for Mac. Made other minor editorial changes. 2021-10-21 Replaced the nested code reference with one to Placing Content in a Bundle. Minor editorial changes. 2020-09-15 Adopted the correct terminology for Automator apps. 2020-03-09 First version.
0
0
6.3k
May ’24