Cumulative patch from commit 06f14421ea8644d12a7b0be6b583114869f9c451 (DO NOT MERGE)

06f1442 TLS: Parse OCSPResponse to extract BasicOCSPResponse
d560288 TLS: Parse CertificateStatus message
eeba168 TLS: Add status_request ClientHello extension if OCSP is requested
4303d53 TLS: Parse ServerHello extensions
6b7bb42 TLS: Add minimal support for PKCS #12
5ce2941 TLS: Extend PKCS #5 to support PKCS #12 style key decryption
f6a62df TLS: Fix and complete ASN.1 tag list
3c108b7 EAP peer: External server certificate chain validation
b6e5e14 EAP-FAST peer: Fix PAC parser error messages
5b904b3 EAP-FAST: Check T-PRF result in MSK/EMSK derivation
b1d8c5c EAP-FAST peer: Fix error path handling for Session-Id
36478a1 OpenSSL: Support new API for HMAC/EVP_MD_CTX in OpenSSL 1.1.x-pre1
9257610 FT: Fix FTIE generation for EAPOL-Key msg 3/4
e44bd28 FT: Fix sm->assoc_resp_ftie storing on the AP side
59e78c2 FT: Fix FTIE generation for 4-way handshake after FT protocol run
b0ecbd3 AP: Use more readable version of management group cipher in error cases
651c6a8 Add TEST_ASSOC_IE for WPA/RSN IE testing on AP side
58059e6 FST: Print debug entry on MB IE update based on EVENT_AUTH
af041f9 dbus: Add support for vendor specific elements
5c8acf7 EAP-IKEv2: Check HMAC SHA1/MD5 result
7b991b4 Use proper build config for parsing proxy_arp
4db29e6 TLS: Add support for PKCS #5 v2.0 PBES2

Change-Id: I10b71e4d3573ef60a52ea6ff56afcd3a06a0b7b0
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 28d5116..5c18978 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -48,6 +48,8 @@
 static const char * eap_sm_method_state_txt(EapMethodState state);
 static const char * eap_sm_decision_txt(EapDecision decision);
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
+			   const char *msg, size_t msglen);
 
 
 
@@ -320,11 +322,14 @@
 	wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
 		   "vendor %u method %u (%s)",
 		   sm->reqVendor, method, sm->m->name);
-	if (reinit)
+	if (reinit) {
 		sm->eap_method_priv = sm->m->init_for_reauth(
 			sm, sm->eap_method_priv);
-	else
+	} else {
+		sm->waiting_ext_cert_check = 0;
+		sm->ext_cert_check = 0;
 		sm->eap_method_priv = sm->m->init(sm);
+	}
 
 	if (sm->eap_method_priv == NULL) {
 		struct eap_peer_config *config = eap_get_config(sm);
@@ -1858,6 +1863,11 @@
 	case TLS_CERT_CHAIN_SUCCESS:
 		eap_notify_status(sm, "remote certificate verification",
 				  "success");
+		if (sm->ext_cert_check) {
+			sm->waiting_ext_cert_check = 1;
+			eap_sm_request(sm, WPA_CTRL_REQ_EXT_CERT_CHECK,
+				       NULL, 0);
+		}
 		break;
 	case TLS_CERT_CHAIN_FAILURE:
 		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
@@ -2180,10 +2190,10 @@
 #endif /* CONFIG_CTRL_IFACE */
 
 
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
 static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
 			   const char *msg, size_t msglen)
 {
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
 	struct eap_peer_config *config;
 	const char *txt = NULL;
 	char *tmp;
@@ -2232,16 +2242,17 @@
 	case WPA_CTRL_REQ_SIM:
 		txt = msg;
 		break;
+	case WPA_CTRL_REQ_EXT_CERT_CHECK:
+		break;
 	default:
 		return;
 	}
 
 	if (sm->eapol_cb->eap_param_needed)
 		sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt);
-}
-#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-#define eap_sm_request(sm, type, msg, msglen) do { } while (0)
 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+}
+
 
 const char * eap_sm_get_method_name(struct eap_sm *sm)
 {
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 2b1a1d5..39ddcff 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -739,6 +739,20 @@
 	 * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
 	 */
 	int erp;
+
+	/**
+	 * pending_ext_cert_check - External server certificate check status
+	 *
+	 * This field should not be set in configuration step. It is only used
+	 * internally when control interface is used to request external
+	 * validation of server certificate chain.
+	 */
+	enum {
+		NO_CHECK = 0,
+		PENDING_CHECK,
+		EXT_CERT_CHECK_GOOD,
+		EXT_CERT_CHECK_BAD,
+	} pending_ext_cert_check;
 };
 
 
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 833dcb6..a7f6bef 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-FAST (RFC 4851)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -67,6 +67,7 @@
 	int simck_idx;
 
 	struct wpabuf *pending_phase2_req;
+	struct wpabuf *pending_resp;
 };
 
 
@@ -254,14 +255,16 @@
 	os_memset(data->emsk, 0, EAP_EMSK_LEN);
 	os_free(data->session_id);
 	wpabuf_free(data->pending_phase2_req);
+	wpabuf_free(data->pending_resp);
 	os_free(data);
 }
 
 
 static int eap_fast_derive_msk(struct eap_fast_data *data)
 {
-	eap_fast_derive_eap_msk(data->simck, data->key_data);
-	eap_fast_derive_eap_emsk(data->simck, data->emsk);
+	if (eap_fast_derive_eap_msk(data->simck, data->key_data) < 0 ||
+	    eap_fast_derive_eap_emsk(data->simck, data->emsk) < 0)
+		return -1;
 	data->success = 1;
 	return 0;
 }
@@ -1567,6 +1570,34 @@
 			res = 1;
 		}
 	} else {
+		if (sm->waiting_ext_cert_check && data->pending_resp) {
+			struct eap_peer_config *config = eap_get_config(sm);
+
+			if (config->pending_ext_cert_check ==
+			    EXT_CERT_CHECK_GOOD) {
+				wpa_printf(MSG_DEBUG,
+					   "EAP-FAST: External certificate check succeeded - continue handshake");
+				resp = data->pending_resp;
+				data->pending_resp = NULL;
+				sm->waiting_ext_cert_check = 0;
+				return resp;
+			}
+
+			if (config->pending_ext_cert_check ==
+			    EXT_CERT_CHECK_BAD) {
+				wpa_printf(MSG_DEBUG,
+					   "EAP-FAST: External certificate check failed - force authentication failure");
+				ret->methodState = METHOD_DONE;
+				ret->decision = DECISION_FAIL;
+				sm->waiting_ext_cert_check = 0;
+				return NULL;
+			}
+
+			wpa_printf(MSG_DEBUG,
+				   "EAP-FAST: Continuing to wait external server certificate validation");
+			return NULL;
+		}
+
 		/* Continue processing TLS handshake (phase 1). */
 		res = eap_peer_tls_process_helper(sm, &data->ssl,
 						  EAP_TYPE_FAST,
@@ -1580,6 +1611,14 @@
 			return resp;
 		}
 
+		if (sm->waiting_ext_cert_check) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP-FAST: Waiting external server certificate validation");
+			wpabuf_free(data->pending_resp);
+			data->pending_resp = resp;
+			return NULL;
+		}
+
 		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
 			char cipher[80];
 			wpa_printf(MSG_DEBUG,
@@ -1644,6 +1683,8 @@
 	data->key_block_p = NULL;
 	wpabuf_free(data->pending_phase2_req);
 	data->pending_phase2_req = NULL;
+	wpabuf_free(data->pending_resp);
+	data->pending_resp = NULL;
 }
 
 
@@ -1721,7 +1762,7 @@
 	struct eap_fast_data *data = priv;
 	u8 *id;
 
-	if (!data->success)
+	if (!data->success || !data->session_id)
 		return NULL;
 
 	id = os_malloc(data->id_len);
diff --git a/src/eap_peer/eap_fast_pac.c b/src/eap_peer/eap_fast_pac.c
index c0986b3..0220cae 100644
--- a/src/eap_peer/eap_fast_pac.c
+++ b/src/eap_peer/eap_fast_pac.c
@@ -455,7 +455,8 @@
 	}
 
 	if (pac) {
-		err = "PAC block not terminated with END";
+		if (!err)
+			err = "PAC block not terminated with END";
 		eap_fast_free_pac(pac);
 	}
 
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 99b44da..6ab2483 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -366,6 +366,8 @@
 	int external_sim;
 
 	unsigned int expected_failure:1;
+	unsigned int ext_cert_check:1;
+	unsigned int waiting_ext_cert_check:1;
 
 	struct dl_list erp_keys; /* struct eap_erp_key */
 };
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 98a48a6..0596098 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -59,6 +59,7 @@
 	size_t id_len;
 
 	struct wpabuf *pending_phase2_req;
+	struct wpabuf *pending_resp;
 	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
 	int crypto_binding_used;
 	u8 binding_nonce[32];
@@ -191,6 +192,7 @@
 	eap_peap_free_key(data);
 	os_free(data->session_id);
 	wpabuf_free(data->pending_phase2_req);
+	wpabuf_free(data->pending_resp);
 	os_free(data);
 }
 
@@ -1006,6 +1008,34 @@
 	    !data->resuming) {
 		res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
 	} else {
+		if (sm->waiting_ext_cert_check && data->pending_resp) {
+			struct eap_peer_config *config = eap_get_config(sm);
+
+			if (config->pending_ext_cert_check ==
+			    EXT_CERT_CHECK_GOOD) {
+				wpa_printf(MSG_DEBUG,
+					   "EAP-PEAP: External certificate check succeeded - continue handshake");
+				resp = data->pending_resp;
+				data->pending_resp = NULL;
+				sm->waiting_ext_cert_check = 0;
+				return resp;
+			}
+
+			if (config->pending_ext_cert_check ==
+			    EXT_CERT_CHECK_BAD) {
+				wpa_printf(MSG_DEBUG,
+					   "EAP-PEAP: External certificate check failed - force authentication failure");
+				ret->methodState = METHOD_DONE;
+				ret->decision = DECISION_FAIL;
+				sm->waiting_ext_cert_check = 0;
+				return NULL;
+			}
+
+			wpa_printf(MSG_DEBUG,
+				   "EAP-PEAP: Continuing to wait external server certificate validation");
+			return NULL;
+		}
+
 		res = eap_peer_tls_process_helper(sm, &data->ssl,
 						  EAP_TYPE_PEAP,
 						  data->peap_version, id, &msg,
@@ -1018,6 +1048,16 @@
 			ret->decision = DECISION_FAIL;
 			return resp;
 		}
+
+
+		if (sm->waiting_ext_cert_check) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP-PEAP: Waiting external server certificate validation");
+			wpabuf_free(data->pending_resp);
+			data->pending_resp = resp;
+			return NULL;
+		}
+
 		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
 			char *label;
 			wpa_printf(MSG_DEBUG,
@@ -1123,6 +1163,8 @@
 	struct eap_peap_data *data = priv;
 	wpabuf_free(data->pending_phase2_req);
 	data->pending_phase2_req = NULL;
+	wpabuf_free(data->pending_resp);
+	data->pending_resp = NULL;
 	data->crypto_binding_used = 0;
 }
 
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index 66a027a..ba8e74b 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -25,6 +25,7 @@
 	size_t id_len;
 	void *ssl_ctx;
 	u8 eap_type;
+	struct wpabuf *pending_resp;
 };
 
 
@@ -142,6 +143,7 @@
 	eap_peer_tls_ssl_deinit(sm, &data->ssl);
 	eap_tls_free_key(data);
 	os_free(data->session_id);
+	wpabuf_free(data->pending_resp);
 	os_free(data);
 }
 
@@ -216,6 +218,32 @@
 	struct eap_tls_data *data = priv;
 	struct wpabuf msg;
 
+	if (sm->waiting_ext_cert_check && data->pending_resp) {
+		struct eap_peer_config *config = eap_get_config(sm);
+
+		if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP-TLS: External certificate check succeeded - continue handshake");
+			resp = data->pending_resp;
+			data->pending_resp = NULL;
+			sm->waiting_ext_cert_check = 0;
+			return resp;
+		}
+
+		if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP-TLS: External certificate check failed - force authentication failure");
+			ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_FAIL;
+			sm->waiting_ext_cert_check = 0;
+			return NULL;
+		}
+
+		wpa_printf(MSG_DEBUG,
+			   "EAP-TLS: Continuing to wait external server certificate validation");
+		return NULL;
+	}
+
 	pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret,
 					reqData, &left, &flags);
 	if (pos == NULL)
@@ -237,6 +265,14 @@
 		return eap_tls_failure(sm, data, ret, res, resp, id);
 	}
 
+	if (sm->waiting_ext_cert_check) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP-TLS: Waiting external server certificate validation");
+		wpabuf_free(data->pending_resp);
+		data->pending_resp = resp;
+		return NULL;
+	}
+
 	if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
 		eap_tls_success(sm, data, ret);
 
@@ -258,6 +294,10 @@
 
 static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
 {
+	struct eap_tls_data *data = priv;
+
+	wpabuf_free(data->pending_resp);
+	data->pending_resp = NULL;
 }
 
 
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index af2b754..4b994fd 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -80,6 +80,10 @@
 		params->flags |= TLS_CONN_DISABLE_TLSv1_2;
 	if (os_strstr(txt, "tls_disable_tlsv1_2=0"))
 		params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
+	if (os_strstr(txt, "tls_ext_cert_check=1"))
+		params->flags |= TLS_CONN_EXT_CERT_CHECK;
+	if (os_strstr(txt, "tls_ext_cert_check=0"))
+		params->flags &= ~TLS_CONN_EXT_CERT_CHECK;
 }
 
 
@@ -177,6 +181,8 @@
 
 	params->openssl_ciphers = config->openssl_ciphers;
 
+	sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK);
+
 	return 0;
 }
 
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index b186c91..9741ded 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -58,6 +58,7 @@
 	size_t id_len;
 
 	struct wpabuf *pending_phase2_req;
+	struct wpabuf *pending_resp;
 
 #ifdef EAP_TNC
 	int ready_for_tnc;
@@ -153,6 +154,7 @@
 	eap_ttls_free_key(data);
 	os_free(data->session_id);
 	wpabuf_free(data->pending_phase2_req);
+	wpabuf_free(data->pending_resp);
 	os_free(data);
 }
 
@@ -1408,6 +1410,32 @@
 {
 	int res;
 
+	if (sm->waiting_ext_cert_check && data->pending_resp) {
+		struct eap_peer_config *config = eap_get_config(sm);
+
+		if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP-TTLS: External certificate check succeeded - continue handshake");
+			*out_data = data->pending_resp;
+			data->pending_resp = NULL;
+			sm->waiting_ext_cert_check = 0;
+			return 0;
+		}
+
+		if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP-TTLS: External certificate check failed - force authentication failure");
+			ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_FAIL;
+			sm->waiting_ext_cert_check = 0;
+			return 0;
+		}
+
+		wpa_printf(MSG_DEBUG,
+			   "EAP-TTLS: Continuing to wait external server certificate validation");
+		return 0;
+	}
+
 	res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
 					  data->ttls_version, identifier,
 					  in_data, out_data);
@@ -1418,6 +1446,15 @@
 		return -1;
 	}
 
+	if (sm->waiting_ext_cert_check) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP-TTLS: Waiting external server certificate validation");
+		wpabuf_free(data->pending_resp);
+		data->pending_resp = *out_data;
+		*out_data = NULL;
+		return 0;
+	}
+
 	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to "
 			   "Phase 2");
@@ -1557,6 +1594,8 @@
 	struct eap_ttls_data *data = priv;
 	wpabuf_free(data->pending_phase2_req);
 	data->pending_phase2_req = NULL;
+	wpabuf_free(data->pending_resp);
+	data->pending_resp = NULL;
 #ifdef EAP_TNC
 	data->ready_for_tnc = 0;
 	data->tnc_started = 0;