How Do I Go About Code Signing a MacOS Application? - xcode

There is a professor at the university I work at that has developed a MacOS application he needs to get signed so that it doesn't get blocked by MacOS when users try to run it. I've gotten his CSR and gotten an Apple Developer cert created for him (using the 'ad hoc' distribution option, which created a cert file named 'distribution.cer').
I've searched the Apple Developer site for information on how to sign the application using XCode, but I can't quite grasp the instructions, not being an XCode user or Apple dev.
From what I can gather, you can also sign an app from a terminal, is that correct? If so, does it only work with .pkg installers, or also pre-compiled applications (.app files)?

Code signing
Apple Certificates
Developer ID Application Certificate - sign a macOS application for distribution outside of the Mac App Store.
Developer ID Installer Certificate - sign an application's Installer Package (if any) for distribution outside of the Mac App Store.
Signing an app
On the command line in a Terminal:
codesign -f -o runtime --timestamp -s "Developer ID Application: YOUR NAME (TEAM_ID)" /path/to/bundle.app
Notarization
Be aware that since macOS 10.14.5 (Mojave), software signed with a new Apple developer certificate must be notarized. Code signing is no longer sufficient to bypass Gatekeeper.
Apple's notary service requires you to:
Enable code-signing for all of the executables you distribute.
Enable the Hardened Runtime capability for your application and command line targets (include -o runtime option when running the codesign tool).
Use a “Developer ID” application, kernel extension, or installer certificate for your code-signing signature.
Include a secure timestamp with your code-signing signature (include the --timestamp option when running the codesign tool).
Don’t include the com.apple.security.get-task-allow entitlement with the value set to any variation of true.
Link against the macOS 10.9 or later SDK.
Step 1 - Create a disk image
Create a disk image of the app by opening a Terminal and running the following command:
hdiutil create -volname MyApp -srcfolder /path/to/MyApp.app -ov -format UDBZ MyApp.dmg
Step 2 - Code sign the disk image
Code sign the disk image by opening a Terminal and running the following command:
codesign -s "Developer ID Application: YOUR NAME (TEAM ID)" --timestamp MyApp.dmg
Step 3 - Generate an app-specific password
Generate an app-specific password, refer to this Apple Support article. Note: this is a password that will be specific to the notarization application (xcrun altool) and not to the application being notarized. You therefore only need to do this once, but make sure you copy the generated password and save it somewhere.
Step 4 - Upload disk image to notary service
Note: When you notarize the container disk image, altool also notarizes the application inside, so you can skip the step of notarizing the application itself.
Upload the disk image file to the Apple notary service by opening a Terminal and running the following command:
xcrun altool --notarize-app --primary-bundle-id "<your identifier>" -u "<your email>" -p "<app-specific pwd>" -t osx -f /path/to/MyApp.dmg
The primary-bundle-id helps you keep track of automated correspondence from the notarization service. The value you give doesn’t need to match the bundle identifier of the submitted app or have any particular value. It only needs to make sense to you. The notarization service includes the value whenever it emails you regarding the given altool submission.
If the upload is successful you should receive output similar to the following:
No errors uploading 'MyApp.dmg'.
RequestUUID = 3af4e56f-162b-75bc-827f-7233f92bf20c
Step 5 - Check the notarization process
The notarization process generally takes less than 15 minutes, so you may want to check its progress from time to time by opening a Terminal and running the following command:
xcrun altool --notarization-history 0 -u "<your email>" -p "<app-specific pwd>"
When the notarization process completes successfully the above command will return information similar to the following:
Notarization History - page 0
Date RequestUUID Status Status Code Status Message
------------------------- ------------------------------------ ------- ----------- ----------------
2019-12-08 06:24:03 +0000 3af4e56f-162b-75bc-827f-7233f92bf20c success 0 Package Approved
You should also receive an email from Apple similar to the following for a successful notarization:
Dear <First_Name>,
Your Mac software has been notarized. You can now export this software and distribute it directly to users.
Bundle Identifier: com.example.MyApp.001
Request Identifier: 3af4e56f-162b-75bc-827f-7233f92bf20c
For details on exporting a notarized app, visit Xcode Help or the notarization guide.
Best Regards,
Apple Developer Relations
Step 6 - Staple the ticket to the disk image
The notarization process produces a ticket that tells Gatekeeper that your application is notarized. After notarization completes successfully, the next time any user attempts to run your application on macOS 10.14 or later, Gatekeeper will find the ticket online. This includes users who downloaded your application before notarization.
After step 5 receives the "Package Approved" status message, you should also attach the ticket to the disk image file using the stapler tool, so that future distributions include the ticket. This ensures that Gatekeeper can find the ticket even when a network connection is not available.
To staple the ticket to the disk image file, open a Terminal and run the following command:
xcrun stapler staple /path/to/MyApp.dmg
If the command completes successfully, the output should be similar to:
Processing: /Path/to/MyApp.dmg
Processing: /Path/to/MyApp.dmg
The staple and validate action worked!
Step 7 - Verify notarization of the disk image
To verify the notarization of the disk image, open a Terminal and run the following command:
spctl -a -vv -t install MyApp.dmg
A successful verification of the notarization process should produce output similar to the following:
MyApp.dmg: accepted
source=Notarized Developer ID
origin=Developer ID Application: <Developer Name> (<TEAM_ID>)
Step 8 - Verify notarization of the application
To verify the notarization of the application, install the application, open a Terminal and run the following command:
spctl -a -vv /Applications/MyApp.app
A successful verification of the notarization process should produce output similar to the following:
/Applications/MyApp.app: accepted
source=Notarized Developer ID
origin=Developer ID Application: <Developer Name> (<TEAM_ID>)
Important: test the application by putting it in the Applications directory. It's treated differently by the Gatekeeper when in the "installed" location.
Alternatively, the Apple-recommended way to verify the notarization of an application is to open a Terminal and run the following command:
xcrun stapler validate MyApp.app
A successful verification of the notarization process should produce output similar to the following:
Processing: MyApp.app
The validate action worked!

Related

Cannot run QT macOS app on another MacBook

A cross-platform QT application is built for macOS. This app works if I test this on the same machine. When I create a .dmg file, this also works on my machine. When I test this on another machine, I get the error:
You do not have permission to open the application "MYAPP".
How can I debug this to see what the problem is?
Steps I do to create the .dmg file:
Run qmake and make until I have MYAPP.app (release build)
binarycreator -c config/config.xml -p packages/ setup_MYAPP
This creates setup_MYAPP.app
codesign -s "Full common name of my Apple Distribution profile" setup_MYAPP.app
When I provide a meaningless name between quotes it throws an error, so I assume this went fine.
hdiutil create -format UDZO -srcfolder setup_MYAPP.app MYAPP.dmg
This creates MYAPP.dmg, and the installer refuses to run on another macbook.
Alternatively:
Run qmake and make until I have MYAPP.app (release build)
codesign -s "Full common name of my Apple Distribution profile" MYAPP.app
macdeployqt MYAPP.app/ -dmg -codesign="Full common name of my Apple Distribution profile" -appstore-compliant
This creates MYAPP.dmg, and the app refuses to run on another macbook.
OK, it seems the correct answer is "it's complicated".
I have not succeeded in creating an installer that I can share outside the MAC App Store. Apple has restricted this to the point at which I just give in to bureaucracy and to good looking but really extremely bad documentation.
Distribution outside the Mac App Store requires notarization since macOS 10.15.5: see https://developer.apple.com/news/?id=04102019a.
Notarization means signing the code and uploading it to Apple. Apple will perform some magic checks and list it in some internal database.
Notarization requires a Developer ID certificate: see https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/resolving_common_notarization_issues#3087721 This is different from a certificate you need for app development and App Store distribution (Why, Apple, why?)
To obtain a developer ID certificate you need to fill in the form at https://developer.apple.com/contact/kext, which is the same form used to be able to write kernel extensions. Kernel extensions. (Why, Apple, why?)
When Apple does not respond to your form submission, you need to poke them a few times. And after they denied your request, you can poke all you want, they likely have set up a vertical classification rule immediately thereafter.
But, should you have been able to get your hands on a precious developer ID certificate, these seem to be the steps to follow to successfully notarize your app:
> security unlock-keychain -p PASSWORD !/Library/Keychains/login.keychain-db
> codesign --timestamp="http://timestamp.apple.com/ts01" --options runtime --verbose=3 --force --deep --sign "NAME OF CERTIFICATE" PATH/TO/APP.app
> xcrun altool -u USER_EMAIL -p APP_SPECIFIC_PASSWORD -notarize-app -t osx --primary-bundle-id INVENT_YOUR_OWN_UNIQUE_ID -f PATH/TO/APP.app
The last run will return another ID, of the form abcdef01-2345-6789-abcd-ef0123456789 and you can use that ID to follow up on your notarization request:
> xcrun altool -u USER_EMAIL -p APP_SPECIFIC_PASSWORD --notarization-info abcdef01-2345-6789-abcd-ef0123456789
You will also get a mail with a link to the notarization results.
I didn't succeed in getting a go, and I'm giving in. I gave up. The next brave soul to run into this may be saved some time after reading this. Good luck, may you succeed where I failed!

How to notarize an MacOS command line tool created outside of XCode?

MacOS now requires that all applications are hardened, signed and notarized. How does one sign and notarize an application created outside of XCode with a tool like PyInstaller?
I've sorted out the signing and notarization for .app files created outside of XTools. There's a really helpful thread here that shows how to add an entitlements.plist which fulfills the hardening of PyInstaller .app files. I believe this also works on command line utilities as well, but could be missing something. Submitting a .dmg containing a .app for notarization using altool will pass the tests and be notarized by Apple.
Submitting a single command line utility using the same process will also pass Notarization, but does not appear signed or notarized to the GateKeeper function on other machines. I assume this has something to do with the fact that a valid Info.plist file is not included in the PyInstaller binary as detailed in this blog post about building and delivering command line tools for Catalina.
Checking the signature of a signed file using codesign -dvv indicates that the Info.plist is "not bound".
$ codesign -dvv ./dist/helloworld
Executable=/Users/aaronciuffo/Documents/src/toy/codesign/dist/helloworld
Identifier=helloworld
Format=Mach-O thin (x86_64)
CodeDirectory v=20500 size=72086 flags=0x10000(runtime) hashes=2244+5 location=embedded
Signature size=9054
Authority=Developer ID Application: Aaron Ciuffo (4H9P6Q65AM)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=Nov 2, 2020 at 9:03:30 PM
Info.plist=not bound
TeamIdentifier=4H9P6Q65AM
Runtime Version=10.11.0
Sealed Resources=none
Internal requirements count=1 size=172
One suggested solution is using the Go gon package but gon does not cover adding the required Info.plist as far as I can tell.
Is there a workflow or application that can assist in this? How does one create an CL application outside of XCode and successfully sign it?
How to Sign and Notarize a Command Line Tool Manually
Apple requires that all distributed binaries are signed and notarized using a paid Apple Developer account. This can be done using commandline tools for binaries created with tools such as PyInstaller, or compiled using gcc.
Automated Python Script for this Process
The script linked below allows you to automate this process using project specific .ini files.
codesign.py
Setup
If you already have a developer account with Developer ID Application and Developer ID Installer certificates configured in XCode, skip this step
Create a developer account with Apple
https://developer.apple.com and shell out $99 for a developer account. Theives
Download and install X-Code from the Apple App Store
Open and run X-Code app and install whatever extras it requires
Open the preferences pane (cmd+,) and choose Accounts
click the + in the lower left corner
choose Apple ID
enter your apple ID and password
Previously created keys can be downloaded and installed from https://developer.apple.com
Select the developer account you wish to use
Choose Manage Certificates...
Click the + in the lower left corner and choose Developer ID Application
Click the + in the lower left corner and choose Developer ID Installer
Create an App-Specific password for altool to use
Instructions from Apple
Open KeyChain Access
Create a "New Password Item"
Keychain Item Name: Developer-altool
Account Name: your developer account email
Password: the application-specific password you just created
Create an executable binary with Pyinstaller or other tool
NB! Additional args such as --add-data may be needed to build a functional binary
Create a onefile binary
pyinstaller --onefile myapp.py
Sign the executable
Add the entitements.plist to the directory (see below)
List the available keys and locate a Developer ID Application certificate:
security find-identity -p basic -v
1) ABC123 "Apple Development: aaronciuffonl#gmail.com ()"
2) XYZ234 "Developer ID Installer: Aaron Ciuffo ()"
3) QRS333 "Developer ID Application: Aaron Ciuffo ()"
4) LMN343 "Developer ID Application: Aaron Ciuffo ()"
5) ZPQ234 "Apple Development: aaron.ciuffo#gmail.com ()"
6) ASD234 "Developer ID Application: Aaron Ciuffo ()"
7) 01010A "Developer ID Application: Aaron Ciuffo ()"
7 valid identities found
codesign --deep --force --options=runtime --entitlements ./entitlements.plist --sign "HASH_OF_DEVELOPER_ID APPLICATION" --timestamp ./dist/foo.app
Package as a pkg for installation
Create a temp directory to build the package:
mkdir /tmp/myapp
Use ditto to build the pkg installer structure
ditto /path/to/myapp /tmp/myapp/path/to/install/location
to install application "WhizBang" into /Applications/ on the target use: ditto ~/src/whiz_bang/dist/whizBang /tmp/whiz_bang/Applications/
repeat for all files that should be packaged
build the package
productbuild --identifier "com.your.pkgname.pkg" --sign "HASH_OF_INSTALLER_ID" --timestamp --root /tmp/myapp / myapp.pkg
NB! the format for the --root option is as follows: --root <ditto path> <relative path on target system to install from> <signed .pkg file>
Notarize
xcrun altool --notarize-app --primary-bundle-id "com.foobar.fooapp" --username="developer#foo.com" --password "#keychain:Developer-altool" --file ./myapp.pkg
Check email for successful notarization
Alternatively check status using:
xcrun altool --notarization-history 0 -u "developer#***" -p "#keychain:Developer-altool"
If notarization fails use the following to review a detailed log:
xcrun altool --notarization-info "Your-Request-UUID" \
--username "username#example.com" \
--password "#keychain:Developer-altool"
Staple notarization to pkg
add the notariztaion to the pkg
xcrun stapler staple ghostscript64.pkg
Useful Resources
Norarize a Commandline utility
This blog details setting up:
a developer profile & certificates
one time passwords
creating keychain entries to allow the -p "#keychain:Key" switch to work
Signing and Notarizing
Satpling
Adding an entitlements.plist to the signing process
ensure that embedded python libraries can be access appropriately
Signing and Notarizing tools compiled outside of XCode
covers:
signing
packaging
notarizing
stapling
DMG distribution
Using Aaron Ciuffo's post swap the PKG commands with this
If you want to distribute your binary in a DMG, in addition to calling codesign on the binary you must create the DMG correctly.
Start by creating your folder and clearing any junk or upload will fail.
mkdir DistributionFolder
xattr -cr ./DistributionFolder
Then move the binary into that folder and create an appropriately sized DMG
hdiutil create -fs HFS+ -volname MyApp -srcfolder ./DistributionFolder ./Distribution.dmg
Eject the drive. Sign the DMG and upload. Once notarised you can staple the same as in Aaron's answer.

How to download notarized files from Apple?

I have successfully notarized a plugin via command line for a Mac application i'm developing plugins for. This plugin is intended for distribution outside of Mac appstore.
xcrun altool --notarize-app --primary-bundle-id "com.demo.bundle.id" --username "email#abc.com" --password "xxx-x-xxxx-xx" --file Plugin.zip
Got an email that it has been successfully notarized and the email has instructions on how to export for distribution. However, it's an instruction for XCode UI but I did the notarization via command line so the instructions doesn't apply for me. Is there a commandline to download the notarized file(Plugin.zip) or else how do I get the Plugin.zip file from Apple to distribute it on my website?
UPDATE:
Turns out you can notarize a .zip file but you can't staple it. So I decided to create a .pkg to distribute my plugin instead of distributing via a zip file.
Here's the steps I followed to successfully notarize and staple my plugin, lets say my plugin name is FileConvertor.PluginExtension
Code sign your binaries to be included in your installer. codesign --sign "Developer ID Application: Developer Name" --verbose=4 --deep --force --strict FileConvertor.PluginExtension
Create your installer (.pkg) adding the above code signed .PluginExtension
Now sign your installer with the installer certificate. productsign --sign "Developer ID Installer: Developer Name" ./FileConvertor.pkg ./FileConvertorSigned.pkg
Send the signed installer for notarization xcrun altool --notarize-app --primary-bundle-id "com.demo.plugin" --username xyz#abc.com" --password "xxxx-xxxx-xxxx-xxxx" --file FileConvertorSigned.pkg
If sucessfully notarized, staple your installer xcrun stapler staple FileConvertorSigned.pkg
Distribute your installer on the web
You don't download your plugin.zip from Apple - just work with the same archive you originally uploaded to them. You are the one that actually staples the notarization ticket to whatever you are notarizing.
I haven't tried it myself with a .zip, but this is the process pieced together from the documentation.
Notarizing Your App Before Distribution says:
Notarize Your Preexisting Software
[...]
Upload your software to the Apple notary service, as described in Upload Your App to the Notarization Service.
You've already done this step.
Staple the returned ticket to your existing software, as described in Staple the Ticket to Your Distribution.
You have to attach the notarization ticket to whatever you're distributing, so Gatekeeper can find it even without a network connection. Normally you use the stapler tool to do this:
xcrun stapler staple MyApp.app
However, stapler doesn't support zip files. Customizing the Notarization Workflow says:
While you can notarize a ZIP archive, you can’t staple to it directly. Instead, run stapler against each individual item that you originally added to the archive. Then create a new ZIP file containing the stapled items for distribution.
So; expand your .zip and run stapler staple {filename} against each item contained inside. Then create a new .zip archive of the stapled contents.
Apple do not return anything from Notarization. Your signed file has a unique ID, in the signature, that Apple have stored. Once notarized, the signed file is accepted if downloaded.

How to properly codesign macOS Screensaver?

I'm trying to codesign my macOS screensaver project to get rid of the "unidentified developer" warning message. Both Apple's documentation and this person on Apple's forums say that you should use the "Developer ID Application" signing certificate to do it. But that doesn't appear to work for me.
When I follow Apple's instructions on how to test for proper signatures the response I get is as follows:
Screensaver.saver: rejected (the code is valid but does not seem to be an app)
My signing settings look like this:
I'm not sure what else I should try at this point. Mostly I'm worried about the rumor future mac apps will have to be signed/notarized and what does that means for screensavers?
Here are additional notarization notes:
You can’t notarize the .saver directly, but you can in a round-about-way notarize a ZIP file, which is how I distribute my screen saver. Here are the steps I use for my simple saver, your mileage will undoubtably vary:
/usr/bin/codesign -f -o runtime --timestamp --sign “insert Developer
ID Installer certificate identifier here” XYZZY.saver
compress the code signed .saver e.g. XYZZY.saver.zip
/usr/bin/xcrun altool --verbose --notarize-app --primary-bundle-id “insert identifier here" -u “xyzzy#plugh.com" -p “insert app-specific PW for your Apple ID here" -t osx -f XYZZY.saver.zip
Aside: store the App-specific password in your keychain and
reference it from the command line like this:
/usr/bin/xcrun altool
--store-password-in-keychain-item
"AC_PASSWORD" -u xyzzy#plugh.com -p “insert App-specific PW from Apple here”
wait for notarization, check status like this:
/usr/bin/xcrun altool --notarization-history 0 -u “xyzzy#plugh.com"
-p "#keychain:AC_PASSWORD”
While you can notarize a ZIP archive, you can’t staple the
notarization ticket to it directly. Instead, run stapler against
each individual item that you originally added to the archive. Then
create a new ZIP file containing the stapled items for distribution.
/usr/bin/xcrun stapler staple XYZZY.saver
Re-zip the saver and
distribute
Just in case someone else stumbles in here...
For now I've realized that a good way around this is to create an installer package and then sign that following Apple's instructions.
I ended up using some free software called Packages to create the installer. After building the installer, I copied it to another folder and used the following command to sign it.
/usr/bin/productsign --sign "<Name of Developer ID Installer Cert in Keychain>" source.pkg destination-signed.pkg
Hope this helps someone out there. As far as I can tell this gets around the unidentified developer warning.

Adobe AIR Mac app returns 'code failed to satisfy specified code requirement'

Initially I tried to codesign our Adobe AIR Mac app with Mac Developer distribution certificate which generally starts as "3rd Parth Mac Developer Application:xxx". Later, I read through https://developer.apple.com/library/mac/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG211 where it's discussed that verification through codesign and spctl commands needs the certificate to be Developer ID certificate only (I'm using 'Developer ID Application:xxx'):
Like Gatekeeper, spctl will only accept Developer ID-signed apps and
apps downloaded from the Mac App Store by default. It will reject apps
signed with Mac App Store development or distribution certificates.
My verification commands were:
./check-signature DEPLOY/Moonshine.app DEPLOY/Application.pkg
(c) 2014 Apple Inc. All rights reserved.
DEPLOY/Application.app: YES
DEPLOY/Application.pkg: YES
and
spctl -a -t exec -vv DEPLOY/Application.app
DEPLOY/Application.app: accepted
source=Developer ID
override=security
disabled
origin=Developer ID Application: xxx (LS9K97G9DD)
Both commands were retuned positive results as discussed in Apple Developers page.
When we submitted the app to App Store we returned with errors like "test-requirement: code failed to satisfy specified code requirement(s)". We also supplied with suggested (Code Requirements) links by Apple: https://developer.apple.com/library/mac/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG4, and we started verifying .app file at our local with following command:
codesign -vvvv -R="anchor apple" DEPLOY/Applications.app
We starts receiving likewise error as Apple sent us:
--prepared:/Users/santanu/Documents/Adobe Flash Builder 4.7/ProjectFolder/build/DEPLOY/Application.app/Contents/Frameworks/Adobe
AIR.framework/Versions/Current/.
--validated:/Users/santanu/Documents/Adobe Flash Builder 4.7/ProjectFolder/build/DEPLOY/Application.app/Contents/Frameworks/Adobe
AIR.framework/Versions/Current/.
DEPLOY/Application.app/: valid on disk
DEPLOY/Application.app/: satisfies its Designated Requirement
test-requirement: code failed to satisfy specified code requirement(s)
Later, I also tried to codesign with Mac Developer distribution certificate (3rd Party Mac Developer Application:xxx) instead of Developer ID certificate, but that didn't improve the situation either.
I'm unable to understand now what else certificate we should use to get that anchor apple in our codesign process to fix this 'code failed to satisfy specified code requirement' error, or any other way we can fix this?

Resources