1#!/bin/bash 2# Copyright (c) 2011 The Chromium OS Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6# Common key generation functions. 7 8SCRIPT_DIR="$(dirname "$0")" 9 10# 0 = (RSA1024 SHA1) 11# 1 = (RSA1024 SHA256) 12# 2 = (RSA1024 SHA512) 13# 3 = (RSA2048 SHA1) 14# 4 = (RSA2048 SHA256) 15# 5 = (RSA2048 SHA512) 16# 6 = (RSA4096 SHA1) 17# 7 = (RSA4096 SHA256) 18# 8 = (RSA4096 SHA512) 19# 9 = (RSA8192 SHA1) 20# 10 = (RSA8192 SHA256) 21# 11 = (RSA8192 SHA512) 22function alg_to_keylen { 23 echo $(( 1 << (10 + ($1 / 3)) )) 24} 25 26# Default algorithms. 27EC_ROOT_KEY_ALGOID=7 28EC_DATAKEY_ALGOID=7 29 30ROOT_KEY_ALGOID=11 31RECOVERY_KEY_ALGOID=11 32 33FIRMWARE_DATAKEY_ALGOID=7 34DEV_FIRMWARE_DATAKEY_ALGOID=7 35 36RECOVERY_KERNEL_ALGOID=11 37INSTALLER_KERNEL_ALGOID=11 38KERNEL_SUBKEY_ALGOID=7 39KERNEL_DATAKEY_ALGOID=4 40 41# Keyblock modes determine which boot modes a signing key is valid for use 42# in verification. 43EC_KEYBLOCK_MODE=7 # Only allow RW EC firmware in non-recovery. 44FIRMWARE_KEYBLOCK_MODE=7 # Only allow RW firmware in non-recovery. 45DEV_FIRMWARE_KEYBLOCK_MODE=6 # Only allow in dev mode. 46RECOVERY_KERNEL_KEYBLOCK_MODE=11 # Only in recovery mode. 47KERNEL_KEYBLOCK_MODE=7 # Only allow in non-recovery. 48INSTALLER_KERNEL_KEYBLOCK_MODE=10 # Only allow in Dev + Recovery. 49 50# Emit .vbpubk and .vbprivk using given basename and algorithm 51# NOTE: This function also appears in ../../utility/dev_make_keypair. Making 52# the two implementations the same would require some common.sh, which is more 53# likely to cause problems than just keeping an eye out for any differences. If 54# you feel the need to change this file, check the history of that other file 55# to see what may need updating here too. 56function make_pair { 57 local base=$1 58 local alg=$2 59 local key_version=${3:-1} 60 local len=$(alg_to_keylen $alg) 61 62 echo "creating $base keypair (version = $key_version)..." 63 64 # make the RSA keypair 65 openssl genrsa -F4 -out "${base}_${len}.pem" $len 66 # create a self-signed certificate 67 openssl req -batch -new -x509 -key "${base}_${len}.pem" \ 68 -out "${base}_${len}.crt" 69 # generate pre-processed RSA public key 70 dumpRSAPublicKey -cert "${base}_${len}.crt" > "${base}_${len}.keyb" 71 72 # wrap the public key 73 vbutil_key \ 74 --pack "${base}.vbpubk" \ 75 --key "${base}_${len}.keyb" \ 76 --version "${key_version}" \ 77 --algorithm $alg 78 79 # wrap the private key 80 vbutil_key \ 81 --pack "${base}.vbprivk" \ 82 --key "${base}_${len}.pem" \ 83 --algorithm $alg 84 85 # remove intermediate files 86 rm -f "${base}_${len}.pem" "${base}_${len}.crt" "${base}_${len}.keyb" 87} 88 89 90# Emit a .keyblock containing flags and a public key, signed by a private key 91# flags are the bitwise OR of these (passed in decimal, though) 92# 0x01 Developer switch off 93# 0x02 Developer switch on 94# 0x04 Not recovery mode 95# 0x08 Recovery mode 96function make_keyblock { 97 local base=$1 98 local flags=$2 99 local pubkey=$3 100 local signkey=$4 101 102 echo "creating $base keyblock..." 103 104 # create it 105 vbutil_keyblock \ 106 --pack "${base}.keyblock" \ 107 --flags $flags \ 108 --datapubkey "${pubkey}.vbpubk" \ 109 --signprivate "${signkey}.vbprivk" 110 111 # verify it 112 vbutil_keyblock \ 113 --unpack "${base}.keyblock" \ 114 --signpubkey "${signkey}.vbpubk" 115} 116 117# File to read current versions from. 118VERSION_FILE="key.versions" 119 120# ARGS: <VERSION_TYPE> [VERSION_FILE] 121get_version() { 122 awk -F= '/^'$1'\>/ { print $NF }' "${2:-${VERSION_FILE}}" 123} 124 125# Loads the current versions prints them to stdout and sets the global version 126# variables: CURR_FIRMKEY_VER CURR_FIRM_VER CURR_KERNKEY_VER CURR_KERN_VER 127load_current_versions() { 128 local key_dir=$1 129 local VERSION_FILE="${key_dir}/${VERSION_FILE}" 130 if [[ ! -f ${VERSION_FILE} ]]; then 131 return 1 132 fi 133 CURR_FIRMKEY_VER=$(get_version "firmware_key_version") 134 # Firmware version is the kernel subkey version. 135 CURR_FIRM_VER=$(get_version "firmware_version") 136 # Kernel data key version is the kernel key version. 137 CURR_KERNKEY_VER=$(get_version "kernel_key_version") 138 CURR_KERN_VER=$(get_version "kernel_version") 139 140 cat <<EOF 141Current Firmware key version: ${CURR_FIRMKEY_VER} 142Current Firmware version: ${CURR_FIRM_VER} 143Current Kernel key version: ${CURR_KERNKEY_VER} 144Current Kernel version: ${CURR_KERN_VER} 145EOF 146} 147 148# Make backups of existing kernel subkeys and keyblocks that will be revved. 149# Backup format: 150# for keyblocks: <keyblock_name>.v<datakey version>.v<subkey version>.keyblock 151# Args: SUBKEY_VERSION DATAKEY_VERSION 152backup_existing_kernel_keyblock() { 153 if [[ ! -e kernel.keyblock ]]; then 154 return 155 fi 156 mv --no-clobber kernel.{keyblock,"v$2.v$1.keyblock"} 157} 158 159# Make backups of existing kernel subkeys and keyblocks that will be revved. 160# Backup format: 161# for keys: <key_name>.v<version>.vb{pub|priv}k 162# for keyblocks: <keyblock_name>.v<datakey version>.v<subkey version>.keyblock 163# Args: SUBKEY_VERSION DATAKEY_VERSION 164backup_existing_kernel_subkeys() { 165 local subkey_ver=$1 166 local datakey_ver=$2 167 # --no-clobber to prevent accidentally overwriting existing 168 # backups. 169 mv --no-clobber kernel_subkey.{vbprivk,"v${subkey_ver}.vbprivk"} 170 mv --no-clobber kernel_subkey.{vbpubk,"v${subkey_ver}.vbpubk"} 171 backup_existing_kernel_keyblock ${subkey_ver} ${datakey_ver} 172} 173 174# Make backups of existing kernel data keys and keyblocks that will be revved. 175# Backup format: 176# for keys: <key_name>.v<version>.vb{pub|priv}k 177# for keyblocks: <keyblock_name>.v<datakey version>.v<subkey version>.keyblock 178# Args: SUBKEY_VERSION DATAKEY_VERSION 179backup_existing_kernel_data_keys() { 180 local subkey_ver=$1 181 local datakey_ver=$2 182 # --no-clobber to prevent accidentally overwriting existing 183 # backups. 184 mv --no-clobber kernel_data_key.{vbprivk,"v${datakey_ver}.vbprivk"} 185 mv --no-clobber kernel_data_key.{vbpubk,"v${datakey_ver}.vbpubk"} 186 backup_existing_kernel_keyblock ${subkey_ver} ${datakey_ver} 187} 188 189# Make backups of existing firmware keys and keyblocks that will be revved. 190# Backup format: 191# for keys: <key_name>.v<version>.vb{pub|priv}k 192# for keyblocks: <keyblock_name>.v<datakey version>.v<subkey version>.keyblock 193# Args: SUBKEY_VERSION DATAKEY_VERSION 194backup_existing_firmware_keys() { 195 local subkey_ver=$1 196 local datakey_ver=$2 197 mv --no-clobber firmware_data_key.{vbprivk,"v${subkey_ver}.vbprivk"} 198 mv --no-clobber firmware_data_key.{vbpubk,"v${subkey_ver}.vbpubk"} 199 mv --no-clobber firmware.{keyblock,"v${datakey_ver}.v${subkey_ver}.keyblock"} 200} 201 202 203# Write new key version file with the updated key versions. 204# Args: FIRMWARE_KEY_VERSION FIRMWARE_VERSION KERNEL_KEY_VERSION 205# KERNEL_VERSION 206write_updated_version_file() { 207 local firmware_key_version=$1 208 local firmware_version=$2 209 local kernel_key_version=$3 210 local kernel_version=$4 211 212 cat > ${VERSION_FILE} <<EOF 213firmware_key_version=${firmware_key_version} 214firmware_version=${firmware_version} 215kernel_key_version=${kernel_key_version} 216kernel_version=${kernel_version} 217EOF 218} 219 220# Returns the incremented version number of the passed in key from the version 221# file. The options are "firmware_key_version", "firmware_version", 222# "kernel_key_version", or "kernel_version". 223# ARGS: KEY_DIR <key_name> 224increment_version() { 225 local key_dir=$1 226 local VERSION_FILE="${key_dir}/${VERSION_FILE}" 227 local old_version=$(get_version $2) 228 local new_version=$(( ${old_version} + 1 )) 229 230 if [[ ${new_version} -gt 0xffff ]]; then 231 echo "Version overflow!" >&2 232 return 1 233 fi 234 echo ${new_version} 235} 236