blob: f7e0ec6cab6a6969cf4c61346482c834d9f9c727 [file] [log] [blame]
inherit hsm-sign-env
python __anonymous () {
depends = d.getVar("DEPENDS", True)
depends = "%s u-boot-mkimage-native dtc-native openssl-native" % depends
d.setVar("DEPENDS", depends)
}
# split input string to multiple quadbyte word (with 0x prefix for each word)
# input:
# $1: input string, e.g., 0123456789ABCDEF...
# $2: "swap", to do byte swap in each quadbyte; otherwise, no swap
# output:
# standard output: 0x67452301 0xEFCDAB89 ... if $2 = "swap"
# 0x01234567 0x89ABCDEF ... otherwise
split_str_to_quadbytes() {
quadbytes=""
if [ $2 = "swap" ]; then
sed_cmd="sed s,\(..\)\(..\)\(..\)\(..\),\4\3\2\1,g"
else
sed_cmd="sed s,\(..\)\(..\)\(..\)\(..\),\1\2\3\4,g"
fi
if [ ! -z "$1" ]; then
for i in $(seq 1 8 ${#1}); do
end_idx=`echo "${i} + 7" | bc`
qb=`echo ${1} | cut -c${i}-${end_idx} | ${sed_cmd}`
quadbytes="${quadbytes} 0x${qb}"
done
# trim leading space
awk '{$quadbytes=$quadbytes};1'
fi
echo $quadbytes
}
# Emit fit header
# input param:
# $1: fit its
fitimage_emit_fit_header() {
cat << EOF >> $1
/dts-v1/;
/ {
description = "bl";
#address-cells = <1>;
EOF
}
# Emit the fitimage image section
# input param:
# $1: fit its
# $2: path to padding binary
# $3: path to lk binary
# $4: lk load address
# $5: lk entry address
# $6: hash algorithm
fitimage_emit_fit_image_section() {
cat << EOF >> $1
images {
bl@1 {
description = "bl";
padding = /incbin/("${2}");
data = /incbin/("${3}");
type = "kernel";
compression = "none";
load = <${4}>;
entry = <${5}>;
hash@1 {
algo = "${6}";
};
};
};
EOF
}
# Emit fitimage configuration section
# input param:
# $1: fit its
# $2: hash algorithm
# $3: rsa algorithm
# $4: key name hint
# $5: aes iv
fitimage_emit_fit_conf_section() {
if [ "${ACK_EN}" = "yes" ]; then
# split aes iv to N 32-bit words
quadbytes=$(split_str_to_quadbytes ${5} noswap)
ack_iv_prop="ack_iv = <${quadbytes}>;"
else
ack_iv_prop=
fi
cat << EOF >> $1
configurations {
default = "conf@1";
conf@1 {
description = "bl";
kernel = "bl@1";
${ack_iv_prop}
signature@1 {
algo = "${2},${3}";
key-name-hint = "${4}";
sign-images = "kernel";
};
};
};
EOF
}
# Emit fitimage trusted-key-certificate oem section
# input param:
# $1: fit its
fitimage_emit_fit_tkc_oem_section() {
cat << EOF >> $1
trusted-key-certificate {
sign-node {
device-check = "skip-device-id-check";
device-id = "N0cI//dxndWXnsh11WzSKG9tPPfs";
trusted-key {
key-name-hint = "TierPubKey";
};
};
};
EOF
}
# Emit fitimage trusted-key-certificate tier section
# input param:
# $1: fit its
# $2: TKC.dtsi
fitimage_emit_fit_tkc_tier_section() {
cat << EOF >> $1
/include/ "$2"
EOF
}
# Emit fitimage fit end
# input param:
# $1: fit its
fitimage_emit_fit_end() {
cat << EOF >> $1
};
EOF
}
# get_fit_data_offset: get data offset from fit image
# input param:
# $1: fit image
get_fit_data_offset() {
FIT_IMAGE=$1
TMPF=$(mktemp ${WORKDIR}/dump-fit-img.XXXXXX)
# dump fit image
fdtdump -d ${FIT_IMAGE} > ${TMPF}
# get props
LINE=$(grep -n '^ *data' ${TMPF} | grep -o '^[0-9]*')
LINE=`expr ${LINE} - 1`
ADDR=$(grep -n "^// [[:xdigit:]]*: value" ${TMPF} | grep "^${LINE}://" | \
grep -o " [[:xdigit:]]*" | grep -o "[[:xdigit:]]*")
# remove temp files
rm -f ${TMPF}
echo ${ADDR}
}
# check_fit_image: check fit image and also check load/entry address if 2nd
# param was present
# input param:
# $1: fit image
# $2: if present, will also check load and entry validity
check_fit_image() {
FIT_IMAGE=$1
CHECK_OPT=$2
# check default cfg
CFG=$(fdtget ${FIT_IMAGE} /configurations default)
if [ "${CFG}" = "" ]; then
echo "ERROR: no default in /configurations"
exit 1
fi
# check image name
IMG_NAME=$(fdtget ${FIT_IMAGE} /configurations/${CFG} kernel)
if [ "${IMG_NAME}" = "" ]; then
echo "ERROR: no image name (kernel prop) in /configurations/${CFG}"
exit 1
fi
# check data
DATA=$(fdtget ${FIT_IMAGE} /images/${IMG_NAME} data)
if [ "${DATA}" = "" ]; then
echo "ERROR: no data in /images/${IMG_NAME}"
exit 1
fi
# check load
LOAD_D=$(fdtget ${FIT_IMAGE} /images/${IMG_NAME} load)
if [ "$LOAD_D" = "" ]; then
echo "ERROR: no load in /images/${IMG_NAME}"
exit 1
fi
# check entry
ENTRY_D=$(fdtget ${FIT_IMAGE} /images/${IMG_NAME} entry)
if [ "$ENTRY_D" = "" ]; then
echo "ERROR: no entry in /images/${IMG_NAME}"
exit 1
fi
if [ "${CHECK_OPT}" != "" ]; then
OFFSET=$(get_fit_data_offset ${FIT_IMAGE})
LOAD=$(printf "%x" ${LOAD_D})
if [ "`expr ${LOAD} : '.*\(....\)'`" != "${OFFSET}" ]; then
echo ERROR: load ${LOAD} is not align with data offset ${OFFSET}
exit 1
fi
LEN=$(echo ${DATA} | wc -w)
ENTRY=$(printf "%x" ${ENTRY_D})
END_D=`echo "${LOAD_D} + ${LEN} * 4" | bc`
END=$(printf "%x" ${END_D})
if [ ${ENTRY_D} -lt ${LOAD_D} -o ${END_D} -le ${ENTRY_D} ]; then
echo ERROR: entry ${ENTRY} is not in data ${LOAD} - ${END}
exit 1
fi
fi
}
# generate fit image: generate lk image in fit format
# input param:
# $1: fit image its file
# $2: key dir
# $3: output file
gen_fit_image() {
FIT_ITS=$1
KEYDIR=$2
OUT=$3
DTB=$(mktemp ${WORKDIR}/dtb.XXXXXX)
KEYDTSI=$(mktemp ${WORKDIR}/key.XXXXXX.dtsi)
KEYITS=$(mktemp ${WORKDIR}/key-fit-image.XXXXXX.its)
if [ "${SBC_SIGN_ALGO}" = "ecc" ]; then
case "${SBC_ECC_ALGO}" in
nistp256)
HSM_SBC_KEY=${SBC_KEY_ECC256}
;;
nistp384)
HSM_SBC_KEY=${SBC_KEY_ECC384}
;;
nistp521)
HSM_SBC_KEY=${SBC_KEY_ECC521}
;;
*)
echo ${SBC_ECC_ALGO} ": not supported."
exit 1
;;
esac
else
case "${SBC_RSA_ALGO}" in
rsa2048 | rsassa-pss2048)
HSM_SBC_KEY=${SBC_KEY}
;;
rsa3072 | rsassa-pss3072)
HSM_SBC_KEY=${SBC_KEY_RSA3072}
;;
rsa4096 | rsassa-pss4096)
HSM_SBC_KEY=${SBC_KEY_RSA4096}
;;
*)
echo ${SBC_RSA_ALGO} ": not supported."
exit 1
;;
esac
fi
echo "HSM_SBC_KEY name is ${HSM_SBC_KEY}"
echo "/dts-v1/; / {};" | dtc -O dtb > ${DTB}
if [ "${TKC_SUPPORT}" = "oem" ]; then
${HSM_ENV} HSM_KEY_NAME=${HSM_SBC_KEY} ${FIT_IMG_TOOL} -f ${FIT_ITS} -k ${KEYDIR} -K ${DTB} -g ${TKC_PUBLIC_KEY_TIER} ${OUT}
elif [ "${TKC_SUPPORT}" = "tier" ]; then
${HSM_ENV} HSM_KEY_NAME=${HSM_SBC_KEY} ${FIT_IMG_TOOL} -f ${FIT_ITS} -k ${KEYDIR} -K ${DTB} -u ${TKC_PUBLIC_KEY_OEM} ${OUT}
else
${HSM_ENV} HSM_KEY_NAME=${HSM_SBC_KEY} ${FIT_IMG_TOOL} -f ${FIT_ITS} -k ${KEYDIR} -K ${DTB} ${OUT}
fi
dtc -I dtb ${DTB} | tail -n+2 > ${KEYDTSI}
sed "s,\/dts-v1\/;,\0\n\/include\/ \"${KEYDTSI}\"," < ${FIT_ITS} > ${KEYITS}
${HSM_ENV} HSM_KEY_NAME=${HSM_SBC_KEY} ${FIT_IMG_TOOL} -f ${KEYITS} -k ${KEYDIR} ${OUT}
# remove temporary files
rm -f ${DTB} ${KEYDTSI} ${KEYITS}
}
# gen_sbc_key_hash
# input param:
# $1: fit image
gen_sbc_key_hash() {
FDT_IMG=$1
TMP_FILE=$(mktemp ${WORKDIR}/col_rgn.XXXXXX.bin)
DEF_CONF=`fdtget -t s ${FDT_IMG} /configurations default`
SIG_NODE=`fdtget -l ${FDT_IMG} /configurations/${DEF_CONF}`
KEY_HINT=`fdtget -t s ${FDT_IMG} /configurations/${DEF_CONF}/${SIG_NODE} key-name-hint`
SHAX=`fdtget -t s ${FDT_IMG} /configurations/${DEF_CONF}/${SIG_NODE} algo | cut -d, -f1`
${WORKDIR}/fit-lk/extract_region ${FDT_IMG} ${TMP_FILE} /signature/key-${KEY_HINT}
KEY_HASH=`${SHAX}sum ${TMP_FILE} | cut -d " " -f 1`
echo "Hash algo: ${SHAX}"
echo "key_hash: ${KEY_HASH}"
key_hash_str=$(split_str_to_quadbytes ${KEY_HASH} swap)
idx=0
for qb in $key_hash_str; do
echo "keyhash_${idx}: ${qb}"
idx=`echo "${idx} + 1" | bc`
done
rm -f ${TMP_FILE}
}
# print_aes_key_iv
# $1: aes key
# $2: aes iv
print_aes_key_iv() {
# print aes keys
echo "AES_KEY(AC_KEY)=${1}"
quadbytes=$(split_str_to_quadbytes ${1} swap)
idx=0
for qb in $quadbytes; do
echo "AC_KEY${idx}: ${qb}"
idx=`echo "${idx} + 1" | bc`
done
# print aes iv
echo "AES_IV=${2}"
quadbytes=$(split_str_to_quadbytes ${2} noswap)
echo "prop ack_iv=<${quadbytes}>"
}
gen_lk_fit_header() {
# generate temp files
BL_BIN=$(mktemp ${WORKDIR}/bl.XXXXXX.bin)
FIT_LK_IMG=${WORKDIR}/fit-lk.img
FIT_ITS=$(mktemp ${WORKDIR}/fit-bl-image.XXXXXX.its)
KEYDIR=${WORKDIR}/lk-key
PADDING=$(mktemp ${WORKDIR}/padding.XXXXXX.bin)
if [ "${ACK_EN}" = "yes" ]; then
# output AES encrypted BL image to working directory
openssl enc -e -aes-128-cbc -in ${LK_OUT}/build-${LK_PROJECT}/${LK_BINARY} \
-out ${BL_BIN} -K ${AES_KEY} -iv ${AES_IV}
else
# copy raw lk binary to working directory
cp ${LK_OUT}/build-${LK_PROJECT}/${LK_BINARY} ${BL_BIN}
fi
# generate a zero-size padding binary
touch ${PADDING}
# prepare rsa key
mkdir -p ${KEYDIR}
if [ "${SBC_SIGN_ALGO}" = "ecc" ]; then
case "${SBC_ECC_ALGO}" in
nistp256)
cp -f ${MTK_KEY_DIR}/${SBC_KEY_ECC256}_priv.pem ${KEYDIR}/dev_priv.key
cp -f ${MTK_KEY_DIR}/${SBC_KEY_ECC256}_public.pem ${KEYDIR}/dev_public.key
;;
nistp384)
cp -f ${MTK_KEY_DIR}/${SBC_KEY_ECC384}_priv.pem ${KEYDIR}/dev_priv.key
cp -f ${MTK_KEY_DIR}/${SBC_KEY_ECC384}_public.pem ${KEYDIR}/dev_public.key
;;
nistp521)
cp -f ${MTK_KEY_DIR}/${SBC_KEY_ECC521}_priv.pem ${KEYDIR}/dev_priv.key
cp -f ${MTK_KEY_DIR}/${SBC_KEY_ECC521}_public.pem ${KEYDIR}/dev_public.key
;;
*)
echo ${SBC_ECC_ALGO} ": not supported."
exit 1
;;
esac
else
case "${SBC_RSA_ALGO}" in
rsa2048 | rsassa-pss2048)
cp -f ${MTK_KEY_DIR}/${SBC_KEY}.crt ${KEYDIR}/dev.crt
cp -f ${MTK_KEY_DIR}/${SBC_KEY}.pem ${KEYDIR}/dev.key
;;
rsa3072 | rsassa-pss3072)
cp -f ${MTK_KEY_DIR}/${SBC_KEY_RSA3072}.crt ${KEYDIR}/dev.crt
cp -f ${MTK_KEY_DIR}/${SBC_KEY_RSA3072}.pem ${KEYDIR}/dev.key
;;
rsa4096 | rsassa-pss4096)
cp -f ${MTK_KEY_DIR}/${SBC_KEY_RSA4096}.crt ${KEYDIR}/dev.crt
cp -f ${MTK_KEY_DIR}/${SBC_KEY_RSA4096}.pem ${KEYDIR}/dev.key
;;
*)
echo ${SBC_RSA_ALGO} ": not supported."
exit 1
;;
esac
fi
# key for trusted-key-certificate
if [ "${TKC_SUPPORT}" = "oem" ]; then
if [ "${SBC_SIGN_ALGO}" = "ecc" ]; then
cp -f ${MTK_KEY_DIR}/${TKC_PUBLIC_KEY_TIER}.pem ${KEYDIR}/tier_public.key
elif [ "${SBC_SIGN_ALGO}" = "rsa" ]; then
cp -f ${MTK_KEY_DIR}/${TKC_PUBLIC_KEY_TIER}.crt ${KEYDIR}/tier_public.crt
fi
elif [ "${TKC_SUPPORT}" = "tier" ]; then
if [ "${SBC_SIGN_ALGO}" = "ecc" ]; then
cp -f ${MTK_KEY_DIR}/${TKC_PUBLIC_KEY_OEM}.pem ${KEYDIR}/oem_public.key
elif [ "${SBC_SIGN_ALGO}" = "rsa" ]; then
cp -f ${MTK_KEY_DIR}/${TKC_PUBLIC_KEY_OEM}.crt ${KEYDIR}/oem_public.crt
fi
fi
# generate base its file
fitimage_emit_fit_header ${FIT_ITS}
# if TKC is supportted, place it here
if [ "${TKC_SUPPORT}" = "oem" ]; then
fitimage_emit_fit_tkc_oem_section ${FIT_ITS} ${SBC_HASH_ALGO} ${SBC_ECC_ALGO} dev
elif [ "${TKC_SUPPORT}" = "tier" ]; then
fitimage_emit_fit_tkc_tier_section ${FIT_ITS} ${MTK_KEY_DIR}/TKC.dtsi
fi
fitimage_emit_fit_image_section ${FIT_ITS} ${PADDING} ${BL_BIN} \
${LK_LOADADDRESS} ${LK_ENTRYPOINT} ${IMAGE_HASH_ALGO}
if [ "${SBC_SIGN_ALGO}" = "ecc" ]; then
fitimage_emit_fit_conf_section ${FIT_ITS} ${SBC_HASH_ALGO} ${SBC_ECC_ALGO} dev ${AES_IV}
else
fitimage_emit_fit_conf_section ${FIT_ITS} ${SBC_HASH_ALGO} ${SBC_RSA_ALGO} dev ${AES_IV}
fi
fitimage_emit_fit_end ${FIT_ITS}
# 1st pass: generate fit-lk image to get padding size
gen_fit_image ${FIT_ITS} ${KEYDIR} ${FIT_LK_IMG}
check_fit_image ${FIT_LK_IMG}
# get data offset and calculate padding size
# padding size = lk load offset - data offset
DATA_OFFSET=$(get_fit_data_offset ${FIT_LK_IMG})
DATA_OFFSET_HEX=0x${DATA_OFFSET}
DATA_OFFSET_D=$(printf "%d" ${DATA_OFFSET_HEX})
LK_LOAD_OFFSET_D=$(printf "%d" ${LK_LOAD_OFFSET})
PADDING_SIZE=`echo "${LK_LOAD_OFFSET_D} - ${DATA_OFFSET_D}" | bc`
rm -f ${PADDING}
dd if=/dev/zero of=${PADDING} bs=1 count=${PADDING_SIZE}
# 2nd pass: generate final fit-lk image
gen_fit_image ${FIT_ITS} ${KEYDIR} ${FIT_LK_IMG}
check_fit_image ${FIT_LK_IMG} all
cp ${FIT_LK_IMG} ${WORKDIR}/${LK_IMAGE}
# gen key hash for convenience
gen_sbc_key_hash ${FIT_LK_IMG}
# output aes key and iv for reference
if [ "${ACK_EN}" = "yes" ]; then
print_aes_key_iv ${AES_KEY} ${AES_IV}
fi
# remove temp files
rm -f ${BL_BIN} ${FIT_ITS} ${PADDING}
rm -rf ${KEYDIR}
}
gen_lk_gfh_header() {
cp ${LK_OUT}/build-${LK_PROJECT}/${LK_BINARY} ${WORKDIR}/temp_gfh
if [ "${SECURE_BOOT_ENABLE}" = "yes" ]; then
cp ${MTK_KEY_DIR}/${SBC_KEY}.pem ${KEY_DIR}/root_prvk.pem
fi
python ${PBP_DIR}/pbp.py -g ${GFH_DIR}/${TARGET_PLATFORM}/gfh_conf.ini \
-i ${KEY_DIR}/lk_key.ini -func sign \
-o ${WORKDIR}/temp_gfh ${WORKDIR}/temp_gfh
if [ "${BOOTDEV_TYPE}" != "nand" ]; then
python ${DEV_INFO_HDR_TOOL} \
${BOOTDEV_TYPE} ${WORKDIR}/temp_gfh ${WORKDIR}/${LK_IMAGE}
else
cp ${WORKDIR}/temp_gfh ${WORKDIR}/${LK_IMAGE}
fi
}