Gaurav Shah | 5746845 | 2011-03-02 14:50:46 -0800 | [diff] [blame] | 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 | |
Bill Richardson | 2448d3b | 2012-05-03 08:40:44 -0700 | [diff] [blame] | 26 | # Default algorithms. |
| 27 | EC_ROOT_KEY_ALGOID=7 |
| 28 | EC_DATAKEY_ALGOID=7 |
| 29 | |
Gaurav Shah | 41f444a | 2011-04-12 17:05:37 -0700 | [diff] [blame] | 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. |
Bill Richardson | 2448d3b | 2012-05-03 08:40:44 -0700 | [diff] [blame] | 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. |
Gaurav Shah | 41f444a | 2011-04-12 17:05:37 -0700 | [diff] [blame] | 45 | DEV_FIRMWARE_KEYBLOCK_MODE=6 # Only allow in dev mode. |
Bill Richardson | 2448d3b | 2012-05-03 08:40:44 -0700 | [diff] [blame] | 46 | RECOVERY_KERNEL_KEYBLOCK_MODE=11 # Only in recovery mode. |
Gaurav Shah | 41f444a | 2011-04-12 17:05:37 -0700 | [diff] [blame] | 47 | KERNEL_KEYBLOCK_MODE=7 # Only allow in non-recovery. |
| 48 | INSTALLER_KERNEL_KEYBLOCK_MODE=10 # Only allow in Dev + Recovery. |
| 49 | |
Gaurav Shah | 5746845 | 2011-03-02 14:50:46 -0800 | [diff] [blame] | 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 |
Gaurav Shah | 41f444a | 2011-04-12 17:05:37 -0700 | [diff] [blame] | 59 | local key_version=${3:-1} |
Gaurav Shah | 5746845 | 2011-03-02 14:50:46 -0800 | [diff] [blame] | 60 | local len=$(alg_to_keylen $alg) |
| 61 | |
Gaurav Shah | 41f444a | 2011-04-12 17:05:37 -0700 | [diff] [blame] | 62 | echo "creating $base keypair (version = $key_version)..." |
Gaurav Shah | 5746845 | 2011-03-02 14:50:46 -0800 | [diff] [blame] | 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" \ |
Gaurav Shah | 41f444a | 2011-04-12 17:05:37 -0700 | [diff] [blame] | 76 | --version "${key_version}" \ |
Gaurav Shah | 5746845 | 2011-03-02 14:50:46 -0800 | [diff] [blame] | 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 | |
Kris Rambish | 40d8651 | 2012-09-06 15:58:37 -0700 | [diff] [blame^] | 117 | # File to read current versions from. |
| 118 | VERSION_FILE="key.versions" |
Gaurav Shah | 5746845 | 2011-03-02 14:50:46 -0800 | [diff] [blame] | 119 | |
Kris Rambish | 40d8651 | 2012-09-06 15:58:37 -0700 | [diff] [blame^] | 120 | # ARGS: <VERSION_TYPE> |
| 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 | if [[ ! -f ${VERSION_FILE} ]]; then |
| 129 | return 1 |
| 130 | fi |
| 131 | CURR_FIRMKEY_VER=$(get_version "firmware_key_version") |
| 132 | # Firmware version is the kernel subkey version. |
| 133 | CURR_FIRM_VER=$(get_version "firmware_version") |
| 134 | # Kernel data key version is the kernel key version. |
| 135 | CURR_KERNKEY_VER=$(get_version "kernel_key_version") |
| 136 | CURR_KERN_VER=$(get_version "kernel_version") |
| 137 | |
| 138 | cat <<EOF |
| 139 | Current Firmware key version: ${CURR_FIRMKEY_VER} |
| 140 | Current Firmware version: ${CURR_FIRM_VER} |
| 141 | Current Kernel key version: ${CURR_KERNKEY_VER} |
| 142 | Current Kernel version: ${CURR_KERN_VER} |
| 143 | EOF |
| 144 | } |
| 145 | |
| 146 | # Make backups of existing kernel subkeys and keyblocks that will be revved. |
| 147 | # Backup format: |
| 148 | # for keyblocks: <keyblock_name>.v<datakey version>.v<subkey version>.keyblock |
| 149 | # Args: SUBKEY_VERSION DATAKEY_VERSION |
| 150 | backup_existing_kernel_keyblock() { |
| 151 | if [[ ! -e kernel.keyblock ]]; then |
| 152 | return |
| 153 | fi |
| 154 | mv --no-clobber kernel.{keyblock,"v$2.v$1.keyblock"} |
| 155 | } |
| 156 | |
| 157 | # Make backups of existing kernel subkeys and keyblocks that will be revved. |
| 158 | # Backup format: |
| 159 | # for keys: <key_name>.v<version>.vb{pub|priv}k |
| 160 | # for keyblocks: <keyblock_name>.v<datakey version>.v<subkey version>.keyblock |
| 161 | # Args: SUBKEY_VERSION DATAKEY_VERSION |
| 162 | backup_existing_kernel_subkeys() { |
| 163 | local subkey_ver=$1 |
| 164 | local datakey_ver=$2 |
| 165 | # --no-clobber to prevent accidentally overwriting existing |
| 166 | # backups. |
| 167 | mv --no-clobber kernel_subkey.{vbprivk,"v${subkey_ver}.vbprivk"} |
| 168 | mv --no-clobber kernel_subkey.{vbpubk,"v${subkey_ver}.vbpubk"} |
| 169 | backup_existing_kernel_keyblock ${subkey_ver} ${datakey_ver} |
| 170 | } |
| 171 | |
| 172 | # Make backups of existing kernel data keys and keyblocks that will be revved. |
| 173 | # Backup format: |
| 174 | # for keys: <key_name>.v<version>.vb{pub|priv}k |
| 175 | # for keyblocks: <keyblock_name>.v<datakey version>.v<subkey version>.keyblock |
| 176 | # Args: SUBKEY_VERSION DATAKEY_VERSION |
| 177 | backup_existing_kernel_data_keys() { |
| 178 | local subkey_ver=$1 |
| 179 | local datakey_ver=$2 |
| 180 | # --no-clobber to prevent accidentally overwriting existing |
| 181 | # backups. |
| 182 | mv --no-clobber kernel_data_key.{vbprivk,"v${datakey_ver}.vbprivk"} |
| 183 | mv --no-clobber kernel_data_key.{vbpubk,"v${datakey_ver}.vbpubk"} |
| 184 | backup_existing_kernel_keyblock ${subkey_ver} ${datakey_ver} |
| 185 | } |
| 186 | |
| 187 | # Make backups of existing firmware keys and keyblocks that will be revved. |
| 188 | # Backup format: |
| 189 | # for keys: <key_name>.v<version>.vb{pub|priv}k |
| 190 | # for keyblocks: <keyblock_name>.v<datakey version>.v<subkey version>.keyblock |
| 191 | # Args: SUBKEY_VERSION DATAKEY_VERSION |
| 192 | backup_existing_firmware_keys() { |
| 193 | local subkey_ver=$1 |
| 194 | local datakey_ver=$2 |
| 195 | mv --no-clobber firmware_data_key.{vbprivk,"v${subkey_ver}.vbprivk"} |
| 196 | mv --no-clobber firmware_data_key.{vbpubk,"v${subkey_ver}.vbpubk"} |
| 197 | mv --no-clobber firmware.{keyblock,"v${datakey_ver}.v${subkey_ver}.keyblock"} |
| 198 | } |
| 199 | |
| 200 | |
| 201 | # Write new key version file with the updated key versions. |
| 202 | # Args: FIRMWARE_KEY_VERSION FIRMWARE_VERSION KERNEL_KEY_VERSION |
| 203 | # KERNEL_VERSION |
| 204 | write_updated_version_file() { |
| 205 | local firmware_key_version=$1 |
| 206 | local firmware_version=$2 |
| 207 | local kernel_key_version=$3 |
| 208 | local kernel_version=$4 |
| 209 | |
| 210 | cat > ${VERSION_FILE} <<EOF |
| 211 | firmware_key_version=${firmware_key_version} |
| 212 | firmware_version=${firmware_version} |
| 213 | kernel_key_version=${kernel_key_version} |
| 214 | kernel_version=${kernel_version} |
| 215 | EOF |
| 216 | } |
| 217 | |
| 218 | # Returns the incremented version number of the passed in key from the version |
| 219 | # file. The options are "firmware_key_version", "firmware_version", |
| 220 | # "kernel_key_version", or "kernel_version". |
| 221 | # ARGS: KEY_DIR <key_name> |
| 222 | increment_version() { |
| 223 | local key_dir=$1 |
| 224 | local VERSION_FILE="${key_dir}/${VERSION_FILE}" |
| 225 | local old_version=$(get_version $2) |
| 226 | local new_version=$(( ${old_version} + 1 )) |
| 227 | |
| 228 | if [[ ${new_version} -gt 0xffff ]]; then |
| 229 | echo "Version overflow!" >&2 |
| 230 | return 1 |
| 231 | fi |
| 232 | echo ${new_version} |
| 233 | } |