mirror of
https://github.com/zen-browser/desktop
synced 2026-04-25 17:15:00 +02:00
* security: enable MAR signature verification for updates Remove `--enable-unverified-updates` from the common mozconfig. This flag was disabling all MAR (Mozilla ARchive) signature verification in the updater binary, meaning update packages were applied without any cryptographic authenticity check. With this flag removed, the Mozilla build system will: - Link NSS and signmar into the updater binary - Enable SecVerifyTransformCreate-based signature verification on macOS - Require MAR files to contain valid signatures before applying REQUIRED FOLLOW-UP (maintainer action): 1. Generate a Zen-specific MAR signing keypair (RSA-PKCS1-SHA384) See: https://firefox-source-docs.mozilla.org/build/buildsystem/mar.html 2. Place the public key DER file(s) in the source tree at toolkit/mozapps/update/updater/release_primary.der 3. Sign MAR files during the release build with the private key 4. Set ACCEPTED_MAR_CHANNEL_IDS in update-settings.ini to restrict which update channels the updater will accept Ref: GHSA-qpj9-m8jc-mw6q * no-bug: Added signature steps * no-bug: Export browser/installer/package-manifest.in --------- Co-authored-by: Maliq Barnard <maliqbarnard@Maliqs-MacBook-Air.local> Co-authored-by: Mr. M <mr.m@tuta.com>
166 lines
5.0 KiB
Bash
166 lines
5.0 KiB
Bash
#!/usr/bin/env bash
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
set -e
|
|
|
|
CERT_PATH_DIR=build/signing
|
|
UPDATER_CERT_DIR="engine/toolkit/mozapps/update/updater"
|
|
NSS_CONFIG_DIR="$CERT_PATH_DIR/nss_config"
|
|
|
|
generate_certs() {
|
|
mkdir temp
|
|
cd temp
|
|
|
|
# 1. Generate private key
|
|
openssl genrsa -out private_key.pem 4096
|
|
|
|
# 2. Generate self-signed certificate (required for PKCS#12 bundling)
|
|
openssl req -new -x509 \
|
|
-key private_key.pem \
|
|
-out cert.pem \
|
|
-subj "/CN=MAR Signing"
|
|
|
|
# 3. Export public key as SPKI DER (for embedding in updater)
|
|
openssl rsa -in private_key.pem -pubout -outform DER -out public_key.der
|
|
|
|
cd ..
|
|
mkdir -p "$CERT_PATH_DIR"
|
|
mv temp/private_key.pem "$CERT_PATH_DIR"/private_key.pem
|
|
mv temp/cert.pem "$CERT_PATH_DIR"/cert.pem
|
|
mv temp/public_key.der "$CERT_PATH_DIR"/public_key.der
|
|
|
|
mkdir -p "$CERT_PATH_DIR/env"
|
|
base64 -w 0 "$CERT_PATH_DIR"/cert.pem > "$CERT_PATH_DIR"/env/ZEN_SIGNING_CERT_PEM_BASE64
|
|
base64 -w 0 "$CERT_PATH_DIR"/private_key.pem > "$CERT_PATH_DIR"/env/ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64
|
|
|
|
# Verify public key
|
|
openssl rsa -in "$CERT_PATH_DIR"/public_key.der \
|
|
-pubin -inform DER -text -noout
|
|
|
|
rm -rf temp
|
|
}
|
|
|
|
import_cert() {
|
|
if [ ! -f "$CERT_PATH_DIR/public_key.der" ]; then
|
|
echo "Error: public_key.der not found. Run with -g first." >&2
|
|
exit 1
|
|
fi
|
|
echo "Importing certificate into $UPDATER_CERT_DIR/release_primary.der"
|
|
cp "$CERT_PATH_DIR/public_key.der" "$UPDATER_CERT_DIR/release_primary.der"
|
|
echo "Importing certificate into $UPDATER_CERT_DIR/release_secondary.der"
|
|
cp "$CERT_PATH_DIR/public_key.der" "$UPDATER_CERT_DIR/release_secondary.der"
|
|
echo "Done. Rebuild the updater to embed the new certificate."
|
|
}
|
|
|
|
create_nss_config_dir() {
|
|
rm -rf "$NSS_CONFIG_DIR"
|
|
mkdir "$NSS_CONFIG_DIR"
|
|
|
|
if [ -z "$ZEN_MAR_SIGNING_PASSWORD" ]; then
|
|
echo "Warning: ZEN_MAR_SIGNING_PASSWORD environment variable not set. Using empty password." >&2
|
|
ZEN_MAR_SIGNING_PASSWORD=""
|
|
fi
|
|
|
|
password_file="$NSS_CONFIG_DIR/password.txt"
|
|
echo "$ZEN_MAR_SIGNING_PASSWORD" > "$password_file"
|
|
|
|
if [ "$ZEN_SIGNING_CERT_PEM_BASE64" ]; then
|
|
echo "Decoding signing certificate from ZEN_SIGNING_CERT_PEM_BASE64 environment variable..."
|
|
echo "$ZEN_SIGNING_CERT_PEM_BASE64" | base64 -d > "$CERT_PATH_DIR/cert.pem"
|
|
fi
|
|
|
|
if [ "$ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64" ]; then
|
|
echo "Decoding signing private key from ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 environment variable..."
|
|
echo "$ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64" | base64 -d > "$CERT_PATH_DIR/private_key.pem"
|
|
fi
|
|
|
|
echo "Generating NSS config directory at $NSS_CONFIG_DIR"
|
|
certutil -N -d "$NSS_CONFIG_DIR" -f "$password_file"
|
|
|
|
echo "Wrapping private key into PKCS#12..."
|
|
echo "Wrapping key + cert into PKCS#12..."
|
|
openssl pkcs12 -export \
|
|
-inkey "$CERT_PATH_DIR/private_key.pem" \
|
|
-in "$CERT_PATH_DIR/cert.pem" \
|
|
-name "private_key" \
|
|
-passout pass:"$ZEN_MAR_SIGNING_PASSWORD" \
|
|
-out "$CERT_PATH_DIR/private_key.p12"
|
|
|
|
echo "Importing PKCS#12 into NSS database..."
|
|
pk12util \
|
|
-i "$CERT_PATH_DIR/private_key.p12" \
|
|
-d "$NSS_CONFIG_DIR" \
|
|
-W "$ZEN_MAR_SIGNING_PASSWORD" \
|
|
-K "$ZEN_MAR_SIGNING_PASSWORD"
|
|
}
|
|
|
|
cleanup_certs() {
|
|
rm -rf "$NSS_CONFIG_DIR"
|
|
rm -rf "$CERT_PATH_DIR/env"
|
|
|
|
rm -f "$CERT_PATH_DIR/private_key.p12"
|
|
rm -f "$CERT_PATH_DIR/private_key.pem"
|
|
rm -f "$CERT_PATH_DIR/cert.pem"
|
|
}
|
|
|
|
sign_mars() {
|
|
if [ ! -f "$SIGNMAR" ]; then
|
|
echo "Error: signmar not found at $SIGNMAR. Build the engine first." >&2
|
|
exit 1
|
|
fi
|
|
|
|
create_nss_config_dir
|
|
|
|
folders=(
|
|
linux.mar
|
|
linux-aarch64.mar
|
|
windows.mar
|
|
windows-arm64
|
|
macos.mar
|
|
)
|
|
# each folder will contain the .mar files for that platform, and the signature will be written in-place
|
|
for folder in "${folders[@]}"; do
|
|
if [ -d "$folder" ]; then
|
|
for mar_file in "$folder"/*.mar; do
|
|
if [ -f "$mar_file" ]; then
|
|
echo ""
|
|
echo "Signing $mar_file..."
|
|
# mar [-C workingDir] -d NSSConfigDir -n certname -s archive.mar out_signed_archive.mar
|
|
"$SIGNMAR" -d "$NSS_CONFIG_DIR" -n "private_key" -s "$mar_file" "$mar_file".signed
|
|
echo "Signed $mar_file. Verifying signature..."
|
|
"$SIGNMAR" -d "$NSS_CONFIG_DIR" -n "private_key" -v "$mar_file".signed
|
|
mv "$mar_file".signed "$mar_file"
|
|
echo "Successfully signed $mar_file"
|
|
else
|
|
echo "No .mar files found in $folder, skipping."
|
|
fi
|
|
done
|
|
else
|
|
echo "Directory $folder not found, skipping."
|
|
fi
|
|
done
|
|
|
|
cleanup_certs
|
|
}
|
|
|
|
case "$1" in
|
|
-g)
|
|
generate_certs
|
|
;;
|
|
-i)
|
|
import_cert
|
|
;;
|
|
-s)
|
|
sign_mars
|
|
;;
|
|
*)
|
|
echo "Usage: $0 [-g] [-i] [-s]" >&2
|
|
echo " -g Generate MAR signing certificates" >&2
|
|
echo " -i Import the certificate into the updater (release_primary.der)" >&2
|
|
echo " -s Sign *.mar files in the current directory in-place" >&2
|
|
exit 1
|
|
;;
|
|
esac
|