mirror of
				https://github.com/flatcar/scripts.git
				synced 2025-10-31 08:11:03 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			163 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			4.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 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) <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}"
 | |
| 	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."
 |