CVE-2020-36316 (C, published 2021-04-07T21:15Z)
Description: value: In RELIC before 2021-04-03, there is a buffer overflow in PKCS#1 v1.5 signature verification because garbage bytes can be present.
Severity: MEDIUM (CVSS v3 base score: 5.5)
Weakness: CWE-120 \u2014 Buffer Copy without Checking Size of Input ('Classic Buffer Overflow')
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.
Repository: https://github.com/relic-toolkit/relic
Files changed:
src/cp/relic_cp_rsa.c
Commit message: Fix #154 and #155 by inverting the padding check logic and being more rigorous.


Vulnerable code:
	int result = RLC_OK;
				if (!bn_is_zero(t)) {
					result = RLC_ERR;
				}
				*p_len = 1;
				do {
					(*p_len)++;
					m_len--;
					bn_rsh(t, m, 8 * m_len);
					pad = (uint8_t)t->dp[0];
				} while (pad == 0 && m_len > 0);
				if (pad != RSA_PAD) {
					result = RLC_ERR;
				bn_mod_2b(m, m, (k_len - *p_len) * 8);
	int len, result = RLC_OK;
				if (!bn_is_zero(t)) {
					result = RLC_ERR;
				}

				*p_len = m_len;
				m_len--;
				bn_rsh(t, m, 8 * m_len);
				pad = (uint8_t)t->dp[0];
				if (pad != RSA_PUB) {
					result = RLC_ERR;
				}
				do {
				} while (pad != 0 && m_len > 0);
				/* Remove padding and trailing zero. */
				*p_len -= (m_len - 1);
				bn_mod_2b(m, m, (k_len - *p_len) * 8);
				if (!bn_is_zero(t)) {
					result = RLC_ERR;
				}
				m_len--;
				bn_rsh(t, m, 8 * m_len);
				pad = (uint8_t)t->dp[0];
				if (pad != RSA_PRV) {
					result = RLC_ERR;
				}
				do {
				} while (pad != 0 && m_len > 0);
				if (m_len == 0) {
					result = RLC_ERR;
				}
				/* Remove padding and trailing zero. */
				id = hash_id(MD_MAP, &len);
				m_len -= len;

				bn_rsh(t, m, m_len * 8);
				int r = 0;
				for (int i = 0; i < len; i++) {
					pad = (uint8_t)t->dp[0];
					r |= pad - id[len - i - 1];
					bn_rsh(t, t, 8);
				*p_len = k_len - m_len;
				bn_mod_2b(m, m, m_len * 8);
				result = (r == 0 ? RLC_OK : RLC_ERR);
				if (!bn_is_zero(t)) {
					result = RLC_ERR;
				}
				m_len--;
				bn_rsh(t, m, 8 * m_len);
				pad = (uint8_t)t->dp[0];
				if (pad != RSA_PRV) {
					result = RLC_ERR;
				}
				do {
				} while (pad != 0 && m_len > 0);
				if (m_len == 0) {
					result = RLC_ERR;
				/* Remove padding and trailing zero. */
				*p_len = k_len - m_len;
				bn_mod_2b(m, m, m_len * 8);
	int result = RLC_OK;
				if (!bn_is_zero(t)) {
					result = RLC_ERR;
				}
				m_len -= RLC_MD_LEN;
				bn_rsh(t, m, 8 * m_len);
				bn_write_bin(h1, RLC_MD_LEN, t);
				bn_mod_2b(m, m, 8 * m_len);
				bn_write_bin(mask, m_len, m);
				md_mgf(h2, RLC_MD_LEN, mask, m_len);
				for (int i = 0; i < RLC_MD_LEN; i++) {
					h1[i] ^= h2[i];
				}
				md_mgf(mask, k_len - RLC_MD_LEN - 1, h1, RLC_MD_LEN);
				bn_read_bin(t, mask, k_len - RLC_MD_LEN - 1);
				for (int i = 0; i < t->used; i++) {
					m->dp[i] ^= t->dp[i];
				}
				m_len -= RLC_MD_LEN;
				bn_rsh(t, m, 8 * m_len);
				bn_write_bin(h2, RLC_MD_LEN, t);
				md_map(h1, NULL, 0);
				pad = 0;
				for (int i = 0; i < RLC_MD_LEN; i++) {
					pad |= h1[i] - h2[i];
				}
				if (result == RLC_OK) {
					result = (pad ? RLC_ERR : RLC_OK);
				}
				bn_mod_2b(m, m, 8 * m_len);
				*p_len = bn_size_bin(m);
				(*p_len)--;
				bn_rsh(t, m, *p_len * 8);
				if (bn_cmp_dig(t, 1) != RLC_EQ) {
					result = RLC_ERR;
				bn_mod_2b(m, m, *p_len * 8);
				*p_len = k_len - *p_len;
				if (bn_cmp_dig(t, RSA_PSS) != RLC_EQ) {
					result = RLC_ERR;
				} else {
							result = RLC_ERR;
					if (!bn_is_zero(m)) {
						result = RLC_ERR;

Fixed code:
	int result = RLC_ERR;
				result = RLC_OK;
				if (bn_is_zero(t)) {
					*p_len = 1;
					do {
						(*p_len)++;
						m_len--;
						bn_rsh(t, m, 8 * m_len);
						pad = (uint8_t)t->dp[0];
					} while (pad == 0 && m_len > 0);
					if (pad == RSA_PAD) {
						result = RLC_OK;
					}
					bn_mod_2b(m, m, (k_len - *p_len) * 8);
	int len, result = RLC_ERR;
				result = RLC_OK;
				if (bn_is_zero(t)) {
					*p_len = m_len;
					if (pad == RSA_PUB) {
						do {
							m_len--;
							bn_rsh(t, m, 8 * m_len);
							pad = (uint8_t)t->dp[0];
						} while (pad != 0 && m_len > 0);
						/* Remove padding and trailing zero. */
						*p_len -= (m_len - 1);
						bn_mod_2b(m, m, (k_len - *p_len) * 8);
						result = (m_len > 0 ? RLC_OK : RLC_ERR);
					}
				}
				result = RLC_OK;
				result = RLC_OK;
				if (bn_is_zero(t)) {
					if (pad == RSA_PRV) {
						int counter = 0;
						do {
							counter++;
							m_len--;
							bn_rsh(t, m, 8 * m_len);
							pad = (uint8_t)t->dp[0];
						} while (pad == RSA_PAD && m_len > 0);
						/* Remove padding and trailing zero. */
						id = hash_id(MD_MAP, &len);
						m_len -= len;

						bn_rsh(t, m, m_len * 8);
						int r = 0;
						for (int i = 0; i < len; i++) {
							pad = (uint8_t)t->dp[0];
							r |= pad ^ id[len - i - 1];
							bn_rsh(t, t, 8);
						}
						*p_len = k_len - m_len;
						bn_mod_2b(m, m, m_len * 8);
						if (r && m_len > 0 && counter >= 8) {
							result = RLC_OK;
						}
					}
				if (bn_is_zero(t)) {
					if (pad == RSA_PRV) {
						int counter = 0;
						do {
							counter++;
							m_len--;
							bn_rsh(t, m, 8 * m_len);
							pad = (uint8_t)t->dp[0];
						} while (pad == RSA_PAD && m_len > 0);
						/* Remove padding and trailing zero. */
						*p_len = k_len - m_len;
						bn_mod_2b(m, m, m_len * 8);
						if (m_len > 0 && counter >= 8) {
							result = RLC_OK;
						}
					}
	int result = RLC_ERR;
				result = RLC_OK;
				result = RLC_OK;
				if (bn_is_zero(t)) {
					m_len -= RLC_MD_LEN;
					bn_rsh(t, m, 8 * m_len);
					bn_write_bin(h1, RLC_MD_LEN, t);
					bn_mod_2b(m, m, 8 * m_len);
					bn_write_bin(mask, m_len, m);
					md_mgf(h2, RLC_MD_LEN, mask, m_len);
					for (int i = 0; i < RLC_MD_LEN; i++) {
						h1[i] ^= h2[i];
					}
					md_mgf(mask, k_len - RLC_MD_LEN - 1, h1, RLC_MD_LEN);
					bn_read_bin(t, mask, k_len - RLC_MD_LEN - 1);
					for (int i = 0; i < t->used; i++) {
						m->dp[i] ^= t->dp[i];
					}
					m_len -= RLC_MD_LEN;
					bn_rsh(t, m, 8 * m_len);
					bn_write_bin(h2, RLC_MD_LEN, t);
					md_map(h1, NULL, 0);
					pad = 0;
					for (int i = 0; i < RLC_MD_LEN; i++) {
						pad |= h1[i] ^ h2[i];
					}
					bn_mod_2b(m, m, 8 * m_len);
					*p_len = bn_size_bin(m);
					(*p_len)--;
					bn_rsh(t, m, *p_len * 8);
					if (pad == 0 && bn_cmp_dig(t, 1) == RLC_EQ) {
						result = RLC_OK;
					}
					bn_mod_2b(m, m, *p_len * 8);
					*p_len = k_len - *p_len;
				result = RLC_OK;
				result = RLC_OK;
				pad = (uint8_t)t->dp[0];
				if (pad == RSA_PSS) {
					int r = 1;
							r = 0;
					if (r == 1 && bn_is_zero(m)) {
						result = RLC_OK;