Cumulative patch from commit e8c08c9a363340c45baf8e13c758c99078bc0d8b

e8c08c9 EAP-FAST server: Fix potential read-after-buffer (by one byte)
8b65fef Interworking: Remove unnecessary placeholder for PAME-BI
27a725c EAP: Do not allow fast session resumption with different network block
52f4abf P2P: Remove PSK/passphrase from P2P-GROUP-STARTED debug log entry
f8723e1 P2P: Use a helper function for P2P_EVENT_GROUP_STARTED events
905c722 Add wpa_msg_global_ctrl()
1f1fe19 EAP-pwd: Clear identity string and temporary buffer explicitly
f119d66 EAP-pwd: Verify BN_rand_range return code
5197f03 EAP-pwd: Use os_memcmp_const() for hash comparisons
26c10f7 OpenSSL: Use EC_POINT_clear_free instead of EC_POINT_free
3248071 OpenSSL: Use BN_clear_free instead of BN_free
870dfe9 EAP-TTLS: Remove FreeRADIUS workaround for EAP-TTLS/MSCHAPv2

Bug: 15615050, 16493485

Change-Id: I7028a61ad6dbda1f336376cc0568b81046045725
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 817ee2d..f02aaac 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -340,10 +340,10 @@
 	ret = 0;
 
 error:
-	BN_free(bn_base);
-	BN_free(bn_exp);
-	BN_free(bn_modulus);
-	BN_free(bn_result);
+	BN_clear_free(bn_base);
+	BN_clear_free(bn_exp);
+	BN_clear_free(bn_modulus);
+	BN_clear_free(bn_result);
 	BN_CTX_free(ctx);
 	return ret;
 }
@@ -571,12 +571,12 @@
 	if (keylen < 0)
 		goto err;
 	wpabuf_put(res, keylen);
-	BN_free(pub_key);
+	BN_clear_free(pub_key);
 
 	return res;
 
 err:
-	BN_free(pub_key);
+	BN_clear_free(pub_key);
 	wpabuf_free(res);
 	return NULL;
 }
@@ -1066,7 +1066,7 @@
 {
 	if (e == NULL)
 		return;
-	BN_free(e->order);
+	BN_clear_free(e->order);
 	EC_GROUP_free(e->group);
 	BN_CTX_free(e->bnctx);
 	os_free(e);
@@ -1138,8 +1138,8 @@
 		ret = 0;
 	}
 
-	BN_free(x_bn);
-	BN_free(y_bn);
+	BN_clear_free(x_bn);
+	BN_clear_free(y_bn);
 	return ret;
 }
 
@@ -1155,20 +1155,20 @@
 	y = BN_bin2bn(val + len, len, NULL);
 	elem = EC_POINT_new(e->group);
 	if (x == NULL || y == NULL || elem == NULL) {
-		BN_free(x);
-		BN_free(y);
-		EC_POINT_free(elem);
+		BN_clear_free(x);
+		BN_clear_free(y);
+		EC_POINT_clear_free(elem);
 		return NULL;
 	}
 
 	if (!EC_POINT_set_affine_coordinates_GFp(e->group, elem, x, y,
 						 e->bnctx)) {
-		EC_POINT_free(elem);
+		EC_POINT_clear_free(elem);
 		elem = NULL;
 	}
 
-	BN_free(x);
-	BN_free(y);
+	BN_clear_free(x);
+	BN_clear_free(y);
 
 	return (struct crypto_ec_point *) elem;
 }
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index 96c9efd..fdcff7f 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -263,18 +263,18 @@
  fail:
 		EC_GROUP_free(grp->group);
 		grp->group = NULL;
-		EC_POINT_free(grp->pwe);
+		EC_POINT_clear_free(grp->pwe);
 		grp->pwe = NULL;
-		BN_free(grp->order);
+		BN_clear_free(grp->order);
 		grp->order = NULL;
-		BN_free(grp->prime);
+		BN_clear_free(grp->prime);
 		grp->prime = NULL;
 		ret = 1;
 	}
 	/* cleanliness and order.... */
-	BN_free(cofactor);
-	BN_free(x_candidate);
-	BN_free(rnd);
+	BN_clear_free(cofactor);
+	BN_clear_free(x_candidate);
+	BN_clear_free(rnd);
 	os_free(prfbuf);
 
 	return ret;
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index a2faeb2..9880d3b 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -153,11 +153,13 @@
 	SM_ENTRY(EAP, INITIALIZE);
 	if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
 	    sm->m->has_reauth_data(sm, sm->eap_method_priv) &&
-	    !sm->prev_failure) {
+	    !sm->prev_failure &&
+	    sm->last_config == eap_get_config(sm)) {
 		wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
 			   "fast reauthentication");
 		sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
 	} else {
+		sm->last_config = eap_get_config(sm);
 		eap_deinit_prev_method(sm, "INITIALIZE");
 	}
 	sm->selectedMethod = EAP_TYPE_NONE;
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 8288ba5..fde809c 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -345,6 +345,7 @@
 	struct wps_context *wps;
 
 	int prev_failure;
+	struct eap_peer_config *last_config;
 
 	struct ext_password_data *ext_pw;
 	struct wpabuf *ext_pw_buf;
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index bdcca0b..1c915ed 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -123,7 +123,7 @@
 	if ((data->password = os_malloc(password_len)) == NULL) {
 		wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail");
 		BN_CTX_free(data->bnctx);
-		os_free(data->id_peer);
+		bin_clear_free(data->id_peer, data->id_peer_len);
 		os_free(data);
 		return NULL;
 	}
@@ -148,21 +148,21 @@
 {
 	struct eap_pwd_data *data = priv;
 
-	BN_free(data->private_value);
-	BN_free(data->server_scalar);
-	BN_free(data->my_scalar);
-	BN_free(data->k);
+	BN_clear_free(data->private_value);
+	BN_clear_free(data->server_scalar);
+	BN_clear_free(data->my_scalar);
+	BN_clear_free(data->k);
 	BN_CTX_free(data->bnctx);
-	EC_POINT_free(data->my_element);
-	EC_POINT_free(data->server_element);
-	os_free(data->id_peer);
-	os_free(data->id_server);
+	EC_POINT_clear_free(data->my_element);
+	EC_POINT_clear_free(data->server_element);
+	bin_clear_free(data->id_peer, data->id_peer_len);
+	bin_clear_free(data->id_server, data->id_server_len);
 	bin_clear_free(data->password, data->password_len);
 	if (data->grp) {
 		EC_GROUP_free(data->grp->group);
-		EC_POINT_free(data->grp->pwe);
-		BN_free(data->grp->order);
-		BN_free(data->grp->prime);
+		EC_POINT_clear_free(data->grp->pwe);
+		BN_clear_free(data->grp->order);
+		BN_clear_free(data->grp->prime);
 		os_free(data->grp);
 	}
 	wpabuf_free(data->inbuf);
@@ -317,11 +317,15 @@
 		goto fin;
 	}
 
-	BN_rand_range(data->private_value, data->grp->order);
-	BN_rand_range(mask, data->grp->order);
-	BN_add(data->my_scalar, data->private_value, mask);
-	BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
-	       data->bnctx);
+	if (BN_rand_range(data->private_value, data->grp->order) != 1 ||
+	    BN_rand_range(mask, data->grp->order) != 1 ||
+	    BN_add(data->my_scalar, data->private_value, mask) != 1 ||
+	    BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
+		   data->bnctx) != 1) {
+		wpa_printf(MSG_INFO,
+			   "EAP-pwd (peer): unable to get randomness");
+		goto fin;
+	}
 
 	if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
 			  data->grp->pwe, mask, data->bnctx)) {
@@ -336,7 +340,7 @@
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail");
 		goto fin;
 	}
-	BN_free(mask);
+	BN_clear_free(mask);
 
 	if (((x = BN_new()) == NULL) ||
 	    ((y = BN_new()) == NULL)) {
@@ -471,11 +475,11 @@
 fin:
 	os_free(scalar);
 	os_free(element);
-	BN_free(x);
-	BN_free(y);
-	BN_free(cofactor);
-	EC_POINT_free(K);
-	EC_POINT_free(point);
+	BN_clear_free(x);
+	BN_clear_free(y);
+	BN_clear_free(cofactor);
+	EC_POINT_clear_free(K);
+	EC_POINT_clear_free(point);
 	if (data->outbuf == NULL)
 		eap_pwd_state(data, FAILURE);
 	else
@@ -589,7 +593,7 @@
 	eap_pwd_h_final(hash, conf);
 
 	ptr = (u8 *) payload;
-	if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
+	if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
 		goto fin;
 	}
@@ -680,9 +684,9 @@
 	wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
 
 fin:
-	os_free(cruft);
-	BN_free(x);
-	BN_free(y);
+	bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
+	BN_clear_free(x);
+	BN_clear_free(y);
 	if (data->outbuf == NULL) {
 		ret->methodState = METHOD_DONE;
 		ret->decision = DECISION_FAIL;
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index e110236..771da58 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -501,16 +501,6 @@
 	wpabuf_put(msg, pos - buf);
 	*resp = msg;
 
-	if (sm->workaround) {
-		/* At least FreeRADIUS seems to be terminating
-		 * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success
-		 * packet. */
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - "
-			   "allow success without tunneled response");
-		ret->methodState = METHOD_MAY_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	}
-
 	return 0;
 #else /* EAP_MSCHAPv2 */
 	wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index 1024510..4691e72 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -187,7 +187,7 @@
 		switch (*pos) {
 		case PAC_OPAQUE_TYPE_PAD:
 			pos = end;
-			break;
+			goto done;
 		case PAC_OPAQUE_TYPE_KEY:
 			if (pos[1] != EAP_FAST_PAC_KEY_LEN) {
 				wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
@@ -218,6 +218,7 @@
 
 		pos += 2 + pos[1];
 	}
+done:
 
 	if (pac_key == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key included in "
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index 9154ab1..7e1278d 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -106,7 +106,7 @@
 	if (data->password == NULL) {
 		wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password "
 			   "fail");
-		os_free(data->id_server);
+		bin_clear_free(data->id_server, data->id_server_len);
 		os_free(data);
 		return NULL;
 	}
@@ -117,7 +117,7 @@
 	if (data->bnctx == NULL) {
 		wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail");
 		bin_clear_free(data->password, data->password_len);
-		os_free(data->id_server);
+		bin_clear_free(data->id_server, data->id_server_len);
 		os_free(data);
 		return NULL;
 	}
@@ -135,21 +135,21 @@
 {
 	struct eap_pwd_data *data = priv;
 
-	BN_free(data->private_value);
-	BN_free(data->peer_scalar);
-	BN_free(data->my_scalar);
-	BN_free(data->k);
+	BN_clear_free(data->private_value);
+	BN_clear_free(data->peer_scalar);
+	BN_clear_free(data->my_scalar);
+	BN_clear_free(data->k);
 	BN_CTX_free(data->bnctx);
-	EC_POINT_free(data->my_element);
-	EC_POINT_free(data->peer_element);
-	os_free(data->id_peer);
-	os_free(data->id_server);
+	EC_POINT_clear_free(data->my_element);
+	EC_POINT_clear_free(data->peer_element);
+	bin_clear_free(data->id_peer, data->id_peer_len);
+	bin_clear_free(data->id_server, data->id_server_len);
 	bin_clear_free(data->password, data->password_len);
 	if (data->grp) {
 		EC_GROUP_free(data->grp->group);
-		EC_POINT_free(data->grp->pwe);
-		BN_free(data->grp->order);
-		BN_free(data->grp->prime);
+		EC_POINT_clear_free(data->grp->pwe);
+		BN_clear_free(data->grp->order);
+		BN_clear_free(data->grp->prime);
 		os_free(data->grp);
 	}
 	wpabuf_free(data->inbuf);
@@ -210,11 +210,15 @@
 		goto fin;
 	}
 
-	BN_rand_range(data->private_value, data->grp->order);
-	BN_rand_range(mask, data->grp->order);
-	BN_add(data->my_scalar, data->private_value, mask);
-	BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
-	       data->bnctx);
+	if (BN_rand_range(data->private_value, data->grp->order) != 1 ||
+	    BN_rand_range(mask, data->grp->order) != 1 ||
+	    BN_add(data->my_scalar, data->private_value, mask) != 1 ||
+	    BN_mod(data->my_scalar, data->my_scalar, data->grp->order,
+		   data->bnctx) != 1) {
+		wpa_printf(MSG_INFO,
+			   "EAP-pwd (server): unable to get randomness");
+		goto fin;
+	}
 
 	if (!EC_POINT_mul(data->grp->group, data->my_element, NULL,
 			  data->grp->pwe, mask, data->bnctx)) {
@@ -230,7 +234,7 @@
 			   "fail");
 		goto fin;
 	}
-	BN_free(mask);
+	BN_clear_free(mask);
 
 	if (((x = BN_new()) == NULL) ||
 	    ((y = BN_new()) == NULL)) {
@@ -282,8 +286,8 @@
 fin:
 	os_free(scalar);
 	os_free(element);
-	BN_free(x);
-	BN_free(y);
+	BN_clear_free(x);
+	BN_clear_free(y);
 	if (data->outbuf == NULL)
 		eap_pwd_state(data, FAILURE);
 }
@@ -406,9 +410,9 @@
 	wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
 
 fin:
-	os_free(cruft);
-	BN_free(x);
-	BN_free(y);
+	bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
+	BN_clear_free(x);
+	BN_clear_free(y);
 	if (data->outbuf == NULL)
 		eap_pwd_state(data, FAILURE);
 }
@@ -724,11 +728,11 @@
 	res = 1;
 
 fin:
-	EC_POINT_free(K);
-	EC_POINT_free(point);
-	BN_free(cofactor);
-	BN_free(x);
-	BN_free(y);
+	EC_POINT_clear_free(K);
+	EC_POINT_clear_free(point);
+	BN_clear_free(cofactor);
+	BN_clear_free(x);
+	BN_clear_free(y);
 
 	if (res)
 		eap_pwd_state(data, PWD_Confirm_Req);
@@ -835,7 +839,7 @@
 	eap_pwd_h_final(hash, conf);
 
 	ptr = (u8 *) payload;
-	if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
+	if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) {
 		wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not "
 			   "verify");
 		goto fin;
@@ -851,9 +855,9 @@
 		eap_pwd_state(data, SUCCESS);
 
 fin:
-	os_free(cruft);
-	BN_free(x);
-	BN_free(y);
+	bin_clear_free(cruft, BN_num_bytes(data->grp->prime));
+	BN_clear_free(x);
+	BN_clear_free(y);
 }
 
 
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index 647f6b4..68cbace 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -685,6 +685,34 @@
 }
 
 
+void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...)
+{
+	va_list ap;
+	char *buf;
+	int buflen;
+	int len;
+
+	if (!wpa_msg_cb)
+		return;
+
+	va_start(ap, fmt);
+	buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
+	va_end(ap);
+
+	buf = os_malloc(buflen);
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR,
+			   "wpa_msg_global_ctrl: Failed to allocate message buffer");
+		return;
+	}
+	va_start(ap, fmt);
+	len = vsnprintf(buf, buflen, fmt, ap);
+	va_end(ap);
+	wpa_msg_cb(ctx, level, 1, buf, len);
+	os_free(buf);
+}
+
+
 void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
 {
 	va_list ap;
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index 50e8ae9..391f197 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -160,6 +160,7 @@
 #define wpa_msg(args...) do { } while (0)
 #define wpa_msg_ctrl(args...) do { } while (0)
 #define wpa_msg_global(args...) do { } while (0)
+#define wpa_msg_global_ctrl(args...) do { } while (0)
 #define wpa_msg_no_global(args...) do { } while (0)
 #define wpa_msg_register_cb(f) do { } while (0)
 #define wpa_msg_register_ifname_cb(f) do { } while (0)
@@ -212,6 +213,21 @@
 PRINTF_FORMAT(3, 4);
 
 /**
+ * wpa_msg_global_ctrl - Conditional global printf for ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ *	with struct wpa_driver_ops::init()
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages.
+ * This function is like wpa_msg_global(), but it sends the output only to the
+ * attached global ctrl_iface monitors. In other words, it can be used for
+ * frequent events that do not need to be sent to syslog.
+ */
+void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+
+/**
  * wpa_msg_no_global - Conditional printf for ctrl_iface monitors
  * @ctx: Pointer to context data; this is the ctx variable registered
  *	with struct wpa_driver_ops::init()