changeset 1409:c721e8c42d2a

add m_mp_free_multi, be more careful freeing when failing to load keys
author Matt Johnston <matt@ucc.asn.au>
date Fri, 26 May 2017 21:08:43 +0800
parents 8d9bad0a1c86
children 771e4a7051e0
files bignum.c bignum.h dss.c rsa.c signkey.c
diffstat 5 files changed, 41 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/bignum.c	Sat Jun 03 09:45:55 2017 +0800
+++ b/bignum.c	Fri May 26 21:08:43 2017 +0800
@@ -68,6 +68,22 @@
 	va_end(args);
 }
 
+void m_mp_free_multi(mp_int **mp, ...) 
+{
+	mp_int** cur_arg = mp;
+	va_list args;
+
+	va_start(args, mp);        /* init args to next argument from caller */
+	while (cur_arg != NULL) {
+		if (*cur_arg) {
+			mp_clear(*cur_arg);
+		}
+		m_free(*cur_arg);
+		cur_arg = va_arg(args, mp_int**);
+	}
+	va_end(args);
+}
+
 void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len) {
 
 	if (mp_read_unsigned_bin(mp, (unsigned char*)bytes, len) != MP_OKAY) {
--- a/bignum.h	Sat Jun 03 09:45:55 2017 +0800
+++ b/bignum.h	Fri May 26 21:08:43 2017 +0800
@@ -30,6 +30,7 @@
 void m_mp_init(mp_int *mp);
 void m_mp_init_multi(mp_int *mp, ...) ATTRIB_SENTINEL;
 void m_mp_alloc_init_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
+void m_mp_free_multi(mp_int **mp, ...)  ATTRIB_SENTINEL;
 void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
 void hash_process_mp(const struct ltc_hash_descriptor *hash_desc, 
 				hash_state *hs, mp_int *mp);
--- a/dss.c	Sat Jun 03 09:45:55 2017 +0800
+++ b/dss.c	Fri May 26 21:08:43 2017 +0800
@@ -44,6 +44,7 @@
  * These should be freed with dss_key_free.
  * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
 int buf_get_dss_pub_key(buffer* buf, dropbear_dss_key *key) {
+	int ret = DROPBEAR_FAILURE;
 
 	TRACE(("enter buf_get_dss_pub_key"))
 	dropbear_assert(key != NULL);
@@ -56,17 +57,24 @@
 	 || buf_getmpint(buf, key->g) == DROPBEAR_FAILURE
 	 || buf_getmpint(buf, key->y) == DROPBEAR_FAILURE) {
 		TRACE(("leave buf_get_dss_pub_key: failed reading mpints"))
-		return DROPBEAR_FAILURE;
+		ret = DROPBEAR_FAILURE;
+		goto out;
 	}
 
 	if (mp_count_bits(key->p) < MIN_DSS_KEYLEN) {
 		dropbear_log(LOG_WARNING, "DSS key too short");
 		TRACE(("leave buf_get_dss_pub_key: short key"))
-		return DROPBEAR_FAILURE;
+		ret = DROPBEAR_FAILURE;
+		goto out;
 	}
 
+	ret = DROPBEAR_SUCCESS;
 	TRACE(("leave buf_get_dss_pub_key: success"))
-	return DROPBEAR_SUCCESS;
+out:
+	if (ret == DROPBEAR_FAILURE) {
+		m_mp_free_multi(&key->p, &key->q, &key->g, &key->y, NULL);
+	}
+	return ret;
 }
 
 /* Same as buf_get_dss_pub_key, but reads a private "x" key at the end.
@@ -86,7 +94,7 @@
 	m_mp_alloc_init_multi(&key->x, NULL);
 	ret = buf_getmpint(buf, key->x);
 	if (ret == DROPBEAR_FAILURE) {
-		m_free(key->x);
+		m_mp_free_multi(&key->x);
 	}
 
 	return ret;
@@ -101,26 +109,7 @@
 		TRACE2(("enter dsa_key_free: key == NULL"))
 		return;
 	}
-	if (key->p) {
-		mp_clear(key->p);
-		m_free(key->p);
-	}
-	if (key->q) {
-		mp_clear(key->q);
-		m_free(key->q);
-	}
-	if (key->g) {
-		mp_clear(key->g);
-		m_free(key->g);
-	}
-	if (key->y) {
-		mp_clear(key->y);
-		m_free(key->y);
-	}
-	if (key->x) {
-		mp_clear(key->x);
-		m_free(key->x);
-	}
+	m_mp_free_multi(&key->p, &key->q, &key->g, &key->y, &key->x, NULL);
 	m_free(key);
 	TRACE2(("leave dsa_key_free"))
 }
--- a/rsa.c	Sat Jun 03 09:45:55 2017 +0800
+++ b/rsa.c	Fri May 26 21:08:43 2017 +0800
@@ -72,8 +72,7 @@
 	ret = DROPBEAR_SUCCESS;
 out:
 	if (ret == DROPBEAR_FAILURE) {
-		m_free(key->e);
-		m_free(key->n);
+		m_mp_free_multi(&key->e, &key->n, NULL);
 	}
 	return ret;
 }
@@ -121,9 +120,7 @@
 	ret = DROPBEAR_SUCCESS;
 out:
 	if (ret == DROPBEAR_FAILURE) {
-		m_free(key->d);
-		m_free(key->p);
-		m_free(key->q);
+		m_mp_free_multi(&key->d, &key->p, &key->q, NULL);
 	}
 	TRACE(("leave buf_get_rsa_priv_key"))
 	return ret;
@@ -139,26 +136,7 @@
 		TRACE2(("leave rsa_key_free: key == NULL"))
 		return;
 	}
-	if (key->d) {
-		mp_clear(key->d);
-		m_free(key->d);
-	}
-	if (key->e) {
-		mp_clear(key->e);
-		m_free(key->e);
-	}
-	if (key->n) {
-		 mp_clear(key->n);
-		 m_free(key->n);
-	}
-	if (key->p) {
-		mp_clear(key->p);
-		m_free(key->p);
-	}
-	if (key->q) {
-		mp_clear(key->q);
-		m_free(key->q);
-	}
+	m_mp_free_multi(&key->d, &key->e, &key->p, &key->q, &key->n, NULL);
 	m_free(key);
 	TRACE2(("leave rsa_key_free"))
 }
--- a/signkey.c	Sat Jun 03 09:45:55 2017 +0800
+++ b/signkey.c	Fri May 26 21:08:43 2017 +0800
@@ -167,7 +167,8 @@
 		key->dsskey = m_malloc(sizeof(*key->dsskey));
 		ret = buf_get_dss_pub_key(buf, key->dsskey);
 		if (ret == DROPBEAR_FAILURE) {
-			m_free(key->dsskey);
+			dss_key_free(key->dsskey);
+			key->dsskey = NULL;
 		}
 	}
 #endif
@@ -177,7 +178,8 @@
 		key->rsakey = m_malloc(sizeof(*key->rsakey));
 		ret = buf_get_rsa_pub_key(buf, key->rsakey);
 		if (ret == DROPBEAR_FAILURE) {
-			m_free(key->rsakey);
+			rsa_key_free(key->rsakey);
+			key->rsakey = NULL;
 		}
 	}
 #endif
@@ -201,7 +203,6 @@
 	TRACE2(("leave buf_get_pub_key"))
 
 	return ret;
-	
 }
 
 /* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
@@ -236,7 +237,8 @@
 		key->dsskey = m_malloc(sizeof(*key->dsskey));
 		ret = buf_get_dss_priv_key(buf, key->dsskey);
 		if (ret == DROPBEAR_FAILURE) {
-			m_free(key->dsskey);
+			dss_key_free(key->dsskey);
+			key->dsskey = NULL;
 		}
 	}
 #endif
@@ -246,7 +248,8 @@
 		key->rsakey = m_malloc(sizeof(*key->rsakey));
 		ret = buf_get_rsa_priv_key(buf, key->rsakey);
 		if (ret == DROPBEAR_FAILURE) {
-			m_free(key->rsakey);
+			rsa_key_free(key->rsakey);
+			key->rsakey = NULL;
 		}
 	}
 #endif