xref: /aosp_15_r20/external/vboot_reference/scripts/keygeneration/uefi/uefi_common.sh (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1#!/bin/bash
2# Copyright 2018 The ChromiumOS Authors
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 UEFI key generation functions.
7
8# shellcheck source=../common.sh
9. "$(dirname "$0")/../common.sh"
10
11# Checks whether the given key directory name is "uefi".
12# Dies if it isn't.
13# ARGS: KEY_DIR
14check_uefi_key_dir_name() {
15  local key_dir="$1"
16  local key_dir_fullpath="$(readlink -f "${key_dir}")"
17  local key_dir_basename="$(basename "${key_dir_fullpath}")"
18  if [[ "${key_dir_basename}" != "uefi" ]]; then
19    die "Key directory base name is not \"uefi\""
20  fi
21}
22
23# File to read current versions from.
24UEFI_VERSION_FILE="uefi_key.versions"
25
26# Prints the version value for the given VERSION_TYPE, from UEFI_VERSION_FILE.
27# ARGS: <VERSION_TYPE> [UEFI_VERSION_FILE]
28get_uefi_version() {
29  local key="$1"
30  local file="${2:-${UEFI_VERSION_FILE}}"
31  awk -F= -vkey="${key}" '$1 == key { print $NF }' "${file}"
32}
33
34# Loads the current versions, prints them to stdout, and sets the global version
35# variables: CURR_PK_KEY_VER CURR_KEK_KEY_VER CURR_DB_KEY_VER
36# CURR_DB_CHILD_KEY_VER
37# ARGS: KEY_DIR
38load_current_uefi_key_versions() {
39  local key_dir="$1"
40  local UEFI_VERSION_FILE="${key_dir}/${UEFI_VERSION_FILE}"
41  if [[ ! -f "${UEFI_VERSION_FILE}" ]]; then
42    return 1
43  fi
44  CURR_PK_KEY_VER=$(get_uefi_version "pk_key_version")
45  CURR_KEK_KEY_VER=$(get_uefi_version "kek_key_version")
46  CURR_DB_KEY_VER=$(get_uefi_version "db_key_version")
47  CURR_DB_CHILD_KEY_VER=$(get_uefi_version "db_child_key_version")
48
49  cat <<EOF
50Current UEFI Platform Key (PK) version: ${CURR_PK_KEY_VER}
51Current UEFI Key Exchange Key (KEK) version: ${CURR_KEK_KEY_VER}
52Current UEFI DB key version: ${CURR_DB_KEY_VER}
53Current UEFI DB child key version: ${CURR_DB_CHILD_KEY_VER}
54EOF
55}
56
57# The common part for the subject of a UEFI key.
58_CHROMIUM_OS_SUBJECT=\
59'/C=US/ST=California/L=Mountain View/O=Google LLC./OU=Chromium OS'
60
61# Prints a UEFI key subject.
62# ARGS: TITLE VERSION
63_get_subj() {
64  local title="$1"
65  local version="$2"
66
67  echo "${_CHROMIUM_OS_SUBJECT}/CN=${title} v${version}"
68}
69
70# Generates a pair of a private key and a self-signed cert at the current
71# directory. Generated files are
72#   $1/$1.rsa: The private key
73#   $1/$1.pem: The self-signed cert in PEM format
74# ARGS: KEY_NAME SUBJECT
75_make_self_signed_pair() {
76  local key_name="$1"
77  local subj="$2"
78
79  mkdir -p "${key_name}"
80  pushd "${key_name}" >/dev/null || return 1
81  openssl req -new -x509 -nodes -newkey rsa:2048 -sha256 \
82      -keyout "${key_name}.rsa" -out "${key_name}.pem" \
83      -subj "${subj}" -days 3650
84  popd >/dev/null
85}
86
87# Generates a pair of a private key and a cert signed by the given CA.
88# "$1" (the first argument) is the CA file name without extension.
89# The results are signed by "$1/$1.{rsa,pem}", and are generated in
90# "$1/$1.children" directory under the current directory. Generated files are
91#   $1/$1.children/$2.rsa: The private key
92#   $1/$1.children/$2.csr: The Certificate Signing Request
93#   $1/$1.children/$2.pem: The certificate signed by "$1.{rsa,pem}"
94# ARGS: CA_NAME CHILD_KEY_NAME SUBJECT
95_make_child_pair() {
96  local ca_name="$1"  # Base filename without extension.
97  local child_key_name="$2"
98  local subj="$3"
99
100  mkdir -p "${ca_name}/${ca_name}.children"
101  pushd "${ca_name}/${ca_name}.children" >/dev/null || return 1
102  openssl req -new -nodes -newkey rsa:2048 -sha256 \
103      -keyout "${child_key_name}.rsa" -out "${child_key_name}.csr" \
104      -subj "${subj}"
105  openssl x509 -req -sha256 -CA "../${ca_name}.pem" -CAkey "../${ca_name}.rsa" \
106      -CAcreateserial -in "${child_key_name}.csr" \
107      -out "${child_key_name}.pem" -days 3650
108  popd >/dev/null
109}
110
111# Makes a PK (Platform Key) keypair.
112# Generated files are
113#   pk/pk.rsa: The private key
114#   pk/pk.pem: The self-signed cert in PEM format
115# ARGS: VERSION
116make_pk_keypair() {
117  local version="$1"
118  _make_self_signed_pair pk \
119      "$(_get_subj "UEFI Platform Key" "${version}")"
120}
121
122# Makes a KEK (Key Exchange Key) keypair.
123# Generated files are
124#   kek/kek.rsa: The private key
125#   kek/kek.pem: The self-signed cert in PEM format
126# ARGS: VERSION
127make_kek_keypair() {
128  local version="$1"
129  _make_self_signed_pair kek \
130      "$(_get_subj "UEFI Key Exchange Key" "${version}")"
131}
132
133# Makes a DB keypair.
134# Generated files are
135#   db/db.rsa: The private key
136#   db/db.pem: The self-signed cert in PEM format
137# ARGS: VERSION
138make_db_keypair() {
139  local version="$1"
140  _make_self_signed_pair db \
141      "$(_get_subj "UEFI DB Key" "${version}")"
142}
143
144# Makes a DB child keypair (a keypair signed by the db key).
145# Generated files are
146#   db/db.children/db_child.rsa: The private key
147#   db/db.children/db_child.csr: The Certificate Signing Request
148#   db/db.children/db_child.pem: The certificate signed by "db/db.{rsa,pem}"
149# ARGS: DB_KEY_VERSION CHILD_KEY_VERSION
150make_db_child_keypair() {
151  local db_key_version="$1"
152  local child_key_version="$2"
153  _make_child_pair db db_child \
154      "$(_get_subj "UEFI DB Child Key" \
155          "${db_key_version}.${child_key_version}")"
156}
157
158# Makes a backup of a self-signed keypair.
159# ARGS: KEY_NAME VERSION
160_backup_self_signed_pair() {
161  local key_name="$1"
162  local version="$2"
163  pushd "${key_name}" >/dev/null || return 1
164  mv --no-clobber "${key_name}".{rsa,"v${version}.rsa"}
165  mv --no-clobber "${key_name}".{pem,"v${version}.pem"}
166  popd >/dev/null
167}
168
169# Makes a backup of a self-signed keypair and its child keys.
170# ARGS: KEY_NAME VERSION
171_backup_self_signed_pair_and_children() {
172  local key_name="$1"
173  local version="$2"
174  _backup_self_signed_pair "${key_name}" "${version}"
175  pushd "${key_name}" >/dev/null || return 1
176  mv --no-clobber "${key_name}".{children,"v${version}.children"}
177  popd >/dev/null
178}
179
180# Makes a backup of a child keypair signed by a CA.
181# ARGS: CA_NAME CHILD_KEY_NAME CHILD_KEY_VERSION
182_backup_child_pair() {
183  local ca_name="$1"
184  local child_key_name="$2"
185  local child_key_version="$3"
186  pushd "${ca_name}/${ca_name}.children" >/dev/null || return 1
187  mv --no-clobber "${child_key_name}".{rsa,"v${child_key_version}.rsa"}
188  mv --no-clobber "${child_key_name}".{csr,"v${child_key_version}.csr"}
189  mv --no-clobber "${child_key_name}".{pem,"v${child_key_version}.pem"}
190  popd >/dev/null
191}
192
193# Makes a backup of the PK (Platform Key) keypair.
194# Backup format: pk.v<pk key version>.{rsa,pem}
195# ARGS: PK_KEY_VERSION
196backup_pk_keypair() {
197  local pk_key_version="$1"
198  _backup_self_signed_pair pk "${pk_key_version}"
199}
200
201# Makes a backup of the KEK (Key Exchange Key) keypair.
202# Backup format: kek.v<kek key version>.{rsa,pem}
203# ARGS: KEK_KEY_VERSION
204backup_kek_keypair() {
205  local kek_key_version="$1"
206  _backup_self_signed_pair kek "${kek_key_version}"
207}
208
209# Makes a backup of the DB keypair and its children.
210# Backup format:
211#   for db keypair: db.v<db key version>.{rsa,pem}
212#   for child keypair: db.v<db key version>.childern/child*.{rsa,csr,pem}
213# ARGS: DB_KEY_VERSION
214backup_db_keypair_and_children() {
215  local db_key_version="$1"
216  _backup_self_signed_pair_and_children db "${db_key_version}"
217}
218
219# Makes a backup of the DB child keypair.
220# Backup format: db.children/child.v<db child key version>.{rsa,csr,pem}
221# ARGS: DB_CHILD_KEY_VERSION
222backup_db_child_keypair() {
223  local db_child_key_version="$1"
224  _backup_child_pair db db_child "${db_child_key_version}"
225}
226
227# Writes new key version file with the updated key versions.
228# Args: PK_KEY_VERSION KEK_KEY_VERSION DB_KEY_VERSION DB_CHILD_KEY_VERSION
229write_updated_uefi_version_file() {
230  local pk_key_version="$1"
231  local kek_key_version="$2"
232  local db_key_version="$3"
233  local db_child_key_version="$4"
234
235  cat > "${UEFI_VERSION_FILE}" <<EOF
236pk_key_version=${pk_key_version}
237kek_key_version=${kek_key_version}
238db_key_version=${db_key_version}
239db_child_key_version=${db_child_key_version}
240EOF
241}
242
243# Returns the incremented version number of the passed in key from the version
244# file.  The options are "pk_key_version", "kek_key_version", "db_key_version",
245# or "db_child_key_version".
246# ARGS: KEY_DIR <key_name>
247increment_uefi_version() {
248  local key_dir="$1"
249  local UEFI_VERSION_FILE="${key_dir}/${UEFI_VERSION_FILE}"
250  local old_version=$(get_uefi_version "$2")
251  local new_version=$(( old_version + 1 ))
252
253  echo "${new_version}"
254}
255