Add the ability to generate rootfs signatures using openssl CMS module if `-c
` is given.
(gitlab ci) Added a CA structure to the codesigning certificates. This to test the functionality of optional CA being in the signing message. (mkarchiso) Removed the ``sign_netboot_artifacts`` variable and instead we'll now rely on ``if [[ -v cert_list ]]; then``. Added ``ARCHISO_TLS_FD`` and ``ARCHISO_TLSCA_FD`` environment variables to override the certificates used. This is so that third party CA's can be used during building in a meaningful way without distrupting the CA trust that is shipped by default. _cms_sign_artifact() was added which signs the rootfs using OpenSSL CMS. The files will be saved as "${artifact}.cms.sig". That would be for instance "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs.cms.sig".
This commit is contained in:
parent
5f135b4342
commit
326cfed7cc
@ -30,6 +30,8 @@ gnupg_homedir=""
|
||||
codesigning_dir=""
|
||||
codesigning_cert=""
|
||||
codesigning_key=""
|
||||
ca_cert=""
|
||||
ca_key=""
|
||||
pgp_key_id=""
|
||||
|
||||
print_section_start() {
|
||||
@ -204,43 +206,103 @@ EOF
|
||||
print_section_end "ephemeral_pgp_key"
|
||||
}
|
||||
|
||||
create_ephemeral_codesigning_key() {
|
||||
create_ephemeral_codesigning_keys() {
|
||||
# create ephemeral certificates used for codesigning
|
||||
print_section_start "ephemeral_codesigning_key" "Creating ephemeral codesigning key"
|
||||
print_section_start "ephemeral_codesigning_key" "Creating ephemeral codesigning keys"
|
||||
|
||||
# The exact steps in creating a CA with Codesigning being signed was taken from
|
||||
# https://jamielinux.com/docs/openssl-certificate-authority/introduction.html
|
||||
# (slight modifications to the process to not disturb default values of /etc/ssl/openssl.cnf)
|
||||
|
||||
codesigning_dir="${tmpdir}/.codesigning/"
|
||||
local codesigning_conf="${codesigning_dir}/openssl.cnf"
|
||||
local ca_dir="${codesigning_dir}/ca/"
|
||||
|
||||
local ca_conf="${ca_dir}/certificate_authority.cnf"
|
||||
local ca_subj="/C=DE/ST=Berlin/L=Berlin/O=Arch Linux/OU=Release Engineering/CN=archlinux.org"
|
||||
ca_cert="${ca_dir}/cacert.pem"
|
||||
ca_key="${ca_dir}/private/cakey.pem"
|
||||
|
||||
local codesigning_conf="${codesigning_dir}/code_signing.cnf"
|
||||
local codesigning_subj="/C=DE/ST=Berlin/L=Berlin/O=Arch Linux/OU=Release Engineering/CN=archlinux.org"
|
||||
codesigning_cert="${codesigning_dir}/codesign.crt"
|
||||
codesigning_key="${codesigning_dir}/codesign.key"
|
||||
|
||||
mkdir -p "${ca_dir}/"{private,newcerts,crl}
|
||||
mkdir -p "${codesigning_dir}"
|
||||
cp -- /etc/ssl/openssl.cnf "${codesigning_conf}"
|
||||
printf "\n[codesigning]\nkeyUsage=digitalSignature\nextendedKeyUsage=codeSigning\n" >> "${codesigning_conf}"
|
||||
cp -- /etc/ssl/openssl.cnf "${ca_conf}"
|
||||
touch "${ca_dir}/index.txt"
|
||||
echo "1000" > "${ca_dir}/serial"
|
||||
|
||||
# Prepare the ca configuration for the change in directory
|
||||
sed -i "s#/etc/ssl#${ca_dir}#g" "${ca_conf}"
|
||||
|
||||
# Create the Certificate Authority
|
||||
openssl req \
|
||||
-newkey rsa:4096 \
|
||||
-sha256 \
|
||||
-nodes \
|
||||
-x509 \
|
||||
-new \
|
||||
-sha256 \
|
||||
-keyout "${ca_key}" \
|
||||
-config "${ca_conf}" \
|
||||
-subj "${ca_subj}" \
|
||||
-out "${ca_cert}"
|
||||
|
||||
cat << EOF >> "${ca_conf}"
|
||||
|
||||
[ v3_intermediate_ca ]
|
||||
# Extensions for a typical intermediate CA ('man x509v3_config').
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer
|
||||
basicConstraints = critical, CA:true, pathlen:0
|
||||
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
||||
|
||||
EOF
|
||||
|
||||
cat << EOF >> "${codesigning_conf}"
|
||||
|
||||
[codesigning]
|
||||
keyUsage=digitalSignature
|
||||
extendedKeyUsage=codeSigning, clientAuth, emailProtection
|
||||
|
||||
EOF
|
||||
|
||||
openssl req \
|
||||
-newkey rsa:4096 \
|
||||
-keyout "${codesigning_key}" \
|
||||
-nodes \
|
||||
-sha256 \
|
||||
-x509 \
|
||||
-days 365 \
|
||||
-out "${codesigning_cert}" \
|
||||
-out "${codesigning_cert}.csr" \
|
||||
-config "${codesigning_conf}" \
|
||||
-subj "${codesigning_subj}" \
|
||||
-extensions codesigning
|
||||
|
||||
# Sign the code signing certificate with the CA
|
||||
openssl ca \
|
||||
-batch \
|
||||
-config "${ca_conf}" \
|
||||
-extensions v3_intermediate_ca \
|
||||
-days 3650 \
|
||||
-notext \
|
||||
-md sha256 \
|
||||
-in "${codesigning_cert}.csr" \
|
||||
-out "${codesigning_cert}"
|
||||
|
||||
print_section_end "ephemeral_codesigning_key"
|
||||
}
|
||||
|
||||
run_mkarchiso() {
|
||||
# run mkarchiso
|
||||
create_ephemeral_pgp_key
|
||||
create_ephemeral_codesigning_key
|
||||
create_ephemeral_codesigning_keys
|
||||
|
||||
print_section_start "mkarchiso" "Running mkarchiso"
|
||||
mkdir -p "${output}/" "${tmpdir}/"
|
||||
GNUPGHOME="${gnupg_homedir}" ./archiso/mkarchiso \
|
||||
-D "${install_dir}" \
|
||||
-c "${codesigning_cert} ${codesigning_key}" \
|
||||
-c "${codesigning_cert} ${codesigning_key} ${ca_cert}" \
|
||||
-g "${pgp_key_id}" \
|
||||
-G "${pgp_sender}" \
|
||||
-o "${output}/" \
|
||||
|
@ -36,3 +36,4 @@ Archiso Authors
|
||||
* Øyvind Heggstad <heggstad@gmail.com>
|
||||
* plain linen <bcdedit@hotmail.com>
|
||||
* Pellegrino Prevete <pellegrinoprevete@gmail.com>
|
||||
* Anton Hvornum <anton@hvornum.se>
|
||||
|
@ -8,6 +8,8 @@ Changelog
|
||||
Added
|
||||
-----
|
||||
|
||||
- The ability to generate rootfs signatures using openssl CMS module if ``-c`` is given.
|
||||
|
||||
Changed
|
||||
-------
|
||||
|
||||
|
@ -43,7 +43,6 @@ bootmodes=()
|
||||
airootfs_image_type=""
|
||||
airootfs_image_tool_options=()
|
||||
cert_list=()
|
||||
sign_netboot_artifacts=""
|
||||
declare -A file_permissions=()
|
||||
efibootimg=""
|
||||
efiboot_files=()
|
||||
@ -94,10 +93,11 @@ usage: ${app_name} [options] <profile_dir>
|
||||
Default: '${iso_label}'
|
||||
-P <publisher> Set the ISO publisher
|
||||
Default: '${iso_publisher}'
|
||||
-c [cert ..] Provide certificates for codesigning of netboot artifacts
|
||||
-c [cert ..] Provide certificates for codesigning of netboot artifacts as
|
||||
well as the rootfs artifact.
|
||||
Multiple files are provided as quoted, space delimited list.
|
||||
The first file is considered as the signing certificate,
|
||||
the second as the key.
|
||||
the second as the key and the third as the optional certificate authority.
|
||||
-g <gpg_key> Set the PGP key ID to be used for signing the rootfs image.
|
||||
Passed to gpg as the value for --default-key
|
||||
-G <mbox> Set the PGP signer (must include an email address)
|
||||
@ -250,14 +250,11 @@ _mkchecksum() {
|
||||
}
|
||||
|
||||
# GPG sign the root file system image.
|
||||
_mksignature() {
|
||||
local airootfs_image_filename gpg_options=()
|
||||
_msg_info "Signing rootfs image..."
|
||||
if [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" ]]; then
|
||||
airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.sfs"
|
||||
elif [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" ]]; then
|
||||
airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.erofs"
|
||||
fi
|
||||
_mk_pgp_signature() {
|
||||
local gpg_options=()
|
||||
local airootfs_image_filename="${1}"
|
||||
_msg_info "Signing rootfs image using GPG..."
|
||||
|
||||
rm -f -- "${airootfs_image_filename}.sig"
|
||||
# Add gpg sender option if the value is provided
|
||||
[[ -z "${gpg_sender}" ]] || gpg_options+=('--sender' "${gpg_sender}")
|
||||
@ -342,6 +339,15 @@ _make_packages() {
|
||||
exec {ARCHISO_GNUPG_FD}<>"${work_dir}/pubkey.gpg"
|
||||
export ARCHISO_GNUPG_FD
|
||||
fi
|
||||
if [[ -v cert_list[0] ]]; then
|
||||
exec {ARCHISO_TLS_FD}<>"${cert_list[0]}"
|
||||
export ARCHISO_TLS_FD
|
||||
fi
|
||||
if [[ -v cert_list[2] ]]; then
|
||||
exec {ARCHISO_TLSCA_FD}<>"${cert_list[2]}"
|
||||
export ARCHISO_TLSCA_FD
|
||||
fi
|
||||
|
||||
|
||||
# Unset TMPDIR to work around https://bugs.archlinux.org/task/70580
|
||||
if [[ "${quiet}" = "y" ]]; then
|
||||
@ -350,6 +356,14 @@ _make_packages() {
|
||||
env -u TMPDIR pacstrap -C "${work_dir}/${buildmode}.pacman.conf" -c -G -M -- "${pacstrap_dir}" "${buildmode_pkg_list[@]}"
|
||||
fi
|
||||
|
||||
if [[ -v cert_list[0] ]]; then
|
||||
exec {ARCHISO_TLS_FD}<&-
|
||||
unset ARCHISO_TLS_FD
|
||||
fi
|
||||
if [[ -v cert_list[2] ]]; then
|
||||
exec {ARCHISO_TLSCA_FD}<&-
|
||||
unset ARCHISO_TLSCA_FD
|
||||
fi
|
||||
if [[ -n "${gpg_key}" ]]; then
|
||||
exec {ARCHISO_GNUPG_FD}<&-
|
||||
unset ARCHISO_GNUPG_FD
|
||||
@ -998,8 +1012,18 @@ _validate_requirements_bootmode_uefi-x64.grub.eltorito() {
|
||||
_prepare_airootfs_image() {
|
||||
_run_once "_mkairootfs_${airootfs_image_type}"
|
||||
_mkchecksum
|
||||
|
||||
if [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" ]]; then
|
||||
airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.sfs"
|
||||
elif [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" ]]; then
|
||||
airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.erofs"
|
||||
fi
|
||||
|
||||
if [[ -n "${gpg_key}" ]]; then
|
||||
_mksignature
|
||||
_mk_pgp_signature "${airootfs_image_filename}"
|
||||
fi
|
||||
if [[ -v cert_list ]]; then
|
||||
_cms_sign_artifact "${airootfs_image_filename}"
|
||||
fi
|
||||
}
|
||||
|
||||
@ -1012,6 +1036,32 @@ _export_netboot_artifacts() {
|
||||
du -hs -- "${out_dir}/${install_dir}"
|
||||
}
|
||||
|
||||
_cms_sign_artifact() {
|
||||
local artifact="${1}"
|
||||
local openssl_flags=(
|
||||
"-sign"
|
||||
"-binary"
|
||||
"-nocerts"
|
||||
"-noattr"
|
||||
"-outform" "DER" "-out" "${artifact}.cms.sig"
|
||||
"-in" "${artifact}"
|
||||
"-signer" "${cert_list[0]}"
|
||||
"-inkey" "${cert_list[1]}"
|
||||
)
|
||||
|
||||
if (( ${#cert_list[@]} > 2 )); then
|
||||
openssl_flags+=("-certfile" "${cert_list[2]}")
|
||||
fi
|
||||
|
||||
_msg_info "Signing ${artifact} image using openssl cms..."
|
||||
|
||||
rm -f -- "${artifact}.cms.sig"
|
||||
|
||||
openssl cms "${openssl_flags[@]}"
|
||||
|
||||
_msg_info "Done!"
|
||||
}
|
||||
|
||||
# sign build artifacts for netboot
|
||||
_sign_netboot_artifacts() {
|
||||
local _file _dir
|
||||
@ -1115,6 +1165,26 @@ _validate_common_requirements_buildmode_iso_netboot() {
|
||||
_msg_error "Packages file '${packages}' does not exist." 0
|
||||
fi
|
||||
|
||||
if [[ -v cert_list ]]; then
|
||||
# Check if the certificate files exist
|
||||
for _cert in "${cert_list[@]}"; do
|
||||
if [[ ! -e "${_cert}" ]]; then
|
||||
(( validation_error=validation_error+1 ))
|
||||
_msg_error "File '${_cert}' does not exist." 0
|
||||
fi
|
||||
done
|
||||
# Check if there are at least three certificate files to sign netboot and rootfs.
|
||||
if (( ${#cert_list[@]} < 2 )); then
|
||||
(( validation_error=validation_error+1 ))
|
||||
_msg_error "Two certificates are required for codesigning netboot artifacts, but '${cert_list[*]}' is provided." 0
|
||||
fi
|
||||
|
||||
if ! command -v openssl &> /dev/null; then
|
||||
(( validation_error=validation_error+1 ))
|
||||
_msg_error "Validating build mode '${_buildmode}': openssl is not available on this host. Install 'openssl'!" 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if the specified airootfs_image_type is supported
|
||||
if typeset -f "_mkairootfs_${airootfs_image_type}" &> /dev/null; then
|
||||
if typeset -f "_validate_requirements_airootfs_image_type_${airootfs_image_type}" &> /dev/null; then
|
||||
@ -1156,31 +1226,8 @@ _validate_requirements_buildmode_iso() {
|
||||
}
|
||||
|
||||
_validate_requirements_buildmode_netboot() {
|
||||
local _override_cert_list=()
|
||||
|
||||
if [[ "${sign_netboot_artifacts}" == "y" ]]; then
|
||||
# Check if the certificate files exist
|
||||
for _cert in "${cert_list[@]}"; do
|
||||
if [[ -e "${_cert}" ]]; then
|
||||
_override_cert_list+=("$(realpath -- "${_cert}")")
|
||||
else
|
||||
(( validation_error=validation_error+1 ))
|
||||
_msg_error "File '${_cert}' does not exist." 0
|
||||
fi
|
||||
done
|
||||
cert_list=("${_override_cert_list[@]}")
|
||||
# Check if there are at least two certificate files
|
||||
if (( ${#cert_list[@]} < 2 )); then
|
||||
(( validation_error=validation_error+1 ))
|
||||
_msg_error "Two certificates are required for codesigning, but '${cert_list[*]}' is provided." 0
|
||||
fi
|
||||
fi
|
||||
_validate_common_requirements_buildmode_iso_netboot
|
||||
_validate_common_requirements_buildmode_all
|
||||
if ! command -v openssl &> /dev/null; then
|
||||
(( validation_error=validation_error+1 ))
|
||||
_msg_error "Validating build mode '${_buildmode}': openssl is not available on this host. Install 'openssl'!" 0
|
||||
fi
|
||||
}
|
||||
|
||||
# SYSLINUX El Torito
|
||||
@ -1541,10 +1588,7 @@ _set_overrides() {
|
||||
fi
|
||||
[[ ! -v override_gpg_key ]] || gpg_key="$override_gpg_key"
|
||||
[[ ! -v override_gpg_sender ]] || gpg_sender="$override_gpg_sender"
|
||||
if [[ -v override_cert_list ]]; then
|
||||
sign_netboot_artifacts="y"
|
||||
fi
|
||||
[[ ! -v override_cert_list ]] || cert_list+=("${override_cert_list[@]}")
|
||||
[[ ! -v override_cert_list ]] || mapfile -t cert_list < <(realpath -- "${override_cert_list[@]}")
|
||||
if [[ -v override_quiet ]]; then
|
||||
quiet="$override_quiet"
|
||||
elif [[ -z "$quiet" ]]; then
|
||||
@ -1675,8 +1719,16 @@ _build_buildmode_netboot() {
|
||||
local run_once_mode="${buildmode}"
|
||||
|
||||
_build_iso_base
|
||||
|
||||
if [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" ]]; then
|
||||
airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.sfs"
|
||||
elif [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" ]]; then
|
||||
airootfs_image_filename="${isofs_dir}/${install_dir}/${arch}/airootfs.erofs"
|
||||
fi
|
||||
|
||||
if [[ -v cert_list ]]; then
|
||||
_run_once _sign_netboot_artifacts
|
||||
_cms_sign_artifact "${airootfs_image_filename}"
|
||||
fi
|
||||
_run_once _export_netboot_artifacts
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user