点击上方蓝字谈思实验室
获取更多汽车网络安全资讯
1. Secure Boot
安全启动想必大家肯定很熟悉,它是通过对启动过程的每个阶段进行加密验证,确保运行系统完整性的一种安全机制。如图1所示,QNX的安全启动可以保证由BootRom、PBL/SBL、IPL和IFS,最后到可选的文件系统的完整性。在启动过程中,每一个后续的固件和软件都是由其前身进行加密验证的。
图1 QNX安全启动流程
QNX可以支持两套安全启动方案,如图1右侧所示:
方案1:将MRK(Master Root Key)作为信任根,其公钥存储在OTP或EEPROM中,由OTP或EEPROM保证MRK不可篡改,由MRK的私钥完成对CVK(Code Verification Key)公钥的签名,由CVK的私钥完成Bootloader等后续代码的签名。启动时,BootRom使用MRK的公钥验证CVK公钥,验证成功后,由CVK公钥验证下面代码的签名。这样做可以将代码签名密钥CVK和信任根MRK解绑。由于CVK由MRK保证其真实性,CVK的公钥不需要存储在有任何保护的存储器中。这在不安全的制造环境中非常有用,因为即使CVK被泄露,我们也可以将其进行替换,而MRK则由芯片厂家保管。
方案2:不使用MRK,将CVK作为信任根,其公钥存储在OTP或EEPROM中。有时候为了节省存储空间,也可以存储CVK的公钥哈希。由于没有MRK,BootRom直接使用CVK完成代码的验签。此时代码签名密钥和信任根都跟CVK关联,一旦CVK的私钥被泄露,基本无解,优点在于ECU的设备制造商可完全掌握代码签名。
Secure Boot中最后一项是可选的完整性保护的文件系统,QTD便是其中一种。QTD(QNX Trusted Disk),是QNX针对数据存储的安全机制,通过结合哈希树和PKI密钥签名,为二进制数据、关键系统配置等提供完整性和真实性保护。它基于 Merkle 树,如图2所示,在构建 QTD 映像时,元数据哈希树是从源文件系统映像的块一层一层构建的,直至RootHash。
图2 QTD哈希树
与AVB中的DM-Verity类似,如图3所示。RootHash会进行签名保护,并纳入到安全启动链中。只要保证哈希树的RootHash未被篡改,便可以保证整个哈希树的完整性。这样可以带来一个好处,在安全启动的时候不用验证整个文件系统,只需要验证哈希树即可。当需要实际访问具体的某个存储块时,再通过对比哈希树中对应的哈希值即可发现存储块是否被更改。QTD的驱动程序位于原始块设备和受支持的上层文件系统层之间(例如,fs-qnx6.so 支持的power-safe文件系统)。在读取访问时,使用哈希树Metadata来验证数据的完整性。如果验证失败,则会返回错误。使用QTD肯定会有一定的性能开销,好在QTD可以通过预先缓存内部哈希计算来减少实际访问时哈希运算的数量。
图3 安全启动中的文件系统保护
需要注意的是,不同QNX版本支持的摘要算法和签名算法不同,当前QNX710支持的密码学算法如表1所示。
表1 QTD密码学算法
架构 | 摘要算法 | 签名算法 | |
128 bits | 256 bits | ||
32-bit | sha256 blake2s256 blake3 | sha512 blake2b512 | RSA-SHA256 ECDSA-SHA256 EDDSA-25519 ECDSA-448 |
64-bit | sha512256 blake2b256 blake3 | sha512 blake2b512 |
QTD 使用由QNX加密库qcrypto提供的加密算法,详细可参考 “QNX Cryptography Library”。当前支持 ECC 和 RSA 签名,其中私钥必须是 PKCS#8 格式,公钥必须是 X.509 格式,所有密钥都必须使用 PEM 编码。对于 RSA,最多支持 16 KiB (kibibits) 的密钥长度。
QTD的挂载由 fs-qtd.so 提供支持,devb-*驱动程序会在挂载QTD设备时加载它。以下命令构建 QTD 映像。-P 选项精确指定 2 MB 的镜像:
mkqfs qtd -s -vv -B 4096 -H sha256 -S ecdsa-sha256 -K ec_test_private_key.pem -P 2097152 -o qtd.img qnx6.img
以下命令通过全盘验证挂载 QTD 镜像:
mount -t qtd -o key=/proc/boot/ec_test_public_key.pem,stats,verbose,verify /dev/hd1 /dev/qtd-1
Power-Safe文件系统是一个可靠的磁盘文件系统,可以承受电源故障而不丢失或损坏数据。它支持file-based加密,密钥类型如表2所示,可以对 Power-Safe 文件系统的全部或部分进行加密,以保护其内容。其中文件和文件夹被聚合到加密域中。每个域都有一个唯一的加密密钥,称之为域密钥,用于加密唯一的文件密钥。访问文件需要一些外部参与者使用主密钥解锁域密钥,向文件系统驱动程序提供域密钥,允许它解密文件密钥并授予对加密文件内容的访问权限。
表2 Power-Safe文件系统密钥种类
密钥类型 | 描述 |
文件密钥 | 私有,在文件创建时随机产生的(如果文件被分配到一个域)。保存关于文件的一些信息,以确保文件和其密钥之间的完整性。用于加密文件数据,并由域密钥加密。密钥由文件系统管理,对用户是隐藏的。 |
域密钥 | 私有,在创建域的时候随机产生。用于加密属于其域的所有文件密钥,并由域的主密钥进行加密。密钥由文件系统管理,对用户是隐藏的。 |
主密钥 | 可以选择公开,因为它是由第三方提供和管理的(不是文件系统)。用于加密域的密钥,在域的创建和随后的解锁请求中需要。 |
具体使用的加密算法如表3所示。
表3 Power-Safe文件系统加密类型
域加密类型 | 常量 | 描述 | 密钥长度 |
0 | FS_CRYPTO_TYPE_NONE | 不加密 | - |
1 | FS_CRYPTO_TYPE_XTS | ASE256-XTS,两个密钥是随机生成的 | 512bit |
2 | FS_CRYPTO_TYPE_CBC | AES256-CBC | 256bit |
3-99 | - | 预留 | - |
Power-Safe文件系统中一个域可以包含任意数量的文件或目录,但一个文件或目录最多只能属于一个域。如果给一个目录指定了一个域,那么随后在该目录中创建的所有文件都会被加密并继承该域,但已经在其中的任何文件或目录不会加密。允许你创建多个加密域,你可以根据需要锁定或解锁这些域。在操作过程中,分配给一个域的文件被加密,只有当相关的域被解锁时,文件的内容才能被使用。当一个域被解锁时,该域下的所有文件和目录--无论它们在卷中的位置如何--也被解锁,因此可以被访问(根据基本文件权限)。当一个域被锁定时,对属于该域的文件内容的任何访问都被拒绝。锁定和解锁操作适用于整个域,而不是特定的文件或目录。
那么如何生成一个Power-Safe文件系统呢?以下命令生成一个小于 2MB 的 Power-Safe 文件系统镜像 (QNX):
mkxfs -t qnx6fsimg qnx6.build qnx6.img
可以使用以下命令挂载 Power-Safe 文件系统镜像:
mount -t qnx6 /dev/qtd-1 /fs
需要注意的是Power-Safe 文件系统可能包含在 QTD 分区中,因此有时候需要先挂载 QTD 分区。
安全启动和QTD可以保证从BootRom到文件系统时软件的完整性,基于Power-Safe的文件加密可以保证存储在该文件系统中文件的机密性。这些都是QNX提供的安全特性,实际应用中可以基于芯片的安全能力,结合QNX的安全属性,搭建更加完善的防御体系。