#!/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 or pkcs11 URI for private keys." DEFINE_string public_keys "" "Path to public keys in .pem format." DEFINE_string keys_separator ":" "Separator for the above keys" # 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}}" 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) # } 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) # } 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}" 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."