QCOM 平台 Secure Boot 配置过程

1.Secure Boot概述

Secure Boot是为安全程序建立可信平台的启动序列。为了确保仅执行授权的软件,Secure Boot使用加密身份验证来启动一个不可变的序列,以验证代码的来源。启动序列会将设备置于已知的安全状态,并保护其免受软件的二进制操作和下载攻击的影响。Secure Boot系统会在启动过程的每个阶段添加加密检查,以执行以下操作:

(1)声明设备执行的所有安全软件images的真实性;

(2)防止任何未经授权或恶意修改的软件在设备上运行。

通过一组HW Fuse启用Secure Boot。HW Fuse中标识的受信任实体必须对代码签名才能执行。如果不使用Qualcomm Fuse Programmable Read Only Memory(QFPROM),即Fuse,则无法保证Secure Boot。被许可方必须通过熔断Fuse才能启用Secure Boot。启用平台Secure Boot所需的Fuse配置包括以下内容:

(1)启用了image认证;

(2)禁用的JTAG访问;

(3)本地签名的读写权限熔断,即可以从本地签名机访问的OEM签名密钥。

使用sectools和本地签名者对image(引导加载程序和外围二进制文件)进行签名,该签名接受在本地签名机上显示的签名证书和密钥。该密钥不安全,在运行sectools的本地计算机上签名期间和之后公开。QTI不提供有关保护密钥的指导。OEM必须通过从CA获取密钥/证书来遵循安全最佳实践,并保护HSM中的密钥。使用OpenSSL工具创建的自生成密钥和证书不会链接到任何证书颁发机构。sectools对image的签名流程大致如下图:

启用Secure Boot的准备条件:

(1)安装OpenSSL 1.0及以上版本(http://www.slproweb.com/products/Win32OpenSSL.html)。

(2)OEM可以通过签署CASS许可证或通过在高通官网CreatePoint从QTI获得唯一的OEM_ID。

(3)OEM可以选择任意16位值作为其product ID。OEM也可以保留默认值。

2.生成Secure Boot Keys

下图显示了Secure Boot key和certificate的生成:

2.1 生成自定义key前准备条件

(1)创建OEM-KEYS目录:

1
mkdir ${sectools_path}/resources/data_prov_assets/Signing/Local/OEM-KEYS/

(2)将opensslroot.cfg拷贝到OEM-KEYS目录中:

1
cp ${sectools_path}/resources/data_prov_assets/General_Assets/Signing/openssl/opensslroot.cfg ${sectools_path}/resources/data_prov_assets/Signing/Local/OEM-KEYS/opensslroot.cfg

(3)将v3.ext拷贝到OEM-KEYS目录中:

1
cp ${sectools_path}/resources/data_prov_assets/General_Assets/Signing/openssl/v3.ext ${sectools_path}/resources/data_prov_assets/Signing/Local/OEM-KEYS/v3.ext

(4)将v3_attest.ext拷贝到OEM-KEYS目录中:

1
cp ${sectools_path}/resources/data_prov_assets/General_Assets/Signing/openssl/v3_attest.ext ${sectools_path}/resources/data_prov_assets/Signing/Local/OEMKEYS/v3_attest.ext

(5)在OEM-KEYS目录中创建config.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<METACONFIG>
<is_mrc>False</is_mrc>
<root_pre>True</root_pre>
<attest_ca_pre>True</attest_ca_pre>
<attest_pre>False</attest_pre>
<root_cert>qpsa_rootca.cer</root_cert>
<root_private_key>qpsa_rootca.key</root_private_key>
<attest_ca_cert>qpsa_attestca.cer</attest_ca_cert>
<attest_ca_private_key>qpsa_attestca.key</attest_ca_private_key>
<root_cert_params>
C=US
ST=California
L=San Diego
OU=General Use Test Key (for testing only)
OU=CDMA Technologies
O=SecTools
CN=Generated Test Root CA
</root_cert_params>
<attest_ca_cert_params>
C=US
ST=California
L=San Diego
O=SecTools
CN=Generated Test Attestation CA
</attest_ca_cert_params>
</METACONFIG>

2.2 生成root key和certificate

(1)依次生成qpsa_rootca.key、rootca_pem.crt、qpsa_rootca.cer:

1
2
3
4
5
openssl genrsa -out qpsa_rootca.key 2048
openssl req -new -sha256 -key qpsa_rootca.key -x509 -out rootca_pem.crt \
-subj /C=US/ST=California/L="San Diego"/OU="General Use Test Key (for testing 13 only)"/OU="CDMA Technologies"/O=QUALCOMM/CN="QCT Root CA 1" \
-days 7300 -set_serial 1 -config opensslroot.cfg -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -sigopt digest:sha256
openssl x509 -in rootca_pem.crt -inform PEM -out qpsa_rootca.cer -outform DER

(2)设置qpsa_rootca.cer中的signature,hash和mask算法,public key和指数值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
openssl x509 -text -inform DER -in qpsa_rootca.cer
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: rsassaPss
Hash Algorithm: sha256
Mask Algorithm: mgf1 with sha256
Salt Length: 0x20
Trailer Field: 0xBC (default)
Issuer: C=US, ST=California, L=San Diego, OU=General Use Test Key (for testing 13 only), OU=CDMA Technologies, O=QUALCOMM, CN=QCT Root CA 1
Validity
Not Before: Oct 4 07:13:09 2019 GMT
Not After : Sep 29 07:13:09 2039 GMT
Subject: C=US, ST=California, L=San Diego, OU=General Use Test Key (for testing 13 only), OU=CDMA Technologies, O=QUALCOMM, CN=QCT Root CA 1
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:a7:83:de:9d:dd:f9:31:a9:ec:13:87:ba:69:5f:
d0:ba:37:2c:13:00:55:76:09:27:09:d2:94:86:2b:
64:80:31:e9:ac:14:0b:00:7d:1d:06:e1:95:8d:a9:
69:59:f1:a1:c9:56:df:0f:db:8d:7d:bb:89:4f:aa:
72:6a:6f:2b:ad:62:35:b3:51:8e:fd:e9:26:9a:bc:
ab:bf:b4:a5:4c:a6:96:25:3a:4e:da:33:69:9e:5e:
20:92:0c:8e:96:74:e0:6c:2b:07:b9:49:3b:20:f4:
97:dd:cc:c1:39:23:ad:06:87:c0:47:70:16:e6:28:
52:0f:0a:69:a6:27:fa:8d:57:94:0d:c8:8b:8b:95:
d8:51:db:aa:d5:fc:ee:6d:8d:1f:57:7f:44:79:7e:
8c:d0:37:22:9a:bc:83:bc:bc:20:13:fb:6e:72:49:
09:d4:0e:2d:73:5d:70:60:2c:5a:41:91:64:a8:7a:
8f:3c:8b:45:1f:14:01:31:00:25:a0:1c:30:b3:8a:
09:1e:af:34:a2:12:2c:58:9c:6a:7e:f3:15:d5:9c:
b9:83:23:47:68:f8:4d:ac:04:29:95:db:a4:ce:bf:
8c:b9:92:d6:7b:4b:f1:7f:d7:9a:43:8f:da:ed:01:
95:40:9d:f2:eb:7a:9f:13:16:25:8e:94:5c:5a:b2:
91:1f
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
01:15:64:78:66:C1:87:23:99:4B:00:44:E1:4F:90:1F:93:8D:60:DF
X509v3 Basic Constraints:
CA:TRUE
X509v3 Key Usage:
Certificate Sign, CRL Sign
Signature Algorithm: rsassaPss
Hash Algorithm: sha256
Mask Algorithm: mgf1 with sha256
Salt Length: 0x20
Trailer Field: 0xBC (default)

2.3 生成attestation CA key和certificate

依次生成qpsa_attestca.key、attestca.csr、attestca_pem.crt、attestca_pem.crt:

1
2
3
4
5
6
7
8
openssl genrsa -out qpsa_attestca.key 2048
openssl req -new -key qpsa_attestca.key -out attestca.csr \
-subj /C=US/ST=CA/L="San Diego"/OU="CDMA Technologies"/O=QUALCOMM/CN="QUALCOMM Attestation CA" \
-days 7300 -config opensslroot.cfg
openssl x509 -req -in attestca.csr -CA rootca_pem.crt -CAkey qpsa_rootca.key \
-out attestca_pem.crt -set_serial 5 -days 7300 -extfile v3.ext \
-sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -sigopt digest:sha256
openssl x509 -inform PEM -in attestca_pem.crt -outform DER -out qpsa_attestca.cer

3.将Root of Trust配置为QFPROM Fuse

运行下面命令生成sha256 root证书内容:

1
openssl dgst -sha256 qpsa_rootca.cer > sha256rootcert.txt

3.1 配置OEM PK HASH

(1)将sha256rootcert.txt中root cert hash复制到${sectools_path}/config/sdm450/sdm450_fuseblower_USER.xml中:

1
2
3
4
5
6
7
8
9
10
11
12
<module id="SECURITY_CONTROL_CORE">
<entry ignore="false">
<description>contains the OEM public key hash as set by OEM</description>
<name>root_cert_hash</name>
<value>a7de005f6f5c0284a1aa6c42300300426f983d38a10fe8a3089a459bcfde1974</value>
</entry>
<entry ignore="true">
<description>SHA-256 signed root cert to generate root hash</description>
<name>root_cert_file</name>
<value>./../../resources/OEM-KEYS/qpsa_rootca.cer</value>
</entry>
...

(2)将root certificate文件作为输入(不是root cert hash),sectools将自动生成OEM PK HASH:

1
2
3
4
5
6
7
8
9
10
11
12
<module id="SECURITY_CONTROL_CORE">
<entry ignore="true">
<description>contains the OEM public key hash as set by OEM</>
<name>root_cert_hash</name>
<value>a7de005f6f5c0284a1aa6c42300300426f983d38a10fe8a3089a459bcfde1974</value>
</entry>
<entry ignore="false">
<description>SHA-256 signed root cert to generate root hash</description>
<name>root_cert_file</name>
<value>>./../../resources/data_prov_assets/Signing/Local/OEM-KEYS/qpsa_rootca.cer</value>
</entry>
...

3.2 配置PK HASH IN FUSE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!-- SEC_BOOT1 -->
<entry ignore="false">
<description>PK Hash is in Fuse for SEC_BOOT1: Apps</description>
<name>SEC_BOOT1_PK_Hash_in_Fuse</name>
<value>true</value>
</entry>
<!-- SEC_BOOT2 -->
<entry ignore="false">
<description>PK Hash is in Fuse for SEC_BOOT2: MBA</description>
<name>SEC_BOOT2_PK_Hash_in_Fuse</name>
<value>true</value>
</entry>
<!-- SEC_BOOT3 -->
<entry ignore="false">
<description>PK Hash is in Fuse for SEC_BOOT3: MPSS</description>
<name>SEC_BOOT3_PK_Hash_in_Fuse</name>
<value>true</value>
</entry>
<!-- OEM HW ID -->
<entry ignore="false">
<description>The OEM hardware ID</description>
<name>oem_hw_id</name>
<value>0x0000</value>
</entry>
<!-- OEM Product ID -->
<entry ignore="false">
<description>The OEM product ID</description>
<name>oem_product_id</name>
<value>0x0000</value>
</entry>

3.3 生成sec.dat

(1)运行Sectools生成sec.dat,该文件可用于将eFuse熔断到设备上:

1
python sectools.py fuseblower -p sdm450 -g –d

(2)在fuseblower_output目录找到包含熔丝信息的sec.dat文件,并在fastboot模式下将其烧入sec分区:

1
fastboot flash sec <sectools>\fuseblower_output\v2\sec.dat

(3)烧录后第一次启动中,SBL从设备中读取sec分区内容,并将其加载到TZ DDR区域。TZ通过读取QFPROM_RAW_WR_PERM_LSB的OEM_SEC_BOOT位判断其是否为空来确认是否熔断Fuse。Blown过程是不可逆的,即只要熔断一次,该机器将永远是Fuse机器。

默认无法用QFIL在fuse设备上进一步烧录。需要特殊配置,才能使用validated image programming (VIP)方法在安全设备上进行安全烧录。

3.4 为Root of trust签名image

(1)从手机中获取JTAG_ID、SOC_HW_VERSION信息:

1
2
<msm_part>0x000910E1</msm_part>
<soc_hw_version>0x60040100</soc_hw_version>

(2)将IN_USE_SOC_HW_VERSION设置为0表示使用MSM_PART,将其设置为1表示使用SOC_HW_VERSION:

1
<in_use_soc_hw_version>1</in_use_soc_hw_version>

(3)使用SN为不同启用Secure Boot的设备创建不同的签名images。当其设置为1时,SN用于验证签名,而不是OEM ID和MODEL ID:

1
<use_serial_number_in_signing>0</use_serial_number_in_signing>

(4)将OEM_ID_INDEPENDENT设置为0以进行客户签名:

1
<oem_id_independent>0</oem_id_independent>

(5)若将非零的OEM ID或OEM_HW_ID用于熔丝,需使用相同的值配置OEM_ID:

1
<oem_id>0x0000</oem_id>

(6)若将非零MODEM ID用于熔丝,需使用相同的值配置MODEL ID。MODEL ID或OEM Product ID是OEM所特有的:

1
<model_id>0x0000</model_id>

(7)将DEBUG OU字段的值设置为0x02以禁用Secure Boot调试:

1
<debug>0x0000000000000002</debug>

(8)使用SERIAL NUMBER将use_serial_number_in_signing设置为1,然后使用平台SN进行填充,如0x12345678:

1
<serial_number>0x12345678</serial_number>

(9)列出平台支持签名的images列表:

1
2
python sectools.py secimage -h --chipset <chipset> --sign_id LIST
xbl、pmic、abl、prog_emmc_ufs_lite、prog_emmc_ufs_ddr、vip、uefi、mba、modem、TZ、hyp、devcfg、rpm、aDSP、STI、venus、efs_tar、sampleapp32、sampleapp64、isdbtmm、Widevine、cppf、PlayReady、cmnlib、cmnlib64、keymaster、hdcp1、hdcp2p2、dxhdcp2、lksecapp、macchiato_sample、gfx_microcode、mcfg_hw、mcfg_sw、tz_tee、cdsp

(10)对单个image进行签名,如tz.mbn:

1
2
cp out/target/product/aosp/tz.mbn ${sectools_path}/input/tz.mbn 
python sectools.py secimage -s -i "input/tz.mbn" -g tz -p <chipset> --cfg_selected_cert_config=OEM-KEYS

签名的image由代码签名和certificate chain组成。在certificate chain中,certificate 带有用于解密证书和image签名的公共密钥。

要启用SFS(Secure File System),需要加密引擎(crypto engine)的硬件密钥(hardware key)访问权限。必须对SHK(Secondary Hardware Key) QFPROM进行烧写,并且必须根据JTAG可访问性对设备进行保护。在熔丝之前,debug key将用于加密SFS中的文件。从SFS访问文件时,相同的debug key将用于解密文件。在熔丝之后,将使用sec.dat将设备唯一的key熔接到设备的SHK,发送到KDF以生成唯一的加密key。该加密key用于加密和解密SFS中的文件。在熔丝之前创建的SFS的任何用户数据将不可访问,应予以删除。在安全设备上重新启用JTAG后,用户数据和SFS将变得不可用,应将其擦除以使设备成功启动。

下图显示了QFPROM和DDR中Secure Boot相关信息:

4.配置Debug policy抓取dump

(1)在/common/tools/sectools/config/sdm450/sdm450_fuseblower_QTI.xml中将ARB fuse、OEM_SEC_BOOT、ARB WR权限fuse配置移除,然后生成sec.dat烧录到sec分区:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
...
<fuse ignore="true" n="2">
<address>0x00780198</address>
<operation>BLOW</operation>
<field id="OEM_CONFIG_BIT_32-35">
<description></description>
<owner>QC</owner>
<value>0x0F</value>
<bits>35:32</bits>
</field>
...
<fuse_region id="QFPROM_RAW_WR_PERM">
<description></description>
<fuse ignore="false" n="0">
<address>0x00780158</address>
...
<!--
<field id="OEM_CONFIG">
<description></description>
<owner>QTI</owner>
<value>0x1</value>
<bits>10</bits>
</field>
-->
...
<!--
<field id="OEM_SEC_BOOT">
<description></description>
<owner>QTI</owner>
<value>0x1</value>
<bits>20</bits>
</field>
-->
...

(2)在/common/tools/sectools/config//_debugpolicy.xml中打开debug policy:

1
2
3
4
<flag> <bit_pos>0</bit_pos> <value>1</value> </flag> <!--DP_ENABLE_ONLINE_CRASH_DUMPS-->
<flag> <bit_pos>1</bit_pos> <value>1</value> </flag> <!--DP_ENABLE_OFFLINE_CRASH_DUMPS-->
<flag> <bit_pos>2</bit_pos> <value>1</value> </flag> <!--DP_ENABLE_JTAG-->
<flag> <bit_pos>3</bit_pos> <value>1</value> </flag> <!--DP_ENABLE_LOGS-->

(3)在trustzone_images/securemsm/trustzone/qsee/mink/oem/config//oem_config.xml中将OEM_enablecrashdumps_before_arb设置为1:

1
2
<!-- Mark third party signed secure applications sandboxed by default -->
<props name="OEM_enablecrashdumps_before_arb" type=DALPROP_ATTR_TYPE_UINT32>1</props>

(4)在/common/tools/sectools/config//_secimage.xml中DEBUG_OU设为0:

1
<debug>0x0000000000000000</debug>

(5)在boot_images\QcomPkg\Library\SecDbgLib\oem\secDbg_oem.c中定义SKIP_SERIAL_NUMBER_CHECK:

1
2
/* Serial Number Flag */
#define SKIP_SERIAL_NUMBER_CHECK 1

(6)在完成上述配置后再将sdm450_fuseblower_QTI.xml中(1)处修改还原回去,生成sec.dat烧录到sec分区进行熔丝。

(7)/common/tools/sectools/config/sdm450/sdm450_debugpolicy.xml中指定SN:

1
2
3
<serial_num_list> <!--Range: 1 to 200-->
<serial_num>9d925867</serial_num>
</serial_num_list>