作者:云鼎實驗室
原文鏈接:https://mp.weixin.qq.com/s/P2aduaUS3s8K7I-cDVJNgA

背景

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。

根據
https://access.redhat.com/security/cve/cve-2021-3711
該漏洞的CVSS3.1打分8.1,屬于嚴重漏洞。

該漏洞影響OpenSSL 1.1.1l之前的所有包含SM2商密算法版本。業界一些基于OpenSSL改造過的商用國密算法版本也可能受該漏洞影響。

本文結合OpenSSL公告、修復前后的OpenSSL代碼和觸發漏洞的sm2密文數據,分析CVE-2021-3711漏洞原理,并評估對騰訊自研國密算法庫的影響。

漏洞分析

根據官網披露的信息細節
https://www.openssl.org/news/secadv/20210824.txt

得出如下分析:

漏洞原因: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->pkey.ec;    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;    }
    *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給出的密文數據示例如下:

3072022070DAD60CDA7C30D64CF4F278A849003581223F5324BFEC9BB329229BFFAD21A6021F18AFAB2B35459D2643243B242BE4EA80C6FA5071D2D847340CC57EB9309E5D04200B772E4DB664B2601E3B85E39C4AA8C2C1910308BE13B331E009C5A9258C29FD040B6D588BE9260A94DA18E0E6

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橢圓曲線方程。

圖片

3、觸發堆溢出

  1. 第一次調用pkey_sm2_decrypt,指針out為NULL,msg_len等于116。 sm2_plaintext_size函數返回10(msg_len - overhead = 116 - 106)。

  2. 通過OPENSSL_malloc分配10字節的內存,out指向該內存。

  3. 第二次調用pkey_sm2_decrypt,由于密文有11字節,因此解密結果也是11字節。

out指向的內存是10字節,而解密結果是11字節,導致越界寫1字節。

騰訊自研國密庫不受該漏洞影響

近年來,國家積極推進國產密碼基礎設施的建設,推廣與應用。

為貫徹落實國家密碼戰略,推進公司產品信息安全,騰訊自研了TencentSM國密算法庫,擺脫對國外開源密碼算法庫的依賴。

TencentSM符合國密SM2、SM3以及SM4算法標準,已在騰訊多個業務中平穩運行。

TencentSM自研了SM2解密實現,未使用和參考OpenSSL該部分所對應的代碼,不受該漏洞影響。


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1695/