243 lines
5.9 KiB
Bash
Executable File
243 lines
5.9 KiB
Bash
Executable File
#!/bin/bash -e
|
|
|
|
# Copyright (c) 2025 Amlogic, Inc. All rights reserved.
|
|
#
|
|
# This source code is subject to the terms and conditions defined in the
|
|
# file 'LICENSE' which is part of this source code package.
|
|
|
|
#set -x
|
|
|
|
SCRIPT_PATH=${SCRIPT_PATH:-$(dirname $(readlink -f $0))}
|
|
|
|
# Temporary files directory
|
|
if [ "$TMP" == "/tmp" ] || [ -z "$TMP" ]; then
|
|
TMP=${SCRIPT_PATH}/tmp
|
|
fi
|
|
|
|
trace ()
|
|
{
|
|
echo ">>> $@" > /dev/null
|
|
}
|
|
|
|
usage() {
|
|
cat << EOF
|
|
Usage: $(basename $0) --help
|
|
|
|
Amlogic Device Vendor Secure Chipset Startup (SCS) Signing
|
|
|
|
$(basename $0) --add-device-keys \\
|
|
--key-dir <key-dir> \\
|
|
--project <project-name> \\
|
|
--input <input img> \\
|
|
{--rootkey-index [0 | 1 | 2 | 3]} \\
|
|
--output <output img>
|
|
EOF
|
|
exit 1
|
|
}
|
|
|
|
check_file() {
|
|
if [ ! -f "$2" ]; then echo Error: Unable to open $1: \""$2"\"; exit 1 ; fi
|
|
}
|
|
|
|
check_dir() {
|
|
if [ ! -d "$1" ]; then echo "Error: directory \""$1"\" does NOT exist"; usage ; fi
|
|
}
|
|
|
|
check_value() {
|
|
local val=$1
|
|
local begin=$2
|
|
local end=$3
|
|
|
|
if [ $val -lt $begin ] || [ $val -gt $end ]; then
|
|
echo "Error: Value $val is not in range [$begin, $end]"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# struct scs_cmn_hdr_t {
|
|
# u64 magic_u64;
|
|
# u16 version_u16;
|
|
# u16 flags_u16;
|
|
# u32 length_u32;
|
|
# };
|
|
# u64 magic = 0x38a41024204c4d40;
|
|
|
|
append_uint32_le() {
|
|
local input=$1
|
|
local output=$2
|
|
local v=
|
|
local vrev=
|
|
v=$(printf %08x $input)
|
|
# 00010001
|
|
vrev=${v:6:2}${v:4:2}${v:2:2}${v:0:2}
|
|
|
|
echo $vrev | xxd -r -p >> $output
|
|
}
|
|
|
|
# Convert RSA PEM key to precomputed binary key file
|
|
# If input is already the precomputed binary key file, then it is simply copied
|
|
# to the output
|
|
# $1: input RSA private .PEM
|
|
# $2: output precomputed binary key file
|
|
# $3: enable N0INV128 if True
|
|
pem_to_bin() {
|
|
local input=$1
|
|
local output=$2
|
|
local n0inv128_enable=$3
|
|
if [ ! -f "$1" ] || [ -z "$2" ]; then
|
|
echo "Argument error, \"$1\", \"$2\" "
|
|
exit 1
|
|
fi
|
|
if [ -z "$n0inv128_enable" ]; then
|
|
n0inv128_enable=False
|
|
fi
|
|
|
|
local insize=$(wc -c < $input)
|
|
if [ $insize -eq 1052 ] || [ $insize -eq 1036 ]; then
|
|
# input is already precomputed binary key file
|
|
cp $input $output
|
|
fi
|
|
|
|
if ! command -v python2 >/dev/null 2>&1; then
|
|
if [ "$n0inv128_enable" = True ] || [ "$n0inv128_enable" = true ]; then
|
|
"${SCRIPT_PATH}/pem_extract_pubkey_py3.py" --n0inv128Enable "$input" "$output"
|
|
else
|
|
"${SCRIPT_PATH}/pem_extract_pubkey_py3.py" "$input" "$output"
|
|
fi
|
|
else
|
|
local pycmd="import sys; \
|
|
sys.path.append(\"${SCRIPT_PATH}\"); \
|
|
import pem_extract_pubkey; \
|
|
sys.stdout.write(pem_extract_pubkey.extract_pubkey( \
|
|
\"$input\", headerMode=False, n0inv128Enable=$n0inv128_enable));"
|
|
/usr/bin/env python2 -c "$pycmd" > $output
|
|
fi
|
|
}
|
|
|
|
add_device_keys() {
|
|
local input=""
|
|
local key_dir=""
|
|
local part=""
|
|
local rootkey_index=0
|
|
local output=""
|
|
local bl33_rsakey=""
|
|
local krnl_rsakey=""
|
|
local sig_scheme="rsa-mldsa"
|
|
local argv=("$@")
|
|
local i=0
|
|
|
|
# Parse args
|
|
i=0
|
|
while [ $i -lt $# ]; do
|
|
arg="${argv[$i]}"
|
|
i=$((i + 1))
|
|
case "$arg" in
|
|
--key-dir)
|
|
key_dir="${argv[$i]}"
|
|
check_dir "${key_dir}"
|
|
;;
|
|
--project)
|
|
part="${argv[$i]}"
|
|
;;
|
|
--input)
|
|
input="${argv[$i]}"
|
|
;;
|
|
--rootkey-index)
|
|
rootkey_index="${argv[$i]}"
|
|
check_value "${rootkey_index}" 0 3
|
|
;;
|
|
--output)
|
|
output="${argv[$i]}"
|
|
;;
|
|
*)
|
|
echo "Unknown option $arg"; exit 1
|
|
;;
|
|
esac
|
|
i=$((i + 1))
|
|
done
|
|
|
|
# Verify args
|
|
if [ -z "${key_dir}" ]; then
|
|
usage
|
|
fi
|
|
|
|
if [ -z "${part}" ]; then
|
|
echo "Error: project cannot be empty"
|
|
usage
|
|
fi
|
|
|
|
if [ -z "${rootkey_index}" ]; then
|
|
rootkey_index=0
|
|
fi
|
|
|
|
check_file "input" "${input}"
|
|
if [ -z "${output}" ]; then
|
|
echo Error: Missing output file option --output; exit 1;
|
|
fi
|
|
|
|
bl33_rsakey=$(readlink -f ${key_dir})/fip/rsa/${part}/rootrsa-${rootkey_index}/key/bl33-level-3-rsa-priv.pem
|
|
check_file "BL33 RSA key" "${bl33_rsakey}"
|
|
krnl_rsakey=$(readlink -f ${key_dir})/fip/rsa/${part}/rootrsa-${rootkey_index}/key/krnl-level-3-rsa-priv.pem
|
|
check_file "Kernel RSA key" "${krnl_rsakey}"
|
|
|
|
pem_to_bin $bl33_rsakey $TMP/bl33key.bin True
|
|
pem_to_bin $krnl_rsakey $TMP/krnlkey.bin True
|
|
|
|
# Create header
|
|
# magic_u64, version_u16, flags_u16, length_u32
|
|
append_uint32_le 0x204c4d40 $TMP/key.hdr
|
|
append_uint32_le 0x38a41024 $TMP/key.hdr
|
|
append_uint32_le 0 $TMP/key.hdr
|
|
append_uint32_le 1072 $TMP/key.hdr
|
|
|
|
cat $TMP/key.hdr $TMP/bl33key.bin > $TMP/bl33key-pl.bin
|
|
cat $TMP/key.hdr $TMP/krnlkey.bin > $TMP/krnlkey-pl.bin
|
|
|
|
if [ ${input} != ${output} ]; then
|
|
cp ${input} ${output}
|
|
fi
|
|
dd if=$TMP/bl33key-pl.bin of=${output} bs=1 seek=4 conv=notrunc &> /dev/null
|
|
dd if=$TMP/krnlkey-pl.bin of=${output} bs=1 seek=2052 conv=notrunc &> /dev/null
|
|
}
|
|
|
|
parse_main() {
|
|
local i=0
|
|
local argv=()
|
|
for arg in "$@" ; do
|
|
argv[$i]="$arg"
|
|
i=$((i + 1))
|
|
done
|
|
|
|
i=0
|
|
while [ $i -lt $# ]; do
|
|
arg="${argv[$i]}"
|
|
case "$arg" in
|
|
-h|--help)
|
|
usage
|
|
break ;;
|
|
--add-device-keys)
|
|
add_device_keys "${argv[@]:$((i + 1))}"
|
|
break ;;
|
|
*)
|
|
echo "Unknown first option $1"; exit 1
|
|
;;
|
|
esac
|
|
i=$((i + 1))
|
|
done
|
|
}
|
|
|
|
cleanup() {
|
|
if [ ! -d "$TMP" ]; then return; fi
|
|
local tmpfiles="$TMP/bl33key.bin $TMP/krnlkey.bin $TMP/key.hdr $TMP/bl33key-pl.bin $TMP/krnlkey-pl.bin "
|
|
for i in $tmpfiles ; do
|
|
rm -f $TMP/$i
|
|
done
|
|
rm -fr $TMP
|
|
}
|
|
|
|
trap cleanup EXIT
|
|
|
|
cleanup
|
|
if [ ! -d "$TMP" ]; then mkdir "$TMP" ; fi
|
|
parse_main "$@"
|