Merge commit from fork

* 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>
This commit is contained in:
JDX50S
2026-04-09 14:28:31 -03:00
committed by GitHub
parent 8b9f449f95
commit 270db6d671
9 changed files with 201 additions and 15 deletions

View File

@@ -505,6 +505,20 @@ jobs:
run: |
git clone https://github.com/zen-browser/windows-binaries.git .github/workflows/object --depth 1
- name: Download signmar-linux-x86_64 from artifacts
uses: actions/download-artifact@v4
with:
name: signmar-linux-x86_64
- name: Sign MAR files
env:
SIGNMAR: ${{ github.workspace }}/signmar-linux-x86_64
ZEN_MAR_SIGNING_PASSWORD: ${{ secrets.ZEN_MAR_SIGNING_PASSWORD }}
ZEN_SIGNING_CERT_PEM_BASE64: ${{ secrets.ZEN_SIGNING_CERT_PEM_BASE64 }}
ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64: ${{ secrets.ZEN_SIGNING_PRIVATE_KEY_PEM_BASE64 }}
run: |
bash scripts/mar_sign.sh -s
- name: Copy update manifests
env:
RELEASE_BRANCH: ${{ inputs.update_branch }}

View File

@@ -173,3 +173,11 @@ jobs:
retention-days: 5
name: linux_update_manifest_${{ matrix.arch }}
path: ./dist/update
- name: Upload signmar
if: ${{ matrix.arch == 'x86_64' }}
uses: actions/upload-artifact@v4
with:
retention-days: 2
name: signmar-linux-x86_64
path: engine/obj-x86_64-pc-linux-gnu/dist/bin/signmar

View File

@@ -10,6 +10,8 @@ fi
. $HOME/.cargo/env
sh ./scripts/mar_sign.sh -i
ulimit -n 4096
if command -v Xvfb &> /dev/null; then

7
.gitignore vendored
View File

@@ -27,3 +27,10 @@ locales/firefox-l10n/
.DS_Store
mozconfig
build/signing/env/
build/signing/nss_config/
build/signing/cert.pem
build/signing/private_key.pem
build/signing/private_key.p12

Binary file not shown.

View File

@@ -48,6 +48,8 @@ if test "$ZEN_RELEASE"; then
ac_add_options --enable-optimize
ac_add_options --enable-verify-mar
ac_add_options --enable-release
ac_add_options --disable-debug
ac_add_options --disable-debug-symbols
@@ -89,8 +91,6 @@ if test "$ZEN_RELEASE"; then
ac_add_options --enable-replace-malloc
fi
ac_add_options --enable-unverified-updates
ac_add_options --enable-jxl
ac_add_options --with-unsigned-addon-scopes=app,system

165
scripts/mar_sign.sh Normal file
View File

@@ -0,0 +1,165 @@
#!/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

View File

@@ -1,18 +1,8 @@
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
index 36eafe35063f02fe3d4acaab24a08dc1b7b0ae24..951889b156498f66118d67d4245aca649e27a3a2 100644
index 36eafe35063f02fe3d4acaab24a08dc1b7b0ae24..b6bf327bf286de5246e5c50d89519d16d5771caf 100644
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -378,17 +378,17 @@ bin/libfreebl_64int_3.so
; [MaintenanceService]
;
#ifdef MOZ_MAINTENANCE_SERVICE
-@BINPATH@/maintenanceservice.exe
-@BINPATH@/maintenanceservice_installer.exe
+;@BINPATH@/maintenanceservice.exe
+;@BINPATH@/maintenanceservice_installer.exe
#endif
; [Crash Reporter]
@@ -386,9 +386,9 @@ bin/libfreebl_64int_3.so
;
#ifdef MOZ_CRASHREPORTER
#ifdef XP_MACOSX

View File

@@ -7,7 +7,7 @@ index 57ea0415653678bb300e277e66c97e332e756cc7..5f757e68a685948c83fee8f963c49bee
"signmar",
]
+ if CONFIG["OS_ARCH"] == "Linux":
+ # Zen: --enable-unverified-updates is enabled, the RPATH is not added
+ # Zen: ensure RPATH is set so NSS/signmar libs are found at runtime
+ OS_LIBS += [
+ "-Wl,-rpath=\\$$ORIGIN",
+ ]