| 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 |
| } |