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