a7bcdb
From 6b522f8780813726799e6b8cf0f1f8e0ce2c8ebf Mon Sep 17 00:00:00 2001
a7bcdb
From: Mathy Vanhoef <Mathy.Vanhoef@nyu.edu>
a7bcdb
Date: Fri, 4 Oct 2019 17:53:52 +0400
a7bcdb
Subject: [PATCH] EAP-pwd: fix DoS due to multithreaded BN_CTX access
a7bcdb
a7bcdb
The EAP-pwd module created one global OpenSSL BN_CTX instance, and
a7bcdb
used this instance in all incoming requests. This means that different
a7bcdb
threads used the same BN_CTX instance, which can result in a crash.
a7bcdb
An adversary can trigger these crashes by concurrently initiating
a7bcdb
multiple EAP-pwd handshakes from different clients.
a7bcdb
a7bcdb
Fix this bug by creating a separate BN_CTX instance for each request.
a7bcdb
---
a7bcdb
 .../rlm_eap/types/rlm_eap_pwd/eap_pwd.h       |  1 +
a7bcdb
 .../rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c   | 24 +++++++++----------
a7bcdb
 .../rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.h   |  2 --
a7bcdb
 3 files changed, 13 insertions(+), 14 deletions(-)
a7bcdb
a7bcdb
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h b/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h
a7bcdb
index 013a6e7992..ca12778f61 100644
a7bcdb
--- a/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h
a7bcdb
+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/eap_pwd.h
a7bcdb
@@ -90,6 +90,7 @@ typedef struct _pwd_session_t {
a7bcdb
     uint8_t *out;     /* message to fragment */
a7bcdb
     size_t out_pos;
a7bcdb
     size_t out_len;
a7bcdb
+    BN_CTX *bnctx;
a7bcdb
     EC_GROUP *group;
a7bcdb
     EC_POINT *pwe;
a7bcdb
     BIGNUM *order;
a7bcdb
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c b/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c
a7bcdb
index 76cc57023e..eefca985d7 100644
a7bcdb
--- a/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c
a7bcdb
+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.c
a7bcdb
@@ -55,8 +55,6 @@ static int mod_detach (void *arg)
a7bcdb
 
a7bcdb
 	inst = (eap_pwd_t *) arg;
a7bcdb
 
a7bcdb
-	if (inst->bnctx) BN_CTX_free(inst->bnctx);
a7bcdb
-
a7bcdb
 	return 0;
a7bcdb
 }
a7bcdb
 
a7bcdb
@@ -76,11 +74,6 @@ static int mod_instantiate (CONF_SECTION *cs, void **instance)
a7bcdb
 		return -1;
a7bcdb
 	}
a7bcdb
 
a7bcdb
-	if ((inst->bnctx = BN_CTX_new()) == NULL) {
a7bcdb
-		cf_log_err_cs(cs, "Failed to get BN context");
a7bcdb
-		return -1;
a7bcdb
-	}
a7bcdb
-
a7bcdb
 	return 0;
a7bcdb
 }
a7bcdb
 
a7bcdb
@@ -96,6 +89,7 @@ static int _free_pwd_session (pwd_session_t *session)
a7bcdb
 	EC_POINT_clear_free(session->pwe);
a7bcdb
 	BN_clear_free(session->order);
a7bcdb
 	BN_clear_free(session->prime);
a7bcdb
+	BN_CTX_free(session->bnctx);
a7bcdb
 
a7bcdb
 	return 0;
a7bcdb
 }
a7bcdb
@@ -217,6 +211,12 @@ static int mod_session_init (void *instance, eap_handler_t *handler)
a7bcdb
 	session->order = NULL;
a7bcdb
 	session->prime = NULL;
a7bcdb
 
a7bcdb
+	session->bnctx = BN_CTX_new();
a7bcdb
+	if (session->bnctx == NULL) {
a7bcdb
+		ERROR("rlm_eap_pwd: Failed to get BN context");
a7bcdb
+		return 0;
a7bcdb
+	}
a7bcdb
+
a7bcdb
 	/*
a7bcdb
 	 *	The admin can dynamically change the MTU.
a7bcdb
 	 */
a7bcdb
@@ -496,7 +496,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
a7bcdb
 		/*
a7bcdb
 		 * compute our scalar and element
a7bcdb
 		 */
a7bcdb
-		if (compute_scalar_element(session, inst->bnctx)) {
a7bcdb
+		if (compute_scalar_element(session, session->bnctx)) {
a7bcdb
 			DEBUG2("failed to compute server's scalar and element");
a7bcdb
 			return 0;
a7bcdb
 		}
a7bcdb
@@ -508,7 +508,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
a7bcdb
 		 * element is a point, get both coordinates: x and y
a7bcdb
 		 */
a7bcdb
 		if (!EC_POINT_get_affine_coordinates_GFp(session->group, session->my_element, x, y,
a7bcdb
-							 inst->bnctx)) {
a7bcdb
+							 session->bnctx)) {
a7bcdb
 			DEBUG2("server point assignment failed");
a7bcdb
 			BN_clear_free(x);
a7bcdb
 			BN_clear_free(y);
a7bcdb
@@ -552,7 +552,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
a7bcdb
 		/*
a7bcdb
 		 * process the peer's commit and generate the shared key, k
a7bcdb
 		 */
a7bcdb
-		if (process_peer_commit(session, in, in_len, inst->bnctx)) {
a7bcdb
+		if (process_peer_commit(session, in, in_len, session->bnctx)) {
a7bcdb
 			RDEBUG2("failed to process peer's commit");
a7bcdb
 			return 0;
a7bcdb
 		}
a7bcdb
@@ -560,7 +560,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
a7bcdb
 		/*
a7bcdb
 		 * compute our confirm blob
a7bcdb
 		 */
a7bcdb
-		if (compute_server_confirm(session, session->my_confirm, inst->bnctx)) {
a7bcdb
+		if (compute_server_confirm(session, session->my_confirm, session->bnctx)) {
a7bcdb
 			ERROR("rlm_eap_pwd: failed to compute confirm!");
a7bcdb
 			return 0;
a7bcdb
 		}
a7bcdb
@@ -591,7 +591,7 @@ static int mod_process(void *arg, eap_handler_t *handler)
a7bcdb
 			RDEBUG2("pwd exchange is incorrect: not commit!");
a7bcdb
 			return 0;
a7bcdb
 		}
a7bcdb
-		if (compute_peer_confirm(session, peer_confirm, inst->bnctx)) {
a7bcdb
+		if (compute_peer_confirm(session, peer_confirm, session->bnctx)) {
a7bcdb
 			RDEBUG2("pwd exchange cannot compute peer's confirm");
a7bcdb
 			return 0;
a7bcdb
 		}
a7bcdb
diff --git a/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.h b/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.h
a7bcdb
index 189530d066..2264566bb6 100644
a7bcdb
--- a/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.h
a7bcdb
+++ b/src/modules/rlm_eap/types/rlm_eap_pwd/rlm_eap_pwd.h
a7bcdb
@@ -40,8 +40,6 @@
a7bcdb
 #include <freeradius-devel/modules.h>
a7bcdb
 
a7bcdb
 typedef struct _eap_pwd_t {
a7bcdb
-    BN_CTX *bnctx;
a7bcdb
-
a7bcdb
     uint32_t	group;
a7bcdb
     uint32_t	fragment_size;
a7bcdb
     char const	*server_id;