From f79af112029d3146d8b1926561ed5834e95c6666 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Mon, 29 Mar 2021 11:06:37 +0200
Subject: [PATCH 4/5] build: avoid integer overflow in additions

Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
 lib/cert-cred.c        |  5 +++++
 lib/hello_ext.c        |  5 +++++
 lib/pkcs11.c           |  6 ++++++
 lib/pkcs11x.c          |  6 ++++++
 lib/supplemental.c     |  5 +++++
 lib/x509/ocsp.c        | 11 +++++++++++
 lib/x509/pkcs12.c      | 10 ++++++++++
 lib/x509/verify-high.c | 40 +++++++++++++++++++++++++++++++++++-----
 lib/x509/x509_ext.c    | 16 ++++++++++++++++
 9 files changed, 99 insertions(+), 5 deletions(-)

diff --git a/lib/cert-cred.c b/lib/cert-cred.c
index 3f1041f73b..c9c5f6ed50 100644
--- a/lib/cert-cred.c
+++ b/lib/cert-cred.c
@@ -43,6 +43,7 @@
 #include "x509/common.h"
 #include "dh.h"
 #include "cert-cred.h"
+#include "intprops.h"
 
 
 /*
@@ -55,6 +56,10 @@ _gnutls_certificate_credential_append_keypair(gnutls_certificate_credentials_t r
 				       gnutls_pcert_st * crt,
 				       int nr)
 {
+	if (unlikely(INT_ADD_OVERFLOW(res->ncerts, 1))) {
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+	}
+
 	res->sorted_cert_idx = _gnutls_reallocarray_fast(res->sorted_cert_idx,
 							 res->ncerts + 1,
 							 sizeof(unsigned int));
diff --git a/lib/hello_ext.c b/lib/hello_ext.c
index 6943d095b3..32385f4c0e 100644
--- a/lib/hello_ext.c
+++ b/lib/hello_ext.c
@@ -57,6 +57,7 @@
 #include <num.h>
 #include <ext/client_cert_type.h>
 #include <ext/server_cert_type.h>
+#include "intprops.h"
 
 static void
 unset_ext_data(gnutls_session_t session, const struct hello_ext_entry_st *, unsigned idx);
@@ -923,6 +924,10 @@ gnutls_session_ext_register(gnutls_session_t session,
 			tmp_mod.validity |= GNUTLS_EXT_FLAG_TLS;
 	}
 
+	if (unlikely(INT_ADD_OVERFLOW(session->internals.rexts_size, 1))) {
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+	}
+
 	exts = _gnutls_reallocarray(session->internals.rexts,
 				    session->internals.rexts_size + 1,
 				    sizeof(*exts));
diff --git a/lib/pkcs11.c b/lib/pkcs11.c
index 7e8c0570ac..364c0c49a9 100644
--- a/lib/pkcs11.c
+++ b/lib/pkcs11.c
@@ -40,6 +40,7 @@
 #include "x509/x509_int.h"
 
 #include <atfork.h>
+#include "intprops.h"
 
 #define MAX_PROVIDERS 16
 
@@ -3291,6 +3292,11 @@ find_multi_objs_cb(struct ck_function_list *module, struct pkcs11_session_info *
 		unsigned j;
 		gnutls_datum_t id;
 
+		if (unlikely(INT_ADD_OVERFLOW(find_data->current, count))) {
+			ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+			goto fail;
+		}
+
 		find_data->p_list =
 			_gnutls_reallocarray_fast(find_data->p_list,
 						  find_data->current + count,
diff --git a/lib/pkcs11x.c b/lib/pkcs11x.c
index 7bb62f64bf..dfaee58a39 100644
--- a/lib/pkcs11x.c
+++ b/lib/pkcs11x.c
@@ -28,6 +28,7 @@
 #include <pkcs11_int.h>
 #include <p11-kit/p11-kit.h>
 #include "pkcs11x.h"
+#include "intprops.h"
 
 struct find_ext_data_st {
 	/* in */
@@ -217,6 +218,11 @@ find_ext_cb(struct ck_function_list *module, struct pkcs11_session_info *sinfo,
 		rv = pkcs11_get_attribute_avalue(sinfo->module, sinfo->pks, obj, CKA_VALUE, &ext);
 		if (rv == CKR_OK) {
 
+			if (unlikely(INT_ADD_OVERFLOW(find_data->exts_size, 1))) {
+				ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+				goto cleanup;
+			}
+
 			find_data->exts =
 				_gnutls_reallocarray_fast(find_data->exts,
 							  find_data->exts_size + 1,
diff --git a/lib/supplemental.c b/lib/supplemental.c
index fc9545526a..becb01e50c 100644
--- a/lib/supplemental.c
+++ b/lib/supplemental.c
@@ -48,6 +48,7 @@
 #include "supplemental.h"
 #include "errors.h"
 #include "num.h"
+#include "intprops.h"
 
 typedef struct gnutls_supplemental_entry_st {
 	char *name;
@@ -252,6 +253,10 @@ _gnutls_supplemental_register(gnutls_supplemental_entry_st *entry)
 			return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);
 	}
 
+	if (unlikely(INT_ADD_OVERFLOW(suppfunc_size, 1))) {
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+	}
+
 	p = _gnutls_reallocarray_fast(suppfunc, suppfunc_size + 1,
 				      sizeof(*suppfunc));
 	if (!p) {
diff --git a/lib/x509/ocsp.c b/lib/x509/ocsp.c
index 7587a2649a..e750ac4724 100644
--- a/lib/x509/ocsp.c
+++ b/lib/x509/ocsp.c
@@ -38,6 +38,7 @@
 #include <auth/cert.h>
 
 #include <assert.h>
+#include "intprops.h"
 
 typedef struct gnutls_ocsp_req_int {
 	ASN1_TYPE req;
@@ -1905,6 +1906,11 @@ gnutls_ocsp_resp_get_certs(gnutls_ocsp_resp_const_t resp,
 			goto error;
 		}
 
+		if (unlikely(INT_ADD_OVERFLOW(ctr, 2))) {
+			ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+			goto error;
+		}
+
 		tmpcerts2 = _gnutls_reallocarray_fast(tmpcerts, ctr + 2,
 						      sizeof(*tmpcerts));
 		if (tmpcerts2 == NULL) {
@@ -2457,6 +2463,11 @@ gnutls_ocsp_resp_list_import2(gnutls_ocsp_resp_t **ocsps,
 				goto fail;
 			}
 
+			if (unlikely(INT_ADD_OVERFLOW(*size, 1))) {
+				ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+				goto fail;
+			}
+
 			new_ocsps = _gnutls_reallocarray(*ocsps,
 							 *size + 1,
 							 sizeof(gnutls_ocsp_resp_t));
diff --git a/lib/x509/pkcs12.c b/lib/x509/pkcs12.c
index ac0d2f565f..965de6fe02 100644
--- a/lib/x509/pkcs12.c
+++ b/lib/x509/pkcs12.c
@@ -37,6 +37,7 @@
 #include "x509_int.h"
 #include "pkcs7_int.h"
 #include <random.h>
+#include "intprops.h"
 
 
 /* Decodes the PKCS #12 auth_safe, and returns the allocated raw data,
@@ -1455,6 +1456,10 @@ static int make_chain(gnutls_x509_crt_t ** chain, unsigned int *chain_len,
 			    != 0)
 				goto skip;
 
+			if (unlikely(INT_ADD_OVERFLOW(*chain_len, 1))) {
+				return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+			}
+
 			*chain = _gnutls_reallocarray_fast(*chain,
 							   ++(*chain_len),
 							   sizeof((*chain)[0]));
@@ -1777,6 +1782,11 @@ gnutls_pkcs12_simple_parse(gnutls_pkcs12_t p12,
 				}
 
 				if (memcmp(cert_id, key_id, cert_id_size) != 0) {	/* they don't match - skip the certificate */
+					if (unlikely(INT_ADD_OVERFLOW(_extra_certs_len, 1))) {
+						ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+						goto done;
+					}
+
 					_extra_certs =
 						_gnutls_reallocarray_fast(_extra_certs,
 									  ++_extra_certs_len,
diff --git a/lib/x509/verify-high.c b/lib/x509/verify-high.c
index 7fdbdc68d5..ab8e006ca7 100644
--- a/lib/x509/verify-high.c
+++ b/lib/x509/verify-high.c
@@ -34,6 +34,7 @@
 #include <common.h>
 #include <gnutls/x509-ext.h>
 #include "verify-high.h"
+#include "intprops.h"
 
 struct named_cert_st {
 	gnutls_x509_crt_t cert;
@@ -128,6 +129,10 @@ cert_set_add(struct cert_set_st *set, const gnutls_x509_crt_t cert)
 	hash = hash_pjw_bare(cert->raw_dn.data, cert->raw_dn.size);
 	hash %= set->size;
 
+	if (unlikely(INT_ADD_OVERFLOW(set->node[hash].size, 1))) {
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+	}
+
 	set->node[hash].certs =
 		_gnutls_reallocarray_fast(set->node[hash].certs,
 					  set->node[hash].size + 1,
@@ -297,6 +302,10 @@ static int
 trust_list_add_compat(gnutls_x509_trust_list_t list,
 			       gnutls_x509_crt_t cert)
 {
+	if (unlikely(INT_ADD_OVERFLOW(list->keep_certs_size, 1))) {
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+	}
+
 	list->keep_certs =
 		_gnutls_reallocarray_fast(list->keep_certs,
 					  list->keep_certs_size + 1,
@@ -378,6 +387,11 @@ gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list,
 			}
 		}
 
+		if (unlikely(INT_ADD_OVERFLOW(list->node[hash].trusted_ca_size, 1))) {
+			gnutls_assert();
+			return i;
+		}
+
 		list->node[hash].trusted_cas =
 			_gnutls_reallocarray_fast(list->node[hash].trusted_cas,
 						  list->node[hash].trusted_ca_size + 1,
@@ -663,6 +677,10 @@ gnutls_x509_trust_list_remove_cas(gnutls_x509_trust_list_t list,
 			}
 		}
 
+		if (unlikely(INT_ADD_OVERFLOW(list->blacklisted_size, 1))) {
+			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+		}
+
 		/* Add the CA (or plain) certificate to the black list as well.
 		 * This will prevent a subordinate CA from being valid, and
 		 * ensure that a server certificate will also get rejected.
@@ -725,6 +743,10 @@ gnutls_x509_trust_list_add_named_crt(gnutls_x509_trust_list_t list,
 			  cert->raw_issuer_dn.size);
 	hash %= list->size;
 
+	if (unlikely(INT_ADD_OVERFLOW(list->node[hash].named_cert_size, 1))) {
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+	}
+
 	list->node[hash].named_certs =
 		_gnutls_reallocarray_fast(list->node[hash].named_certs,
 					  list->node[hash].named_cert_size + 1,
@@ -838,16 +860,17 @@ gnutls_x509_trust_list_add_crls(gnutls_x509_trust_list_t list,
 			}
 		}
 
+		if (unlikely(INT_ADD_OVERFLOW(list->node[hash].crl_size, 1))) {
+			gnutls_assert();
+			goto error;
+		}
+
 		tmp = _gnutls_reallocarray(list->node[hash].crls,
 					   list->node[hash].crl_size + 1,
 					   sizeof(list->node[hash].crls[0]));
 		if (tmp == NULL) {
-			ret = i;
 			gnutls_assert();
-			if (flags & GNUTLS_TL_NO_DUPLICATES)
-				while (i < crl_size)
-					gnutls_x509_crl_deinit(crl_list[i++]);
-			return ret;
+			goto error;
 		}
 		list->node[hash].crls = tmp;
 
@@ -861,6 +884,13 @@ gnutls_x509_trust_list_add_crls(gnutls_x509_trust_list_t list,
 	}
 
 	return j;
+
+ error:
+	ret = i;
+	if (flags & GNUTLS_TL_NO_DUPLICATES)
+		while (i < crl_size)
+			gnutls_x509_crl_deinit(crl_list[i++]);
+	return ret;
 }
 
 /* Takes a certificate list and shortens it if there are
diff --git a/lib/x509/x509_ext.c b/lib/x509/x509_ext.c
index fda936e8ff..387f5fbea2 100644
--- a/lib/x509/x509_ext.c
+++ b/lib/x509/x509_ext.c
@@ -31,6 +31,7 @@
 #include "x509_ext_int.h"
 #include "virt-san.h"
 #include <gnutls/x509-ext.h>
+#include "intprops.h"
 
 #define MAX_ENTRIES 64
 struct gnutls_subject_alt_names_st {
@@ -137,6 +138,10 @@ int subject_alt_names_set(struct name_st **names,
 	void *tmp;
 	int ret;
 
+	if (unlikely(INT_ADD_OVERFLOW(*size, 1))) {
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+	}
+
 	tmp = _gnutls_reallocarray(*names, *size + 1, sizeof((*names)[0]));
 	if (tmp == NULL) {
 		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
@@ -2316,6 +2321,10 @@ int crl_dist_points_set(gnutls_x509_crl_dist_points_t cdp,
 {
 	void *tmp;
 
+	if (unlikely(INT_ADD_OVERFLOW(cdp->size, 1))) {
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+	}
+
 	/* new dist point */
 	tmp = _gnutls_reallocarray(cdp->points, cdp->size + 1,
 				   sizeof(cdp->points[0]));
@@ -2733,6 +2742,10 @@ int gnutls_x509_aia_set(gnutls_x509_aia_t aia,
 	void *tmp;
 	unsigned indx;
 
+	if (unlikely(INT_ADD_OVERFLOW(aia->size, 1))) {
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+	}
+
 	tmp = _gnutls_reallocarray(aia->aia, aia->size + 1, sizeof(aia->aia[0]));
 	if (tmp == NULL) {
 		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
@@ -2785,6 +2798,9 @@ static int parse_aia(ASN1_TYPE c2, gnutls_x509_aia_t aia)
 		}
 
 		indx = aia->size;
+		if (unlikely(INT_ADD_OVERFLOW(aia->size, 1))) {
+			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+		}
 		tmp = _gnutls_reallocarray(aia->aia, aia->size + 1,
 					   sizeof(aia->aia[0]));
 		if (tmp == NULL) {
-- 
2.30.2

