wpa_supplicant: Update to 07-Jul-2012 TOT

commit a5ed45586c63ffd8f9d2b44e27c251d7bacbeaf4
Author: Jouni Malinen <j@w1.fi>
Date:   Sat Jul 7 13:01:45 2012 +0300

    WPS SSDP: Fix socket leaks on error paths

Change-Id: I0864aac7fc88fa2a60f5cca7d524b94363410c85
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 6a88589..8b43be4 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -1,6 +1,6 @@
 /*
  * EAP peer state machines (RFC 4137)
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -81,6 +81,16 @@
 }
 
 
+static void eap_notify_status(struct eap_sm *sm, const char *status,
+				      const char *parameter)
+{
+	wpa_printf(MSG_DEBUG, "EAP: Status notification: %s (param=%s)",
+		   status, parameter);
+	if (sm->eapol_cb->notify_status)
+		sm->eapol_cb->notify_status(sm->eapol_ctx, status, parameter);
+}
+
+
 static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
 {
 	if (sm->m == NULL || sm->eap_method_priv == NULL)
@@ -213,6 +223,7 @@
 {
 	int reinit;
 	EapType method;
+	const struct eap_method *eap_method;
 
 	SM_ENTRY(EAP, GET_METHOD);
 
@@ -221,18 +232,24 @@
 	else
 		method = sm->reqMethod;
 
+	eap_method = eap_peer_get_eap_method(sm->reqVendor, method);
+
 	if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) {
 		wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed",
 			   sm->reqVendor, method);
 		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
 			"vendor=%u method=%u -> NAK",
 			sm->reqVendor, method);
+		eap_notify_status(sm, "refuse proposed method",
+				  eap_method ?  eap_method->name : "unknown");
 		goto nak;
 	}
 
 	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
 		"vendor=%u method=%u", sm->reqVendor, method);
 
+	eap_notify_status(sm, "accept proposed method",
+			  eap_method ?  eap_method->name : "unknown");
 	/*
 	 * RFC 4137 does not define specific operation for fast
 	 * re-authentication (session resumption). The design here is to allow
@@ -256,7 +273,7 @@
 
 	sm->selectedMethod = sm->reqMethod;
 	if (sm->m == NULL)
-		sm->m = eap_peer_get_eap_method(sm->reqVendor, method);
+		sm->m = eap_method;
 	if (!sm->m) {
 		wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: "
 			   "vendor %d method %d",
@@ -938,7 +955,7 @@
 static int eap_sm_imsi_identity(struct eap_sm *sm,
 				struct eap_peer_config *conf)
 {
-	int aka = 0;
+	enum { EAP_SM_SIM, EAP_SM_AKA, EAP_SM_AKA_PRIME } method = EAP_SM_SIM;
 	char imsi[100];
 	size_t imsi_len;
 	struct eap_method_type *m = conf->eap_methods;
@@ -966,8 +983,14 @@
 	for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF ||
 			  m[i].method != EAP_TYPE_NONE); i++) {
 		if (m[i].vendor == EAP_VENDOR_IETF &&
+		    m[i].method == EAP_TYPE_AKA_PRIME) {
+			method = EAP_SM_AKA_PRIME;
+			break;
+		}
+
+		if (m[i].vendor == EAP_VENDOR_IETF &&
 		    m[i].method == EAP_TYPE_AKA) {
-			aka = 1;
+			method = EAP_SM_AKA;
 			break;
 		}
 	}
@@ -980,7 +1003,17 @@
 		return -1;
 	}
 
-	conf->identity[0] = aka ? '0' : '1';
+	switch (method) {
+	case EAP_SM_SIM:
+		conf->identity[0] = '1';
+		break;
+	case EAP_SM_AKA:
+		conf->identity[0] = '0';
+		break;
+	case EAP_SM_AKA_PRIME:
+		conf->identity[0] = '6';
+		break;
+	}
 	os_memcpy(conf->identity + 1, imsi, imsi_len);
 	conf->identity_len = 1 + imsi_len;
 
@@ -1219,10 +1252,12 @@
 		break;
 	case EAP_CODE_SUCCESS:
 		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
+		eap_notify_status(sm, "completion", "success");
 		sm->rxSuccess = TRUE;
 		break;
 	case EAP_CODE_FAILURE:
 		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
+		eap_notify_status(sm, "completion", "failure");
 		sm->rxFailure = TRUE;
 		break;
 	default:
@@ -1240,6 +1275,10 @@
 	char *hash_hex = NULL;
 
 	switch (ev) {
+	case TLS_CERT_CHAIN_SUCCESS:
+		eap_notify_status(sm, "remote certificate verification",
+				  "success");
+		break;
 	case TLS_CERT_CHAIN_FAILURE:
 		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
 			"reason=%d depth=%d subject='%s' err='%s'",
@@ -1247,6 +1286,8 @@
 			data->cert_fail.depth,
 			data->cert_fail.subject,
 			data->cert_fail.reason_txt);
+		eap_notify_status(sm, "remote certificate verification",
+				  data->cert_fail.reason_txt);
 		break;
 	case TLS_PEER_CERTIFICATE:
 		if (!sm->eapol_cb->notify_cert)
@@ -1267,6 +1308,14 @@
 					  data->peer_cert.subject,
 					  hash_hex, data->peer_cert.cert);
 		break;
+	case TLS_ALERT:
+		if (data->alert.is_local)
+			eap_notify_status(sm, "local TLS alert",
+					  data->alert.description);
+		else
+			eap_notify_status(sm, "remote TLS alert",
+					  data->alert.description);
+		break;
 	}
 
 	os_free(hash_hex);
@@ -1321,6 +1370,13 @@
 		return NULL;
 	}
 
+	sm->ssl_ctx2 = tls_init(&tlsconf);
+	if (sm->ssl_ctx2 == NULL) {
+		wpa_printf(MSG_INFO, "SSL: Failed to initialize TLS "
+			   "context (2).");
+		/* Run without separate TLS context within TLS tunnel */
+	}
+
 	return sm;
 }
 
@@ -1338,6 +1394,8 @@
 		return;
 	eap_deinit_prev_method(sm, "EAP deinit");
 	eap_sm_abort(sm);
+	if (sm->ssl_ctx2)
+		tls_deinit(sm->ssl_ctx2);
 	tls_deinit(sm->ssl_ctx);
 	os_free(sm);
 }
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index b95a285..6e87475 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -226,6 +226,15 @@
 	 */
 	void (*notify_cert)(void *ctx, int depth, const char *subject,
 			    const char *cert_hash, const struct wpabuf *cert);
+
+	/**
+	 * notify_status - Notification of the current EAP state
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @status: Step in the process of EAP authentication
+	 * @parameter: Step-specific parameter, e.g., EAP method name
+	 */
+	void (*notify_status)(void *ctx, const char *status,
+			      const char *parameter);
 };
 
 /**
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 7e37e44..1cec4d8 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -1,6 +1,6 @@
 /*
- * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448)
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -229,19 +229,19 @@
 
 static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
 {
-	if (id & CLEAR_PSEUDONYM) {
+	if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
 		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym");
 		os_free(data->pseudonym);
 		data->pseudonym = NULL;
 		data->pseudonym_len = 0;
 	}
-	if (id & CLEAR_REAUTH_ID) {
+	if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
 		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
 		os_free(data->reauth_id);
 		data->reauth_id = NULL;
 		data->reauth_id_len = 0;
 	}
-	if (id & CLEAR_EAP_ID) {
+	if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
 		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id");
 		os_free(data->last_eap_identity);
 		data->last_eap_identity = NULL;
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 06d6db6..3318b81 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -317,6 +317,7 @@
 	void *msg_ctx;
 	void *scard_ctx;
 	void *ssl_ctx;
+	void *ssl_ctx2;
 
 	unsigned int workaround;
 
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index 37e9234..267d0a5 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -9,6 +9,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/sha256.h"
 #include "eap_peer/eap_i.h"
 #include "eap_common/eap_pwd_common.h"
 
@@ -459,10 +460,10 @@
 				 const u8 *payload, size_t payload_len)
 {
 	BIGNUM *x = NULL, *y = NULL;
-	HMAC_CTX ctx;
+	struct crypto_hash *hash;
 	u32 cs;
 	u16 grp;
-	u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+	u8 conf[SHA256_MAC_LEN], *cruft = NULL, *ptr;
 	int offset;
 
 	/*
@@ -489,7 +490,9 @@
 	 * server's commit is H(k | server_element | server_scalar |
 	 *			peer_element | peer_scalar | ciphersuite)
 	 */
-	H_Init(&ctx);
+	hash = eap_pwd_h_init();
+	if (hash == NULL)
+		goto fin;
 
 	/*
 	 * zero the memory each time because this is mod prime math and some
@@ -498,7 +501,7 @@
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
 	BN_bn2bin(data->k, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server element: x, y */
 	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -511,18 +514,18 @@
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
 	BN_bn2bin(x, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
 	BN_bn2bin(y, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->order) -
 		BN_num_bytes(data->server_scalar);
 	BN_bn2bin(data->server_scalar, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
 	/* my element: x, y */
 	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -536,27 +539,27 @@
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
 	BN_bn2bin(x, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
 	BN_bn2bin(y, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
 	/* my scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->order) -
 		BN_num_bytes(data->my_scalar);
 	BN_bn2bin(data->my_scalar, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
 	/* the ciphersuite */
-	H_Update(&ctx, (u8 *) &cs, sizeof(u32));
+	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
 
 	/* random function fin */
-	H_Final(&ctx, conf);
+	eap_pwd_h_final(hash, conf);
 
 	ptr = (u8 *) payload;
-	if (os_memcmp(conf, ptr, SHA256_DIGEST_LENGTH)) {
+	if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) {
 		wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify");
 		goto fin;
 	}
@@ -568,13 +571,15 @@
 	 *  H(k | peer_element | peer_scalar | server_element | server_scalar |
 	 *    ciphersuite)
 	 */
-	H_Init(&ctx);
+	hash = eap_pwd_h_init();
+	if (hash == NULL)
+		goto fin;
 
 	/* k */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
 	BN_bn2bin(data->k, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
 	/* my element */
 	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -587,18 +592,18 @@
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
 	BN_bn2bin(x, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
 	BN_bn2bin(y, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
 	/* my scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->order) -
 		BN_num_bytes(data->my_scalar);
 	BN_bn2bin(data->my_scalar, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
 	/* server element: x, y */
 	if (!EC_POINT_get_affine_coordinates_GFp(data->grp->group,
@@ -611,24 +616,24 @@
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
 	BN_bn2bin(x, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
 	BN_bn2bin(y, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
 	offset = BN_num_bytes(data->grp->order) -
 		BN_num_bytes(data->server_scalar);
 	BN_bn2bin(data->server_scalar, cruft + offset);
-	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
+	eap_pwd_h_update(hash, cruft, BN_num_bytes(data->grp->order));
 
 	/* the ciphersuite */
-	H_Update(&ctx, (u8 *) &cs, sizeof(u32));
+	eap_pwd_h_update(hash, (u8 *) &cs, sizeof(u32));
 
 	/* all done */
-	H_Final(&ctx, conf);
+	eap_pwd_h_final(hash, conf);
 
 	if (compute_keys(data->grp, data->bnctx, data->k,
 			 data->my_scalar, data->server_scalar, conf, ptr,
@@ -638,11 +643,11 @@
 		goto fin;
 	}
 
-	data->outbuf = wpabuf_alloc(SHA256_DIGEST_LENGTH);
+	data->outbuf = wpabuf_alloc(SHA256_MAC_LEN);
 	if (data->outbuf == NULL)
 		goto fin;
 
-	wpabuf_put_data(data->outbuf, conf, SHA256_DIGEST_LENGTH);
+	wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN);
 
 fin:
 	os_free(cruft);
@@ -725,6 +730,7 @@
 		 */
 		if (data->out_frag_pos >= wpabuf_len(data->outbuf)) {
 			wpabuf_free(data->outbuf);
+			data->outbuf = NULL;
 			data->out_frag_pos = 0;
 		}
 		wpa_printf(MSG_DEBUG, "EAP-pwd: Send %s fragment of %d bytes",
@@ -856,8 +862,11 @@
 	/*
 	 * if we're not fragmenting then there's no need to carry this around
 	 */
-	if (data->out_frag_pos == 0)
+	if (data->out_frag_pos == 0) {
 		wpabuf_free(data->outbuf);
+		data->outbuf = NULL;
+		data->out_frag_pos = 0;
+	}
 
 	return resp;
 }
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index a3067fa..ed52fb6 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, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -21,6 +21,7 @@
 struct eap_tls_data {
 	struct eap_ssl_data ssl;
 	u8 *key_data;
+	void *ssl_ctx;
 };
 
 
@@ -40,6 +41,9 @@
 	if (data == NULL)
 		return NULL;
 
+	data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+		sm->ssl_ctx;
+
 	if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
 		wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
 		eap_tls_deinit(sm, data);
@@ -165,7 +169,7 @@
 		return eap_tls_failure(sm, data, ret, res, resp, id);
 	}
 
-	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
+	if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
 		eap_tls_success(sm, data, ret);
 
 	if (res == 1) {
@@ -180,7 +184,7 @@
 static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
 {
 	struct eap_tls_data *data = priv;
-	return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
+	return tls_connection_established(data->ssl_ctx, data->ssl.conn);
 }
 
 
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 52549f4..69e83d9 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -1,6 +1,6 @@
 /*
  * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -136,14 +136,14 @@
 {
 	int res;
 
-	data->conn = tls_connection_init(sm->ssl_ctx);
+	data->conn = tls_connection_init(data->ssl_ctx);
 	if (data->conn == NULL) {
 		wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
 			   "connection");
 		return -1;
 	}
 
-	res = tls_connection_set_params(sm->ssl_ctx, data->conn, params);
+	res = tls_connection_set_params(data->ssl_ctx, data->conn, params);
 	if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
 		/*
 		 * At this point with the pkcs11 engine the PIN might be wrong.
@@ -162,13 +162,13 @@
 		config->pin = NULL;
 		eap_sm_request_pin(sm);
 		sm->ignore = TRUE;
-		tls_connection_deinit(sm->ssl_ctx, data->conn);
+		tls_connection_deinit(data->ssl_ctx, data->conn);
 		data->conn = NULL;
 		return -1;
 	} else if (res) {
 		wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
 			   "parameters");
-		tls_connection_deinit(sm->ssl_ctx, data->conn);
+		tls_connection_deinit(data->ssl_ctx, data->conn);
 		data->conn = NULL;
 		return -1;
 	}
@@ -197,6 +197,8 @@
 
 	data->eap = sm;
 	data->phase2 = sm->init_phase2;
+	data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+		sm->ssl_ctx;
 	if (eap_tls_params_from_conf(sm, data, &params, config, data->phase2) <
 	    0)
 		return -1;
@@ -234,7 +236,7 @@
  */
 void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
 {
-	tls_connection_deinit(sm->ssl_ctx, data->conn);
+	tls_connection_deinit(data->ssl_ctx, data->conn);
 	eap_peer_tls_reset_input(data);
 	eap_peer_tls_reset_output(data);
 }
@@ -265,8 +267,8 @@
 		return NULL;
 
 	/* First, try to use TLS library function for PRF, if available. */
-	if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
-	    0)
+	if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len)
+	    == 0)
 		return out;
 
 	/*
@@ -274,7 +276,7 @@
 	 * session parameters and use an internal implementation of TLS PRF to
 	 * derive the key.
 	 */
-	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+	if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys))
 		goto fail;
 
 	if (keys.client_random == NULL || keys.server_random == NULL ||
@@ -441,14 +443,14 @@
 		WPA_ASSERT(data->tls_out == NULL);
 	}
 	appl_data = NULL;
-	data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn,
+	data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn,
 						 msg, &appl_data);
 
 	eap_peer_tls_reset_input(data);
 
 	if (appl_data &&
-	    tls_connection_established(sm->ssl_ctx, data->conn) &&
-	    !tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+	    tls_connection_established(data->ssl_ctx, data->conn) &&
+	    !tls_connection_get_failed(data->ssl_ctx, data->conn)) {
 		wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data",
 				    appl_data);
 		*out_data = appl_data;
@@ -616,7 +618,7 @@
 		return -1;
 	}
 
-	if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+	if (tls_connection_get_failed(data->ssl_ctx, data->conn)) {
 		/* TLS processing has failed - return error */
 		wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
 			   "report error");
@@ -675,7 +677,7 @@
 {
 	eap_peer_tls_reset_input(data);
 	eap_peer_tls_reset_output(data);
-	return tls_connection_shutdown(sm->ssl_ctx, data->conn);
+	return tls_connection_shutdown(data->ssl_ctx, data->conn);
 }
 
 
@@ -694,7 +696,8 @@
 	char name[128];
 	int len = 0, ret;
 
-	if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) {
+	if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) == 0)
+	{
 		ret = os_snprintf(buf + len, buflen - len,
 				  "EAP TLS cipher=%s\n", name);
 		if (ret < 0 || (size_t) ret >= buflen - len)
@@ -741,7 +744,7 @@
 	size_t left;
 	unsigned int tls_msg_len;
 
-	if (tls_get_errors(sm->ssl_ctx)) {
+	if (tls_get_errors(data->ssl_ctx)) {
 		wpa_printf(MSG_INFO, "SSL: TLS errors detected");
 		ret->ignore = TRUE;
 		return NULL;
@@ -849,7 +852,7 @@
 	if (msg == NULL)
 		return need_more_input ? 1 : -1;
 
-	*in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->conn, msg);
+	*in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg);
 	eap_peer_tls_reset_input(data);
 	if (*in_decrypted == NULL) {
 		wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data");
@@ -877,8 +880,8 @@
 {
 	if (in_data) {
 		eap_peer_tls_reset_output(data);
-		data->tls_out = tls_connection_encrypt(sm->ssl_ctx, data->conn,
-						       in_data);
+		data->tls_out = tls_connection_encrypt(data->ssl_ctx,
+						       data->conn, in_data);
 		if (data->tls_out == NULL) {
 			wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 "
 				   "data (in_len=%lu)",
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index 7426467..771385b 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -1,6 +1,6 @@
 /*
  * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -63,6 +63,11 @@
 	 * eap - EAP state machine allocated with eap_peer_sm_init()
 	 */
 	struct eap_sm *eap;
+
+	/**
+	 * ssl_ctx - TLS library context to use for the connection
+	 */
+	void *ssl_ctx;
 };
 
 
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 0204ba2..e09f5e5 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -435,7 +435,6 @@
 			   "implicit challenge");
 		return -1;
 	}
-	peer_challenge = challenge + 1 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
 
 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
 			       RADIUS_VENDOR_ID_MICROSOFT, 1,
@@ -448,7 +447,14 @@
 	data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN];
 	*pos++ = data->ident;
 	*pos++ = 0; /* Flags */
-	os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
+	if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) {
+		os_free(challenge);
+		wpabuf_free(msg);
+		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get "
+			   "random data for peer challenge");
+		return -1;
+	}
+	peer_challenge = pos;
 	pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
 	os_memset(pos, 0, 8); /* Reserved, must be zero */
 	pos += 8;
@@ -456,6 +462,7 @@
 				     password_len, pwhash, challenge,
 				     peer_challenge, pos, data->auth_response,
 				     data->master_key)) {
+		os_free(challenge);
 		wpabuf_free(msg);
 		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
 			   "response");
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index 4473b90..d007a57 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -1,6 +1,6 @@
 /*
  * EAP-WSC peer for Wi-Fi Protected Setup
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2009, 2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -137,6 +137,8 @@
 	struct wps_context *wps;
 	struct wps_credential new_ap_settings;
 	int res;
+	u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN];
+	int nfc = 0;
 
 	wps = sm->wps;
 	if (wps == NULL) {
@@ -184,13 +186,26 @@
 		while (*pos != '\0' && *pos != ' ')
 			pos++;
 		cfg.pin_len = pos - (const char *) cfg.pin;
+		if (cfg.pin_len >= WPS_OOB_DEVICE_PASSWORD_MIN_LEN * 2 &&
+		    cfg.pin_len <= WPS_OOB_DEVICE_PASSWORD_LEN * 2 &&
+		    hexstr2bin((const char *) cfg.pin, dev_pw,
+			       cfg.pin_len / 2) == 0) {
+			/* Convert OOB Device Password to binary */
+			cfg.pin = dev_pw;
+			cfg.pin_len /= 2;
+		}
+		if (cfg.pin_len == 6 && os_strncmp(pos, "nfc-pw", 6) == 0) {
+			cfg.pin = NULL;
+			cfg.pin_len = 0;
+			nfc = 1;
+		}
 	} else {
 		pos = os_strstr(phase1, "pbc=1");
 		if (pos)
 			cfg.pbc = 1;
 	}
 
-	if (cfg.pin == NULL && !cfg.pbc) {
+	if (cfg.pin == NULL && !cfg.pbc && !nfc) {
 		wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
 			   "configuration data");
 		os_free(data);