OpenSSL国密爆出8.1分⾼危漏洞CVE-2021-3711背景
OpenSSL是⼀个知名的开源安全套接字层密码库。全球成千上万的web服务器的⽹站加密技术使⽤OpenSSL。
⽹银、在线⽀付、电商⽹站、门户⽹站、电⼦邮件等互联⽹应⽤⼴泛使⽤OpenSSL实现数据的安全传输和安全存储。
历史上,OpenSSL多次出现安全漏洞。
2014年,OpenSSL爆出Heartbleed(⼼脏滴⾎)漏洞,⽹络出现了“致命内伤”。
⼼脏滴⾎称为互联⽹安全历史上最严重的漏洞之⼀,当时全球三分之⼆的⽹站可被该漏洞攻击。
⼼脏滴⾎漏洞的CVE编号是CVE-2014-0160,CVSS3.1打分7.5,属于严重漏洞。
业界使⽤CVE ID作为漏洞编号。CVE是通⽤漏洞披露(Common Vulnerabilities and Exposures)的英⽂缩写。
业界采⽤CVSS量化漏洞影响。CVSS是通⽤漏洞评分系统(Common Vulnerability Scoring System)的英⽂缩写。
CVSS得分最⼤为10,最⼩为0。得分7~10的漏洞通常认为严重,得分在4~6.9之间是中级漏洞,0~3.9是低级漏洞。
2021年8⽉24⽇,OpenSSL发布了OpenSSL 1.1.1l,该版本修复了⼀个⾼危漏洞:CVE-2021-3711。
根据
该漏洞的CVSS3.1打分8.1,属于严重漏洞。
该漏洞影响OpenSSL 1.1.1l之前的所有包含SM2商密算法版本。业界⼀些基于OpenSSL改造过的商⽤国密算法版本也可能受该漏洞影响。
本⽂结合OpenSSL公告、修复前后的OpenSSL代码和触发漏洞的sm2密⽂数据,分析CVE-2021-3711漏洞原理,并评估对腾讯⾃研国密算法库的影响。
漏洞分析
得出如下分析:
漏洞原因:SM2解密时分配了⼀块内存,解密后的结果可能⼤于该分配内存的容量,造成内存越界写。
以下是具体分析,使⽤CVE-2021-3711漏洞修复之前的OpenSSL 1.1.1代码。
1、OpenSSL EVP解密操作
OpenSSL EVP将常⽤的密码算法进⾏了封装,提供统⼀的密码学各种函数。
看⽰例图规律,OpenSSL对密⽂的解密是什么样的操作?
⽰例1:crypto/evp/p_open.c
⽰例2:crypto/crmf/crmf_lib.c
⽰例3:crypto/cms/cms_env.c
⽰例4:crypto/pkcs7/pk7_doit.c
实际应⽤中密⽂的解密⼀般需要调⽤两次EVP_PKEY_decrypt。
第⼀次调⽤EVP_PKEY_decrypt,指针out为NULL,返回长度keylen。
通过OPENSSL_malloc分配⼀块keylen⼤⼩的堆内存。
第⼆次调⽤EVP_PKEY_decrypt,指针out为第⼀次调⽤所分配的内存,运算结束后存放解密结果。
2、EVP_PKEY_decrypt实现
在初始化EVP_PKEY_CTX结构后,通过EVP_PKEY_decrypt可以调⽤到具体的密码算法执⾏解密运算。
int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx,
unsigned char *out, size_t *outlen,
const unsigned char *in, size_t inlen)
{
int ret;
...
if (ctx->op.ciph.algctx == NULL)
goto legacy;
ret = ctx->op.ciph.cipher->decrypt(ctx->op.ciph.algctx, out,
outlen, (out == NULL ? 0 : *outlen), in, inlen);
return ret;
legacy:
...
}
3、pkey_sm2_decrypt实现
对于SM2解密,EVP_PKEY_decrypt中的ctx->op.ciph.cipher->decrypt对应的是pkey_sm2_decrypt。
pkey_sm2_decrypt函数位于crypto/sm2/sm2_pmeth.c。
static int pkey_sm2_decrypt(EVP_PKEY_CTX *ctx,
unsigned char *out, size_t *outlen,
const unsigned char *in, size_t inlen)
{
EC_KEY *ec = ctx->pkey-&;
SM2_PKEY_CTX *dctx = ctx->data;
const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;
if (out == NULL) {
if (!sm2_plaintext_size(ec, md, inlen, outlen))
return -1;
else
return 1;
}
return sm2_decrypt(ec, md, in, inlen, out, outlen);
}
根据第⼀节OpenSSL EVP解密操作可知,第⼀次调⽤EVP_PKEY_decrypt函数时,指针out为NULL,返回长度作为接下来分配堆内存的⼤⼩。
这⾥sm2_plaintext_size函数返回outlen,作为接下来分配堆内存的⼤⼩。
4、sm2_plaintext_size实现
sm2_plaintext_size函数位于crypto/sm2/sm2_crypt.c
int sm2_plaintext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len,
size_t *pt_size)
{
const size_t field_size = ec_field_size(EC_KEY_get0_group(key));
const int md_size = EVP_MD_size(digest);
size_t overhead;
if (md_size < 0) {
SM2err(SM2_F_SM2_PLAINTEXT_SIZE, SM2_R_INVALID_DIGEST);
return 0;
}
if (field_size == 0) {
SM2err(SM2_F_SM2_PLAINTEXT_SIZE, SM2_R_INVALID_FIELD);
return 0;
}
overhead = 10 + 2 * field_size + (size_t)md_size;
if (msg_len <= overhead) {
SM2err(SM2_F_SM2_PLAINTEXT_SIZE, SM2_R_INVALID_ENCODING);
return 0;
cve漏洞库}
*pt_size = msg_len - overhead;
return 1;
}
注意:返回的长度等于msg_len - overhead,⽽overhead = 10 + 2 * field_size+(size_t)md_size。
5、overhead存在的问题
sm2国密算法知识
关于overhead的设置,涉及SM2算法和SM2密⽂格式的知识,在此进⾏补充。
1. SM2(SM是“商密”拼⾳的缩写)是我国商⽤密码的公钥密码标准,标准号为:GM/T 0003-2012。
2. SM2标准中规定采⽤256⽐特的椭圆曲线域参数。
3. SM2算法采⽤SM3算法作为算法步骤中的哈希算法,SM3算法的输出是256⽐特的哈希值。
4. 根据GM/T 0009-2012,SM2密⽂格式如下:
这⾥,XCoordinate和YCoordinate是加密过程基于随机数计算出的椭圆曲线点的X坐标和Y坐标。overhead取值分析
查看sm2_plaintext_size函数:
1. field_size = ec_field_size(EC_KEY_get0_group(key)),对于SM2算法,field_size等于32。
2. md_size = EVP_MD_size(digest),SM2算法采⽤SM3算法,因此md_size等于32。
从上述2点可知,sm2_plaintext_size函数中的overhead取值等于106(10+2*32+32)。
这⾥的magic number 10背后有什么含义呢?
1. 对于SM2密⽂,ASN.1包括5个Tag和5个Length,ASN.1编码引⼊的长度不⼩于10个字节。分析如下:每个Tag占1个字节,5个
Tag占5个字节。XCoordinate、YCoordinate和HASH由于值的长度范围相对固定,这3个Length占3个字节。取决于CipherText 值,CipherText和第⼀个tag后⾯的Length长度不定,这2个Length可能超过2个字节。
2. 这⾥overhead选择10,是选择SM2密⽂ASN.1编码引⼊的长度的最⼩值。
返回的长度等于msg_len - overhead,若overhead取值⼩,则返回长度⼤,分配内存⼤于实际需要,不会溢出。
这⾥的field_size没有考虑XCoordinate和YCoordinate的具体取值,有没有风险?
1)XCoordinate和YCoordinate是加密过程基于随机数计算出的椭圆曲线点的X坐标和Y坐标,满⾜以下⽅程:
YCoordinate * YCoordinate ≡ XCoordinate * XCoordinate * XCoordinate - 3 * XCoordinate + b(mod p)
这⾥,≡表⽰⽅程的左右两边模p的结果相等,p和b是SM2国密标准中规定的常数。
2)满⾜上述⽅程的XCoordinate和YCoordinate通常都是占32字节的⼤数。
3)如果密⽂中携带的XCoordinate占31字节,YCoordinate占32字节,则真实的overhead可能⼩于106。
此时使⽤msg_len - 106的结果去会分配空间,导致分配的空间⼩于解密后的结果,内存越界写。
4)存在满⾜上述⽅程的占31字节甚⾄更少的XCoordinate或YCoordinate吗?
OpenSSL给出的SM2密⽂数据⽰例给出了肯定的回答。
触发漏洞的数据⽰例
1、SM2密⽂数据
OpenSSL给出的密⽂数据⽰例如下:
3072022070DAD60CDA7C30D64CF4F278A849003581223F5324BFEC9BB329229BFFAD21A6021F18AFAB2B35459D
2、解析SM2密⽂
这组密⽂的长度是116字节。按照ASN.1格式解析这组密⽂:
3072 //30表⽰SEQUENCE类型,72表⽰后续的数据总长度是114字节
0220 //02表⽰INTEGER类型,20表⽰该整数的长度是32字节
70DAD60CDA7C30D64CF4F278A849003581223F5324BFEC9BB329229BFFAD21A6 //32字节的XCoordinate
021F //02表⽰INTEGER类型,1F表⽰该整数的长度是31字节
18AFAB2B35459D2643243B242BE4EA80C6FA5071D2D847340CC57EB9309E5D //31字节的YCoordinate
0420 //04表⽰OCTETSTRING类型,20表⽰该字符串的长度是32字节
0B772E4DB664B2601E3B85E39C4AA8C2C1910308BE13B331E009C5A9258C29FD //32字节的HASH
040B //04表⽰OCTETSTRING类型,0B表⽰该字符串的长度是11字节
6D588BE9260A94DA18E0E6 //11字节的密⽂
经过验证,上述的XCoordinate和YCoordinate满⾜SM2椭圆曲线⽅程。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论