Home | History | Annotate | Download | only in keygeneration
      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