mirror of
https://github.com/flatcar/scripts.git
synced 2025-08-07 21:16:57 +02:00
The sdk user in the container might rejected by the pcscd on the host. Work around that by running the openssl command as root.
186 lines
5.9 KiB
Bash
Executable File
186 lines
5.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Copyright (c) 2014 CoreOS, Inc. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
# usage: ./core_generate_update_payload --image coreos_production_update.bin \
|
|
# --output update.gz \
|
|
# --private_keys update.key.pem:update2.key.pem
|
|
# --public_keys update.pub.pem:update2.pub.pem
|
|
|
|
SCRIPT_ROOT=$(dirname $(readlink -f "$0"))
|
|
# We have to simple-mindedly set GCLIENT_ROOT in case we're running from
|
|
# au-generator.zip because common.sh will fail while auto-detect it.
|
|
export GCLIENT_ROOT=$(readlink -f "${SCRIPT_ROOT}/../../")
|
|
. "${SCRIPT_ROOT}/common.sh" || exit 1
|
|
|
|
DEFINE_string image "" "The filesystem image of /usr"
|
|
DEFINE_string kernel "" "The kernel image"
|
|
DEFINE_string output "" "Output file"
|
|
DEFINE_string private_keys "" "Path, pkcs11 URI, or fero:<keyname> for private keys."
|
|
DEFINE_string public_keys "" "Path to public keys in .pem format."
|
|
DEFINE_string keys_separator ":" "Separator for the above keys"
|
|
DEFINE_string user_signatures "" \
|
|
"Colon-separated paths to user signatures to provide to signing server"
|
|
DEFINE_string signing_server_address "" "Hostname of the signing server"
|
|
DEFINE_integer signing_server_port "50051" "Port of the signing server"
|
|
|
|
# Parse command line
|
|
FLAGS "$@" || exit 1
|
|
eval set -- "${FLAGS_ARGV}"
|
|
|
|
set -e
|
|
|
|
cleanup() {
|
|
rm -f padding
|
|
rm -f padding-pkcs11
|
|
rm -f update
|
|
rm -f update.hash
|
|
rm -f update.padhash
|
|
rm -f update.pkcs11-padhash
|
|
rm -f update.signed
|
|
rm -f update.sig.*
|
|
}
|
|
|
|
trap cleanup INT TERM EXIT
|
|
|
|
echo "=== Creating signable update payload... ==="
|
|
delta_generator \
|
|
-new_image "$FLAGS_image" \
|
|
-new_kernel "$FLAGS_kernel" \
|
|
-out_file update
|
|
|
|
# The separator is configurable for backwards compatibility with old `sign.sh` scripts.
|
|
IFS="${FLAGS_keys_separator}" read -a private_keys <<< "$FLAGS_private_keys"
|
|
IFS="${FLAGS_keys_separator}" read -a public_keys <<< "$FLAGS_public_keys"
|
|
|
|
if [ ${#private_keys[@]} -ne ${#public_keys[@]} ]; then
|
|
echo "mismatch in count of private keys and public keys"
|
|
exit 1
|
|
fi
|
|
|
|
i=0
|
|
signature_sizes=""
|
|
for key in "${private_keys[@]}"; do
|
|
signature_sizes=${signature_sizes}:256
|
|
let "i += 1"
|
|
done
|
|
signature_sizes="${signature_sizes:1:${#signature_sizes}}"
|
|
|
|
# We don't need to maintain backwards compatibility with old `sign.sh` scripts here, so we only
|
|
# allow colon-separated values for user signature files.
|
|
IFS=":" read -a user_signatures <<< "$FLAGS_user_signatures"
|
|
|
|
user_signatures_arg=""
|
|
for user_signature in "${user_signatures[@]}"; do
|
|
user_signatures_arg="${user_signatures_arg} --signature ${user_signature}"
|
|
done
|
|
user_signatures_arg="${user_signatures_arg:1:${#user_signatures_arg}}"
|
|
|
|
delta_generator \
|
|
--signature_size ${signature_sizes} \
|
|
--in_file update \
|
|
--out_hash_file update.hash
|
|
|
|
# padding for openssl rsautl -pkcs (smartcard keys)
|
|
#
|
|
# The following is an ASN.1 header. It is prepended to the actual signature
|
|
# (32 bytes) to form a sequence of 51 bytes. OpenSSL will add additional
|
|
# PKCS#1 1.5 padding during the signing operation. The padded hash will look
|
|
# as follows:
|
|
#
|
|
# ASN1HEADER SHA256HASH
|
|
# |----19----||----32----|
|
|
#
|
|
# where ASN1HEADER is the ASN.1 description of the signed data. The complete 51
|
|
# bytes of actual data (i.e. the ASN.1 header complete with the hash) are
|
|
# packed as follows:
|
|
#
|
|
# SEQUENCE(2+49) {
|
|
# SEQUENCE(2+13) {
|
|
# OBJECT(2+9) id-sha256
|
|
# NULL(2+0)
|
|
# }
|
|
# OCTET STRING(2+32) <actual signature bytes...>
|
|
# }
|
|
echo "MDEwDQYJYIZIAWUDBAIBBQAEIA==" | base64 -d > padding-pkcs11
|
|
cat padding-pkcs11 update.hash > update.pkcs11-padhash
|
|
|
|
# Legacy padding for openssl -raw (non smartcard keys)
|
|
#
|
|
# The following is a standard PKCS1-v1_5 padding for SHA256 signatures, as
|
|
# defined in RFC3447. It is prepended to the actual signature (32 bytes) to
|
|
# form a sequence of 256 bytes (2048 bits) that is amenable to RSA signing. The
|
|
# padded hash will look as follows:
|
|
#
|
|
# 0x00 0x01 0xff ... 0xff 0x00 ASN1HEADER SHA256HASH
|
|
# |--------------205-----------||----19----||----32----|
|
|
#
|
|
# where ASN1HEADER is the ASN.1 description of the signed data. The complete 51
|
|
# bytes of actual data (i.e. the ASN.1 header complete with the hash) are
|
|
# packed as follows:
|
|
#
|
|
# SEQUENCE(2+49) {
|
|
# SEQUENCE(2+13) {
|
|
# OBJECT(2+9) id-sha256
|
|
# NULL(2+0)
|
|
# }
|
|
# OCTET STRING(2+32) <actual signature bytes...>
|
|
# }
|
|
echo "AAH/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////ADAxMA0GCWCGSAFlAwQCAQUABCA=" | base64 -d > padding
|
|
cat padding update.hash > update.padhash
|
|
|
|
echo "=== Signing update payload... ==="
|
|
i=1
|
|
signature_sizes=""
|
|
for key in "${private_keys[@]}"; do
|
|
if [[ "${key}" == pkcs11* ]]; then
|
|
sudo OPENSSL_CONF=/etc/ssl/pkcs11.cnf openssl pkeyutl -engine pkcs11 -sign -keyform engine -inkey "${key}" -in update.pkcs11-padhash -out "update.sig.${i}"
|
|
elif [[ "${key}" == fero* ]]; then
|
|
fero-client \
|
|
--address $FLAGS_signing_server_address \
|
|
--port $FLAGS_signing_server_port \
|
|
sign --pkcs1 \
|
|
--file update.hash \
|
|
--output update.sig.${i} \
|
|
--secret-key ${key:5:${#key}} \
|
|
${user_signatures_arg}
|
|
else
|
|
openssl rsautl -raw -sign -inkey ${key} -in update.padhash -out update.sig.${i}
|
|
fi
|
|
let "i += 1"
|
|
done
|
|
|
|
files=""
|
|
for i in update.sig.*; do
|
|
files=${files}:${i}
|
|
done
|
|
files="${files:1:${#files}}"
|
|
echo ${files}
|
|
|
|
delta_generator --signature_file ${files} --in_file update --out_file update.signed
|
|
|
|
i=1
|
|
for key in "${public_keys[@]}"; do
|
|
version="${i}"
|
|
if [ ${#public_keys[@]} == 1 ]; then
|
|
version=2
|
|
fi
|
|
|
|
delta_generator \
|
|
--public_key_version "${version}" \
|
|
--public_key "${key}" \
|
|
--in_file update.signed
|
|
|
|
let "i += 1"
|
|
done
|
|
|
|
mv update.signed ${FLAGS_output}
|
|
echo "=== Update payload signed successfully. ==="
|
|
|
|
trap - INT TERM EXIT
|
|
cleanup noexit
|
|
|
|
echo "Done generating full update."
|