[tor-commits] [tor-browser-bundle/master] Bug 13379: Sign our MAR files.

brade at torproject.org brade at torproject.org
Wed Dec 17 22:07:58 UTC 2014


commit d852329ac0979d8005e9e8bdd9b3f8a049fc2db4
Author: Kathy Brade <brade at pearlcrescent.com>
Date:   Wed Dec 17 16:57:28 2014 -0500

    Bug 13379: Sign our MAR files.
    
    In the Linux mar-tools package, include certutil, signmar, and the required
      NSS and NSPR libraries.
    Change update_responses to select the action to be done based on the
      program name, thereby separating the incremental MAR file generation (done
      via a new 'gen_incrementals' symlink) from the htdocs generation.  Also added
      an 'update_responses' make target.  Thanks to boklm for help with this.
    Add a series of 'signmar' make targets which run a new signmars.sh script,
    which does the following:
      1. Prompts for an NSS password (the script assumes that an nssdb directory
         exists that contains the signing key/cert).
      2. Moves original (unsigned) MAR files to a TORBROWSER_VERSION-unsigned/
         directory.
      3. Signs each of the MAR files, placing the signed files in the
         TORBROWSER_VERSION/ directory.
      You may set NSS_DB_DIR and/or NSS_CERTNAME before running signmars.sh; the
      defaults are ./nssdb and marsigner
---
 gitian/Makefile                             |   15 +++
 gitian/descriptors/linux/gitian-firefox.yml |   11 +++
 gitian/signmars.sh                          |  135 +++++++++++++++++++++++++++
 tools/update-responses/gen_incrementals     |    1 +
 tools/update-responses/update_responses     |   34 +++++--
 5 files changed, 189 insertions(+), 7 deletions(-)

diff --git a/gitian/Makefile b/gitian/Makefile
index 2c17656..9613db6 100644
--- a/gitian/Makefile
+++ b/gitian/Makefile
@@ -33,6 +33,21 @@ build-beta:
 	./hash-bundles.sh versions.beta
 
 incrementals:
+	../tools/update-responses/gen_incrementals
+
+signmars:
+	./signmars.sh versions
+
+signmars-alpha:
+	./signmars.sh versions.alpha
+
+signmars-beta:
+	./signmars.sh versions.beta
+
+signmars-nightly:
+	./signmars.sh versions.nightly
+
+update_responses:
 	../tools/update-responses/update_responses
 
 hash:
diff --git a/gitian/descriptors/linux/gitian-firefox.yml b/gitian/descriptors/linux/gitian-firefox.yml
index 5f96b6e..a1abf2e 100644
--- a/gitian/descriptors/linux/gitian-firefox.yml
+++ b/gitian/descriptors/linux/gitian-firefox.yml
@@ -136,12 +136,23 @@ script: |
   rm -f $INSTDIR/Browser/*.chk
   #
   # Make MAR-based update tools available for use during the bundle phase.
+  # Note that mar and mbsdiff are standalone tools, compiled for the build
+  # host's architecture.  We also include signmar, certutil, and the libraries
+  # they require; these utilities and libraries are built for the target
+  # architecture.
   MARTOOLS=~/build/mar-tools
   mkdir -p $MARTOOLS
   cp -p config/createprecomplete.py $MARTOOLS/
   cp -p tools/update-packaging/*.sh $MARTOOLS/
   cp -p obj-*/dist/host/bin/mar $MARTOOLS/
   cp -p obj-*/dist/host/bin/mbsdiff $MARTOOLS/
+  cp -p obj-*/modules/libmar/tool/signmar $MARTOOLS/
+  cp -p obj-*/security/nss/cmd/certutil/certutil $MARTOOLS/
+  NSS_LIBS="libfreebl3.so libmozsqlite3.so libnss3.so libnssdbm3.so libnssutil3.so libsmime3.so libsoftokn3.so libssl3.so"
+  NSPR_LIBS="libnspr4.so libplc4.so libplds4.so"
+  for LIB in $NSS_LIBS $NSPR_LIBS; do
+    cp -p obj-*/dist/bin/$LIB $MARTOOLS/
+  done
   cd ~/build
   zip -r mar-tools-linux${GBUILD_BITS}.zip mar-tools
   cp -p mar-tools-linux${GBUILD_BITS}.zip $OUTDIR/
diff --git a/gitian/signmars.sh b/gitian/signmars.sh
new file mode 100755
index 0000000..fdb531e
--- /dev/null
+++ b/gitian/signmars.sh
@@ -0,0 +1,135 @@
+#!/bin/bash
+#
+#
+# You may set NSS_DB_DIR and/or NSS_CERTNAME before invoking this script.
+
+set -e
+set -u
+
+WRAPPER_DIR=$(dirname "$0")
+WRAPPER_DIR=$(readlink -e "$WRAPPER_DIR")
+
+if [ -z "${NSS_DB_DIR+x}" ]; then
+  NSS_DB_DIR=$WRAPPER_DIR/nssdb
+fi
+
+if [ -z "${NSS_CERTNAME+x}" ]; then
+  NSS_CERTNAME=marsigner
+fi
+
+# Incorporate definitions from the versions file.
+if [ -z "$1" ]; then
+  VERSIONS_FILE=$WRAPPER_DIR/versions
+else
+  VERSIONS_FILE=$1
+fi
+
+if ! [ -e $VERSIONS_FILE ]; then
+  echo >&2 "Error: $VERSIONS_FILE file does not exist"
+  exit 1
+fi
+
+. $VERSIONS_FILE
+
+export LC_ALL=C
+
+# Check some prerequisites.
+if [ ! -r "$NSS_DB_DIR/cert8.db" ]; then
+  >&2 echo "Please create and populate the $NSS_DB_DIR directory"
+  exit 2
+fi
+
+OSNAME=""
+ARCH="$(uname -s)-$(uname -m)"
+case $ARCH in
+  Linux-x86_64)
+    OSNAME="linux64"
+    ;;
+  Linux-i*86)
+    OSNAME="linux32"
+    ;;
+  *)
+    >&2 echo "Unsupported architecture $ARCH"
+    exit 2
+esac
+
+# Extract the MAR tools so we can use the signmar program.
+MARTOOLS_TMP_DIR=$(mktemp -d)
+trap "rm -rf $MARTOOLS_TMP_DIR" EXIT
+MARTOOLS_ZIP="$WRAPPER_DIR/../../gitian-builder/inputs/mar-tools-${OSNAME}.zip"
+cd $MARTOOLS_TMP_DIR
+unzip -q "$MARTOOLS_ZIP"
+cd $WRAPPER_DIR
+export PATH="$MARTOOLS_TMP_DIR/mar-tools:$PATH"
+if [ -z "${LD_LIBRARY_PATH+x}" ]; then
+  export LD_LIBRARY_PATH="$MARTOOLS_TMP_DIR/mar-tools"
+else
+  export LD_LIBRARY_PATH="$MARTOOLS_TMP_DIR/mar-tools:$LD_LIBRARY_PATH"
+fi
+
+# Prompt for the NSS password.
+# TODO: Test that the entered NSS password is correct.  But how?  Unfortunately,
+# both certutil and signmar keep trying to read a new password when they are
+# given an incorrect one.
+read -s -p "NSS password:" NSSPASS
+echo ""
+
+# Sign each MAR file.
+#
+# Our strategy is to first move all .mar files out of the TORBROWSER_VERSION
+# directory into a TORBROWSER_VERSION-unsigned/ directory.  Details:
+#   If a file has not been signed, we move it to the -unsigned/ directory.
+#   If a file has already been signed and a file with the same name exists in
+#     the -unsigned/ directory, we just delete the signed file.
+#   If a file has already been signed but no corresponding file exists in
+#     the -unsigned/ directory, we report an error and exit.
+#
+# Once the above is done,  the -unsigned/ directory contains a set of .mar
+# files that need to be signed, so we go ahead and sign them one-by-one.
+SIGNED_DIR="$WRAPPER_DIR/$TORBROWSER_VERSION"
+UNSIGNED_DIR="$WRAPPER_DIR/${TORBROWSER_VERSION}-unsigned"
+mkdir -p "$UNSIGNED_DIR"
+cd "$SIGNED_DIR"
+for marfile in *.mar; do
+  if [ ! -f "$marfile" ]; then
+    continue;
+  fi
+
+  # First, we check for an existing signature.  The signmar -T output will
+  # include a line like "Signature block found with N signatures".
+  SIGINFO_PREFIX="Signature block found with "
+  SIGINFO=$(signmar -T "$marfile" | grep "^${SIGINFO_PREFIX}")
+  SIGCOUNT=0
+  if [ ! -z "$SIGINFO" ]; then
+    SIGCOUNT=$(echo $SIGINFO | sed -e "s/${SIGINFO_PREFIX}//" -e 's/\([0-9]*\).*$/\1/')
+  fi
+  if [ $SIGCOUNT -eq 0 ]; then
+    # No signature; move this .mar file to the -unsigned/ directory.
+    mv "$marfile" "$UNSIGNED_DIR/"
+  elif [ -e "$UNSIGNED_DIR/$marfile" ]; then
+    # We have an -unsigned/ copy; discard this file.
+    rm "$marfile"
+  else
+    >&2 echo "Error: $SIGNED_DIR/$marfile is already signed but $UNSIGNED_DIR/$marfile is missing"
+    # TODO: Try to remove the existing signature(s) from marfile?
+    exit 1
+  fi
+done
+
+# Use signmar to sign each .mar file that is now in the -unsigned directory.
+TMPMAR="$SIGNED_DIR/tmp.mar"
+trap "rm -f $TMPMAR" EXIT
+cd "$UNSIGNED_DIR"
+COUNT=0
+for marfile in *.mar; do
+  if [ ! -f "$marfile" ]; then
+    continue;
+  fi
+  echo "$NSSPASS" | signmar -d "$NSS_DB_DIR" -n "$NSS_CERTNAME" -s \
+      "$marfile" "$TMPMAR"
+  mv "$TMPMAR" "$SIGNED_DIR/$marfile"
+  COUNT=$((COUNT + 1))
+done
+
+echo "The $COUNT MAR files located in $SIGNED_DIR/ have been signed."
+echo "The unsigned (original) MAR files are in $UNSIGNED_DIR/"
diff --git a/tools/update-responses/gen_incrementals b/tools/update-responses/gen_incrementals
new file mode 120000
index 0000000..3766925
--- /dev/null
+++ b/tools/update-responses/gen_incrementals
@@ -0,0 +1 @@
+update_responses
\ No newline at end of file
diff --git a/tools/update-responses/update_responses b/tools/update-responses/update_responses
index b28b575..5b85037 100755
--- a/tools/update-responses/update_responses
+++ b/tools/update-responses/update_responses
@@ -1,6 +1,7 @@
 #!/usr/bin/perl -w
 
 use strict;
+use English;
 use FindBin;
 use YAML qw(LoadFile);
 use File::Slurp;
@@ -13,6 +14,7 @@ use File::Which;
 use POSIX qw(setlocale LC_ALL);
 use IO::CaptureOutput qw(capture_exec);
 use Parallel::ForkManager;
+use File::Basename;
 
 # Set umask and locale to provide a consistent environment for MAR file
 # generation, etc.
@@ -158,7 +160,7 @@ sub create_incremental_mar {
     $pm->finish;
 }
 
-sub create_missing_incremental_mars {
+sub create_missing_incremental_mars_for_version {
     my ($config, $version) = @_;
     my $pm = Parallel::ForkManager->new(get_nbprocs);
     $pm->run_on_finish(sub { $_[2]->(@_) });
@@ -178,6 +180,14 @@ sub create_missing_incremental_mars {
     $pm->wait_all_children;
 }
 
+sub create_all_missing_incremental_mars {
+    my ($config) = @_;
+    foreach my $version (values %{$config->{channels}}) {
+        get_version_files($config, $version);
+        create_missing_incremental_mars_for_version($config, $version);
+    }
+}
+
 sub get_config {
     my ($config, $version, $os, $name) = @_;
     return $config->{versions}{$version}{$os}{$name}
@@ -224,7 +234,6 @@ sub write_responses {
     my ($config) = @_;
     foreach my $version (values %{$config->{channels}}) {
         get_version_files($config, $version);
-        create_missing_incremental_mars($config, $version);
         my $files = $config->{versions}{$version}{files};
         my $migrate_archs = $config->{versions}{$version}{migrate_archs} // {};
         foreach my $old_os (keys %$migrate_archs) {
@@ -309,8 +318,19 @@ sub extract_martools {
     $ENV{PATH} .= ":$martools_tmpdir/mar-tools";
 }
 
-extract_martools;
-check_deps;
-write_responses($config);
-write_htaccess($config);
-clean_htdocs;
+my %actions = (
+    update_responses => sub {
+        write_responses(@_);
+        write_htaccess(@_);
+        clean_htdocs;
+    },
+    gen_incrementals => sub {
+        extract_martools;
+        check_deps;
+        create_all_missing_incremental_mars(@_);
+    },
+);
+
+my $action = fileparse($PROGRAM_NAME);
+exit_error "Unknown action $action" unless $actions{$action};
+$actions{$action}->($config);



More information about the tor-commits mailing list