blob: ba5369b6e7095b2483da7bacf3a1c1c3c0e324a1 [file] [log] [blame]
#!/bin/bash
# Copyright 2018 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 UEFI key generation functions.
. "$(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: <VERSION_TYPE> [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 <<EOF
Current UEFI Platform Key (PK) version: ${CURR_PK_KEY_VER}
Current UEFI Key Exchange Key (KEK) version: ${CURR_KEK_KEY_VER}
Current UEFI DB key version: ${CURR_DB_KEY_VER}
Current UEFI DB child key version: ${CURR_DB_CHILD_KEY_VER}
EOF
}
# The common part for the subject of a UEFI key.
_CHROMIUM_OS_SUBJECT=\
'/C=US/ST=California/L=Mountain View/O=Google LLC./OU=Chromium OS'
# Prints a UEFI key subject.
# ARGS: TITLE VERSION
_get_subj() {
local title="$1"
local version="$2"
echo "${_CHROMIUM_OS_SUBJECT}/CN=${title} v${version}"
}
# Generates a pair of a private key and a self-signed cert at the current
# directory. Generated files are
# $1/$1.rsa: The private key
# $1/$1.pem: The self-signed cert in PEM format
# ARGS: KEY_NAME SUBJECT
_make_self_signed_pair() {
local key_name="$1"
local subj="$2"
mkdir -p "${key_name}"
pushd "${key_name}" >/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<pk key version>.{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<kek key version>.{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<db key version>.{rsa,pem}
# for child keypair: db.v<db key version>.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<db child key version>.{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}" <<EOF
pk_key_version=${pk_key_version}
kek_key_version=${kek_key_version}
db_key_version=${db_key_version}
db_child_key_version=${db_child_key_version}
EOF
}
# Returns the incremented version number of the passed in key from the version
# file. The options are "pk_key_version", "kek_key_version", "db_key_version",
# or "db_child_key_version".
# ARGS: KEY_DIR <key_name>
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}"
}