diff options
-rwxr-xr-x | scripts/image_signing/sign_official_build.sh | 121 |
1 files changed, 91 insertions, 30 deletions
diff --git a/scripts/image_signing/sign_official_build.sh b/scripts/image_signing/sign_official_build.sh index 340c95ed..de73504a 100755 --- a/scripts/image_signing/sign_official_build.sh +++ b/scripts/image_signing/sign_official_build.sh @@ -196,22 +196,29 @@ calculate_rootfs_hash() { } # Re-calculate rootfs hash, update rootfs and kernel command line(s). -# Args: LOOPDEV KERNEL KERN_A_KEYBLOCK KERN_A_PRIVKEY KERN_B_KEYBLOCK \ -# KERN_B_PRIVKEY +# Args: LOOPDEV KERNEL \ +# KERN_A_KEYBLOCK KERN_A_PRIVKEY \ +# KERN_B_KEYBLOCK KERN_B_PRIVKEY SHOULD_SIGN_KERN_B \ +# KERN_C_KEYBLOCK KERN_C_PRIVKEY SHOULD_SIGN_KERN_C # # The rootfs is hashed by tool 'verity', and the hash data is stored after the # rootfs. A hash of those hash data (also known as final verity hash) may be # contained in kernel 2 or kernel 4 command line. # # This function reads dm-verity configuration from KERNEL, rebuilds the rootfs -# hash, and then resigns kernel A & B by their keyblock and private key files. +# hash, and then resigns kernel A & B (& C if needed) by their keyblock and +# private key files. update_rootfs_hash() { local loopdev="$1" # Input image. local loop_kern="$2" # Kernel that contains verity args. local kern_a_keyblock="$3" # Keyblock file for kernel A. local kern_a_privkey="$4" # Private key file for kernel A. local kern_b_keyblock="$5" # Keyblock file for kernel B. - local kern_b_privkey="$6" # Private key file for kernel A. + local kern_b_privkey="$6" # Private key file for kernel B. + local should_sign_kern_b="$7" + local kern_c_keyblock="$8" # Keyblock file for kernel C. + local kern_c_privkey="$9" # Private key file for kernel C. + local should_sign_kern_c="${10}" local loop_rootfs="${loopdev}p3" # Note even though there are two kernels, there is one place (after rootfs) @@ -274,7 +281,7 @@ update_rootfs_hash() { local priv_key= local new_kernel_config= - for kernelpart in 2 4; do + for kernelpart in 2 4 6; do loop_kern="${loopdev}p${kernelpart}" if ! new_kernel_config="$( sudo "${FUTILITY}" dump_kernel_config "${loop_kern}" 2>/dev/null)" && @@ -283,6 +290,14 @@ update_rootfs_hash() { info "Skipping empty kernel partition 4 (legacy images)." continue fi + if [[ "${should_sign_kern_b}" == "false" && "${kernelpart}" == 4 ]]; then + info "Skip signing kernel B." + continue + fi + if [[ "${should_sign_kern_c}" == "false" && "${kernelpart}" == 6 ]]; then + info "Skip signing kernel C." + continue + fi # shellcheck disable=SC2001 new_kernel_config="$(echo "${new_kernel_config}" | sed -e 's#\(.*dm="\)\([^"]*\)\(".*\)'"#\1${dm_args}\3#g")" @@ -292,9 +307,12 @@ update_rootfs_hash() { if [[ "${kernelpart}" == 2 ]]; then keyblock="${kern_a_keyblock}" priv_key="${kern_a_privkey}" - else + elif [[ "${kernelpart}" == 4 ]]; then keyblock="${kern_b_keyblock}" priv_key="${kern_b_privkey}" + else + keyblock="${kern_c_keyblock}" + priv_key="${kern_c_privkey}" fi sudo "${FUTILITY}" vbutil_kernel --repack "${loop_kern}" \ --keyblock "${keyblock}" \ @@ -934,18 +952,22 @@ EOF } # Re-calculate recovery kernel hash. -# Args: LOOPDEV +# Args: LOOPDEV RECOVERY_KERNEL_PARTITION KEYBLOCK PRIVKEY update_recovery_kernel_hash() { local loopdev="$1" - local loop_kerna="${loopdev}p2" + local recovery_kernel_partition="$2" + local keyblock="$3" + local privkey="$4" + + local loop_recovery_kernel="${loopdev}p${recovery_kernel_partition}" local loop_kernb="${loopdev}p4" - # Update the Kernel B hash in Kernel A command line - local old_kerna_config - old_kerna_config="$(sudo "${FUTILITY}" \ - dump_kernel_config "${loop_kerna}")" + # Update the kernel B hash in the recovery kernel command line. + local old_kernel_config + old_kernel_config="$(sudo "${FUTILITY}" \ + dump_kernel_config "${loop_recovery_kernel}")" local old_kernb_hash - old_kernb_hash="$(echo "${old_kerna_config}" | + old_kernb_hash="$(echo "${old_kernel_config}" | sed -nEe "s#.*kern_b_hash=([a-z0-9]*).*#\1#p")" local new_kernb_hash if [[ "${#old_kernb_hash}" -lt 64 ]]; then @@ -954,21 +976,21 @@ update_recovery_kernel_hash() { new_kernb_hash=$(sudo sha256sum "${loop_kernb}" | cut -f1 -d' ') fi - new_kerna_config=$(make_temp_file) + new_kernel_config=$(make_temp_file) # shellcheck disable=SC2001 - echo "${old_kerna_config}" | + echo "${old_kernel_config}" | sed -e "s#\(kern_b_hash=\)[a-z0-9]*#\1${new_kernb_hash}#" \ - > "${new_kerna_config}" - info "New config for kernel partition 2 is" - cat "${new_kerna_config}" + > "${new_kernel_config}" + info "New config for kernel partition ${recovery_kernel_partition} is" + cat "${new_kernel_config}" # Re-calculate kernel partition signature and command line. - sudo "${FUTILITY}" vbutil_kernel --repack "${loop_kerna}" \ - --keyblock "${KEY_DIR}"/recovery_kernel.keyblock \ - --signprivate "${KEY_DIR}"/recovery_kernel_data_key.vbprivk \ + sudo "${FUTILITY}" vbutil_kernel --repack "${loop_recovery_kernel}" \ + --keyblock "${keyblock}" \ + --signprivate "${privkey}" \ --version "${KERNEL_VERSION}" \ - --oldblob "${loop_kerna}" \ - --config "${new_kerna_config}" + --oldblob "${loop_recovery_kernel}" \ + --config "${new_kernel_config}" } # Re-sign miniOS kernels with new keys. @@ -1072,7 +1094,8 @@ update_legacy_bootloader() { # Sign an image file with proper keys. # Args: IMAGE_TYPE INPUT OUTPUT DM_PARTNO KERN_A_KEYBLOCK KERN_A_PRIVKEY \ -# KERN_B_KEYBLOCK KERN_B_PRIVKEY MINIOS_KEYBLOCK MINIOS_PRIVKEY +# KERN_B_KEYBLOCK KERN_B_PRIVKEY KERN_C_KEYBLOCK KERN_C_PRIVKEY \ +# MINIOS_KEYBLOCK MINIOS_PRIVKEY # # A ChromiumOS image file (INPUT) always contains 2 partitions (kernel A & B). # This function will rebuild hash data by DM_PARTNO, resign kernel partitions by @@ -1080,6 +1103,8 @@ update_legacy_bootloader() { # special images (specified by IMAGE_TYPE, like 'recovery' or 'factory_install') # may have additional steps (ex, tweaking verity hash or not stripping files) # when generating output file. +# Some recovery images also have a kernel C, which is identical to kernel A, +# but signed with a different key (see b/266502803). sign_image_file() { local image_type="$1" local input="$2" @@ -1089,8 +1114,10 @@ sign_image_file() { local kernA_privkey="$6" local kernB_keyblock="$7" local kernB_privkey="$8" - local minios_keyblock="$9" - local minios_privkey="${10}" + local kernC_keyblock="$9" + local kernC_privkey="${10}" + local minios_keyblock="${11}" + local minios_privkey="${12}" info "Preparing ${image_type} image..." cp --sparse=always "${input}" "${output}" @@ -1102,6 +1129,28 @@ sign_image_file() { local is_reven is_reven=$(get_is_reven "${loopdev}") + # b/266502803: Some devices have a second recovery key which is used to sign: + # - a second recovery kernel KERN-C in recovery images + # - a second installer kernel KERN-B in factory images + # If a device does not have a second recovery key, then these additional + # kernels are not signed. If they are present, they will remain in the image + # signed with dev keys. + # + # Sign KERN-B unless it's a factory image and this device doesn't have a + # second recovery key. + local should_sign_kernB="true" + if [[ "${image_type}" == "factory_install" && + ! -f "${kernB_keyblock}" ]]; then + should_sign_kernB="false" + fi + # Sign KERN-C unless this image type doesn't have KERN-C, or it's a + # recovery image and this device doesn't have a second recovery key. + local should_sign_kernC="true" + if [[ -z "${kernC_keyblock}" || + ( "${image_type}" == "recovery" && ! -f "${kernC_keyblock}" ) ]]; then + should_sign_kernC="false" + fi + # The reven board needs to produce recovery images since some # downstream tools (e.g. the Chromebook Recovery Utility) expect # them. However, reven's recovery images are not like other boards @@ -1142,11 +1191,17 @@ sign_image_file() { fi update_rootfs_hash "${loopdev}" "${loop_kern}" \ "${kernA_keyblock}" "${kernA_privkey}" \ - "${kernB_keyblock}" "${kernB_privkey}" + "${kernB_keyblock}" "${kernB_privkey}" "${should_sign_kernB}" \ + "${kernC_keyblock}" "${kernC_privkey}" "${should_sign_kernC}" update_stateful_partition_vblock "${loopdev}" if [[ "${image_type}" == "recovery" && "${sign_recovery_like_base}" == "false" ]]; then - update_recovery_kernel_hash "${loopdev}" + update_recovery_kernel_hash "${loopdev}" 2 "${kernA_keyblock}" \ + "${kernA_privkey}" + if [[ "${should_sign_kernC}" == "true" ]]; then + update_recovery_kernel_hash "${loopdev}" 6 "${kernC_keyblock}" \ + "${kernC_privkey}" + fi fi if ! resign_minios_kernels "${loopdev}" "${minios_keyblock}" \ "${minios_privkey}"; then @@ -1203,6 +1258,8 @@ if [[ "${TYPE}" == "base" ]]; then "${KEY_DIR}/kernel_data_key.vbprivk" \ "${KEY_DIR}/kernel.keyblock" \ "${KEY_DIR}/kernel_data_key.vbprivk" \ + "" \ + "" \ "${KEY_DIR}/minios_kernel.keyblock" \ "${KEY_DIR}/minios_kernel_data_key.vbprivk" elif [[ "${TYPE}" == "recovery" ]]; then @@ -1211,14 +1268,18 @@ elif [[ "${TYPE}" == "recovery" ]]; then "${KEY_DIR}/recovery_kernel_data_key.vbprivk" \ "${KEY_DIR}/kernel.keyblock" \ "${KEY_DIR}/kernel_data_key.vbprivk" \ + "${KEY_DIR}/recovery_kernel.v1.keyblock" \ + "${KEY_DIR}/recovery_kernel_data_key.vbprivk" \ "${KEY_DIR}/minios_kernel.keyblock" \ "${KEY_DIR}/minios_kernel_data_key.vbprivk" elif [[ "${TYPE}" == "factory" ]]; then sign_image_file "factory_install" "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" 2 \ "${KEY_DIR}/installer_kernel.keyblock" \ "${KEY_DIR}/installer_kernel_data_key.vbprivk" \ - "${KEY_DIR}/kernel.keyblock" \ - "${KEY_DIR}/kernel_data_key.vbprivk" \ + "${KEY_DIR}/installer_kernel.v1.keyblock" \ + "${KEY_DIR}/installer_kernel_data_key.vbprivk" \ + "" \ + "" \ "${KEY_DIR}/minios_kernel.keyblock" \ "${KEY_DIR}/minios_kernel_data_key.vbprivk" elif [[ "${TYPE}" == "firmware" ]]; then |