skip to Main Content

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?

2

Answers


  1. Chosen as BEST ANSWER

    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
    • 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: [email protected] ()"
      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: [email protected] ()"
      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="[email protected]" --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 "[email protected]"                                     
                 --password "@keychain:Developer-altool"   
    

    Staple notarization to pkg

    • add the notariztaion to the pkg
      • xcrun stapler staple ghostscript64.pkg

    Useful Resources


  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search