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 # Algorithm ID mappings: 11 RSA1024_SHA1_ALGOID=0 12 RSA1024_SHA256_ALGOID=1 13 RSA1024_SHA512_ALGOID=2 14 RSA2048_SHA1_ALGOID=3 15 RSA2048_SHA256_ALGOID=4 16 RSA2048_SHA512_ALGOID=5 17 RSA4096_SHA1_ALGOID=6 18 RSA4096_SHA256_ALGOID=7 19 RSA4096_SHA512_ALGOID=8 20 RSA8192_SHA1_ALGOID=9 21 RSA8192_SHA256_ALGOID=10 22 RSA8192_SHA512_ALGOID=11 23 alg_to_keylen() { 24 echo $(( 1 << (10 + ($1 / 3)) )) 25 } 26 27 # Default algorithms. 28 EC_ROOT_KEY_ALGOID=${RSA4096_SHA256_ALGOID} 29 EC_DATAKEY_ALGOID=${RSA4096_SHA256_ALGOID} 30 31 ROOT_KEY_ALGOID=${RSA8192_SHA512_ALGOID} 32 RECOVERY_KEY_ALGOID=${RSA8192_SHA512_ALGOID} 33 34 FIRMWARE_DATAKEY_ALGOID=${RSA4096_SHA256_ALGOID} 35 DEV_FIRMWARE_DATAKEY_ALGOID=${RSA4096_SHA256_ALGOID} 36 37 RECOVERY_KERNEL_ALGOID=${RSA8192_SHA512_ALGOID} 38 INSTALLER_KERNEL_ALGOID=${RSA8192_SHA512_ALGOID} 39 KERNEL_SUBKEY_ALGOID=${RSA4096_SHA256_ALGOID} 40 KERNEL_DATAKEY_ALGOID=${RSA2048_SHA256_ALGOID} 41 42 # Keyblock modes determine which boot modes a signing key is valid for use 43 # in verification. 44 EC_KEYBLOCK_MODE=7 # Only allow RW EC firmware in non-recovery. 45 FIRMWARE_KEYBLOCK_MODE=7 # Only allow RW firmware in non-recovery. 46 DEV_FIRMWARE_KEYBLOCK_MODE=6 # Only allow in dev mode. 47 RECOVERY_KERNEL_KEYBLOCK_MODE=11 # Only in recovery mode. 48 KERNEL_KEYBLOCK_MODE=7 # Only allow in non-recovery. 49 INSTALLER_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. 57 function 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 97 function 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. 119 VERSION_FILE="key.versions" 120 121 # ARGS: <VERSION_TYPE> [VERSION_FILE] 122 get_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 128 load_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 142 Current Firmware key version: ${CURR_FIRMKEY_VER} 143 Current Firmware version: ${CURR_FIRM_VER} 144 Current Kernel key version: ${CURR_KERNKEY_VER} 145 Current Kernel version: ${CURR_KERN_VER} 146 EOF 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 153 backup_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 165 backup_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 180 backup_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 195 backup_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 207 write_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 214 firmware_key_version=${firmware_key_version} 215 firmware_version=${firmware_version} 216 kernel_key_version=${kernel_key_version} 217 kernel_version=${kernel_version} 218 EOF 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> 225 increment_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