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