meta-phosphor: npcm8xx.bbclass: support sign images feature

Add sign images feature according customer's requirement.
Set "SECURED_IMAGE" to "True" and enable sign images feature.
When sign images feature be enabled. Use default keys to sign
images if customer didn't point their own local keys path.

Note: "SECURED_IMAGE" default is "True".

Tested:
Use default keys sign:
That will use default path and keys from igps to sign.

Use local keys sign:
That will use local path and keys to sign.
When KEY_FOLDER and KEY definition both are valid.

However, when KEY_FOLDER and KEY definition are invalid either,
that will output sign images failed then stop build full images.

Tested: build pass and boot up successfully with signed

Signed-off-by: Tim Lee <timlee660101@gmail.com>
Change-Id: If2b793906ab338aec391062d9bfeae2b1e790078
diff --git a/meta-nuvoton/conf/machine/include/igps-keys.inc b/meta-nuvoton/conf/machine/include/igps-keys.inc
new file mode 100644
index 0000000..dcc5f7c
--- /dev/null
+++ b/meta-nuvoton/conf/machine/include/igps-keys.inc
@@ -0,0 +1,20 @@
+# There are two valid types: "openssl" or "HSM".
+# Currently, default support openssl only.
+SIGN_TYPE ?= "openssl"
+
+KEY_BB_INDEX ?= "1"
+SKMT_BL31_KEY_INDEX ?= "1"
+SKMT_BL32_KEY_INDEX ?= "1"
+SKMT_BL33_KEY_INDEX ?= "1"
+
+KEY_BB_ID ?= "11"
+KEY_BL31_ID ?= "11"
+KEY_OPTEE_ID ?= "11"
+KEY_UBOOT_ID ?= "11"
+
+KEY_FOLDER ?= ""
+KEY_FOLDER_DEFAULT ?= "${DEPLOY_DIR_IMAGE}/${SIGN_TYPE}"
+KEY_BB ?= "skmt_ecc_key_1.der"
+KEY_BL31 ?= "skmt_ecc_key_1.der"
+KEY_OPTEE ?= "skmt_ecc_key_1.der"
+KEY_UBOOT ?= "skmt_ecc_key_1.der"
diff --git a/meta-nuvoton/conf/machine/include/npcm8xx.inc b/meta-nuvoton/conf/machine/include/npcm8xx.inc
index 349d53b..0a753a1 100644
--- a/meta-nuvoton/conf/machine/include/npcm8xx.inc
+++ b/meta-nuvoton/conf/machine/include/npcm8xx.inc
@@ -3,6 +3,7 @@
 #@DESCRIPTION: Common machine configuration for Nuvoton NPCM8XX Chip
 
 require conf/machine/include/nuvoton.inc
+require conf/machine/include/igps-keys.inc
 
 KERNEL_IMAGETYPE ?= "Image"
 KERNEL_EXTRA_ARGS ?= "UIMAGE_LOADADDR=0x00008000"
@@ -59,4 +60,6 @@
 
 OPTEEMACHINE ?= "nuvoton"
 
+SECURED_IMAGE ?= "True"
+
 TIP_IMAGE ?= "True"
diff --git a/meta-nuvoton/recipes-bsp/images/npcm8xx-igps.inc b/meta-nuvoton/recipes-bsp/images/npcm8xx-igps.inc
index ace078e..099fa47 100644
--- a/meta-nuvoton/recipes-bsp/images/npcm8xx-igps.inc
+++ b/meta-nuvoton/recipes-bsp/images/npcm8xx-igps.inc
@@ -21,14 +21,26 @@
 
 do_install() {
 	install -d ${DEST}
-	if [ "${TIP_IMAGE}" = "True" ] ; then
-		install py_scripts/ImageGeneration/references/BootBlockAndHeader_${DEVICE_GEN}_${IGPS_MACHINE}.xml ${DEST}
+    if [ "${TIP_IMAGE}" = "True" ] ; then
+        install py_scripts/ImageGeneration/references/BootBlockAndHeader_${DEVICE_GEN}_${IGPS_MACHINE}.xml ${DEST}
 	else
-		install py_scripts/ImageGeneration/references/BootBlockAndHeader_A1_${IGPS_MACHINE}_NoTip.xml ${DEST}
-	fi
+        install py_scripts/ImageGeneration/references/BootBlockAndHeader_${DEVICE_GEN}_${IGPS_MACHINE}_NoTip.xml ${DEST}
+    fi
 	install py_scripts/ImageGeneration/references/UbootHeader_${DEVICE_GEN}.xml ${DEST}
 	install py_scripts/ImageGeneration/inputs/BL31_AndHeader.xml ${DEST}
 	install py_scripts/ImageGeneration/inputs/OpTeeAndHeader.xml ${DEST}
+	install py_scripts/ImageGeneration/asn1.py ${DEST}
+	install py_scripts/ImageGeneration/BinarySignatureGenerator.py ${DEST}
+}
+
+inherit deploy
+
+do_deploy () {
+	# copy default keys to deploy folder
+	install -d ${DEPLOYDIR}
+	cp -vur py_scripts/ImageGeneration/keys/${SIGN_TYPE} ${DEPLOYDIR}/
 }
 
 inherit native
+
+addtask deploy before do_build after do_compile
diff --git a/meta-phosphor/classes/image_types_phosphor_nuvoton_npcm8xx.bbclass b/meta-phosphor/classes/image_types_phosphor_nuvoton_npcm8xx.bbclass
index 913286e..eb78494 100644
--- a/meta-phosphor/classes/image_types_phosphor_nuvoton_npcm8xx.bbclass
+++ b/meta-phosphor/classes/image_types_phosphor_nuvoton_npcm8xx.bbclass
@@ -1,15 +1,21 @@
 UBOOT_BINARY := "u-boot.${UBOOT_SUFFIX}"
-BOOTBLOCK = "BootBlockAndHeader.bin"
-ATF_BINARY := "bl31AndHeader.bin"
-OPTEE_BINARY := "teeAndHeader.bin"
+BB_HEADER_BINARY := "BootBlockAndHeader.bin"
+BL31_HEADER_BINARY := "bl31AndHeader.bin"
+OPTEE_HEADER_BINARY := "teeAndHeader.bin"
 KMT_TIPFW_BINARY := "Kmt_TipFwL0_Skmt_TipFwL1.bin"
 KMT_TIPFW_BB_BINARY = "Kmt_TipFw_BootBlock.bin"
 KMT_TIPFW_BB_BL31_BINARY = "Kmt_TipFw_BootBlock_BL31.bin"
 KMT_TIPFW_BB_BL31_TEE_BINARY = "Kmt_TipFw_BootBlock_BL31_Tee.bin"
 KMT_TIPFW_BB_UBOOT_BINARY = "u-boot.bin.merged"
+
+BB_BL31_BINARY = "BootBlock_BL31_no_tip.bin"
+BB_BL31_TEE_BINARY = "BootBlock_BL31_Tee_no_tip.bin"
+BB_BL31_TEE_UBOOT_BINARY = "u-boot.bin.merged"
+
 FULL_SUFFIX = "full"
 MERGED_SUFFIX = "merged"
 UBOOT_SUFFIX:append = ".${MERGED_SUFFIX}"
+UBOOT_HEADER_BINARY := "${UBOOT_BINARY}.${FULL_SUFFIX}"
 
 IGPS_DIR = "${STAGING_DIR_NATIVE}/${datadir}/npcm8xx-igps"
 
@@ -17,9 +23,11 @@
 BL31_BIN = "bl31.bin"
 OPTEE_BIN = "tee.bin"
 UBOOT_BIN = "u-boot.bin"
+BB_NO_TIP_BIN = "arbel_a35_bootblock_no_tip.bin"
 
 # Align images if needed
 python do_pad_binary() {
+    TIP_IMAGE = d.getVar('TIP_IMAGE', True)
     def Pad_bin_file_inplace(inF, align):
         padding_size = 0
         padding_size_end = 0
@@ -33,14 +41,18 @@
         infile.write(b'\x00' * padding_size)
         infile.close()
 
-    Pad_bin_file_inplace(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True),
+    if TIP_IMAGE == "True":
+        Pad_bin_file_inplace(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True),
         '%s' % d.getVar('BB_BIN',True)), int(d.getVar('PAD_ALIGN', True)))
+    else:
+        Pad_bin_file_inplace(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True),
+        '%s' % d.getVar('BB_NO_TIP_BIN',True)), int(d.getVar('PAD_ALIGN', True)))
 
     Pad_bin_file_inplace(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True),
-        '%s' % d.getVar('BL31_BIN',True)), int(d.getVar('PAD_ALIGN', True)))
+    '%s' % d.getVar('BL31_BIN',True)), int(d.getVar('PAD_ALIGN', True)))
 
     Pad_bin_file_inplace(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True),
-        '%s' % d.getVar('OPTEE_BIN',True)), int(d.getVar('PAD_ALIGN', True)))
+    '%s' % d.getVar('OPTEE_BIN',True)), int(d.getVar('PAD_ALIGN', True)))
 
     Pad_bin_file_inplace(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True),
         '%s' % d.getVar('UBOOT_BIN',True)), int(d.getVar('PAD_ALIGN', True)))
@@ -52,22 +64,97 @@
     cd ${DEPLOY_DIR_IMAGE}
 
     bingo ${IGPS_DIR}/BL31_AndHeader.xml \
-            -o ${DEPLOY_DIR_IMAGE}/${ATF_BINARY}
+            -o ${BL31_HEADER_BINARY}
 
     bingo ${IGPS_DIR}/OpTeeAndHeader.xml \
-            -o ${DEPLOY_DIR_IMAGE}/${OPTEE_BINARY}
+            -o ${OPTEE_HEADER_BINARY}
 
+    if [ "${TIP_IMAGE}" = "True" ]; then
     bingo ${IGPS_DIR}/BootBlockAndHeader_${DEVICE_GEN}_${IGPS_MACHINE}.xml \
-            -o ${DEPLOY_DIR_IMAGE}/${BOOTBLOCK}
+            -o ${BB_HEADER_BINARY}
+    else
+    bingo ${IGPS_DIR}/BootBlockAndHeader_${DEVICE_GEN}_${IGPS_MACHINE}_NoTip.xml \
+            -o ${BB_HEADER_BINARY}
+    fi
 
     bingo ${IGPS_DIR}/UbootHeader_${DEVICE_GEN}.xml \
-            -o ${UBOOT_BINARY}.${FULL_SUFFIX}
+            -o ${UBOOT_HEADER_BINARY}
 
     cd "$olddir"
 }
 
-python do_merge_bootloaders() {
+check_keys() {
+    if [ -n "${KEY_FOLDER}" ]; then
+        echo "local"
+    else
+        echo "default"
+    fi
+}
 
+# Sign images for secure os be enabled
+do_sign_binary() {
+    if [ "${SECURED_IMAGE}" != "True" ]; then
+       return
+    fi
+    checked=`check_keys`
+    if [ "${checked}" = "local" ]; then
+        bbnote "Sign image with local keys"
+        key_bb=${KEY_FOLDER}/${KEY_BB}
+        key_bl31=${KEY_FOLDER}/${KEY_BL31}
+        key_optee=${KEY_FOLDER}/${KEY_OPTEE}
+        key_uboot=${KEY_FOLDER}/${KEY_UBOOT}
+    else
+        bbnote "Sign image with default keys"
+        key_bb=${KEY_FOLDER_DEFAULT}/${KEY_BB}
+        key_bl31=${KEY_FOLDER_DEFAULT}/${KEY_BL31}
+        key_optee=${KEY_FOLDER_DEFAULT}/${KEY_OPTEE}
+        key_uboot=${KEY_FOLDER_DEFAULT}/${KEY_UBOOT}
+    fi
+    bbnote "BB sign key from ${checked}: ${key_bb}"
+    bbnote "BL31 sign key from ${checked}: ${key_bl31}"
+    bbnote "OPTEE sign key from ${checked}: ${key_optee}"
+    bbnote "UBOOT sign key from ${checked}: ${key_uboot}"
+    # Used to embed the key index inside the image, usually at offset 0x140
+    python3 ${IGPS_DIR}/BinarySignatureGenerator.py Replace_binary_single_byte \
+        ${DEPLOY_DIR_IMAGE}/${BB_HEADER_BINARY} 140 ${KEY_BB_INDEX}
+
+    python3 ${IGPS_DIR}/BinarySignatureGenerator.py Replace_binary_single_byte \
+        ${DEPLOY_DIR_IMAGE}/${BL31_HEADER_BINARY} 140 ${SKMT_BL31_KEY_INDEX}
+
+    python3 ${IGPS_DIR}/BinarySignatureGenerator.py Replace_binary_single_byte \
+        ${DEPLOY_DIR_IMAGE}/${OPTEE_HEADER_BINARY} 140 ${SKMT_BL32_KEY_INDEX}
+
+    python3 ${IGPS_DIR}/BinarySignatureGenerator.py Replace_binary_single_byte \
+        ${DEPLOY_DIR_IMAGE}/${UBOOT_HEADER_BINARY} 140 ${SKMT_BL33_KEY_INDEX}
+
+    # Sign specific image with specific key
+    res=`python3 ${IGPS_DIR}/BinarySignatureGenerator.py Sign_binary \
+        ${DEPLOY_DIR_IMAGE}/${BB_HEADER_BINARY} 112 ${key_bb} 16 \
+        ${DEPLOY_DIR_IMAGE}/${BB_HEADER_BINARY} ${SIGN_TYPE} 0 ${KEY_BB_ID}
+
+        python3 ${IGPS_DIR}/BinarySignatureGenerator.py Sign_binary \
+        ${DEPLOY_DIR_IMAGE}/${BL31_HEADER_BINARY} 112 ${key_bl31} 16 \
+        ${DEPLOY_DIR_IMAGE}/${BL31_HEADER_BINARY} ${SIGN_TYPE} 0 ${KEY_BL31_ID}
+
+        python3 ${IGPS_DIR}/BinarySignatureGenerator.py Sign_binary \
+        ${DEPLOY_DIR_IMAGE}/${OPTEE_HEADER_BINARY} 112 ${key_optee} 16 \
+        ${DEPLOY_DIR_IMAGE}/${OPTEE_HEADER_BINARY} ${SIGN_TYPE} 0 ${KEY_OPTEE_ID}
+
+        python3 ${IGPS_DIR}/BinarySignatureGenerator.py Sign_binary \
+        ${DEPLOY_DIR_IMAGE}/${UBOOT_HEADER_BINARY} 112 ${key_uboot} 16 \
+        ${DEPLOY_DIR_IMAGE}/${UBOOT_HEADER_BINARY} ${SIGN_TYPE} 0 ${KEY_UBOOT_ID}`
+
+    # Stop full image build process when sign binary got failed
+    set +e
+    err=`echo $res | grep -E "missing|Invalid|failed"`
+    if [ -n "${err}" ]; then
+        bbfatal "Sign binary failed: keys are not found or invalid. Please check your KEY_FOLDER and KEY definition."
+    fi
+    set -e
+}
+
+python do_merge_bootloaders() {
+    TIP_IMAGE = d.getVar('TIP_IMAGE', True)
     def Merge_bin_files_and_pad(inF1, inF2, outF, align, align_end):
         padding_size = 0
         padding_size_end = 0
@@ -93,25 +180,41 @@
 
             file3.write(b'\xFF' * padding_size_end)
 
-    Merge_bin_files_and_pad(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('KMT_TIPFW_BINARY',True)),
-        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('BOOTBLOCK',True)),
+    if TIP_IMAGE == "True":
+        Merge_bin_files_and_pad(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('KMT_TIPFW_BINARY',True)),
+        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('BB_HEADER_BINARY',True)),
         os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('KMT_TIPFW_BB_BINARY',True)),
         int(d.getVar('BB_ALIGN', True)), int(d.getVar('ALIGN_END', True)))
 
-    Merge_bin_files_and_pad(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('KMT_TIPFW_BB_BINARY',True)),
-        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('ATF_BINARY',True)),
+        Merge_bin_files_and_pad(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('KMT_TIPFW_BB_BINARY',True)),
+        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('BL31_HEADER_BINARY',True)),
         os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('KMT_TIPFW_BB_BL31_BINARY',True)),
         int(d.getVar('ATF_ALIGN', True)), int(d.getVar('ALIGN_END', True)))
 
-    Merge_bin_files_and_pad(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('KMT_TIPFW_BB_BL31_BINARY',True)),
-        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('OPTEE_BINARY',True)),
+        Merge_bin_files_and_pad(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('KMT_TIPFW_BB_BL31_BINARY',True)),
+        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('OPTEE_HEADER_BINARY',True)),
         os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('KMT_TIPFW_BB_BL31_TEE_BINARY',True)),
         int(d.getVar('OPTEE_ALIGN', True)), int(d.getVar('ALIGN_END', True)))
 
-    Merge_bin_files_and_pad(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('KMT_TIPFW_BB_BL31_TEE_BINARY',True)),
-        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s.full' % d.getVar('UBOOT_BINARY',True)),
+        Merge_bin_files_and_pad(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('KMT_TIPFW_BB_BL31_TEE_BINARY',True)),
+        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('UBOOT_HEADER_BINARY',True)),
         os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('KMT_TIPFW_BB_UBOOT_BINARY',True)),
         int(d.getVar('UBOOT_ALIGN', True)), int(d.getVar('ALIGN_END', True)))
+    else:
+        Merge_bin_files_and_pad(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('BB_HEADER_BINARY',True)),
+        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('BL31_HEADER_BINARY',True)),
+        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('BB_BL31_BINARY',True)),
+        int(d.getVar('ATF_ALIGN', True)), int(d.getVar('ALIGN_END', True)))
+
+        Merge_bin_files_and_pad(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('BB_BL31_BINARY',True)),
+        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('OPTEE_HEADER_BINARY',True)),
+        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('BB_BL31_TEE_BINARY',True)),
+        int(d.getVar('OPTEE_ALIGN', True)), int(d.getVar('ALIGN_END', True)))
+
+        Merge_bin_files_and_pad(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('BB_BL31_TEE_BINARY',True)),
+        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('UBOOT_HEADER_BINARY',True)),
+        os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True), '%s' % d.getVar('BB_BL31_TEE_UBOOT_BINARY',True)),
+        int(d.getVar('UBOOT_ALIGN', True)), int(d.getVar('ALIGN_END', True)))
 }
 
 do_pad_binary[depends] += " \
@@ -135,8 +238,9 @@
 }
 
 addtask do_pad_binary before do_prepare_bootloaders
+addtask do_sign_binary before do_merge_bootloaders after do_prepare_bootloaders
 addtask do_prepare_bootloaders before do_generate_static after do_generate_rwfs_static
-addtask do_merge_bootloaders before do_generate_static after do_prepare_bootloaders
+addtask do_merge_bootloaders before do_generate_static after do_sign_binary
 addtask do_merge_bootloaders before do_generate_ext4_tar after do_prepare_bootloaders
 
 # Include the full bootblock and u-boot in the final static image