文/林璟锵 刘广祺 孟令佳 万会庆 王琼霄 王伟 王文杰 徐博文
中国科学院数据与通信保护研究教育中心
中国科学院信息工程研究所 信息安全国家重点实验室
1.CVE-2020-0601漏洞
2020年1月15日,微软公布了1月份的补丁更新列表,其中包括有CVE-2020-0601,是Windows操作系统CryptoAPI (Crypt32.dll)的椭圆曲线密码(Elliptic Curve Cryptography, ECC)数字证书验证相关的漏洞;该漏洞会导致Windows操作系统将攻击者伪造的数字证书误判为由操作系统预置信任的根CA所签发。该漏洞由美国国家安全局(National Security Agency, NSA)发现并汇报给微软公司;这一漏洞被认为是第一个NSA公开披露的软件系统漏洞。
2.影响
基于该漏洞,攻击者可以基于某一张Windows操作系统预置信任的根CA证书、伪造任意虚假信息的数字证书,而且会被Windows操作系统误判为“该证书没有问题”、误判为是由操作系统预置信任的根CA所签发。进一步,攻击者能够(结合其它的攻击手段)任意创建可被验证通过的代码签名证书、安装恶意可执行代码,创建任意域名的服务器TLS证书、发起TLS中间人攻击,创建可被验证通过的电子邮件证书、以其它人名义发送安全电子邮件。
只有支持“定制参数的ECC数字证书”的Windows操作系统版本会受到影响。这一机制最早在Windows 10引入,所以该漏洞只影响Windows 10和Windows Server 2016/2019、以及各种依赖于Windows操作系统数字证书验证功能的应用程序。2020年1月14日起停止维护的Windows 7和Windows Server 2008不支持“定制参数的ECC数字证书”,不受影响。
3.漏洞基本原理
Windows操作系统CryptoAPI的CertGetCertificateChain()函数,在构建证书链过程中,对ECDSA (Elliptic Curve Digital Signature Algorithm)算法的公钥参数验证存在漏洞。构建证书链、判定是否由操作系统预置信任的根CA所签发,过程如下:先逐层验证输入者提供的各数字证书的CA数字签名是否正确有效、直至输入者提供的根CA自签名证书,然后比较输入者提供的根CA自签名证书与操作系统预置信任的根CA证书列表。如果CA数字签名全部正确有效、且输入者提供的根CA自签名证书在Windows操作系统预置信任列表中,则判定该证书链“该证书没有问题”。
其中,Windows操作系统CryptoAPI在比较输入者提供的根CA自签名证书与操作系统预置信任的根CA证书列表过程中,存在缺陷。攻击者可以自己生成恶意的根CA自签名证书,满足:(a)ECC公钥坐标点与某一张Windows操作系统预置信任的根CA证书的ECC公钥坐标点完全一致,(b)但是二者ECC曲线参数不一致,即椭圆曲线基点不一致,(c)且攻击者能够自动拥有该根CA自签名证书的私钥。然后,Windows操作系统CryptoAPI会将攻击者伪造的根CA自签名证书误判为是操作系统预置信任的根CA证书(只是比较ECC公钥坐标点、没有比较所有的ECC曲线参数;因为ECC公钥坐标点相同,所以Subject Key Identifier扩展值相同)。
对于ECDSA算法,ECC曲线参数包括素域p、方程参数a和b、基点G、阶n和cofactor系数h,私钥d是随机数,公钥P = [d]G、是椭圆曲线的点坐标。美国NIST已经标准化地确定了多条椭圆曲线(也就是,确定了各条曲线的p、a、b、G、n和h参数);所以,在X.509数字证书中,ECC曲线参数可以直接以OID的形式表示、不需要一一列出各参数,例如,曲线secp224k1的OID就是1.3.132.0.32。同时,X.509数字证书也允许以定制参数的方式来给出ECC曲线参数,也就是,在X.509数字证书中,直接一一列出曲线的p、a、b、G、n和h参数。
攻击者伪造数字证书的过程如下。对于某一张Windows操作系统预置信任的根CA证书,已有公钥P = [d]G;攻击者生成随机数r,计算G’ = [R]P,其中R是r的逆元,则有[r]G’ = [r*R]P = P。也就是,对于基点为G’的椭圆曲线,攻击者拥有公钥P对应的私钥r,甚至r可以等于1。注意:对于基点为G的椭圆曲线,公钥P对应的私钥是d、攻击者并不知道。基于以上原理,攻击者就可以任意伪造Windows操作系统CryptoAPI验证通过的证书链。
4.实验
我们基于Microsoft ECC Product Root Certificate Authority 2018(使用NIST P384曲线,OID是1.3.132.0.34)生成了用于攻击测试的根CA自签名证书,然后签发了用于代码签名攻击测试的终端证书,进行代码数字签名,结果如下(在未安装补丁的Windows操作系统):
相应的证书路径如下(注意,左图的颁发者是xu,右图的证书路径则显示是颁发者Microsoft ECC Product Root Certificate Authority 2018):
在已经安装了补丁的Windows操作系统上,则显示如下、验证不通过:
类似的,我们也生成了用于HTTPS攻击测试的服务器证书,在Edge浏览器上显示如下(浏览器有警告提示“不安全”、但是Windows操作系统的证书路径显示成功):
浏览器应该在Windows操作系统CryptoAPI之外,有进一步的额外处理。注意:按照Internet公开的其它攻击测试,有些浏览器没有警告提示。
5.讨论
CVE-2020-0601数字证书验证漏洞涉及ECC椭圆曲线密码的基础知识,否则难以发现漏洞;同时,Windows操作系统CryptoAPI在比较根CA证书时,只处理了公钥坐标点(或者,可能是Subject Key Identifier扩展值),也是实现上的常见疏忽。
对于国产公钥密码算法SM2,有不同的情况。目前SM2算法只支持唯一的一条ECC曲线,实现中出现类似漏洞的可能性很小;但是,也不能完全排除可能性:如果系统支持“定制参数的ECC数字证书”,就有可能会有类似问题。
参考资料
https://github.com/ollypwn/CVE-2020-0601
https://securityaffairs.co/wordpress/96414/security/microsoft-cve-2020-0601-flaw-nsa.html