Skip to content

Commit 59f5e75

Browse files
committed
Correctly calculate the length of SM2 plaintext given the ciphertext
Previously the length of the SM2 plaintext could be incorrectly calculated. The plaintext length was calculated by taking the ciphertext length and taking off an "overhead" value. The overhead value was assumed to have a "fixed" element of 10 bytes. This is incorrect since in some circumstances it can be more than 10 bytes. Additionally the overhead included the length of two integers C1x and C1y, which were assumed to be the same length as the field size (32 bytes for the SM2 curve). However in some cases these integers can have an additional padding byte when the msb is set, to disambiguate them from negative integers. Additionally the integers can also be less than 32 bytes in length in some cases. If the calculated overhead is incorrect and larger than the actual value this can result in the calculated plaintext length being too small. Applications are likely to allocate buffer sizes based on this and therefore a buffer overrun can occur. CVE-2021-3711 Issue reported by John Ouyang. Reviewed-by: Paul Dale <pauli@openssl.org> Reviewed-by: Nicola Tuveri <nic.tuv@gmail.com>
1 parent 8c74c9d commit 59f5e75

File tree

4 files changed

+10
-20
lines changed

4 files changed

+10
-20
lines changed

Diff for: crypto/sm2/sm2_crypt.c

+7-16
Original file line numberDiff line numberDiff line change
@@ -61,29 +61,20 @@ static size_t ec_field_size(const EC_GROUP *group)
6161
return field_size;
6262
}
6363

64-
int sm2_plaintext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len,
65-
size_t *pt_size)
64+
int sm2_plaintext_size(const unsigned char *ct, size_t ct_size, size_t *pt_size)
6665
{
67-
const size_t field_size = ec_field_size(EC_KEY_get0_group(key));
68-
const int md_size = EVP_MD_size(digest);
69-
size_t overhead;
66+
struct SM2_Ciphertext_st *sm2_ctext = NULL;
7067

71-
if (md_size < 0) {
72-
SM2err(SM2_F_SM2_PLAINTEXT_SIZE, SM2_R_INVALID_DIGEST);
73-
return 0;
74-
}
75-
if (field_size == 0) {
76-
SM2err(SM2_F_SM2_PLAINTEXT_SIZE, SM2_R_INVALID_FIELD);
77-
return 0;
78-
}
68+
sm2_ctext = d2i_SM2_Ciphertext(NULL, &ct, ct_size);
7969

80-
overhead = 10 + 2 * field_size + (size_t)md_size;
81-
if (msg_len <= overhead) {
70+
if (sm2_ctext == NULL) {
8271
SM2err(SM2_F_SM2_PLAINTEXT_SIZE, SM2_R_INVALID_ENCODING);
8372
return 0;
8473
}
8574

86-
*pt_size = msg_len - overhead;
75+
*pt_size = sm2_ctext->C2->length;
76+
SM2_Ciphertext_free(sm2_ctext);
77+
8778
return 1;
8879
}
8980

Diff for: crypto/sm2/sm2_pmeth.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ static int pkey_sm2_decrypt(EVP_PKEY_CTX *ctx,
151151
const EVP_MD *md = (dctx->md == NULL) ? EVP_sm3() : dctx->md;
152152

153153
if (out == NULL) {
154-
if (!sm2_plaintext_size(ec, md, inlen, outlen))
154+
if (!sm2_plaintext_size(in, inlen, outlen))
155155
return -1;
156156
else
157157
return 1;

Diff for: include/crypto/sm2.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ int sm2_verify(const unsigned char *dgst, int dgstlen,
6060
int sm2_ciphertext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len,
6161
size_t *ct_size);
6262

63-
int sm2_plaintext_size(const EC_KEY *key, const EVP_MD *digest, size_t msg_len,
64-
size_t *pt_size);
63+
int sm2_plaintext_size(const unsigned char *ct, size_t ct_size, size_t *pt_size);
6564

6665
int sm2_encrypt(const EC_KEY *key,
6766
const EVP_MD *digest,

Diff for: test/sm2_internal_test.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ static int test_sm2_crypt(const EC_GROUP *group,
185185
if (!TEST_mem_eq(ctext, ctext_len, expected, ctext_len))
186186
goto done;
187187

188-
if (!TEST_true(sm2_plaintext_size(key, digest, ctext_len, &ptext_len))
188+
if (!TEST_true(sm2_plaintext_size(ctext, ctext_len, &ptext_len))
189189
|| !TEST_int_eq(ptext_len, msg_len))
190190
goto done;
191191

0 commit comments

Comments
 (0)