CVE-2022-29242: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow') (CWE-120)
value: GOST engine is a reference implementation of the Russian GOST crypto algorithms for OpenSSL. TLS clients using GOST engine when ciphersuite `TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC` is agreed and the server uses 512 bit GOST secret keys are vulnerable to buffer overflow. GOST engine version 3.0.1 contains a patch for this issue. Disabling ciphersuite `TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC` is a possible workaround.
CWE description: The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow.
CVSS v3 base score: 7.5
Published: 2022-05-24T15:15Z
Repository: https://github.com/gost-engine/engine
Language: C
Files changed: e_gost_err.c, e_gost_err.h, gost_ec_keyx.c
Commit date: 2022-05-23 09:45:14 +0200
Commit message: Fix buffer overrun in creating key transport blob according to RFC 9189, 4.2.4.1

Resolves: CVE-2022-29242

Diff: diff --git a/e_gost_err.c b/e_gost_err.c
index 51599ca..c6d221b 100644
--- a/e_gost_err.c
+++ b/e_gost_err.c
@@ -139,10 +139,11 @@ static ERR_STRING_DATA GOST_str_reasons[] = {
     "error parsing key transport info"},
     {ERR_PACK(0, 0, GOST_R_ERROR_POINT_MUL), "error point mul"},
     {ERR_PACK(0, 0, GOST_R_ERROR_SETTING_PEER_KEY), "error setting peer key"},
     {ERR_PACK(0, 0, GOST_R_INCOMPATIBLE_ALGORITHMS), "incompatible algorithms"},
     {ERR_PACK(0, 0, GOST_R_INCOMPATIBLE_PEER_KEY), "incompatible peer key"},
+    {ERR_PACK(0, 0, GOST_R_INVALID_BUFFER_SIZE), "invalid buffer size"},
     {ERR_PACK(0, 0, GOST_R_INVALID_CIPHER), "invalid cipher"},
     {ERR_PACK(0, 0, GOST_R_INVALID_CIPHER_PARAMS), "invalid cipher params"},
     {ERR_PACK(0, 0, GOST_R_INVALID_CIPHER_PARAM_OID),
     "invalid cipher param oid"},
     {ERR_PACK(0, 0, GOST_R_INVALID_DIGEST_TYPE), "invalid digest type"},
diff --git a/e_gost_err.h b/e_gost_err.h
index d69534f..6f6ea1b 100644
--- a/e_gost_err.h
+++ b/e_gost_err.h
@@ -113,10 +113,11 @@ void ERR_GOST_error(int function, int reason, char *file, int line);
 # define GOST_R_ERROR_PARSING_KEY_TRANSPORT_INFO          106
 # define GOST_R_ERROR_POINT_MUL                           107
 # define GOST_R_ERROR_SETTING_PEER_KEY                    139
 # define GOST_R_INCOMPATIBLE_ALGORITHMS                   108
 # define GOST_R_INCOMPATIBLE_PEER_KEY                     109
+# define GOST_R_INVALID_BUFFER_SIZE                       140
 # define GOST_R_INVALID_CIPHER                            134
 # define GOST_R_INVALID_CIPHER_PARAMS                     110
 # define GOST_R_INVALID_CIPHER_PARAM_OID                  111
 # define GOST_R_INVALID_DIGEST_TYPE                       112
 # define GOST_R_INVALID_IV_LENGTH                         113
diff --git a/gost_ec_keyx.c b/gost_ec_keyx.c
index 944db40..5e677dc 100644
--- a/gost_ec_keyx.c
+++ b/gost_ec_keyx.c
@@ -404,10 +404,11 @@ static int pkey_gost2018_encrypt(EVP_PKEY_CTX *pctx, unsigned char *out,
     int mac_nid = NID_undef;
     size_t mac_len = 0;
     int exp_len = 0, iv_len = 0;
     unsigned char *exp_buf = NULL;
     int key_is_ephemeral = 0;
+    int res_len = 0;
 
     switch (data->cipher_nid) {
     case NID_magma_ctr:
         mac_nid = NID_magma_mac;
         mac_len = 8;
@@ -497,12 +498,30 @@ static int pkey_gost2018_encrypt(EVP_PKEY_CTX *pctx, unsigned char *out,
     if (!X509_PUBKEY_set(&pst->ephem_key, out ? sec_key : pubk)) {
         GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, GOST_R_CANNOT_PACK_EPHEMERAL_KEY);
         goto err;
     }
 
-    if ((*out_len = i2d_PSKeyTransport_gost(pst, out ? &out : NULL)) > 0)
+    res_len = i2d_PSKeyTransport_gost(pst, NULL);
+    if (res_len <= 0) {
+        GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, ERR_R_ASN1_LIB);
+        goto err;
+    }
+
+    if (out == NULL) {
+        *out_len = res_len;
         ret = 1;
+    } else {
+        if ((size_t)res_len > *out_len) {
+            GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, GOST_R_INVALID_BUFFER_SIZE);
+            goto err;
+        }
+        if ((*out_len = i2d_PSKeyTransport_gost(pst, &out)) > 0)
+            ret = 1;
+        else
+            GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, ERR_R_ASN1_LIB);
+    }
+
  err:
     OPENSSL_cleanse(expkeys, sizeof(expkeys));
     if (key_is_ephemeral)
         EVP_PKEY_free(sec_key);
 

Vulnerable code:     if ((*out_len = i2d_PSKeyTransport_gost(pst, out ? &out : NULL)) > 0)
Fixed code:     {ERR_PACK(0, 0, GOST_R_INVALID_BUFFER_SIZE), "invalid buffer size"},
# define GOST_R_INVALID_BUFFER_SIZE                       140
    int res_len = 0;
    res_len = i2d_PSKeyTransport_gost(pst, NULL);
    if (res_len <= 0) {
        GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, ERR_R_ASN1_LIB);
        goto err;
    }

    if (out == NULL) {
        *out_len = res_len;
    } else {
        if ((size_t)res_len > *out_len) {
            GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, GOST_R_INVALID_BUFFER_SIZE);
            goto err;
        }
        if ((*out_len = i2d_PSKeyTransport_gost(pst, &out)) > 0)
            ret = 1;
        else
            GOSTerr(GOST_F_PKEY_GOST2018_ENCRYPT, ERR_R_ASN1_LIB);
    }