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