xref: /aosp_15_r20/external/vboot_reference/scripts/image_signing/sign_firmware.sh (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1#!/bin/bash
2# Copyright 2011 The ChromiumOS Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6# Wrapper script for re-signing a firmware image.
7
8# Determine script directory.
9SCRIPT_DIR=$(dirname "$0")
10
11# Load common constants and variables.
12. "${SCRIPT_DIR}/common_minimal.sh"
13. "${SCRIPT_DIR}/lib/keycfg.sh"
14
15# Abort on error.
16set -e
17
18usage() {
19  cat<<EOF
20Usage: $0 <input_firmware> <key_dir> <output_firmware> [firmware_version] \
21[loem_output_dir]
22
23Signs <input_firmware> with keys in <key_dir>, setting firmware version
24to <firmware_version>. Outputs signed firmware to <output_firmware>.
25The <input_firmware> and <output_firmware> paths may be the same.
26If no firmware version is specified, it is set as 1.
27EOF
28  exit 1
29}
30
31gbb_update() {
32  local in_firmware="$1"
33  local key_dir="$2"
34  local out_firmware="$3"
35  local rootkey="$4"
36
37  # Replace the root and recovery key in the Google Binary Block of the
38  # firmware.  Note: This needs to happen after calling resign_firmwarefd.sh
39  # since it needs to be able to verify the firmware using the root key to
40  # determine the preamble flags.
41  futility gbb \
42    -s \
43    --recoverykey="${KEYCFG_RECOVERY_KEY_VBPUBK}" \
44    --rootkey="${rootkey}" \
45    "${in_firmware}" \
46    "${out_firmware}"
47}
48
49# Sign a single firmware image.
50# ARGS: [key_dir] [loem_index] [loemid]
51sign_one() {
52  local key_dir="$1"
53  local loem_index="$2"
54  local loemid="$3"
55
56  # Resign the firmware with new keys.
57  "${SCRIPT_DIR}/resign_firmwarefd.sh" \
58    "${in_firmware}" \
59    "${temp_fw}" \
60    "$(get_firmware_vbprivk "${loem_index}")" \
61    "$(get_firmware_keyblock "${loem_index}")" \
62    "${KEYCFG_KERNEL_SUBKEY_VBPUBK}" \
63    "${firmware_version}" \
64    "" \
65    "${loem_output_dir}" \
66    "${loemid}"
67}
68
69# Process all the keysets in the loem.ini file.
70# ARGS: [key_dir]
71sign_loems() {
72  local key_dir="$1"
73  local line loem_section=false loem_index loemid
74  local rootkey
75
76  while read line; do
77    # Find the [loem] section.
78    if ! ${loem_section}; then
79      if grep -q "^ *\[loem\] *$" <<<"${line}"; then
80        loem_section=true
81      fi
82      continue
83    # Abort when we hit the next section.
84    elif [[ ${line} == *"["* ]]; then
85      break
86    fi
87
88    # Strip comments/whitespace.
89    line=$(sed -e 's:#.*::' -e 's:^ *::' -e 's: *$::' <<<"${line}")
90    if [[ -z "${line}" ]]; then
91      # Skip blank lines.
92      continue
93    fi
94
95    loem_index=$(cut -d= -f1 <<<"${line}" | sed 's: *$::')
96    loemid=$(cut -d= -f2 <<<"${line}" | sed 's:^ *::')
97
98    echo "### Processing LOEM ${loem_index} ${loemid}"
99    sign_one "${key_dir}" "${loem_index}" "${loemid}"
100
101    rootkey="$(get_root_key_vbpubk "${key_index}")"
102    cp "${rootkey}" "${loem_output_dir}/rootkey.${loemid}"
103
104    if [[ ${loem_index} == "1" ]]; then
105      gbb_update "${temp_fw}" "${key_dir}" "${out_firmware}" "${rootkey}"
106    fi
107    echo
108  done <"${key_dir}/loem.ini"
109}
110
111main() {
112  if [[ $# -lt 3 || $# -gt 5 ]]; then
113    usage
114  fi
115
116  local in_firmware=$1
117  local key_dir=$2
118  local out_firmware=$3
119  local firmware_version=${4:-1}
120  local loem_output_dir=${5:-}
121
122  local temp_fw=$(make_temp_file)
123
124  setup_keycfg "${key_dir}"
125  if [[ -e ${key_dir}/loem.ini ]]; then
126    if [[ -z ${loem_output_dir} ]]; then
127      die "need loem_output_dir w/loem keysets"
128    fi
129    sign_loems "${key_dir}"
130  else
131    sign_one "${key_dir}"
132    gbb_update "${temp_fw}" "${key_dir}" "${out_firmware}" \
133      "$(get_root_key_vbpubk)"
134  fi
135}
136main "$@"
137