blob: 5e04f9ccc681f0f5017050c75098871388b750a9 [file] [view]
# Signing Scripts for Chrome on macOS
This directory contains Python modules that modify the Chrome application bundle
for various release channels, sign the resulting bundle, package it into
`.dmg`/`.pkg` files for distribution, and sign those resulting `.dmg`/`.pkg`
files.
## Invoking
Signing requires a statically linked build (i.e. `is_component_build = false`),
which you can set up in a new GN out directory with the following args:
is_debug = false
is_component_build = false
The scripts are invoked using the driver located at
`//chrome/installer/mac/sign_chrome.py`. In order to sign a binary, a signing
identity is required. Googlers can use the [internal development
identity](https://goto.google.com/ioscerts); otherwise you must supply your
own. Note that a
[self-signed](https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/Procedures/Procedures.html)
identity is incompatible with the _library validation_ signing option that
Chrome uses.
A sample invocation to use the
[internal Google development identity](https://goto.google.com/appledev/book/getting_started/provisioning/index.md#googles-development-certificate) during development would be:
$ ninja -C out/release chrome chrome/installer/mac
$ ./out/release/Chromium\ Packaging/sign_chrome.py --input out/release --output out/release/signed --identity 'Google Development' --development --disable-packaging
The `--disable-packaging` flag skips the creation of DMG and PKG files, which
speeds up the signing process when one is only interested in a signed .app
bundle. The `--development` flag skips over code signing requirements and checks
that do not work without the official Google signing identity, and it injects
the `com.apple.security.get-task-allow` that lets the app be debugged.
## The Installer Identity
The above section speaks of the `--identity` parameter to `sign_chrome.py`, and
how the normal development identity will do, and how a self-signed identity will
not work. However, the identity used for Installer (.pkg) files is different.
Installer files require a special Installer Package Signing Certificate, which
is different than a normal certificate in that it has a special Extended Key
Usage extension.
For the normal identity, Apple provides both a development and a deployment
certificate, and while the deployment certificate can be (and should be)
carefully guarded, the development certificate can be more widely used by the
development team. However, Apple provides _only_ a deployment installer
certificate. For development purposes, you must self-sign your own.
Directions on how to create a self-signed certificate with the special Extended
Key Usage extension for installer use can be found on
[security.stackexchange](https://security.stackexchange.com/a/47908).
You will need to explicitly mark the certificate as trusted. This can be done
with
`sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain my_installer_cert.crt`.
Be sure that `sudo security -v find-identity` lists this new certificate as a
valid identity.
## Chromium
There are slight differences between the official Google Chrome signed build and
a development-signed Chromium build. Specifically, the entitlements will vary
because the default
[chrome/app/app-entitlements.plist](../../../app/app-entitlements.plist) omits
[specific entitlements](../../../app/app-entitlements-chrome.plist) that are
tied to the official Google signing identity.
In addition, the Chromium [code sign
config](https://cs.chromium.org/chromium/src/chrome/installer/mac/signing/chromium_config.py)
only produces one Distribution to sign just the .app. An
`is_chrome_branded=true` build produces several Distributions for the official
release system.
## Google Chrome
If you attempt to sign an `is_chrome_branded=true` build locally, the app will
fail to launch because certain entitlements are tied to the official Google code
signing identity/certificate. To test an `is_chrome_branded=true` build locally,
build with `include_branded_entitlements=false` or replace the contents of
[`app-entitlements-chrome.plist`](../../../app/app-entitlements-chrome.plist)
with an empty plist.
### TCC Permissions
MacOS grants applications access to privileged resources using the TCC
(Transparency, Consent, and Control) subsystem. TCC records user authorization
decisions, in part, based on the code signing identity of the responsible
application.
One important point, as discussed in the [debugging
tips](../../../../docs/mac/debugging.md#system-permission-prompts_transparency_consent_and-control-tcc)
is if Chrome/Chromium is launched as a subprocess of another GUI application
(such as Terminal), the parent GUI process not the browser is considered the
responsible application for TCC's purposes.
An authorization decision can be reset manually using the `tccutil(1)` command.
For example, this would reset the microphone access permission:
tccutil reset Microphone org.chromium.Chromium
Unfortunately there is not an authoritative list of service names for resetting,
but the value `All` will remove all decisions. The decisions are recorded in a
SQLite database, which can be inspected using the command below. This requires
granting the **Full Disk Access** permission in System Settings to the Terminal
or disabling System Integrity Protection.
sqlite3 ~"/Library/Application Support/com.apple.TCC/TCC.db"
The `access.service` column's values corresponds to the `tccutil reset` service,
sans the `kTCCService` prefix.
### System Detached Signatures
MacOS may itself sign Chromium build binaries when it needs to record a
signature for certain OS operations. The signature is not attached to the
application bundle, as the signing scripts do, but it is instead recorded in a
_detached signature database_. This happens, e.g. when a network request
is filtered by the Application Firewall.
If you get errors saying the build is already signed, before signing the build
yourself, this is likely the issue. To fix it:
1. Disable the Application Firewall in **System Preferences > Security &
Privacy > Firewall > Turn Off Firewall**.
2. `sudo rm /var/db/DetachedSignatures`
3. Reboot
## Running Tests
The `signing` module is thoroughly unit-tested. When making changes to the
signing scripts, please be sure to add new tests too. To run the tests, simply
run the wrapper script at
`//chrome/installer/mac/signing/run_mac_signing_tests.py`.
You can pass `--coverage` or `-c` to show coverage information. To generate a
HTML coverage report and Python coverage package is available (via `pip install
coverage`), run:
coverage3 run -m unittest discover -p '*_test.py'
coverage3 html
## Formatting
The code is automatically formatted with YAPF. Run:
git cl format --python