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 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
|
#!/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: <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}"
}
|