Signing Local macOS Builds

Background

Firefox for macOS is mainly signed in one of two different ways: one for production releases, and one for builds that run on try. Typically, developers testing local builds don’t need to be concerned with signing unless they are working on an area specifically affected by macOS entitlements such as passkeys, loading third party libraries, or adding a new process type. However, it is good practice to test builds that are as close as possible to the production configuration or the try server configuration. Local builds are not signed automatically and mach doesn’t include support for running tests on signed builds. However, the mach command macos-sign can be used to sign local packaged builds for manual testing. macos-sign supports signing builds to match try or production builds.

Note: On Apple Silicon Macs, where all executables are required to be signed, Firefox binaries will be “ad-hoc” self-signed automatically by the linker during compilation, but this is a per-binary sign with no Firefox-specific runtime settings or entitlements. This document ignores automatic signing.

To sign your own local build so that it has the same set of entitlements as a production release requires a signing certificate and provisioning profile issued from Mozilla’s Apple Developer account. Entitlements are used to grant Firefox certain permissions as well as impose security restrictions when it is run on macOS. Some entitlements are considered restricted and can only be enabled when signed by a certificate from an account that has been granted permission to use the entitlement, such as the passkey macOS entitlement. As an example of the production restrictions, production builds use an entitlement that disallows debugger attachment. Disallowing debuggers is required for distribution because it is required by the Notarization system. When signing locally, developers can modify entitlements as needed.

Summary

Production build: requires Mozilla’s official Apple Developer ID certificate, private key, and provisioning profile. Only Mozilla Release Engineering has access to the official Developer ID certificate and private key. Mozilla developers can request a limited-use Apple Developer certificate which can be used to generated production-like builds for local testing. See Signing Your Build Like Production below.

Developer build: requires generating a self-signed certificate (to sign like a try push is signed) or using ad-hoc signing (no setup required and only usable locally), will have no passkey support (or any other restricted entitlement), has fewer restrictions with respect to module loading, is debuggable.

Signing Your Build Like try

To sign your own local build with entitlements that match what is used for try push automated testing, generate a self-signed code signing certificate using the macOS Keychain Access application. During the process, supply a unique name not used by other Keychain entries making sure to not use any spaces. For example, my-firefox-selfsign-cert-2024. This string will be used as the signing identity and passed to macos-sign with the -s option. ./mach passes this to the codesign command which looks up the entry in the keychain. When running the signing command, you’ll be prompted to allow codesign to access the keychain entry. Select Always Allow when prompted.

$ ./mach build package
$ open <path-to-dmg>
<drag Browser to the Desktop>
$ ./mach macos-sign -s my-firefox-selfsign-cert-2024 -a ~/Desktop/Nightly.app

The entitlements in the tree used for this configuration are labeled as developer and we call this the developer build. Developer signed builds differ from production signed in the following ways:

  • They allow debugger attachment

  • They allow loading of third party libraries in all processes

  • They respect dyld environment variables

  • They don’t include restricted entitlements such as the passkey entitlement (and therefore passkeys can’t be used)

Ad-hoc Signing Your Build - Like try Signing, but Requires no Configuration and is For Local Use Only

Omitting the -s option will use ad-hoc signing which requires no setup. The build will be more limited than builds signed with a self-signed cert. Ad-hoc signed builds are not verifiable or runnable on any other system. There is little documentation available about the limitations.

$ ./mach build package
$ open <path-to-dmg>
<drag Browser to the Desktop>
$ ./mach macos-sign -a ~/Desktop/Nightly.app

Signing Your Build Like Production

To sign your local build like a production Firefox build, you’ll need an Apple Developer signing certificate and provisioning profile issued from Mozilla’s Apple Developer account. Developers will be given a development-role login allowing a signing certificate and provisioning profile to be generated. The provisioning profile used with Development certificates limits the signed application to Mozilla developer machines via a hardware ID. Employees can file a bug here to request an account. Once the developer’s Apple account is setup as a member of Mozilla’s Apple account, Xcode can be used to download a Developer signing certificate and provisioning profile for development use. Use Keychain Access to get the codesigning identifier for your development cert which should be passed as the -s codesigning identity to mach macos-sign:

$ ./mach build package
$ open <path-to-dmg>
<drag Browser to the Desktop>
$ ./mach macos-sign -a ~/Desktop/Nightly.app -s <MOZILLA_DEVELOPER_CERT_ID>

Example: Re-Signing Official Nightly

$ ditto /Applications/Firefox\ Nightly.app ~/Desktop/FirefoxNightly.app
$ ./mach macos-sign -a ~/Desktop/FirefoxNightly.app
0:00.20 Using ad-hoc signing identity
0:00.20 Using nightly channel signing configuration
0:00.20 Using developer entitlements
0:00.20 Reading build config file /Users/me/r/mc/taskcluster/ci/config.yml
0:00.23 Stripping existing xattrs and signatures
0:01.91 Signing with codesign
0:02.72 Verification of signed app /Users/me/Desktop/FirefoxNightly.app OK

Example: Re-Signing Official Developer Edition With rcodesign Using a pkcs12 Certificate Key Pair

More information about rcodesign can be found on the rust crate page or github repo. Certificates can be exported from Keychain Access in .p12 format.

$ ditto /Applications/Firefox\ Developer\ Edition.app/ ~/Desktop/DevEdition.app
$ ./mach macos-sign -r -a ~/Desktop/DevEdition.app \
  --rcodesign-p12-file ./myDevId.p12 \
  --rcodesign-p12-password-file ./myDevId.p12.passwd
0:00.26 Using pkcs12 signing identity
0:00.26 Using devedition channel signing configuration
0:00.26 Using developer entitlements
0:00.26 Reading build config file /Users/me/r/mc/taskcluster/ci/config.yml
0:00.29 Stripping existing xattrs and signatures
0:02.09 Signing with rcodesign
0:11.16 Verification of signed app /Users/me/Desktop/DevEdition.app OK