APP下载

密码应用安全技术研究及软件密码模块检测的讨论*

2020-07-03郑昉昱林璟锵王琼霄

密码学报 2020年3期

郑昉昱, 林璟锵,3,4, 魏 荣,3, 王琼霄,3

1. 中国科学院 数据与通信保护研究教育中心, 北京100093

2. 中国科学院 信息工程研究所 信息安全国家重点实验室, 北京100093

3. 中国科学院大学 网络空间安全学院, 北京100049

4. 中国科学技术大学 网络空间安全学院, 合肥230026

1 引言

密码学是网络空间安全的基础理论, 基于密码学原理的安全方案在网络空间中发挥了重要作用, 例如广泛使用的TLS 协议[1,2]和PKI 数字证书服务[3,4]. 近年来, 随着密码技术在网络空间安全的应用日渐深入和扩大, 出现了大量关于密码应用方案自身的安全性研究[5], 包括算法使用不当[6-8]、密钥泄露[9-12]、可预测随机数[13-16]和协议功能实现漏洞[17-20]等问题及相应解决方案. 密码应用安全技术研究, 能够促进密码技术更有效地在网络空间中发挥安全作用.

密码模块检测是针对密码算法实现的安全性检测, 在世界多个国家都有实行[21-24]. 密码模块是实现密码算法功能的软硬件功能集合, 密码模块检测标准提出了密码模块安全要求, 以确保密码模块的设计、实现和运行满足密码算法理论的要求. 其中, 美国NIST 发布的FIPS 140 系列标准[21,25,26]是目前影响力最大的密码模块安全要求标准, 涵盖了硬件、固件、软件和混合形态的密码算法实现.

密码应用安全技术研究和密码模块检测, 都致力于使密码技术在信息系统中更加有效地发挥安全作用. 但是, 二者的发展路径有明显不同. 密码应用安全技术研究是开放的学术研究, 更多地针对现有通用的计算机和网络系统, 探索其中密码应用方案的实现、部署和运行, 发现的安全问题涉及各种不同形态的密码实现、涉及符合检测标准的密码模块、也涉及未经检测的密码实现, 提出的解决方案百花齐放、有不同的解决思路. 另一方面, 密码模块检测的安全要求标准, 更多地从传统的专用密码设备出发, 提出要求、并将其扩展至通用计算机系统的密码算法功能软件模块.

密码应用安全技术的学术研究与标准化的密码模块检测, 都有共同的长远技术目标. 二者之间的技术关系是什么?能否相互参考和借鉴?本文尝试从密码模块检测的视角来分析总结现有的密码应用安全技术研究现状, 并讨论其对密码模块检测的将来可能造成的影响.

本文包括如下部分. 首先, 我们阐述了现有密码应用安全技术研究的总体情况和密码模块检测技术要求的各方面; 从密码模块检测的视角出发, 分析二者的关系. 然后, 我们逐一总结了密码应用技术研究的各个方向, 包括: 密码算法、密码协议以及密钥长度的选用, 随机数发生器的设计和实现, 密钥安全, 密码计算的使用控制, 密钥管理和PKI 基础设施, 和应用功能密码协议的实现等. 最后, 我们讨论了现有密码应用安全技术研究对于密码模块检测(尤其是软件密码模块检测) 的可能影响.

2 密码技术的实现和应用安全

密码理论方案是以对称密码算法、公钥密码算法、杂凑算法及其它密码算法为核心的、解决网络空间各种安全需求的方案. 密码理论方案从基本假设出发、提供安全服务, 有着严谨的分析和证明; 在网络空间中应用基于密码理论的解决方案, 能够有效提高网络空间的安全性.

2.1 密码应用安全技术的研究方向

现有的公开研究成果表明, 在现实计算机和网络系统中运行的、基于密码学原理的安全服务仍然有着各种漏洞或缺陷, 并不能达到预期的、密码学理论强度的安全保障. 大量的漏洞和缺陷, 并不是密码理论方案的问题, 而是在实现和部署密码理论方案过程中、由于现实系统与理论方案之间的差异而产生的技术问题. 针对这些问题开展的技术研究, 本文称之为“密码应用安全技术研究”[5].

在网络空间中, 实现和部署语义安全的密码学理论方案, 应该重点解决哪些方面的技术问题?在已有完备密码学理论成果的前提下, 在计算机和网络系统中达到预期的安全目标和安全强度, 我们还应该解决哪些方面的技术问题?本文总结现有公开的研究成果, 考虑密码学、计算机系统安全和网络安全之间的关系, 在现实系统中的相关技术内容包括:

(1) 选用合适的密码算法、密码协议以及密钥长度. 在Internet 上运行的大量密码应用系统仍然在使用不安全的密码算法(例如, SHA-1、MD5 和RC4 等)、密钥长度不足的密码算法(例如, 512 位DH 密钥交换、512 位RSA 等) 和不安全的密码协议(例如, SSL 3.0 和TLS 1.0 等)[6-8,27,28].

(2) 产生不可预测的随机数. 很多密码理论方案需要随机数(例如, 作为长期密钥、会话密钥或者共享秘密等), 但是实际运行系统的随机数发生器被发现有各种问题, 导致攻击者可以预测或者部分预测随机数: 攻击者可控的随机数发生器初态和运行时熵源[15,16]、随机数发生器的初态熵不足和运行时熵不足[29-31]、甚至是有缺陷的随机数发生器标准和设计等[13,14,32,33].

(3) 确保密钥安全. 保护密码应用系统的密钥数据、防止攻击者非授权访问, 防止密钥泄露: 一旦密钥被攻击者掌握, 则密码理论方案的安全保障就形同虚设. 常见威胁和问题包括: 窃取密钥的层出不穷的侧信道攻击[12,34-45]和不同原理的内存攻击[9-11,46]等.

(4) 实施密码计算的使用控制. 有些情况下, 攻击者不能窃取密钥, 但是可以访问密码计算、执行恶意操作. 例如, 攻击者利用计算机系统漏洞恶意调用密码计算、或者内部操作员违反安全策略调用密码计算[47-51].

(5) 有效绑定密钥与实体. 在大量密码理论方案中, 利用密钥与实体的绑定, 使得各种密码计算能够支撑应用功能的需求. 现有Internet 上运行的密码应用系统, 主要依赖于PKI 基础设施实现密钥与实体绑定; 但是PKI 数字证书在使用中仍然有不少问题: 根CA 证书和实体身份标识验证不足[52-55]、数字证书解析漏洞[18,56-59]、以及CA 证书认证中心的安全事故[48-51]. 从密钥管理角度而言, 如下问题也阻碍密钥与实体的有效绑定: 不同设备使用相同的厂商默认密钥[30,31]、在密钥泄露安全事故后没有及时更新密钥[60-63].

(6) 正确实现和使用各种应用功能密码协议. 例如, 应用广泛的TLS 协议和单点登录协议, 实现和使用的逻辑漏洞[17,20,64-66]仍然影响密码技术发挥作用(虽然从网络协议栈分层角度TLS 协议是会话层协议, 但是从密码理论的角度来看, TLS 协议则是典型的密码应用). 另外, 代码签名和文档安全等, 也可以视为非实时交互的密码协议, 同样也有实现和使用方面的逻辑漏洞[19,67,68].

2.2 密码模块检测的安全要求

密码模块是实现了密码算法功能的软硬件集合, 例如对称密码计算和公钥密码计算. 密码算法是密码应用安全解决方案的核心, 相应地, 密码模块也是密码应用系统的核心部件. 密码模块必须按照预期的安全要求运行; 否则, 密码应用系统难以正确有效地发挥安全作用. 所以, 密码模块检测致力于密码计算在密码模块中的正确运行和安全运行, 也一直受到各国密码管理机构的高度重视.

目前, 世界多国发布了密码模块的安全技术要求, 例如, 美国NIST FIPS PUB 140-3 Security requirements for cryptographic modules 标准[21], 由FIPS 140-3 标准发展而来的国际标准ISO/IEC 19790 Information technology—Security techniques—Security requirements for cryptographic modules[22], 我国的国家标准GB/T 37092-2018《信息安全技术密码模块安全要求》[23]和密码行业标准GM/T 0028-2014《密码模块安全技术要求》[24]. 美国NIST 和加拿大网络空间安全中心(Canadian Centre for Cyber Security, CCCS) 共同建立了CMVP (Cryptographic Module Validation Program, 密码模块验证体系), CMVP 按照FIPS 140 标准开展密码模块的检测认证. 密码模块获得CMVP 检测认证的前提是通过CAVP (Cryptographic Algorithm Validation Program, 密码算法验证体系), 也就是, 要求密码模块正确地实现美国NIST 核准的密码算法. 我国也于近年来开始了商用密码检测认证, 按照密码行业标准GM/T 0028-2014 以及其它配套标准来检测各种密码模块.

不同国家的密码模块检测标准略有差异、但是技术思路基本一致, 本文后面的讨论和分析都是基于NIST FIPS PUB 140-3(也相当于是国际标准ISO/IEC 19790) 开展的. FIPS 140-3 定义了11 个独立的安全域, 针对不同类别、不同用途的密码模块, 每个安全域都提出了不同等级的技术要求, 涵盖了硬件、固件、软件和混合形态的密码算法实现. 11 个安全域简述如下:

(1) 密码模块规格: 说明密码模块的组成和边界, 说明所支持的密码算法功能(也就是, 核准的安全功能).

(2) 密码模块接口: 提出各种接口的安全要求, 包括数据输入输出接口、控制输入输出接口、状态输出接口以及电源输入接口.

(3) 角色、服务和鉴别: 定义密码模块的不同角色和每个服务对应的角色, 说明不同操作员的鉴别机制要求.

(4) 软件/固件安全: 定义密码模块的软件和固件的完整性和起源鉴别要求.

(5) 运行环境: 说明密码模块运行所需要的操作系统以及虚拟化环境和运行时环境的安全要求, 尤其对于可修改的运行环境, 包括运行环境的进程隔离机制、访问控制机制、身份鉴别机制、审计机制, 以及各种进程对密码模块的软件、数据和状态的执行、修改和读取等操作的控制.

(6) 物理安全: 采用物理安全机制, 限制非授权的物理访问.

(7) 非入侵式安全: 针对无物理破坏而获取密钥等关键安全参数的非入侵式攻击, 实施缓解措施. 常见的非入侵式攻击是在密码计算运行时窃取密钥的侧信道攻击.

(8) 敏感安全参数管理: 密钥数据和随机数发生器等关键安全参数的生命周期安全要求, 防止非授权的访问、使用、泄露、修改和替换; 公钥和数字证书等公开安全参数的生命周期安全要求, 防止非授权的修改和替换.

(9) 自测试: 提供密码算法功能服务之前, 密码模块自测试、确保没有故障; 或者周期性、条件性的自测试.

(10) 生命周期保障: 规范生产厂商在密码模块的设计、开发、操作和终止期间的各种实践方法.

(11) 对其它攻击的缓解: 未定义的其它攻击的缓解.

2.3 密码模块检测的技术思路

我们尝试对上述11 个安全域大致总结如下, 如图1 所示. 首先, (1) 密码模块规格主要说明密码模块所实现的安全功能、划定密码边界. (5) 运行环境和(6) 物理安全的安全要求, 构建了密码模块的密码边界(Cryptographic Boundary, 包括物理边界和依赖运行环境实现的逻辑边界), 使得密码模块与外部的所有交互都必须通过密码模块接口. 对于硬件密码模块, 边界是有形的物理边线; 对于软件密码模块, 边界则是逻辑边界. (2) 密码模块接口, 规定了在边界上的、所有的各种不同类型的输入/输出接口, 由此来实现密码算法功能, 密码模块与外部的所有正常交互都通过接口来完成; 接口可以是物理接口或者逻辑接口. (3)角色、服务和鉴别, 就是对正常接口所提供的密码算法功能的使用控制, 阻止外部对密码服务功能的非授权访问.

(8)敏感安全参数管理,主要是规定了密码算法功能的密钥和随机数等关键安全参数在生成、使用、存储销毁和输入/输出过程的安全要求, 避免非授权的泄露或修改. (7) 非入侵式安全, 考虑了攻击者从正常接口或者在边界之外收集可利用信息、分析获得密钥和随机数等关键安全参数的侧信道攻击. (11) 对其它攻击的缓解, 可以认为是为了标准内容完备性而增加的说明, 没有深入的实质性要求.

(10) 生命周期保障, 规范了密码模块的全生命周期, 涉及过程控制和质量控制, 保证密码模块的设计和实现的正确性. (4) 软件/固件安全, 要求实现密码模块内部的软件/固件的完整性和起源鉴别, 保证密码模块的自身功能没有被恶意修改或替换. (9) 自测试是密码模块确保自身功能没有发生故障的、运行时的安全措施. 也就是, 分别从设计开发、实施部署、运行时测试等3 个角度, 确保密码模块实现的密码算法功能服务源自于生产厂商、且不会失效或被修改.

图1 FIPS 140-3 安全域关系Figure 1 Relationship of FIPS 140-3 security requirement areas

按照上述分析,密码模块应当具备以下性质: (1)有明确的边界,边界上有可靠的隔离机制; (2)外部只能通过边界上的已知接口访问和操作密码模块, 而且只有经过鉴别的授权用户才能访问和操作密码模块;(3) 密码模块按照设计运行、提供安全功能服务, 且敏感安全参数在安全功能服务过程中不会有非授权的泄露和修改; (4) 防御从正常接口或者在边界之外收集可利用信息的非入侵式攻击.

在密码模块的安全技术思路中, 边界和接口是最重要的概念. 边界决定了密码模块的类型; 例如, 按照FIPS 140-3 的规定, 硬件密码模块是指有明确硬件边线的密码模块. 与字面意思略有不同, 并不是只有由芯片或SoC 等硬件组成的密码模块才称为硬件密码模块, 硬件密码模块内部也可以包含各种软件和固件.边界的作用是隔离内部和外部, 从而确保密码模块与外部的所有正常交互都通过有限的、明确的接口来完成. 角色、服务和鉴别的安全要求, 是对通过接口提供的密码服务的使用控制, 只有当接口是有限且明确的、才能够保证鉴别机制不会被绕过.

2.4 二者关系的讨论

如前所述, 密码应用安全技术的学术研究与标准化的密码模块检测, 目标都是使密码技术在信息系统中更加有效地发挥安全作用. 本文尝试分析他们之间的技术关系, 如图2 所示.

首先, “选用合适的密码算法、密码协议以及密钥长度” 基本对应了密码模块检测所必需的密码算法检测. 密码算法检测是密码模块检测的前提, 要求密码模块使用核准的密码算法(不仅是语义安全的密码算法, 而且必须是语义安全且检测标准限定的密码算法). 密码算法检测的要求更加严格.

其次, 在密码模块检测中, 与密码算法功能服务的安全实现直接相关的7 个安全域, 关系如下. (3) 角色、服务和鉴别, 目标主要是为了“实施密码计算的使用控制”. 从密码模块检测标准可以看出, 角色、服务和鉴别的安全要求, 定义了访问各种密码服务功能所需要的角色控制、以及各种角色的身份鉴别, 是为了防止攻击者或者非授权用户恶意地通过正常接口来访问密码服务功能. (8) 敏感安全参数管理和(7) 非入侵式安全, 分别从密码模块内部功能实现步骤和防御外部攻击角度来提出要求, 关系到密码模块的关键安全参数和公开安全参数, 尤其是随机数和密钥等关键安全参数, 目标是为了“产生不可预测的随机数” 和“确保密钥安全”. 密码模块检测的敏感安全参数管理要求, 是关于随机数和密钥的数据安全要求, 要求密码模块的各种正常功能步骤都不会向外部泄露密钥和随机数发生器状态信息. 非入侵式安全则是从侧信道攻击的角度来要求密码模块实现密钥安全.

另一方面,(5)运行环境、(6)物理安全和(2)密码模块接口,严格确立了密码模块的边界和接口(边界上不允许与外部有输入输出, 所有的输入输出都在接口上). 密码模块利用物理安全和运行环境的技术措施, 确定了物理边界和逻辑边界. 对于开放的密码应用安全技术学术研究, 并不限定密码算法实现的形态,所以密码模块检测的这一部分内容更多体现在密码应用安全技术研究的安全假设和威胁模型(例如, 有不少密钥安全解决方案能够在操作系统不完全满足密码模块检测的运行环境要求、物理安全也不满足密码模块检测要求的前提下, 防御对密钥数据的内存攻击). (4) 软件/固件安全, 是关于软件/固件的代码完整性和起源鉴别, 也是密码应用安全技术研究的安全假设和威胁模型的一部分. 例如, 在密码应用安全研究中, 有涉及对于不同权限代码的完整性和起源假设;通常而言, 最高权限的可执行代码假设已有完整性保护且不含恶意代码, 以及攻击者可以任意运行非最高权限的可执行代码等.

图2 密码应用安全技术研究方向与密码模块检测安全要求的对比Figure 2 Comparison between security applications of cryptography and validation of software cryptographic modules

最后, 在密码应用安全技术研究中, “有效绑定密钥与实体” 大致对应了密钥管理和PKI 数字证书的安全服务和解决方案. 作为普适性的安全基础设施, 密钥管理和PKI 数字证书建立了密码学与网络空间之间的联系, 通过绑定密钥与实体, 使得每一个密钥就代表了网络空间中的某一个实体、进而利用密钥的某种密码计算就代表了网络空间实体的操作. 然后, 在此基础上, 就可以开展各种上层应用功能密码协议的实现、部署和使用. 虽然各种密钥管理系统和PKI 数字证书系统都需要使用密码模块, 但是密码模块检测不涉及外部用户的密钥管理和PKI 数字证书功能.

综合以上, 密码应用安全技术研究涉及的范围更广, 研究对象不受限制、而且更多时候是常用的软件密码实现. 但是, 密码应用安全技术研究成果涵盖攻击和防御, 分散在不同环节、并没有形成严密的密码计算安全实现思路. 反之, 密码模块检测的技术标准给出了明确的、遵循执行即可获得密码计算安全实现的技术思路.

3 密码应用安全技术研究进展

下面, 我们总结现有密码应用安全技术研究在几个方向的公开成果. 这些研究成果大部分针对的都是通用计算机系统中的软件密码实现, 而不是合规的密码模块. 同时, 我们也会大概说明密码模块检测在相关方向的要求.

3.1 密码算法、密码协议以及密钥长度的选用

密码应用系统应选用语义安全的密码算法和密钥协议、配置足够的密钥长度. 早在2007 年和2011年, Internet 范围的SSL/TLS 网站分析表明[6,7], 有大量不安全的密码套件在使用: DES 算法、RC4 算法、MD5 算法和SHA-1 算法, SSL 2.0 协议, 512 位、768 位和1024 位的RSA 密钥等等. 虽然研究表明,近几年来在SSL/TLS 协议通信中, 不安全密码算法和低版本协议的使用比例明显下降[69]. 但是, 2016年针对电子邮件和即时通讯的SSL/TLS 数据分析表明[8,27], 有安全缺陷的低版本SSL/TLS 仍有使用,RC4 和MD5 等算法、512 位和768 位的DH 密钥协商也有较大比例. 2017 年针对路由器、Modem、摄像头、打印机等网络设备的分析表明[70], 不安全密码套件的使用比例, 远远大于Alexa Top-1M 的主流网站. 最近的主流浏览器分析同样也表明, 在浏览器SSL/TLS 通信中使用MD5 和SHA-1 算法、512 位和1024 位RSA 密钥, 没有触发足够的安全警告[28].

在密码模块检测的工作中, 核准的密码算法和密钥长度有很明确的列表. 例如, 对于美国CMVP 和CAVP, NIST SP 800-131A[71]给出了详细说明. 虽然大量的密码应用系统并不需要通过密码模块检测,但是上述核准列表应该是密码应用系统的重要参考. 此外, NIST SP 800 系列还规范了密码算法的不同工作模式[72-75]、随机数发生器的结构设计[76,77]等, 也是美国CMVP 和CAVP 的标准依据.

3.2 随机数发生器的设计和实现

随机数在各种密码理论方案中大量使用, 随机数发生器直接关系到密钥等参数的安全性. 虽然有各种基于物理噪声源的随机数芯片设计, 但是在通用计算机系统中, 密码应用系统主要使用的仍然是软件随机数发生器. 本文所述的随机数发生器, 除非专门说明, 都是指软件实现的确定性随机数发生器(Deterministic Random Bit Generator, DRBG). 随机数发生器包含内部状态、其中有攻击者不能访问的变量, 在确定性的运行过程中, 一方面根据内部状态输出随机数, 一方面从环境中获得熵源输入、更新内部状态.

首先, 非专业设计的随机数发生器可能导致攻击者可以预测随机数、进而获得密钥[78-80]. 文献[80]分析了4 种Java 实现的用户态随机数发生器, 指出了其中的明显安全缺陷、主要是结构设计的问题. 目前,经常使用的、长期维护改进的随机数发生器主要有Windows 操作系统的CryptGenRandom()、Linux操作系统的/dev/random 和/dev/urandom、以及OpenSSL 软件包的随机数发生器. 这些软件随机数发生器引起了广泛的安全性分析, 尤其是结合计算机系统攻击的安全性分析. 文献[81] 对Windows XP 操作系统CryptGenRandom() 的分析表明, 该随机数发生器不满足前向安全, 而且由于随机数发生器内部状态的软件安全措施不足、发起前向安全攻击并不需要操作系统内核权限; 该攻击披露之后, 微软公司改用了NIST SP 800 规范的随机数发生器结构设计[76,77]. 由于设计和实现公开, Linux 操作系统的随机数发生器(包括阻塞式的/dev/random 和非阻塞式的/dev/urandom) 有更详细的分析结果. 在2005 年和2013 年, 文献[82] 和[83] 分别定义了随机数发生器的安全特性(包括Resilience、Forward security 和Backward security), 并基于此分析了Linux /dev/random 随机数发生器, 分析结果表明仍有安全缺陷.

对于各种结构复杂的随机数发生器, 如果初态熵不足(也就是, 初态的取值空间有限), 攻击者即使不能获取内部状态、仍可以预测随机数输出. 2006 年, 文献[84] 发现了Linux 随机数发生器的前向安全攻击, 而且也提示了随机数发生器初态熵不足的问题. 2012 年的研究结果表明, 大量不同的网络设备使用相同的随机数作为密钥对[30,31], 其中的原因之一就是Linux 随机数发生器的初态熵不足问题(也就是, 系统初次启动后的随机数发生器内部状态取值空间有限). OpenSSL 也是广泛使用的密码工具软件包, 运行在用户态内存空间、不同于Windows 操作系统和Linux 操作系统的随机数发生器. 在2008 年Debian发行版本中, OpenSSL 随机数发生器由于少量代码被注释而导致初态熵不足、结果是产生可预测的密钥对[29,63]. 文献[85] 分析了Android 平台的OpenSSL 随机数发生器, 发现其初态的熵源依赖于Linux/dev/urandom 随机数发生器、仍然有初态熵不足的问题[31].

在密码模块检测的随机数生成器中, 也涉及对于运行时从环境中获得熵源输入的要求. 但是, 随机数发生器初态熵不足的问题, 在通过密码模块检测认证的硬件密码模块上也有出现[13,86]. 所以, 美国标准NIST SP 800-90B 要求随机数发生器应有重启测试; 在运行阶段, 随机数发生器也应及时从环境中获得熵源输入、更新内部状态. FIPS 140 模块检测的OpenSSL 版本曾经有类似安全漏洞, 在自测试中没有更新随机数种子, 导致随机数发生器处于低熵状态[87].

在虚拟化环境中, 虚拟机镜像保存了计算机系统的所有运行状态、包括随机数发生器的内部状态, 即使随机数发生器已经长时间运行、状态已经有充分的随机性, 攻击者仍然可以利用虚拟机镜像重现随机数输出[15], 甚至可以利用Linux /dev/random 和/dev/urandom 之间的关系、控制/dev/urandom 的输出[16].

以上攻击和缺陷主要是利用随机数发生器的初态熵不足和特定运行阶段的熵源输入不足, 另一方面,随机数发生器的结构设计也有可能存在问题. Entroposcope[88]分析了5 个软件随机数发生器, 并且发现了Libgcrypt 和OpenSSL 随机数发生器的设计缺陷. 美国NIST SP 800-90A 标准给出了若干随机数发生器的结构设计, 基于对称密码算法、Hash 算法和HMAC 算法等[76]. 但是, NIST SP 800-90A标准的历史版本曾包括Dual EC 随机数发生器, 被广泛质疑其中包含有意置入的陷门[14,33,89]. ANSI X9.17/X9.31 也曾经是美国CMVP 核准的随机数发生器结构设计[32]; 1998 年公开文献表明, 该随机数发生器结构设计有安全缺陷[90]. 虽然在此之后美国CMVP 不再允许使用ANSI X9.17/X9.31, 文献[13]仍然利用该缺陷成功预测了市场上已有密码设备的密钥.

3.3 密钥安全

密钥是密码算法实现中最重要的安全参数. 在现有的计算机系统中, 保护密钥数据面临着种种挑战.虽然密码模块检测标准要求运行环境提供进程隔离机制(事实上, 各种隔离机制也是操作系统等运行环境的合理功能设计)、保护密钥免受非授权的访问, 但是操作系统的漏洞或者攻击防不胜防, 导致攻击者能够突破运行环境的保护、窃取密钥. 首先, 最有问题的做法是在代码中以硬编码的方式存储密钥[13,91], 攻击者很容易就可以分析获得.

对于软件密码实现, 密码计算运行期的密钥数据通常要以明文形式出现在计算机内存中, 面临着内存信息泄露攻击(Memory Disclosure Attack)[46,92,93]、冷启动攻击[9,94-97]和DMA 攻击[11,98,99]等. 内存信息泄露攻击是指攻击者突破操作系统等运行环境的隔离机制、非授权地读取本该无权读取的内存数据. 根据2014 年的统计[100], 16.2% 的Linux 系统漏洞使得攻击者能够非授权地从内核态空间或者用户态空间读取内存数据. 软件密码通常以如下的不同方式实现密码计算: 作为动态或者静态链接库, 运行在应用进程的内存地址空间, 例如OpenSSL 等用户态密码软件包; 作为内核进程运行在操作系统的内核态空间, 应用进程通过操作系统调用访问密码计算服务; 例如Windows 操作系统的CryptoAPI 和CNG.首先, 软件密码实现应尽量减少密钥明文在内存中的副本数量、避免在计算过程中过多的数据复制[46,101]:在内存中的密钥副本越多, 内存攻击成功率越高. 其次, 上述不同的方式中, 密钥数据分别位于用户态空间和内核态空间, 攻击者突破隔离机制的难度也各不一样. 第三, 冷启动攻击利用了内存芯片的延迟消失效应: 攻击者在获得正在运行的受害计算机后, 利用恶意的启动介质重启该计算机系统, 启动之后立即读取内存芯片的数据内容. 由于内存芯片上的数据在重启之后并未立即消失, 所以攻击者能获得上面的数据内容, 包括密钥. 冷启动攻击能够用于攻击常见的笔记本电脑、智能手机、硬件令牌等[9,94,97]. 最后, DMA是外设与内存之间的、不需要CPU 参与的高速数据访问通道, DMA 攻击就是在受害计算机上插入恶意外设、发起DMA 请求, 然后直接读写本应该无权读取的内存地址. DMA 攻击甚至可以利用受害计算机上原有外设, 远程地控制有漏洞的外设、然后发起DMA 攻击. 以上各种攻击, 都使得攻击者能够非授权地读取软件密码实现的密钥数据.

进一步, 在软件密码实现中, 仍然有多种看似正常的情况会导致内存数据扩散和残余, 其中就可能包括密钥数据. 计算机系统的休眠、Core Dump、快照等正常功能, 会导致内存数据扩散到硬盘, 应用程序的崩溃报告也可能会包含密钥数据[102]. 在软件密码实现中, 尤其是公钥密码算法, 通常会有频繁的动态内存申请和释放操作, 有可能导致密钥数据泄露. 例如, 使用realloc 函数扩大密钥数据的缓冲区时, 如果当前内存块不足, 操作系统会重新分配更大的内存块, 并将敏感安全参数拷贝进去, 但是遗留在原内存块的数据将无法清除. 而且, 由于编译器的自动优化, 内存空间中的密钥等敏感参数在使用之后难以被真正清除, 因为该部分清零之后不再使用, 所以清零代码可能被编译器当作无用代码移除[103]. 另外, 为了优化程序, 编译器有时也会自动重排和复制数据, 从而产生一些不可控的数据副本, 同样会泄露密钥等内存数据. 面对智能化追求速度的编译器, 操作系统也提供了安全内存操作接口, 例如Windows XP 和Windows Server 2003 以上版本的SecureZeroMemory 接口、OpenBSD 5.5 和FreeBSD 11.0 以上版本的explicit_zero 接口, C11 标准也加入了安全字符串函数memset_s, 很多开源密码软件也利用volatile指针来提高数据清除的可靠性. 然而上述方法、接口和技巧并未完全得到应用, 而且也不能保证在所有编译器优化情况下都能够安全清除数据[103]. 虽然操作系统的内存Copy-on-Write 机制可以阻止恶意进程读取空闲内存中的数据、避免数据泄露, 但是为了保证低配设备的运行速度, Linux 系统允许在内核编译时关闭内存Copy-on-Write 机制. 为此, 有一些密码库定义了自己的安全堆栈和内存操作函数, 可以将敏感安全参数集中在指定内存区域内, 减少不可控的扩散.

近年频繁披露的各种CPU 硬件漏洞, 也使得攻击者能够突破各种隔离措施获得软件密码实现的内存关键数据,包括Meltdown、Spectre、Foreshadow、ZombieLoad 和CacheOut 等CPU 硬件漏洞[104-108],可以危及Intel 和ARM 的大部分CPU, 能够突破CPU 特权级、操作系统进程隔离、虚拟机等隔离机制, 其中Foreshadow 和ZombieLoad 甚至可以攻击Intel SGX 保护的内存数据.

利用密钥的数据结构特征[109]、编码特征[110,111]和高熵特性[112]等, 攻击者能够快速地从内存数据片段中定位到密钥. 即使攻击者仅仅获得部分密钥参数或者带有部分错误结果, 也可以借助密钥数据之间的关系来恢复完整密钥, 例如利用对称密码算法各轮密钥的关系和RSA 算法dp、dq与其它私钥参数的关系[9].

密钥安全的开放学术研究, 一方面是上文所述的攻击方法(事实上, 不仅仅是针对密钥、同样也威胁各种内存关键数据),同时也包括在漏洞和攻击情况下的密钥保护方案. TRESOR、Amnesia 和ARMORED是基于寄存器的、对称密码算法的密钥安全方案[113-115], 在寄存器中实现AES 算法、避免密钥出现在内存中, 从而能够防御冷启动攻击. PRIME 和RegRSA 是用于RSA 算法的密钥安全方案, 同样在寄存器中实现RSA 算法、防御冷启动攻击, 但相比常规实现, 性能有所下降[116,117]. Copker 和Sentry 分别在Intel 和ARM CPU 平台上, 利用Cache 控制, 在Cache 上实现密码计算, 进而防范物理攻击[118,119].Mimosa 则利用硬件事务内存机制, 动态地在Intel CPU 上构建密码计算执行环境, 能够有效防范内存信息泄露攻击、冷启动攻击和DMA 攻击[92]. TrustOTP 提出在ARM TrustZone 的安全模式内存中存储密钥、执行密码计算, 避免来自于Android 系统的恶意软件攻击[120]; CaSE 进一步结合了ARM TrustZone 的安全模式和Cache 控制, 同时能够防御冷启动攻击[121]. 文献[122-124] 则利用ARM 设备的iRAM 存储来执行密码计算, 保护密钥、防御冷启动攻击.

在密码模块检测的敏感安全参数管理要求中, 涉及对密钥如下步骤的安全要求, 包括: 生成、建立、输入/输出、存储和清零等, 指导原则是密钥等关键安全参数不能以明文形式、在正常步骤过程中非授权地泄露到密码模块的边界之外. 密码应用安全技术的密钥安全研究, 则主要是考虑攻击者突破边界的攻击和防御; 与密码模块检测要求形成互补.

最后, 不论是硬件密码实现还是软件密码实现, 都有各种形式的侧信道攻击(也就是典型的非入侵式攻击). 在密码计算过程中, 执行的指令与密钥直接相关、不同的密钥会有不同的执行步骤, 进而会以不同的形式泄露与执行步骤相关的信息, 例如计算时间、能量、电磁辐射等. 攻击者可以收集利用这些信息、恢复密钥. 典型的侧信道攻击包括: 计时攻击[34,42,125]、碰撞攻击[126-129]、能量和电磁辐射攻击[35,37,38,40,130]、声音攻击[36]、Cache 攻击[12,34,39,41,43-45,131-133]等等. 侧信道攻击者可以是远程的网络用户、在密码设备旁边的物理信号收集者、共享运行环境的进程或者虚拟机等. 侧信道攻击涉及对称密码算法、RSA 和ECDSA 等传统公钥密码算法, 新型的后量子密码算法也有侧信道攻击问题[134-136].

在密码模块检测的标准要求中, 要求密码模块有非入侵式攻击的缓解方法; 但是并没有给出明确的、要求必须防御的非入侵式攻击. 事实上, 由于不同技术原理的侧信道攻击一直在不断被发现, 详细全面地给出可能的攻击列表是非常困难的.

3.4 密码计算的使用控制

对于软件密码实现, 由于没有明显控制的边界(尤其当有缺陷或者恶意的应用进程访问密码软件静态或者动态链接库), 攻击者可以通过控制流劫持攻击绕过身份鉴别机制、调用密码计算. 控制流劫持攻击是通用的软件攻击方法, 在不改变可执行代码的前提下, 改变软件控制流、完成恶意操作. 即使是边界严格控制的密码设备, 攻击者虽然无法窃取密钥, 但是仍然可能绕过系统的安全策略控制, 发起网络攻击、恶意地调用密码计算[47-51].

另一与使用控制相关的问题则涉及到了应用进程对软件密码实现的验证: 攻击者利用DLL Preloading 或DLL Injection 攻击[137,138], 替换软件密码实现的动态链接库, 或者获得系统环境变量配置文件的控制权, 插入错误的动态库查找路径, 让应用程序链接到同名的恶意库, 进而窃取输入的口令、密钥等敏感安全参数.

在密码模块检测中, 要求依赖角色、服务和鉴别来实现密码计算的使用控制. 例如, FIPS 140-3 要求通过口令、生物特征等多种鉴别机制来控制密码计算服务的调用. 但是, 如果每一次密码计算都需要用户鉴别和操作, 则显然只能用于低计算量的应用场景. 对于没有用户/管理员实时参与操作、或者长期连续调用密码计算的应用场景, FIPS 140 定义了自启动密码服务能力: 无需操作员请求、密码模块就能执行密码计算功能, 但是自启动密码服务至少需要经过两个独立操作来激活.

3.5 密钥管理和PKI 基础设施

在密码应用方案的理论设计和分析中, 通常默认实体和密钥的绑定关系是明确的; 也就是, 每一个实体都有着不同于其它实体的公私密钥对、而且对应的公钥是其它实体都知道的, 或者在对称密钥方案中,每一个实体与管理中心共享着不同于其它实体的对称密钥. 在现实系统中, 最常用的方式是使用PKI 数字证书来实现绑定关系. PKI 基础设施是应用广泛的安全基础设施, 连接了密码学与现实的网络空间: 在密码学理论方案中, 元素是明文、密文、密钥、消息等数据, PKI 基础设施实现了它们与网络空间实体之间的联系. PKI 基础设施是发展多年的技术, 已有大量的公开技术标准[3,4]和系统实现.

然而, 现实运行的系统仍然会有一些不足, 导致PKI 数字证书并不能完善地实现实体和密钥的绑定.文献[52,53] 分析发现, 现有大量软件在HTTPS 数字证书验证过程中缺少根CA 检查和域名检查, 有中间人攻击隐患; 开发人员的疏忽和API 接口的混乱是重要原因. 后续的自动化漏洞研究表明, 此类安全漏洞在更大范围内也大量存在[54,55,139], 无须重新编译源代码的解决方案也有提出[140,141]. 事实上, 数字证书验证过程的不严谨导致无效的数字证书在Internet 中大量使用[142]. 另外, PKI 数字证书使用中必要的证书扩展验证和证书撤销检查, 在实际应用中也有实现问题. 例如, OpenSSL 的关键证书扩展验证有缺陷, 导致普通用户也可以承担CA 角色、签发数字证书[59]; 文献[56-58] 分别使用差分测试和符号执行的方法来分析各种数字证书软件的验证漏洞. 最典型的证书撤销检查方法需要额外的通信开销来访问CRL和OCSP[143-145]; 研究发现, 在现有的HTTPS 通信和代码签名验证中, 并没有执行严格的证书撤销检查[144-146].

从密钥生成角度, 现实系统也存在着与密码理论方案假设不符的情况. Internet 上各种SSL/TLS 设备有大量的共享密钥对, 有一些是设备缺陷导致的[30,31]、有一些则是用户有意识的共享[147,148]. 共享密钥对的情况, 表明用户缺乏对密码理论方案的深入理解; 其它分析调研也表明了相同的问题[149]. 密钥管理的另一常见问题与密钥安全相关: 在可能导致密钥泄露的安全事故被公开之后, 没有及时更新密钥. 广泛报道的OpenSSL HeartBleed 漏洞和Debian 发行版OpenSSL 随机数漏洞被公开之后很长时间, 一些问题密钥仍然在使用, 或者有不少网站虽然及时安装了软件补丁、却没有更换之前的问题密钥/数字证书[61-63].

3.6 应用功能密码协议的实现

基于密码技术的应用系统安全方案原理各异, 本文仅列举少量具有代表性的研究工作. 以数字签名验证过程为例, 基本的步骤是: 验证者获得对方的公钥, 然后验证所接收消息的数字签名, 确认正确之后, 解析消息、获得应用层的信息. 攻击者可以在不篡改公钥(或者数字证书) 的前提下操纵消息格式, 构造错误的应用层消息, 使其可以通过数字签名验证. 文献[17] 和[19] 分别给出了对XML 文件和PDF 文件的攻击, 都是因为应用层消息格式处理复杂、导致其中有数字签名验证的漏洞. 另一种攻击方式就是篡改公钥,进而攻击者就可以伪造任意消息. 例如, Cisco node-jose 软件包没有正确验证公钥来源、就将其用于数字签名验证[150]. CVE-2020-0601 漏洞是影响面极大的Windows 操作系统数字证书验证漏洞[18], 攻击者通过修改数字证书中的椭圆曲线基点, 可以在不改变公钥坐标值的前提下构造出一对新密钥, 从而伪造任意消息; 由于验证者只对比公钥坐标点, 没有对比全部椭圆曲线参数, 用新私钥伪造的签名可以通过验证.最后一种方式是Cross-Protocol 攻击[151-153], 公钥、消息和数字签名都没有变化, 但是采取不同的方式来解析消息, 就可以获得不同的应用层信息. 文献[151] 分析了TLS 协议的Cross-Protocol 攻击, 讨论了ECDHE ServerKeyExchange 消息和DHE ServerKeyExchange 消息的交叉解析问题.

单点登录协议也是被广泛使用的、基于密码技术的应用系统安全方案. 常见方案步骤是: 用户在访问RP 时, 被重定向到IdP, IdP 鉴别用户身份之后签发带有数字签名的凭据, 然后用户向RP 出示该凭据;RP 在验证数字签名有效之后, 允许用户登录访问. 研究表明, 现有的系统存在着不同的实现问题, 包括:用户身份标识等关键域没有被数字签名保护[17,20,64], 身份凭据和授权凭据的误用[64-66], 智能移动终端的身份凭据泄露[154-156]等.

4 现有密码应用安全技术研究对软件密码实现的启示

下面, 我们针对软件密码实现(或者是软件密码模块) 展开讨论. 根据实际情况, 软件密码模块是密码应用的最主要形式. 根据2020 年3 月30 日NIST 公开的数据[157]显示, FIPS 140 证书仍然有效的1365 个密码模块中, 软件密码模块共541 款、接近40%, 其余大多数为硬件密码模块; 这些软件密码模块大多是通用操作系统中的密码库、SSL/TLS、SSH 等实现, 使用广泛.

上文所述的密码应用安全技术研究成果, 充分表明了软件密码实现所面临的技术挑战; 这些技术挑战也会影响到软件密码模块的安全性. 下面, 我们结合已有密码应用安全技术研究成果发现的问题, 讨论软件密码模块检测面临的难题; 希望将技术研究成果转化为更细致的检测指导, 使得现实系统使用的软件密码实现更加安全.

4.1 软件密码模块的特殊性

如前所述, 密码模块检测的主要技术思路是“边界+ 接口”: 利用边界防御外部攻击, 仅使用有限的、明确的接口与外部交互. 这种技术思路非常适合于硬件密码模块: 有形的物理边线提供独享的计算和存储环境, 即便内部的软件/固件有缺陷、内部的敏感安全参数没有额外保护, 物理隔离也可以阻断大部分的攻击和入侵. 然而, “边界+ 接口” 的技术思路难以适用于软件密码模块: 软件完全依赖于运行环境提供的逻辑隔离机制来实现边界. 在运行环境的安全漏洞和攻击手段之下, 逻辑边界容易被突破; 相比之下, 即使是最简单的物理隔离, 也能够阻断大部分的软件攻击.

从突破逻辑边界的角度来看, 大致可以分为如下几类相互独立的攻击:

(1) 非授权读取内存数据、导致密钥等关键参数泄露, 与密码模块检测的敏感安全参数管理相关.

(2) 非授权修改可执行代码、破坏, 与密码模块检测的软件/固件安全相关.

(3) 共享运行环境导致的侧信道攻击, 与密码模块检测的非入侵式攻击相关.

(4) 在不改变可执行代码和软件控制流的前提下, 直接调用密码计算, 与密码模块检测的角色、服务和鉴别相关.

4.2 运行环境和密码模块接口

以上几类实际情况的软件系统攻击, 突破了运行环境的隔离机制和接口的使用控制. 对于软件密码模块检测(或者是软件密码实现的安全性分析), 我们认为应该充分考虑如下情况:

(1) 软件密码实现运行在不同的位置, 攻击难度有所不同. 软件密码实现可以运行在用户态空间或者是内核态空间, 内核态空间的攻击难度大于用户态空间; 进一步, 软件密码实现还可以运行在虚拟机监控器的内存空间、甚至是ARM TrustZone 和Intel SGX 等硬件安全增强的执行环境. 不同的位置, 数据、代码和控制流攻击的难度明显不同.

(2) 应用进程和软件密码实现的相对位置, 也有不同的攻击难度. 例如, 如果软件密码实现作为动态或者静态链接库、运行在应用进程的内存地址空间, 则应用进程绕过使用控制的难度低; 如果应用进程和软件密码实现分别位于用户态空间和内核态空间(甚至ARM TrustZone 和Intel SGX等执行环境[66]), 则密码计算使用控制被绕过的难度明显提升.

(3) 软件密码实现与其它应用软件在不同程度上共享运行环境, 侧信道泄露信息的程度也不一样. 例如, 动态链接库的跨进程代码页共享、甚至跨虚拟机的代码页共享, 发起恶意攻击的条件不一样;共享L1 Cache 和共享L3 Cache 情况的攻击难度也不同.

总体说来, 一方面可以充分利用运行环境的已有安全机制, 同时还应该考虑运行环境隔离和接口限制被攻击突破之后的情况, 软件密码实现的安全性不能完全依赖于运行环境.

4.3 敏感安全参数管理

从现有攻击研究来看, 与软件密码模块敏感安全参数管理关系密切的攻击手段主要有: (1) 内存数据的非授权读取和扩散导致的关键安全参数泄露, 包括密钥和随机数发生器内部状态的泄露. 现有各种内存攻击和防御方案可以作为软件密码实现的重要参考; (2) 随机数发生器的初态和和运行时熵源问题. 二者都需要运行环境的配合, 使其快速进入足熵状态; (3) 敏感数据的保存问题. 应该避免在运行环境的非易失存储区内存放密钥文件(尤其是使用口令加密) 和口令鉴别校验文件, 相比于内存数据的非授权读取, 针对硬盘等非易失存储区的非授权读取更容易成功; 攻击者获得上述文件之后就可以实施暴力攻击. 而且, 对于固态硬盘的Flash 存储介质、非原位存储特性使得数据更新不会覆盖原数据, 清除数据更加困难[158].

4.4 软件/固件安全

在软件/固件安全方面,与敏感安全参数管理一样,应该考虑运行期的、突破运行环境逻辑边界的攻击;除了常见的代码签名等启动时安全机制, 还应该考虑Stack Canary、DEP (Data Execution Prevention)和Write XOR Execute 等运行期的运行环境内存保护机制[159-161]; 还可以借助虚拟机自省技术, 实现虚拟机代码的运行期完整性保护[162-165]. 对于动态链接库形式的密码软件实现, DLL Preloading 或DLL Injection 攻击也应该有防御考虑, 避免攻击者直接替换; 常见的解决方案可以参考文献[136,137].

4.5 角色、服务和鉴别

ROP (Return-Oriented Programming) 和控制流劫持(Control Flow Hijacking) 等攻击可以在不改变可执行代码的前提下, 改变软件控制流、完成恶意操作; 也就是, 即使软件/固件安全的技术要求已经满足, 攻击者仍然可能绕过角色、服务和鉴别的安全机制. 常见的防御措施包括ASLR (Address Space Layout Randomization,地址空间布局随机化)[166]、CFI(Control Flow Integrity,控制流完整性)[92,167]、Code-Pointer Integrity[168]以及减少代码的攻击利用[169,170]等.

4.6 非入侵式攻击

最后, 由于软件密码实现与其它任务共享执行环境, 更容易受到侧信道攻击. 除了硬件密码模块的侧信道攻击, 尤其在软件密码实现中, 由于共享内存和共享Cache 导致的侧信道攻击近年来屡有披露[12,34,39,41,43-45,130-132]等, 运行环境角度的解决方案思路是切断运行时的内存和Cache 的共享[91,171-174]、但是对于性能会有一定影响.

5 结束语

随着《中华人民共和国密码法》的颁布和施行, 密码理论方案必将在网络空间中得到更多应用, 从计算机和网络系统的角度来考虑密码技术, 很有必要. 本文尝试总结密码应用安全技术研究现状, 而且主要从系统安全与网络安全的角度来讨论密码理论方案的实现、部署和运行, 希望能够有更多研究学者关注密码技术与系统安全/网络安全的结合和交叉研究, 从而促进密码技术方案在网络空间的更深入应用. 所以,对于白盒密码实现、门限密码算法等与本文主题相关、但是理论性更强的密码应用安全研究内容, 本文没有讨论.

密码模块检测是密码技术应用的重要环节. 作为典型的密码模块检测标准, FIPS 140-3 带有明显的硬件密码模块痕迹. 在传统上, 密码模块呈现专用的硬件设备形态, 几百年前、上千年前的古典密码设备就是如此. 软件密码实现(或者软件密码模块) 同样也是密码技术走向网络空间的必然技术趋势, 所以本文也专门对软件密码模块检测展开了初步讨论.

虽然本文列出了大量密码技术应用中的漏洞和缺陷, 但是我们必须强调: 各种问题应是瑕不掩瑜; 即使是安全强度不足的密码算法和密钥长度、即使是有缺陷的随机数发生器, 密码技术的使用也能够提高攻击难度. 本文的目标是让更多人重视密码实现、部署和运行的安全性, 更进一步提升网络空间安全.