-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Recipe OSX Code Signing
$$\color{red}{\text{Note from maintainer}}$$ This guide appears to be long out of date. Self signed certificates are no longer allowed. Users tell me good things about this recipe instead.
App bundles created by PyInstaller can be code signed on OS X.
- Use Apple Keychain utility: Open Applications > Utilities > Keychain Access.
- From the Keychain Access menu, choose Certificate Assistant > Create a Certificate.
- Pick up a unique name for the certificate e.g.
Code Signing Test - Follow the rest of the wizard or the Apple Code Signing Guide.
-
codesigntool requires the signing certificate to be present in the Keychain. - Find out the certificate Common Name that you used for creating the certificate. In my case it was
Code Signing Test. - Make sure
Info.plistcontains itemsCFBundleIdentifierandCFBundleName. These two are essential for codesign. You could use PyInstaller option--osx-bundle-identifierto specify the identifier. By default it is the first script's basename. They should look like this:<plist version="1.0"> <dict> <key>CFBundleIdentifier</key> <string>com.mycompany.department.appname</string> <key>CFBundleName</key> <string>CodeSignTest</string> </dict> </plist>
- Use your certificate name in the following command to sign the .app bundle that pyinstaller created:
codesign -s "Code Signing Test" MyAppName.app
Some common error messages of codesign utility and how to solve them.
Issue: code object is not signed at all
- Codesign requires by default to have all subcomponents (Frameworks, plugins, etc.) already signed independently. This means that any of your subcomponents are not signed.
- With option
--deepyou can force codesign to sign even subcomponents. - You can find more information at:
Issue: User interaction is not allowed.
- This basically means that codesign utility is not allowed to access certificates stored in Keychain.
- Enable access to Keychain:
security unlock-keychain ${HOME}/Library/Keychains/login.keychain- Verifies access to Keychain:
security show-keychain-info ${HOME}/Library/Keychains/login.keychain- If you still get this message even after unlocking Keychain, you probably need to allow codesign to access your certificate:
- Run the Keychain Access GUI
- Right clicking on your private key Code Signing Test and select Get Info.
- Selecting the Access Control tab and then select the Allow all applications to access this item radio or the list of Always allow access by these applications list.
- You can find more information at:
Issue:
file.app/Contents/MacOS/file: bundle format unrecognized, invalid, or unsuitable
In subcomponent: file.app/Contents/MacOS/PyQt5/Qt/qml/QtQml/Models.2- Your application is using Qt and its QML feature, check this page for more informations: Recipe OSX Code Signing Qt.
PyInstaller breaks OSX code signing because it appends python code at the end of the binary. Appending data at the end of executable breaks the Mach-o format structure. codesign utility complains with the following messages.
the __LINKEDIT segment does not cover the end of the file (can't be processed)
file not in an order that can be processed (link edit information does not fill the __LINKEDIT segment)
- Fix __LINKEDIT - File Size (offset + File size == exe size), VM Size- same as 'File Size'
- Fix LC_SYMTAB - String Table Size - last data in mach-o file (offset + size = exe size on the filesystem) - The data appended to the executable will be part of the 'String Table' (Last data section in Mach-O file).
- Example of using macholib library.
from macholib.MachO import MachO
exe_data = MachO('executable')
# Fat binary could contain multiple architectures.
for h in exe_data.headers:
# Access Mach-O load commands
for c in h.commands:
# 'c' is a tupple (command_metadata, segment, [section1, section2])
c[0].get_cmd_name()
# The 4th (last) 'LC_SEGMENT_64' is the __LINKEDIT segment.
linkedit = h.commands[3]
# Change some header parameters.
# Write changes back.
file_object = open(exe_data.filename, 'rb+')
exe_data.write(file_object)
file_object.close()- At run-time the bootloader has to skip the signature segment that is appended at the end of exe file by
codesigntool.