#!/bin/bash # Copyright 2018 The ChromiumOS Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # Common UEFI key generation functions. # shellcheck source=../common.sh . "$(dirname "$0")/../common.sh" # Checks whether the given key directory name is "uefi". # Dies if it isn't. # ARGS: KEY_DIR check_uefi_key_dir_name() { local key_dir="$1" local key_dir_fullpath="$(readlink -f "${key_dir}")" local key_dir_basename="$(basename "${key_dir_fullpath}")" if [[ "${key_dir_basename}" != "uefi" ]]; then die "Key directory base name is not \"uefi\"" fi } # File to read current versions from. UEFI_VERSION_FILE="uefi_key.versions" # Prints the version value for the given VERSION_TYPE, from UEFI_VERSION_FILE. # ARGS: [UEFI_VERSION_FILE] get_uefi_version() { local key="$1" local file="${2:-${UEFI_VERSION_FILE}}" awk -F= -vkey="${key}" '$1 == key { print $NF }' "${file}" } # Loads the current versions, prints them to stdout, and sets the global version # variables: CURR_PK_KEY_VER CURR_KEK_KEY_VER CURR_DB_KEY_VER # CURR_DB_CHILD_KEY_VER # ARGS: KEY_DIR load_current_uefi_key_versions() { local key_dir="$1" local UEFI_VERSION_FILE="${key_dir}/${UEFI_VERSION_FILE}" if [[ ! -f "${UEFI_VERSION_FILE}" ]]; then return 1 fi CURR_PK_KEY_VER=$(get_uefi_version "pk_key_version") CURR_KEK_KEY_VER=$(get_uefi_version "kek_key_version") CURR_DB_KEY_VER=$(get_uefi_version "db_key_version") CURR_DB_CHILD_KEY_VER=$(get_uefi_version "db_child_key_version") cat </dev/null || return 1 openssl req -new -x509 -nodes -newkey rsa:2048 -sha256 \ -keyout "${key_name}.rsa" -out "${key_name}.pem" \ -subj "${subj}" -days 3650 popd >/dev/null } # Generates a pair of a private key and a cert signed by the given CA. # "$1" (the first argument) is the CA file name without extension. # The results are signed by "$1/$1.{rsa,pem}", and are generated in # "$1/$1.children" directory under the current directory. Generated files are # $1/$1.children/$2.rsa: The private key # $1/$1.children/$2.csr: The Certificate Signing Request # $1/$1.children/$2.pem: The certificate signed by "$1.{rsa,pem}" # ARGS: CA_NAME CHILD_KEY_NAME SUBJECT _make_child_pair() { local ca_name="$1" # Base filename without extension. local child_key_name="$2" local subj="$3" mkdir -p "${ca_name}/${ca_name}.children" pushd "${ca_name}/${ca_name}.children" >/dev/null || return 1 openssl req -new -nodes -newkey rsa:2048 -sha256 \ -keyout "${child_key_name}.rsa" -out "${child_key_name}.csr" \ -subj "${subj}" openssl x509 -req -sha256 -CA "../${ca_name}.pem" -CAkey "../${ca_name}.rsa" \ -CAcreateserial -in "${child_key_name}.csr" \ -out "${child_key_name}.pem" -days 3650 popd >/dev/null } # Makes a PK (Platform Key) keypair. # Generated files are # pk/pk.rsa: The private key # pk/pk.pem: The self-signed cert in PEM format # ARGS: VERSION make_pk_keypair() { local version="$1" _make_self_signed_pair pk \ "$(_get_subj "UEFI Platform Key" "${version}")" } # Makes a KEK (Key Exchange Key) keypair. # Generated files are # kek/kek.rsa: The private key # kek/kek.pem: The self-signed cert in PEM format # ARGS: VERSION make_kek_keypair() { local version="$1" _make_self_signed_pair kek \ "$(_get_subj "UEFI Key Exchange Key" "${version}")" } # Makes a DB keypair. # Generated files are # db/db.rsa: The private key # db/db.pem: The self-signed cert in PEM format # ARGS: VERSION make_db_keypair() { local version="$1" _make_self_signed_pair db \ "$(_get_subj "UEFI DB Key" "${version}")" } # Makes a DB child keypair (a keypair signed by the db key). # Generated files are # db/db.children/db_child.rsa: The private key # db/db.children/db_child.csr: The Certificate Signing Request # db/db.children/db_child.pem: The certificate signed by "db/db.{rsa,pem}" # ARGS: DB_KEY_VERSION CHILD_KEY_VERSION make_db_child_keypair() { local db_key_version="$1" local child_key_version="$2" _make_child_pair db db_child \ "$(_get_subj "UEFI DB Child Key" \ "${db_key_version}.${child_key_version}")" } # Makes a backup of a self-signed keypair. # ARGS: KEY_NAME VERSION _backup_self_signed_pair() { local key_name="$1" local version="$2" pushd "${key_name}" >/dev/null || return 1 mv --no-clobber "${key_name}".{rsa,"v${version}.rsa"} mv --no-clobber "${key_name}".{pem,"v${version}.pem"} popd >/dev/null } # Makes a backup of a self-signed keypair and its child keys. # ARGS: KEY_NAME VERSION _backup_self_signed_pair_and_children() { local key_name="$1" local version="$2" _backup_self_signed_pair "${key_name}" "${version}" pushd "${key_name}" >/dev/null || return 1 mv --no-clobber "${key_name}".{children,"v${version}.children"} popd >/dev/null } # Makes a backup of a child keypair signed by a CA. # ARGS: CA_NAME CHILD_KEY_NAME CHILD_KEY_VERSION _backup_child_pair() { local ca_name="$1" local child_key_name="$2" local child_key_version="$3" pushd "${ca_name}/${ca_name}.children" >/dev/null || return 1 mv --no-clobber "${child_key_name}".{rsa,"v${child_key_version}.rsa"} mv --no-clobber "${child_key_name}".{csr,"v${child_key_version}.csr"} mv --no-clobber "${child_key_name}".{pem,"v${child_key_version}.pem"} popd >/dev/null } # Makes a backup of the PK (Platform Key) keypair. # Backup format: pk.v.{rsa,pem} # ARGS: PK_KEY_VERSION backup_pk_keypair() { local pk_key_version="$1" _backup_self_signed_pair pk "${pk_key_version}" } # Makes a backup of the KEK (Key Exchange Key) keypair. # Backup format: kek.v.{rsa,pem} # ARGS: KEK_KEY_VERSION backup_kek_keypair() { local kek_key_version="$1" _backup_self_signed_pair kek "${kek_key_version}" } # Makes a backup of the DB keypair and its children. # Backup format: # for db keypair: db.v.{rsa,pem} # for child keypair: db.v.childern/child*.{rsa,csr,pem} # ARGS: DB_KEY_VERSION backup_db_keypair_and_children() { local db_key_version="$1" _backup_self_signed_pair_and_children db "${db_key_version}" } # Makes a backup of the DB child keypair. # Backup format: db.children/child.v.{rsa,csr,pem} # ARGS: DB_CHILD_KEY_VERSION backup_db_child_keypair() { local db_child_key_version="$1" _backup_child_pair db db_child "${db_child_key_version}" } # Writes new key version file with the updated key versions. # Args: PK_KEY_VERSION KEK_KEY_VERSION DB_KEY_VERSION DB_CHILD_KEY_VERSION write_updated_uefi_version_file() { local pk_key_version="$1" local kek_key_version="$2" local db_key_version="$3" local db_child_key_version="$4" cat > "${UEFI_VERSION_FILE}" < increment_uefi_version() { local key_dir="$1" local UEFI_VERSION_FILE="${key_dir}/${UEFI_VERSION_FILE}" local old_version=$(get_uefi_version "$2") local new_version=$(( old_version + 1 )) echo "${new_version}" }