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 8 SCRIPT_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) 22 function alg_to_keylen { 23 echo $(( 1 << (10 + ($1 / 3)) )) 24 } 25 26 # Default algorithms. 27 EC_ROOT_KEY_ALGOID=7 28 EC_DATAKEY_ALGOID=7 29 30 ROOT_KEY_ALGOID=11 31 RECOVERY_KEY_ALGOID=11 32 33 FIRMWARE_DATAKEY_ALGOID=7 34 DEV_FIRMWARE_DATAKEY_ALGOID=7 35 36 RECOVERY_KERNEL_ALGOID=11 37 INSTALLER_KERNEL_ALGOID=11 38 KERNEL_SUBKEY_ALGOID=7 39 KERNEL_DATAKEY_ALGOID=4 40 41 # Keyblock modes determine which boot modes a signing key is valid for use 42 # in verification. 43 EC_KEYBLOCK_MODE=7 # Only allow RW EC firmware in non-recovery. 44 FIRMWARE_KEYBLOCK_MODE=7 # Only allow RW firmware in non-recovery. 45 DEV_FIRMWARE_KEYBLOCK_MODE=6 # Only allow in dev mode. 46 RECOVERY_KERNEL_KEYBLOCK_MODE=11 # Only in recovery mode. 47 KERNEL_KEYBLOCK_MODE=7 # Only allow in non-recovery. 48 INSTALLER_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. 56 function 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 96 function 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. 118 VERSION_FILE="key.versions" 119 120 # ARGS: <VERSION_TYPE> [VERSION_FILE] 121 get_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 127 load_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 141 Current Firmware key version: ${CURR_FIRMKEY_VER} 142 Current Firmware version: ${CURR_FIRM_VER} 143 Current Kernel key version: ${CURR_KERNKEY_VER} 144 Current Kernel version: ${CURR_KERN_VER} 145 EOF 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 152 backup_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 164 backup_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 179 backup_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 194 backup_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 206 write_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 213 firmware_key_version=${firmware_key_version} 214 firmware_version=${firmware_version} 215 kernel_key_version=${kernel_key_version} 216 kernel_version=${kernel_version} 217 EOF 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> 224 increment_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