Add tool for generating bios image tarball

Adding a gen-bios-tar tool for generating a bios image tarball from given bios
image file as input along with version, machine name parameter. It creates a
MANIFEST for image verification and recreation. It also packages the image and
MANIFEST together in a tarball.

Currently machine name is optional but it will become mandatory in future.

This tarball is required for bios upgrade through image updater

Tested: Verified this with actual image.

Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
Change-Id: I6e9ec57d2b38c9e144bd725026c64106d16c6a6f
diff --git a/gen-bios-tar b/gen-bios-tar
new file mode 100755
index 0000000..d0ddd8e
--- /dev/null
+++ b/gen-bios-tar
@@ -0,0 +1,170 @@
+#!/bin/bash
+set -eo pipefail
+
+help=$'Generate Tarball with Bios image and MANIFEST Script
+
+Generates a Bios image tarball from given file as input.
+Creates a MANIFEST for image verification and recreation
+Packages the image and MANIFEST together in a tarball
+
+usage: gen-bios-tar [OPTION] <Bios FILE>...
+
+Options:
+   -o, --out <file>       Specify destination file. Defaults to
+                          `pwd`/obmc-bios.tar.gz if unspecified.
+   -s, --sign <path>      Sign the image. The optional path argument specifies
+                          the private key file. Defaults to the bash variable
+                          PRIVATE_KEY_PATH if available, or else uses the
+                          open-source private key in this script.
+   -m, --machine <name>   Optionally specify the target machine name of this
+                          image.
+   -v, --version <name>   Specify the version of bios image file
+   -h, --help             Display this help text and exit.
+'
+
+#################################################################
+# It's the OpenBMC "public" private key (currently under
+# meta-phosphor/recipes-phosphor/flash/files/OpenBMC.priv):
+# https://gerrit.openbmc-project.xyz/c/openbmc/openbmc/+/8949/15/
+# meta-phosphor/common/recipes-phosphor/flash/files/OpenBMC.priv
+#
+#################################################################
+private_key=$'-----BEGIN PRIVATE KEY-----
+MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAPvSDLu6slkP1gri
+PaeQXL9ysD69J/HjbBCIQ0RPfeWBb75US1tRTjPP0Ub8CtH8ExVf8iF1ulsZA78B
+zIjBYZVp9pyD6LbpZ/hjV7rIH6dTNhoVpdA+F8LzmQ7cyhHG8l2JMvdunwF2uX5k
+D4WDcZt/ITKZNQNavPtmIyD5HprdAgMBAAECgYEAuQkTSi5ZNpAoWz76xtGRFSwU
+zUT4wQi3Mz6tDtjKTYXasiQGa0dHC1M9F8fDu6BZ9W7W4Dc9hArRcdzEighuxoI/
+nZI/0uL89iUEywnDEIHuS6D5JlZaj86/nx9YvQnO8F/seM+MX0EAWVrd5wC7aAF1
+h6Fu7ykZB4ggUjQAWwECQQD+AUiDOEO+8btLJ135dQfSGc5VFcZiequnKWVm6uXt
+rX771hEYjYMjLqWGFg9G4gE3GuABM5chMINuQQUivy8tAkEA/cxfy19XkjtqcMgE
+x/UDt6Nr+Ky/tk+4Y65WxPRDas0uxFOPk/vEjgVmz1k/TAy9G4giisluTvtmltr5
+DCLocQJBAJnRHx9PiD7uVhRJz6/L/iNuOzPtTsi+Loq5F83+O6T15qsM1CeBMsOw
+cM5FN5UeMcwz+yjfHAsePMkcmMaU7jUCQHlg9+N8upXuIo7Dqj2zOU7nMmkgvSNE
+5yuNImRZabC3ZolwaTdd7nf5r1y1Eyec5Ag5yENV6JKPe1Xkbb1XKJECQDngA0h4
+6ATvfP1Vrx4CbP11eKXbCsZ9OGPHSgyvVjn68oY5ZP3uPsIattoN7dE2BRfuJm7m
+F0nIdUAhR0yTfKM=
+-----END PRIVATE KEY-----
+'
+
+do_sign=false
+private_key_path="${PRIVATE_KEY_PATH}"
+outfile=""
+machine=""
+version=""
+
+while [[ $# -gt 0 ]]; do
+  key="$1"
+  case $key in
+    -o|--out)
+      outfile="$2"
+      shift 2
+      ;;
+    -s|--sign)
+      do_sign=true
+      if [[ ! -z "${2}"  && "${2}" != -* ]]; then
+        private_key_path="$2"
+        shift 2
+      else
+        shift 1
+      fi
+      ;;
+    -m|--machine)
+      machine="$2"
+      shift 2
+      ;;
+    -v|--version)
+      version="$2"
+      shift 2
+      ;;
+    -h|--help)
+      echo "$help"
+      exit
+      ;;
+    -*)
+      echo "Unrecognised option $1"
+      echo "$help"
+      exit
+      ;;
+    *)
+      file="$1"
+      shift 1
+      ;;
+  esac
+done
+
+if [ ! -f "${file}" ]; then
+  echo "${file} not found, Please enter a valid Bios image file"
+  echo "$help"
+  exit 1
+fi
+
+if [[ -z $version ]]; then
+  echo "Please provide version of image with -v option"
+  exit 1
+fi
+
+if [[ -z $outfile ]]; then
+  outfile=`pwd`/obmc-bios.tar.gz
+else
+  if [[ $outfile != /* ]]; then
+    outfile=`pwd`/$outfile
+  fi
+fi
+
+scratch_dir=`mktemp -d`
+# Remove the temp directory on exit.
+# The files in the temp directory may contain read-only files, so add
+# --interactive=never to skip the prompt.
+trap "{ rm -r --interactive=never ${scratch_dir}; }" EXIT
+
+if [[ "${do_sign}" == true ]]; then
+  if [[ -z "${private_key_path}" ]]; then
+    private_key_path=${scratch_dir}/OpenBMC.priv
+    echo "${private_key}" > "${private_key_path}"
+    echo "Image is NOT secure!! Signing with the open private key!"
+  else
+    if [[ ! -f "${private_key_path}" ]]; then
+      echo "Couldn't find private key ${private_key_path}."
+      exit 1
+    fi
+
+    echo "Signing with ${private_key_path}."
+  fi
+
+  public_key_file=publickey
+  public_key_path=${scratch_dir}/$public_key_file
+  openssl pkey -in "${private_key_path}" -pubout -out ${public_key_path}
+fi
+
+manifest_location="MANIFEST"
+files_to_sign="$manifest_location $public_key_file"
+
+# Go to scratch_dir
+cp ${file} ${scratch_dir}
+cd "${scratch_dir}"
+files_to_sign+=" $(basename ${file})"
+
+echo "Creating MANIFEST for the image"
+echo -e "purpose=xyz.openbmc_project.Software.Version.VersionPurpose.Host\n\
+version=$version" > $manifest_location
+
+if [[ ! -z "${machine}" ]]; then
+    echo -e "MachineName=${machine}" >> $manifest_location
+fi
+
+if [[ "${do_sign}" == true ]]; then
+  private_key_name=$(basename "${private_key_path}")
+  key_type="${private_key_name%.*}"
+  echo KeyType="${key_type}" >> $manifest_location
+  echo HashType="RSA-SHA256" >> $manifest_location
+
+  for file in $files_to_sign; do
+    openssl dgst -sha256 -sign ${private_key_path} -out "${file}.sig" $file
+  done
+
+  additional_files="*.sig"
+fi
+
+tar -czvf $outfile $files_to_sign $additional_files
+echo "Bios image tarball is at $outfile"