[pkg-wpa-devel] r878 - in /wpasupplicant/branches/upstream/current: patches/ src/common/ src/crypto/ src/drivers/ src/eap_common/ src/eap_peer/ src/eap_server/ src/l2_packet/ src/radius/ src/rsn_supp/ src/tls/ src/utils/ wpa_supplicant/ wpa_supplicant/doc/ wpa_supplicant/doc/docbook/ wpa_supplicant/tests/

kelmo-guest at users.alioth.debian.org kelmo-guest at users.alioth.debian.org
Sat Nov 3 08:40:37 UTC 2007


Author: kelmo-guest
Date: Sat Nov  3 08:40:37 2007
New Revision: 878

URL: http://svn.debian.org/wsvn/?sc=1&rev=878
Log:
[svn-upgrade] Integrating new upstream version, wpasupplicant (0.6.1~git20071103)

Added:
    wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch
    wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch
    wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h
    wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.c
    wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.h
    wpasupplicant/branches/upstream/current/src/drivers/driver_iphone.m
    wpasupplicant/branches/upstream/current/src/drivers/driver_osx.m
    wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h
    wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h
    wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_i.h
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_read.c
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_write.c
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.c
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.h
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.c
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.h
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.c
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.h
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_i.h
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_read.c
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_write.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist.sh   (with props)
    wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist2.sh   (with props)
Removed:
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_background.8
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.8
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_passphrase.8
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.8
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
Modified:
    wpasupplicant/branches/upstream/current/src/common/defs.h
    wpasupplicant/branches/upstream/current/src/common/wpa_common.c
    wpasupplicant/branches/upstream/current/src/common/wpa_common.h
    wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c
    wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.h
    wpasupplicant/branches/upstream/current/src/crypto/crypto.h
    wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c
    wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c
    wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.h
    wpasupplicant/branches/upstream/current/src/crypto/sha256.c
    wpasupplicant/branches/upstream/current/src/crypto/tls.h
    wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c
    wpasupplicant/branches/upstream/current/src/crypto/tls_internal.c
    wpasupplicant/branches/upstream/current/src/crypto/tls_none.c
    wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c
    wpasupplicant/branches/upstream/current/src/crypto/tls_schannel.c
    wpasupplicant/branches/upstream/current/src/drivers/driver.h
    wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c
    wpasupplicant/branches/upstream/current/src/drivers/drivers.c
    wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.c
    wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.h
    wpasupplicant/branches/upstream/current/src/eap_peer/eap.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast_pac.h
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_gtc.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_leap.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.h
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c
    wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap.h
    wpasupplicant/branches/upstream/current/src/eap_server/eap_gpsk.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h
    wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_tlv.c
    wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_freebsd.c
    wpasupplicant/branches/upstream/current/src/radius/radius_client.c
    wpasupplicant/branches/upstream/current/src/radius/radius_server.c
    wpasupplicant/branches/upstream/current/src/radius/radius_server.h
    wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c
    wpasupplicant/branches/upstream/current/src/tls/asn1.c
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.h
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.c
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.h
    wpasupplicant/branches/upstream/current/src/tls/x509v3.c
    wpasupplicant/branches/upstream/current/src/utils/common.h
    wpasupplicant/branches/upstream/current/src/utils/os_unix.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog
    wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile
    wpasupplicant/branches/upstream/current/wpa_supplicant/config.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/config_ssid.h
    wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/ctrl_iface.doxygen
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml
    wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt
    wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/events.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_aes.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h

Added: wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch (added)
+++ wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch Sat Nov  3 08:40:37 2007
@@ -1,0 +1,346 @@
+This patch adds support for TLS SessionTicket extension (RFC 4507) for
+the parts used by EAP-FAST (RFC 4851).
+
+This is based on the patch from Alexey Kobozev <akobozev at cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+OpenSSL 0.9.8g does not enable TLS extension support by default, so it
+will need to be enabled by adding enable-tlsext to config script
+command line.
+
+
+diff -upr openssl-0.9.8g.orig/ssl/s3_clnt.c openssl-0.9.8g/ssl/s3_clnt.c
+--- openssl-0.9.8g.orig/ssl/s3_clnt.c	2007-08-30 17:28:51.000000000 -0700
++++ openssl-0.9.8g/ssl/s3_clnt.c	2007-11-01 20:08:08.000000000 -0700
+@@ -660,7 +660,7 @@ int ssl3_get_server_hello(SSL *s)
+ 	STACK_OF(SSL_CIPHER) *sk;
+ 	SSL_CIPHER *c;
+ 	unsigned char *p,*d;
+-	int i,al,ok;
++	int i,al,ok,pre_shared;
+ 	unsigned int j;
+ 	long n;
+ #ifndef OPENSSL_NO_COMP
+@@ -727,7 +727,26 @@ int ssl3_get_server_hello(SSL *s)
+ 		goto f_err;
+ 		}
+ 
+-	if (j != 0 && j == s->session->session_id_length
++	/* check if we want to resume the session based on external pre-shared secret */
++	pre_shared = 0;
++#ifndef OPENSSL_NO_TLSEXT
++	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++			NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->hit=1;
++			s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
++			s->session->session_id_length = j;
++			memcpy(s->session->session_id, p, j);
++			pre_shared = 1;
++		}
++	}
++#endif /* OPENSSL_NO_TLSEXT */
++
++	if ((pre_shared || j != 0) && j == s->session->session_id_length
+ 	    && memcmp(p,s->session->session_id,j) == 0)
+ 	    {
+ 	    if(s->sid_ctx_length != s->session->sid_ctx_length
+diff -upr openssl-0.9.8g.orig/ssl/s3_srvr.c openssl-0.9.8g/ssl/s3_srvr.c
+--- openssl-0.9.8g.orig/ssl/s3_srvr.c	2007-09-30 11:55:59.000000000 -0700
++++ openssl-0.9.8g/ssl/s3_srvr.c	2007-11-02 19:24:20.000000000 -0700
+@@ -928,6 +928,59 @@ int ssl3_get_client_hello(SSL *s)
+ 			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ 			goto err;
+ 		}
++
++	/* Check if we want to use external pre-shared secret for this
++	 * handshake for not reused session only. We need to generate
++	 * server_random before calling tls_session_secret_cb in order to allow
++	 * SessionTicket processing to use it in key derivation. */
++	{
++		unsigned long Time;
++		unsigned char *pos;
++		Time=(unsigned long)time(NULL);			/* Time */
++		pos=s->s3->server_random;
++		l2n(Time,pos);
++		if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
++		{
++			al=SSL_AD_INTERNAL_ERROR;
++			goto f_err;
++		}
++	}
++
++	if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, 
++			ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->hit=1;
++			s->session->ciphers=ciphers;
++			s->session->verify_result=X509_V_OK;
++			
++			ciphers=NULL;
++			
++			/* check if some cipher was preferred by call back */
++			pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++			if (pref_cipher == NULL)
++				{
++				al=SSL_AD_HANDSHAKE_FAILURE;
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++				goto f_err;
++				}
++
++			s->session->cipher=pref_cipher;
++
++			if (s->cipher_list)
++				sk_SSL_CIPHER_free(s->cipher_list);
++
++			if (s->cipher_list_by_id)
++				sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++			s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++			s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++		}
++	}
+ #endif
+ 	/* Worst case, we will use the NULL compression, but if we have other
+ 	 * options, we will now look for them.  We have i-1 compression
+@@ -1066,16 +1119,22 @@ int ssl3_send_server_hello(SSL *s)
+ 	unsigned char *buf;
+ 	unsigned char *p,*d;
+ 	int i,sl;
+-	unsigned long l,Time;
++	unsigned long l;
++#ifdef OPENSSL_NO_TLSEXT
++	unsigned long Time;
++#endif
+ 
+ 	if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ 		{
+ 		buf=(unsigned char *)s->init_buf->data;
++#ifdef OPENSSL_NO_TLSEXT
+ 		p=s->s3->server_random;
++		/* Generate server_random if it was not needed previously */
+ 		Time=(unsigned long)time(NULL);			/* Time */
+ 		l2n(Time,p);
+ 		if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+ 			return -1;
++#endif
+ 		/* Do the message type and length last */
+ 		d=p= &(buf[4]);
+ 
+diff -upr openssl-0.9.8g.orig/ssl/ssl.h openssl-0.9.8g/ssl/ssl.h
+--- openssl-0.9.8g.orig/ssl/ssl.h	2007-10-19 00:42:38.000000000 -0700
++++ openssl-0.9.8g/ssl/ssl.h	2007-11-01 20:08:08.000000000 -0700
+@@ -342,6 +342,7 @@ extern "C" {
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -363,6 +364,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+ 
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -1004,6 +1007,14 @@ struct ssl_st
+ 	                       */
+ 	/* RFC4507 session ticket expected to be received or sent */
+ 	int tlsext_ticket_expected;
++
++	/* TLS extensions */
++	TLS_EXTENSION *tls_extension;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
++
+ 	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+ #define session_ctx initial_ctx
+ #else
+@@ -1589,6 +1600,12 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1778,6 +1795,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC					 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION			 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+diff -upr openssl-0.9.8g.orig/ssl/ssl_err.c openssl-0.9.8g/ssl/ssl_err.c
+--- openssl-0.9.8g.orig/ssl/ssl_err.c	2007-10-11 07:36:59.000000000 -0700
++++ openssl-0.9.8g/ssl/ssl_err.c	2007-11-01 20:08:08.000000000 -0700
+@@ -250,6 +250,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_ENC),	"TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
+ {0,NULL}
+ 	};
+ 
+diff -upr openssl-0.9.8g.orig/ssl/ssl_sess.c openssl-0.9.8g/ssl/ssl_sess.c
+--- openssl-0.9.8g.orig/ssl/ssl_sess.c	2007-10-19 00:36:34.000000000 -0700
++++ openssl-0.9.8g/ssl/ssl_sess.c	2007-11-01 20:08:08.000000000 -0700
+@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ 	return(s->session_timeout);
+ 	}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, 
++	STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++{
++	if (s == NULL) return(0);
++	s->tls_session_secret_cb = tls_session_secret_cb;
++	s->tls_session_secret_cb_arg = arg;
++	return(1);
++}
++
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
++{
++	if(s->version >= TLS1_VERSION)
++	{
++		if(s->tls_extension)
++		{
++			OPENSSL_free(s->tls_extension);
++			s->tls_extension = NULL;
++		}
++
++		s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
++		if(!s->tls_extension)
++		{
++			SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
++			return 0;
++		}
++
++		s->tls_extension->type = ext_type;
++
++		if(ext_data)
++		{
++			s->tls_extension->length = ext_len;
++			s->tls_extension->data = s->tls_extension + 1;
++			memcpy(s->tls_extension->data, ext_data, ext_len);
++		} else {
++			s->tls_extension->length = 0;
++			s->tls_extension->data = NULL;
++		}
++
++		return 1;
++	}
++
++	return 0;
++}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ typedef struct timeout_param_st
+ 	{
+ 	SSL_CTX *ctx;
+diff -upr openssl-0.9.8g.orig/ssl/t1_lib.c openssl-0.9.8g/ssl/t1_lib.c
+--- openssl-0.9.8g.orig/ssl/t1_lib.c	2007-10-19 00:44:10.000000000 -0700
++++ openssl-0.9.8g/ssl/t1_lib.c	2007-11-01 20:08:08.000000000 -0700
+@@ -105,6 +105,12 @@ int tls1_new(SSL *s)
+ 
+ void tls1_free(SSL *s)
+ 	{
++#ifndef OPENSSL_NO_TLSEXT
++	if(s->tls_extension)
++	{
++		OPENSSL_free(s->tls_extension);
++	}
++#endif
+ 	ssl3_free(s);
+ 	}
+ 
+@@ -174,8 +180,24 @@ unsigned char *ssl_add_clienthello_tlsex
+ 		int ticklen;
+ 		if (s->session && s->session->tlsext_tick)
+ 			ticklen = s->session->tlsext_ticklen;
++		else if (s->session && s->tls_extension &&
++			s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++			s->tls_extension->data)
++		{
++			ticklen = s->tls_extension->length;
++			s->session->tlsext_tick = OPENSSL_malloc(ticklen);
++			if (!s->session->tlsext_tick)
++				return NULL;
++			memcpy(s->session->tlsext_tick, s->tls_extension->data,
++			       ticklen);
++			s->session->tlsext_ticklen = ticklen;
++		}
+ 		else
+ 			ticklen = 0;
++		if (ticklen == 0 && s->tls_extension &&
++		    s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++		    s->tls_extension->data == NULL)
++			goto skip_ext;
+ 		/* Check for enough room 2 for extension type, 2 for len
+  		 * rest for ticket
+   		 */
+@@ -189,6 +211,7 @@ unsigned char *ssl_add_clienthello_tlsex
+ 			ret += ticklen;
+ 			}
+ 		}
++		skip_ext:
+ 
+ 	if ((extdatalen = ret-p-2)== 0) 
+ 		return p;
+@@ -543,6 +566,8 @@ int tls1_process_ticket(SSL *s, unsigned
+ 				s->tlsext_ticket_expected = 1;
+ 				return 0;	/* Cache miss */
+ 				}
++			if (s->tls_session_secret_cb)
++				return 0;
+ 			return tls_decrypt_ticket(s, p, size, session_id, len,
+ 									ret);
+ 			}
+diff -upr openssl-0.9.8g.orig/ssl/tls1.h openssl-0.9.8g/ssl/tls1.h
+--- openssl-0.9.8g.orig/ssl/tls1.h	2007-08-27 18:12:44.000000000 -0700
++++ openssl-0.9.8g/ssl/tls1.h	2007-11-01 20:08:08.000000000 -0700
+@@ -365,6 +365,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SER
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS extension struct */
++struct tls_extension_st
++{
++	unsigned short type;
++	unsigned short length;
++	void *data;
++};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff -upr openssl-0.9.8g.orig/util/ssleay.num openssl-0.9.8g/util/ssleay.num
+--- openssl-0.9.8g.orig/util/ssleay.num	2007-08-12 15:31:16.000000000 -0700
++++ openssl-0.9.8g/util/ssleay.num	2007-11-01 20:08:08.000000000 -0700
+@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb              
+ SSL_set_SSL_CTX                         290	EXIST::FUNCTION:
+ SSL_get_servername                      291	EXIST::FUNCTION:TLSEXT
+ SSL_get_servername_type                 292	EXIST::FUNCTION:TLSEXT
++SSL_set_hello_extension			305	EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb		306	EXIST::FUNCTION:TLSEXT

Added: wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch (added)
+++ wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch Sat Nov  3 08:40:37 2007
@@ -1,0 +1,342 @@
+This patch adds support for TLS SessionTicket extension (RFC 4507) for
+the parts used by EAP-FAST (RFC 4851).
+
+This is based on the patch from Alexey Kobozev <akobozev at cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+
+
+diff -upr openssl-SNAP-20071101.orig/ssl/s3_clnt.c openssl-SNAP-20071101/ssl/s3_clnt.c
+--- openssl-SNAP-20071101.orig/ssl/s3_clnt.c	2007-10-26 06:00:28.000000000 -0700
++++ openssl-SNAP-20071101/ssl/s3_clnt.c	2007-11-01 19:19:43.000000000 -0700
+@@ -715,7 +715,7 @@ int ssl3_get_server_hello(SSL *s)
+ 	STACK_OF(SSL_CIPHER) *sk;
+ 	SSL_CIPHER *c;
+ 	unsigned char *p,*d;
+-	int i,al,ok;
++	int i,al,ok,pre_shared;
+ 	unsigned int j;
+ 	long n;
+ #ifndef OPENSSL_NO_COMP
+@@ -782,7 +782,26 @@ int ssl3_get_server_hello(SSL *s)
+ 		goto f_err;
+ 		}
+ 
+-	if (j != 0 && j == s->session->session_id_length
++	/* check if we want to resume the session based on external pre-shared secret */
++	pre_shared = 0;
++#ifndef OPENSSL_NO_TLSEXT
++	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++			NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->hit=1;
++			s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
++			s->session->session_id_length = j;
++			memcpy(s->session->session_id, p, j);
++			pre_shared = 1;
++		}
++	}
++#endif /* OPENSSL_NO_TLSEXT */
++
++	if ((pre_shared || j != 0) && j == s->session->session_id_length
+ 	    && memcmp(p,s->session->session_id,j) == 0)
+ 	    {
+ 	    if(s->sid_ctx_length != s->session->sid_ctx_length
+diff -upr openssl-SNAP-20071101.orig/ssl/s3_srvr.c openssl-SNAP-20071101/ssl/s3_srvr.c
+--- openssl-SNAP-20071101.orig/ssl/s3_srvr.c	2007-10-26 06:00:29.000000000 -0700
++++ openssl-SNAP-20071101/ssl/s3_srvr.c	2007-11-01 19:19:43.000000000 -0700
+@@ -992,6 +992,59 @@ int ssl3_get_client_hello(SSL *s)
+ 			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ 			goto err;
+ 		}
++
++	/* Check if we want to use external pre-shared secret for this
++	 * handshake for not reused session only. We need to generate
++	 * server_random before calling tls_session_secret_cb in order to allow
++	 * SessionTicket processing to use it in key derivation. */
++	{
++		unsigned long Time;
++		unsigned char *pos;
++		Time=(unsigned long)time(NULL);			/* Time */
++		pos=s->s3->server_random;
++		l2n(Time,pos);
++		if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
++		{
++			al=SSL_AD_INTERNAL_ERROR;
++			goto f_err;
++		}
++	}
++
++	if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, 
++			ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->hit=1;
++			s->session->ciphers=ciphers;
++			s->session->verify_result=X509_V_OK;
++			
++			ciphers=NULL;
++			
++			/* check if some cipher was preferred by call back */
++			pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++			if (pref_cipher == NULL)
++				{
++				al=SSL_AD_HANDSHAKE_FAILURE;
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++				goto f_err;
++				}
++
++			s->session->cipher=pref_cipher;
++
++			if (s->cipher_list)
++				sk_SSL_CIPHER_free(s->cipher_list);
++
++			if (s->cipher_list_by_id)
++				sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++			s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++			s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++		}
++	}
+ #endif
+ 
+ 	/* Worst case, we will use the NULL compression, but if we have other
+@@ -1118,16 +1171,22 @@ int ssl3_send_server_hello(SSL *s)
+ 	unsigned char *buf;
+ 	unsigned char *p,*d;
+ 	int i,sl;
+-	unsigned long l,Time;
++	unsigned long l;
++#ifdef OPENSSL_NO_TLSEXT
++	unsigned long Time;
++#endif
+ 
+ 	if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ 		{
+ 		buf=(unsigned char *)s->init_buf->data;
++#ifdef OPENSSL_NO_TLSEXT
+ 		p=s->s3->server_random;
++		/* Generate server_random if it was not needed previously */
+ 		Time=(unsigned long)time(NULL);			/* Time */
+ 		l2n(Time,p);
+ 		if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+ 			return -1;
++#endif
+ 		/* Do the message type and length last */
+ 		d=p= &(buf[4]);
+ 
+diff -upr openssl-SNAP-20071101.orig/ssl/ssl.h openssl-SNAP-20071101/ssl/ssl.h
+--- openssl-SNAP-20071101.orig/ssl/ssl.h	2007-10-26 17:01:28.000000000 -0700
++++ openssl-SNAP-20071101/ssl/ssl.h	2007-11-01 19:20:47.000000000 -0700
+@@ -353,6 +353,7 @@ extern "C" {
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -379,6 +380,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+ 
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -1121,6 +1124,13 @@ struct ssl_st
+ 	void *tlsext_opaque_prf_input;
+ 	size_t tlsext_opaque_prf_input_len;
+ 
++	/* TLS extensions */
++	TLS_EXTENSION *tls_extension;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
++
+ 	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+ #define session_ctx initial_ctx
+ #else
+@@ -1721,6 +1731,12 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1920,6 +1936,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_PRF					 284
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION			 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+diff -upr openssl-SNAP-20071101.orig/ssl/ssl_err.c openssl-SNAP-20071101/ssl/ssl_err.c
+--- openssl-SNAP-20071101.orig/ssl/ssl_err.c	2007-10-26 17:01:29.000000000 -0700
++++ openssl-SNAP-20071101/ssl/ssl_err.c	2007-11-01 19:19:43.000000000 -0700
+@@ -260,6 +260,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_PRF),	"tls1_prf"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
+ {0,NULL}
+ 	};
+ 
+diff -upr openssl-SNAP-20071101.orig/ssl/ssl_sess.c openssl-SNAP-20071101/ssl/ssl_sess.c
+--- openssl-SNAP-20071101.orig/ssl/ssl_sess.c	2007-10-17 11:00:45.000000000 -0700
++++ openssl-SNAP-20071101/ssl/ssl_sess.c	2007-11-01 19:19:43.000000000 -0700
+@@ -831,6 +831,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ 	return(s->session_timeout);
+ 	}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, 
++	STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++{
++	if (s == NULL) return(0);
++	s->tls_session_secret_cb = tls_session_secret_cb;
++	s->tls_session_secret_cb_arg = arg;
++	return(1);
++}
++
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
++{
++	if(s->version >= TLS1_VERSION)
++	{
++		if(s->tls_extension)
++		{
++			OPENSSL_free(s->tls_extension);
++			s->tls_extension = NULL;
++		}
++
++		s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
++		if(!s->tls_extension)
++		{
++			SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
++			return 0;
++		}
++
++		s->tls_extension->type = ext_type;
++
++		if(ext_data)
++		{
++			s->tls_extension->length = ext_len;
++			s->tls_extension->data = s->tls_extension + 1;
++			memcpy(s->tls_extension->data, ext_data, ext_len);
++		} else {
++			s->tls_extension->length = 0;
++			s->tls_extension->data = NULL;
++		}
++
++		return 1;
++	}
++
++	return 0;
++}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ typedef struct timeout_param_st
+ 	{
+ 	SSL_CTX *ctx;
+diff -upr openssl-SNAP-20071101.orig/ssl/t1_lib.c openssl-SNAP-20071101/ssl/t1_lib.c
+--- openssl-SNAP-20071101.orig/ssl/t1_lib.c	2007-10-26 06:00:29.000000000 -0700
++++ openssl-SNAP-20071101/ssl/t1_lib.c	2007-11-01 19:19:43.000000000 -0700
+@@ -154,6 +154,12 @@ int tls1_new(SSL *s)
+ 
+ void tls1_free(SSL *s)
+ 	{
++#ifndef OPENSSL_NO_TLSEXT
++	if(s->tls_extension)
++	{
++		OPENSSL_free(s->tls_extension);
++	}
++#endif
+ 	ssl3_free(s);
+ 	}
+ 
+@@ -355,8 +361,24 @@ unsigned char *ssl_add_clienthello_tlsex
+ 		int ticklen;
+ 		if (s->session && s->session->tlsext_tick)
+ 			ticklen = s->session->tlsext_ticklen;
++		else if (s->session && s->tls_extension &&
++			s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++			s->tls_extension->data)
++		{
++			ticklen = s->tls_extension->length;
++			s->session->tlsext_tick = OPENSSL_malloc(ticklen);
++			if (!s->session->tlsext_tick)
++				return NULL;
++			memcpy(s->session->tlsext_tick, s->tls_extension->data,
++			       ticklen);
++			s->session->tlsext_ticklen = ticklen;
++		}
+ 		else
+ 			ticklen = 0;
++		if (ticklen == 0 && s->tls_extension &&
++		    s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++		    s->tls_extension->data == NULL)
++			goto skip_ext;
+ 		/* Check for enough room 2 for extension type, 2 for len
+  		 * rest for ticket
+   		 */
+@@ -369,6 +391,7 @@ unsigned char *ssl_add_clienthello_tlsex
+ 			ret += ticklen;
+ 			}
+ 		}
++		skip_ext:
+ 
+ #ifdef TLSEXT_TYPE_opaque_prf_input
+ 	if (s->s3->client_opaque_prf_input != NULL)
+@@ -1422,6 +1445,8 @@ int tls1_process_ticket(SSL *s, unsigned
+ 				s->tlsext_ticket_expected = 1;
+ 				return 0;	/* Cache miss */
+ 				}
++			if (s->tls_session_secret_cb)
++				return 0;
+ 			return tls_decrypt_ticket(s, p, size, session_id, len,
+ 									ret);
+ 			}
+diff -upr openssl-SNAP-20071101.orig/ssl/tls1.h openssl-SNAP-20071101/ssl/tls1.h
+--- openssl-SNAP-20071101.orig/ssl/tls1.h	2007-09-26 15:01:39.000000000 -0700
++++ openssl-SNAP-20071101/ssl/tls1.h	2007-11-01 19:19:43.000000000 -0700
+@@ -509,6 +509,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPA
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS extension struct */
++struct tls_extension_st
++{
++	unsigned short type;
++	unsigned short length;
++	void *data;
++};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff -upr openssl-SNAP-20071101.orig/util/ssleay.num openssl-SNAP-20071101/util/ssleay.num
+--- openssl-SNAP-20071101.orig/util/ssleay.num	2007-08-31 06:03:14.000000000 -0700
++++ openssl-SNAP-20071101/util/ssleay.num	2007-11-01 19:19:43.000000000 -0700
+@@ -253,3 +253,5 @@ PEM_write_bio_SSL_SESSION               
+ PEM_read_SSL_SESSION                    302	EXIST:!WIN16:FUNCTION:
+ PEM_read_bio_SSL_SESSION                303	EXIST::FUNCTION:
+ PEM_write_SSL_SESSION                   304	EXIST:!WIN16:FUNCTION:
++SSL_set_hello_extension			305	EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb		306	EXIST::FUNCTION:TLSEXT

Modified: wpasupplicant/branches/upstream/current/src/common/defs.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/defs.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/defs.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/defs.h Sat Nov  3 08:40:37 2007
@@ -50,7 +50,7 @@
 
 
 typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP,
-	       WPA_ALG_IGTK } wpa_alg;
+	       WPA_ALG_IGTK, WPA_ALG_PMK } wpa_alg;
 typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
 	       CIPHER_WEP104 } wpa_cipher;
 typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,

Modified: wpasupplicant/branches/upstream/current/src/common/wpa_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/wpa_common.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/wpa_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/common/wpa_common.c Sat Nov  3 08:40:37 2007
@@ -396,7 +396,7 @@
 /**
  * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
  *
- * IEEE 802.11r/D5.0 - 8.5.1.5.3
+ * IEEE 802.11r/D8.0 - 8.5.1.5.3
  */
 void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
 		       const u8 *ssid, size_t ssid_len,
@@ -410,7 +410,7 @@
 	size_t len[2];
 
 	/*
-	 * R0-Key-Data = KDF-384(XXKey, "R0 Key Derivation",
+	 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
 	 *                       SSIDlength || SSID || MDID || R0KHlength ||
 	 *                       R0KH-ID || S0KH-ID)
 	 * XXKey is either the second 256 bits of MSK or PSK.
@@ -431,15 +431,15 @@
 	os_memcpy(pos, s0kh_id, ETH_ALEN);
 	pos += ETH_ALEN;
 
-	sha256_prf(xxkey, xxkey_len, "R0 Key Derivation", buf, pos - buf,
+	sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
 		   r0_key_data, sizeof(r0_key_data));
 	os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
 
 	/*
-	 * PMKR0Name = Truncate-128(SHA-256("R0 Key Name" || PMK-R0Name-Salt)
+	 * PMKR0Name = Truncate-128(SHA-256("FT-R0" || PMK-R0Name-Salt)
 	 */
-	addr[0] = (const u8 *) "R0 Key Name";
-	len[0] = 11;
+	addr[0] = (const u8 *) "FT-R0";
+	len[0] = 5;
 	addr[1] = r0_key_data + PMK_LEN;
 	len[1] = 16;
 
@@ -451,7 +451,7 @@
 /**
  * wpa_derive_pmk_r1_name - Derive PMKR1Name
  *
- * IEEE 802.11r/D5.0 - 8.5.1.5.4
+ * IEEE 802.11r/D8.0 - 8.5.1.5.4
  */
 void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
 			    const u8 *s1kh_id, u8 *pmk_r1_name)
@@ -461,11 +461,11 @@
 	size_t len[4];
 
 	/*
-	 * PMKR1Name = Truncate-128(SHA-256("R1 Key Name" || PMKR0Name ||
+	 * PMKR1Name = Truncate-128(SHA-256("FT-R1" || PMKR0Name ||
 	 *                                  R1KH-ID || S1KH-ID))
 	 */
-	addr[0] = (const u8 *) "R1 Key Name";
-	len[0] = 11;
+	addr[0] = (const u8 *) "FT-R1";
+	len[0] = 5;
 	addr[1] = pmk_r0_name;
 	len[1] = WPA_PMK_NAME_LEN;
 	addr[2] = r1kh_id;
@@ -481,7 +481,7 @@
 /**
  * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
  *
- * IEEE 802.11r/D5.0 - 8.5.1.5.4
+ * IEEE 802.11r/D8.0 - 8.5.1.5.4
  */
 void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
 		       const u8 *r1kh_id, const u8 *s1kh_id,
@@ -490,15 +490,14 @@
 	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
 	u8 *pos;
 
-	/* PMK-R1 = KDF-256(PMK-R0, "R1 Key Derivation", R1KH-ID || S1KH-ID) */
+	/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
 	pos = buf;
 	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
 	pos += FT_R1KH_ID_LEN;
 	os_memcpy(pos, s1kh_id, ETH_ALEN);
 	pos += ETH_ALEN;
 
-	sha256_prf(pmk_r0, PMK_LEN, "R1 Key Derivation", buf, pos - buf,
-		   pmk_r1, PMK_LEN);
+	sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
 
 	wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
 }
@@ -507,7 +506,7 @@
 /**
  * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
  *
- * IEEE 802.11r/D5.0 - 8.5.1.5.5
+ * IEEE 802.11r/D8.0 - 8.5.1.5.5
  */
 void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
 		       const u8 *sta_addr, const u8 *bssid,
@@ -520,7 +519,7 @@
 	size_t len[6];
 
 	/*
-	 * PTK = KDF-PTKLen(PMK-R1, "PTK Key derivation", SNonce || ANonce ||
+	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
 	 *                  BSSID || STA-ADDR)
 	 */
 	pos = buf;
@@ -533,17 +532,16 @@
 	os_memcpy(pos, sta_addr, ETH_ALEN);
 	pos += ETH_ALEN;
 
-	sha256_prf(pmk_r1, PMK_LEN, "PTK Key derivation", buf, pos - buf,
-		   ptk, ptk_len);
+	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
 
 	/*
-	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "PTK Name" || SNonce ||
+	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTK" || SNonce ||
 	 *                                ANonce || BSSID || STA-ADDR))
 	 */
 	addr[0] = pmk_r1_name;
 	len[0] = WPA_PMK_NAME_LEN;
-	addr[1] = (const u8 *) "PTK Name";
-	len[1] = 8;
+	addr[1] = (const u8 *) "FT-PTK";
+	len[1] = 6;
 	addr[2] = snonce;
 	len[2] = WPA_NONCE_LEN;
 	addr[3] = anonce;

Modified: wpasupplicant/branches/upstream/current/src/common/wpa_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/wpa_common.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/wpa_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/wpa_common.h Sat Nov  3 08:40:37 2007
@@ -281,9 +281,8 @@
 	u8 ft_capab;
 } STRUCT_PACKED;
 
-#define RSN_FT_CAPAB_FT_OVER_AIR BIT(0)
-#define RSN_FT_CAPAB_FT_OVER_DS BIT(1)
-#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(2)
+#define RSN_FT_CAPAB_FT_OVER_DS BIT(0)
+#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1)
 
 struct rsn_ftie {
 	u8 mic_control[2];

Modified: wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c Sat Nov  3 08:40:37 2007
@@ -7,7 +7,7 @@
  * - AES-128 EAX mode encryption/decryption
  * - AES-128 CBC
  *
- * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -29,10 +29,11 @@
 
 /**
  * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
- * @kek: Key encryption key (KEK)
- * @n: Length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
- * @plain: Plaintext key to be wrapped, n * 64 bit
- * @cipher: Wrapped key, (n + 1) * 64 bit
+ * @kek: 16-octet Key encryption key (KEK)
+ * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
+ * bytes
+ * @plain: Plaintext key to be wrapped, n * 64 bits
+ * @cipher: Wrapped key, (n + 1) * 64 bits
  * Returns: 0 on success, -1 on failure
  */
 int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
@@ -88,9 +89,10 @@
 /**
  * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
  * @kek: Key encryption key (KEK)
- * @n: Length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
- * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bit
- * @plain: Plaintext key, n * 64 bit
+ * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
+ * bytes
+ * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits
+ * @plain: Plaintext key, n * 64 bits
  * Returns: 0 on success, -1 on failure (e.g., integrity verification failed)
  */
 int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
@@ -162,10 +164,11 @@
 
 
 /**
- * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
+ * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
  * @key: 128-bit key for the hash operation
- * @data: Data buffer for which a MAC is determined
- * @data: Length of data buffer in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
  * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
  * Returns: 0 on success, -1 on failure
  *
@@ -173,21 +176,37 @@
  * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
  * (SP) 800-38B.
  */
-int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+			 const u8 *addr[], const size_t *len, u8 *mac)
 {
 	void *ctx;
 	u8 cbc[BLOCK_SIZE], pad[BLOCK_SIZE];
-	const u8 *pos = data;
-	size_t i, left = data_len;
+	const u8 *pos, *end;
+	size_t i, e, left, total_len;
 
 	ctx = aes_encrypt_init(key, 16);
 	if (ctx == NULL)
 		return -1;
 	os_memset(cbc, 0, BLOCK_SIZE);
 
+	total_len = 0;
+	for (e = 0; e < num_elem; e++)
+		total_len += len[e];
+	left = total_len;
+
+	e = 0;
+	pos = addr[0];
+	end = pos + len[0];
+
 	while (left >= BLOCK_SIZE) {
-		for (i = 0; i < BLOCK_SIZE; i++)
+		for (i = 0; i < BLOCK_SIZE; i++) {
 			cbc[i] ^= *pos++;
+			if (pos >= end) {
+				e++;
+				pos = addr[e];
+				end = pos + len[e];
+			}
+		}
 		if (left > BLOCK_SIZE)
 			aes_encrypt(ctx, cbc, cbc);
 		left -= BLOCK_SIZE;
@@ -197,9 +216,15 @@
 	aes_encrypt(ctx, pad, pad);
 	gf_mulx(pad);
 
-	if (left || data_len == 0) {
-		for (i = 0; i < left; i++)
+	if (left || total_len == 0) {
+		for (i = 0; i < left; i++) {
 			cbc[i] ^= *pos++;
+			if (pos >= end) {
+				e++;
+				pos = addr[e];
+				end = pos + len[e];
+			}
+		}
 		cbc[left] ^= 0x80;
 		gf_mulx(pad);
 	}
@@ -209,6 +234,24 @@
 	aes_encrypt(ctx, pad, mac);
 	aes_encrypt_deinit(ctx);
 	return 0;
+}
+
+
+/**
+ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
+ * @key: 128-bit key for the hash operation
+ * @data: Data buffer for which a MAC is determined
+ * @data_len: Length of data buffer in bytes
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+	return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
 }
 
 #endif /* CONFIG_NO_AES_OMAC1 */

Modified: wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.h (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.h Sat Nov  3 08:40:37 2007
@@ -7,7 +7,7 @@
  * - AES-128 EAX mode encryption/decryption
  * - AES-128 CBC
  *
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -24,6 +24,8 @@
 
 int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher);
 int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain);
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+			 const u8 *addr[], const size_t *len, u8 *mac);
 int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac);
 int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
 int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,

Modified: wpasupplicant/branches/upstream/current/src/crypto/crypto.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/crypto.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/crypto.h (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/crypto.h Sat Nov  3 08:40:37 2007
@@ -316,6 +316,23 @@
 int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
 					const u8 *in, size_t inlen,
 					u8 *out, size_t *outlen);
+
+/**
+ * crypto_private_key_decrypt_pkcs1_v15 - Private key decryption (PKCS #1 v1.5)
+ * @key: Private key
+ * @in: Encrypted buffer
+ * @inlen: Length of encrypted buffer in bytes
+ * @out: Output buffer for encrypted data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key,
+					 const u8 *in, size_t inlen,
+					 u8 *out, size_t *outlen);
 
 /**
  * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1)

Modified: wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c Sat Nov  3 08:40:37 2007
@@ -539,6 +539,39 @@
 }
 
 
+int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key,
+					 const u8 *in, size_t inlen,
+					 u8 *out, size_t *outlen)
+{
+	struct crypto_rsa_key *rkey = (struct crypto_rsa_key *) key;
+	int res;
+	u8 *pos, *end;
+
+	res = crypto_rsa_exptmod(in, inlen, out, outlen, rkey, 1);
+	if (res)
+		return res;
+
+	if (*outlen < 2 || out[0] != 0 || out[1] != 2)
+		return -1;
+
+	/* Skip PS (pseudorandom non-zero octets) */
+	pos = out + 2;
+	end = out + *outlen;
+	while (*pos && pos < end)
+		pos++;
+	if (pos == end)
+		return -1;
+	pos++;
+
+	*outlen -= pos - out;
+
+	/* Strip PKCS #1 header */
+	os_memmove(out, pos, *outlen);
+
+	return 0;
+}
+
+
 int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
 				  const u8 *in, size_t inlen,
 				  u8 *out, size_t *outlen)
@@ -576,21 +609,39 @@
 	 * PKCS #1 v1.5, 8.1:
 	 *
 	 * EB = 00 || BT || PS || 00 || D
-	 * BT = 01
-	 * PS = k-3-||D|| times FF
+	 * BT = 00 or 01
+	 * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01)
 	 * k = length of modulus in octets
 	 */
 
 	if (len < 3 + 8 + 16 /* min hash len */ ||
-	    plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
+	    plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) {
 		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
 			   "structure");
 		return -1;
 	}
 
 	pos = plain + 3;
-	while (pos < plain + len && *pos == 0xff)
-		pos++;
+	if (plain[1] == 0x00) {
+		/* BT = 00 */
+		if (plain[2] != 0x00) {
+			wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
+				   "PS (BT=00)");
+			return -1;
+		}
+		while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00)
+			pos++;
+	} else {
+		/* BT = 01 */
+		if (plain[2] != 0xff) {
+			wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
+				   "PS (BT=01)");
+			return -1;
+		}
+		while (pos < plain + len && *pos == 0xff)
+			pos++;
+	}
+
 	if (pos - plain - 2 < 8) {
 		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
 		wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "

Modified: wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c Sat Nov  3 08:40:37 2007
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -411,9 +411,8 @@
  * @block: 16-octet Block (IN)
  * @cypher: 16-octer Cypher (OUT)
  */
-static void nt_password_hash_encrypted_with_block(const u8 *password_hash,
-						  const u8 *block,
-						  u8 *cypher)
+void nt_password_hash_encrypted_with_block(const u8 *password_hash,
+					   const u8 *block, u8 *cypher)
 {
 	des_encrypt(password_hash, block, cypher);
 	des_encrypt(password_hash + 8, block + 7, cypher + 8);

Modified: wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.h (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.h Sat Nov  3 08:40:37 2007
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
- * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -47,10 +47,15 @@
 void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
 			     size_t session_key_len, int is_send,
 			     int is_server);
+int encrypt_pw_block_with_password_hash(
+	const u8 *password, size_t password_len,
+	const u8 *password_hash, u8 *pw_block);
 void new_password_encrypted_with_old_nt_password_hash(
 	const u8 *new_password, size_t new_password_len,
 	const u8 *old_password, size_t old_password_len,
 	u8 *encrypted_pw_block);
+void nt_password_hash_encrypted_with_block(const u8 *password_hash,
+					   const u8 *block, u8 *cypher);
 void old_nt_password_hash_encrypted_with_new_nt_password_hash(
 	const u8 *new_password, size_t new_password_len,
 	const u8 *old_password, size_t old_password_len,

Modified: wpasupplicant/branches/upstream/current/src/crypto/sha256.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/sha256.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/sha256.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/sha256.c Sat Nov  3 08:40:37 2007
@@ -107,7 +107,7 @@
 
 
 /**
- * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5a.3)
+ * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
  * @key: Key for PRF
  * @key_len: Length of the key in bytes
  * @label: A unique label for each purpose of the PRF
@@ -132,7 +132,7 @@
 	addr[0] = counter_le;
 	len[0] = 2;
 	addr[1] = (u8 *) label;
-	len[1] = os_strlen(label) + 1;
+	len[1] = os_strlen(label);
 	addr[2] = data;
 	len[2] = data_len;
 	addr[3] = length_le;

Modified: wpasupplicant/branches/upstream/current/src/crypto/tls.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls.h (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls.h Sat Nov  3 08:40:37 2007
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / SSL/TLS interface definition
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -364,17 +364,6 @@
  */
 int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn);
 
-/**
- * tls_connection_set_master_key - Configure master secret for TLS connection
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @key: TLS pre-master-secret
- * @key_len: length of key in bytes
- * Returns: 0 on success, -1 on failure
- */
-int tls_connection_set_master_key(void *tls_ctx, struct tls_connection *conn,
-				  const u8 *key, size_t key_len);
-
 enum {
 	TLS_CIPHER_NONE,
 	TLS_CIPHER_RC4_SHA /* 0x0005 */,
@@ -518,4 +507,13 @@
 					   struct tls_connection *conn,
 					   const u8 *key, size_t key_len);
 
+typedef int (*tls_session_ticket_cb)
+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
+ const u8 *server_random, u8 *master_secret);
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+					 struct tls_connection *conn,
+					 tls_session_ticket_cb cb,
+					 void *ctx);
+
 #endif /* TLS_H */

Modified: wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c Sat Nov  3 08:40:37 2007
@@ -1157,14 +1157,6 @@
 }
 
 
-int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
-				  const u8 *key, size_t key_len)
-{
-	/* TODO */
-	return -1;
-}
-
-
 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
 				   u8 *ciphers)
 {

Modified: wpasupplicant/branches/upstream/current/src/crypto/tls_internal.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls_internal.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_internal.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_internal.c Sat Nov  3 08:40:37 2007
@@ -20,16 +20,20 @@
 #include "common.h"
 #include "tls.h"
 #include "tls/tlsv1_client.h"
+#include "tls/tlsv1_server.h"
 
 
 static int tls_ref_count = 0;
 
 struct tls_global {
-	int dummy;
+	int server;
+	struct tlsv1_credentials *server_cred;
+	int check_crl;
 };
 
 struct tls_connection {
 	struct tlsv1_client *client;
+	struct tlsv1_server *server;
 };
 
 
@@ -38,8 +42,14 @@
 	struct tls_global *global;
 
 	if (tls_ref_count == 0) {
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
 		if (tlsv1_client_global_init())
 			return NULL;
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+		if (tlsv1_server_global_init())
+			return NULL;
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
 	}
 	tls_ref_count++;
 
@@ -55,7 +65,13 @@
 	struct tls_global *global = ssl_ctx;
 	tls_ref_count--;
 	if (tls_ref_count == 0) {
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
 		tlsv1_client_global_deinit();
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+		tlsv1_cred_free(global->server_cred);
+		tlsv1_server_global_deinit();
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
 	}
 	os_free(global);
 }
@@ -70,16 +86,30 @@
 struct tls_connection * tls_connection_init(void *tls_ctx)
 {
 	struct tls_connection *conn;
+	struct tls_global *global = tls_ctx;
 
 	conn = os_zalloc(sizeof(*conn));
 	if (conn == NULL)
 		return NULL;
 
-	conn->client = tlsv1_client_init();
-	if (conn->client == NULL) {
-		os_free(conn);
-		return NULL;
-	}
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (!global->server) {
+		conn->client = tlsv1_client_init();
+		if (conn->client == NULL) {
+			os_free(conn);
+			return NULL;
+		}
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (global->server) {
+		conn->server = tlsv1_server_init(global->server_cred);
+		if (conn->server == NULL) {
+			os_free(conn);
+			return NULL;
+		}
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
 
 	return conn;
 }
@@ -89,74 +119,170 @@
 {
 	if (conn == NULL)
 		return;
-	tlsv1_client_deinit(conn->client);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		tlsv1_client_deinit(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		tlsv1_server_deinit(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
 	os_free(conn);
 }
 
 
 int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
 {
-	return tlsv1_client_established(conn->client);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_established(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_established(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return 0;
 }
 
 
 int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
 {
-	return tlsv1_client_shutdown(conn->client);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_shutdown(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_shutdown(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
 }
 
 
 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 			      const struct tls_connection_params *params)
 {
-	if (tlsv1_client_set_ca_cert(conn->client, params->ca_cert,
-				     params->ca_cert_blob,
-				     params->ca_cert_blob_len,
-				     params->ca_path)) {
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	struct tlsv1_credentials *cred;
+
+	if (conn->client == NULL)
+		return -1;
+
+	cred = tlsv1_cred_alloc();
+	if (cred == NULL)
+		return -1;
+
+	if (tlsv1_set_ca_cert(cred, params->ca_cert,
+			      params->ca_cert_blob, params->ca_cert_blob_len,
+			      params->ca_path)) {
 		wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
 			   "certificates");
-		return -1;
-	}
-
-	if (tlsv1_client_set_client_cert(conn->client, params->client_cert,
-					 params->client_cert_blob,
-					 params->client_cert_blob_len)) {
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (tlsv1_set_cert(cred, params->client_cert,
+			   params->client_cert_blob,
+			   params->client_cert_blob_len)) {
 		wpa_printf(MSG_INFO, "TLS: Failed to configure client "
 			   "certificate");
-		return -1;
-	}
-
-	if (tlsv1_client_set_private_key(conn->client,
-					 params->private_key,
-					 params->private_key_passwd,
-					 params->private_key_blob,
-					 params->private_key_blob_len)) {
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (tlsv1_set_private_key(cred, params->private_key,
+				  params->private_key_passwd,
+				  params->private_key_blob,
+				  params->private_key_blob_len)) {
 		wpa_printf(MSG_INFO, "TLS: Failed to load private key");
-		return -1;
-	}
-
-	return 0;
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
+			       params->dh_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (tlsv1_client_set_cred(conn->client, cred) < 0) {
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	return 0;
+#else /* CONFIG_TLS_INTERNAL_CLIENT */
+	return -1;
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
 }
 
 
 int tls_global_set_params(void *tls_ctx,
 			  const struct tls_connection_params *params)
 {
-	wpa_printf(MSG_INFO, "TLS: not implemented - %s", __func__);
-	return -1;
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	struct tls_global *global = tls_ctx;
+	struct tlsv1_credentials *cred;
+
+	/* Currently, global parameters are only set when running in server
+	 * mode. */
+	global->server = 1;
+	tlsv1_cred_free(global->server_cred);
+	global->server_cred = cred = tlsv1_cred_alloc();
+	if (cred == NULL)
+		return -1;
+
+	if (tlsv1_set_ca_cert(cred, params->ca_cert, params->ca_cert_blob,
+			      params->ca_cert_blob_len, params->ca_path)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
+			   "certificates");
+		return -1;
+	}
+
+	if (tlsv1_set_cert(cred, params->client_cert, params->client_cert_blob,
+			   params->client_cert_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to configure server "
+			   "certificate");
+		return -1;
+	}
+
+	if (tlsv1_set_private_key(cred, params->private_key,
+				  params->private_key_passwd,
+				  params->private_key_blob,
+				  params->private_key_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load private key");
+		return -1;
+	}
+
+	if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
+			       params->dh_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
+		return -1;
+	}
+
+	return 0;
+#else /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
 }
 
 
 int tls_global_set_verify(void *tls_ctx, int check_crl)
 {
-	wpa_printf(MSG_INFO, "TLS: not implemented - %s", __func__);
-	return -1;
+	struct tls_global *global = tls_ctx;
+	global->check_crl = check_crl;
+	return 0;
 }
 
 
 int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
 			      int verify_peer)
 {
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_set_verify(conn->server, verify_peer);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
 	return -1;
 }
 
@@ -171,7 +297,15 @@
 int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
 			    struct tls_keys *keys)
 {
-	return tlsv1_client_get_keys(conn->client, keys);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_get_keys(conn->client, keys);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_keys(conn->server, keys);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
 }
 
 
@@ -179,8 +313,21 @@
 		       const char *label, int server_random_first,
 		       u8 *out, size_t out_len)
 {
-	return tlsv1_client_prf(conn->client, label, server_random_first,
-				out, out_len);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		return tlsv1_client_prf(conn->client, label,
+					server_random_first,
+					out, out_len);
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server) {
+		return tlsv1_server_prf(conn->server, label,
+					server_random_first,
+					out, out_len);
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
 }
 
 
@@ -189,6 +336,10 @@
 			      size_t *out_len, u8 **appl_data,
 			      size_t *appl_data_len)
 {
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client == NULL)
+		return NULL;
+
 	if (appl_data)
 		*appl_data = NULL;
 
@@ -196,6 +347,9 @@
 		   __func__, in_data, (unsigned long) in_len);
 	return tlsv1_client_handshake(conn->client, in_data, in_len, out_len,
 				      appl_data, appl_data_len);
+#else /* CONFIG_TLS_INTERNAL_CLIENT */
+	return NULL;
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
 }
 
 
@@ -204,8 +358,20 @@
 				     const u8 *in_data, size_t in_len,
 				     size_t *out_len)
 {
-	wpa_printf(MSG_INFO, "TLS: not implemented - %s", __func__);
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	u8 *out;
+	if (conn->server == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "TLS: %s(in_data=%p in_len=%lu)",
+		   __func__, in_data, (unsigned long) in_len);
+	out = tlsv1_server_handshake(conn->server, in_data, in_len, out_len);
+	if (out == NULL && tlsv1_server_established(conn->server))
+		out = os_malloc(1);
+	return out;
+#else /* CONFIG_TLS_INTERNAL_SERVER */
 	return NULL;
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
 }
 
 
@@ -213,8 +379,19 @@
 			   const u8 *in_data, size_t in_len,
 			   u8 *out_data, size_t out_len)
 {
-	return tlsv1_client_encrypt(conn->client, in_data, in_len, out_data,
-				    out_len);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		return tlsv1_client_encrypt(conn->client, in_data, in_len,
+					    out_data, out_len);
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server) {
+		return tlsv1_server_encrypt(conn->server, in_data, in_len,
+					    out_data, out_len);
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
 }
 
 
@@ -222,28 +399,48 @@
 			   const u8 *in_data, size_t in_len,
 			   u8 *out_data, size_t out_len)
 {
-	return tlsv1_client_decrypt(conn->client, in_data, in_len, out_data,
-				    out_len);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		return tlsv1_client_decrypt(conn->client, in_data, in_len,
+					    out_data, out_len);
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server) {
+		return tlsv1_server_decrypt(conn->server, in_data, in_len,
+					    out_data, out_len);
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
 }
 
 
 int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
 {
-	return tlsv1_client_resumed(conn->client);
-}
-
-
-int tls_connection_set_master_key(void *tls_ctx, struct tls_connection *conn,
-				  const u8 *key, size_t key_len)
-{
-	return tlsv1_client_set_master_key(conn->client, key, key_len);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_resumed(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_resumed(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
 }
 
 
 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
 				   u8 *ciphers)
 {
-	return tlsv1_client_set_cipher_list(conn->client, ciphers);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_set_cipher_list(conn->client, ciphers);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_set_cipher_list(conn->server, ciphers);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
 }
 
 
@@ -252,7 +449,15 @@
 {
 	if (conn == NULL)
 		return -1;
-	return tlsv1_client_get_cipher(conn->client, buf, buflen);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_get_cipher(conn->client, buf, buflen);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_cipher(conn->server, buf, buflen);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
 }
 
 
@@ -267,7 +472,13 @@
 				    int ext_type, const u8 *data,
 				    size_t data_len)
 {
-	return tlsv1_client_hello_ext(conn->client, ext_type, data, data_len);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		return tlsv1_client_hello_ext(conn->client, ext_type,
+					      data, data_len);
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+	return -1;
 }
 
 
@@ -293,7 +504,15 @@
 int tls_connection_get_keyblock_size(void *tls_ctx,
 				     struct tls_connection *conn)
 {
-	return tlsv1_client_get_keyblock_size(conn->client);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_get_keyblock_size(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_keyblock_size(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
 }
 
 
@@ -325,3 +544,24 @@
 {
 	return -1;
 }
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+					 struct tls_connection *conn,
+					 tls_session_ticket_cb cb,
+					 void *ctx)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx);
+		return 0;
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server) {
+		tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx);
+		return 0;
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}

Modified: wpasupplicant/branches/upstream/current/src/crypto/tls_none.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls_none.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_none.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_none.c Sat Nov  3 08:40:37 2007
@@ -147,13 +147,6 @@
 }
 
 
-int tls_connection_set_master_key(void *tls_ctx, struct tls_connection *conn,
-				  const u8 *key, size_t key_len)
-{
-	return -1;
-}
-
-
 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
 				   u8 *ciphers)
 {

Modified: wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c Sat Nov  3 08:40:37 2007
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / SSL/TLS interface functions for openssl
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -49,8 +49,12 @@
 	char *subject_match, *altsubject_match;
 	int read_alerts, write_alerts, failed;
 
-	u8 *pre_shared_secret;
-	size_t pre_shared_secret_len;
+	tls_session_ticket_cb session_ticket_cb;
+	void *session_ticket_cb_ctx;
+
+	/* SessionTicket received from OpenSSL hello_extension_cb (server) */
+	u8 *session_ticket;
+	size_t session_ticket_len;
 };
 
 
@@ -919,11 +923,11 @@
 {
 	if (conn == NULL)
 		return;
-	os_free(conn->pre_shared_secret);
 	SSL_free(conn->ssl);
 	tls_engine_deinit(conn);
 	os_free(conn->subject_match);
 	os_free(conn->altsubject_match);
+	os_free(conn->session_ticket);
 	os_free(conn);
 }
 
@@ -1760,6 +1764,80 @@
 }
 
 
+static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
+{
+#ifdef OPENSSL_NO_DH
+	if (dh_file == NULL)
+		return 0;
+	wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
+		   "dh_file specified");
+	return -1;
+#else /* OPENSSL_NO_DH */
+	DH *dh;
+	BIO *bio;
+
+	/* TODO: add support for dh_blob */
+	if (dh_file == NULL)
+		return 0;
+	if (ssl_ctx == NULL)
+		return -1;
+
+	bio = BIO_new_file(dh_file, "r");
+	if (bio == NULL) {
+		wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
+			   dh_file, ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+	BIO_free(bio);
+#ifndef OPENSSL_NO_DSA
+	while (dh == NULL) {
+		DSA *dsa;
+		wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
+			   " trying to parse as DSA params", dh_file,
+			   ERR_error_string(ERR_get_error(), NULL));
+		bio = BIO_new_file(dh_file, "r");
+		if (bio == NULL)
+			break;
+		dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
+		BIO_free(bio);
+		if (!dsa) {
+			wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
+				   "'%s': %s", dh_file,
+				   ERR_error_string(ERR_get_error(), NULL));
+			break;
+		}
+
+		wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
+		dh = DSA_dup_DH(dsa);
+		DSA_free(dsa);
+		if (dh == NULL) {
+			wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
+				   "params into DH params");
+			break;
+		}
+		break;
+	}
+#endif /* !OPENSSL_NO_DSA */
+	if (dh == NULL) {
+		wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
+			   "'%s'", dh_file);
+		return -1;
+	}
+
+	if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) {
+		wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
+			   "%s", dh_file,
+			   ERR_error_string(ERR_get_error(), NULL));
+		DH_free(dh);
+		return -1;
+	}
+	DH_free(dh);
+	return 0;
+#endif /* OPENSSL_NO_DH */
+}
+
+
 int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
 			    struct tls_keys *keys)
 {
@@ -1998,57 +2076,6 @@
 {
 	return conn ? conn->ssl->hit : 0;
 }
-
-
-#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC)
-/* Pre-shared secred requires a patch to openssl, so this function is
- * commented out unless explicitly needed for EAP-FAST in order to be able to
- * build this file with unmodified openssl. */
-
-static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
-			   STACK_OF(SSL_CIPHER) *peer_ciphers,
-			   SSL_CIPHER **cipher, void *arg)
-{
-	struct tls_connection *conn = arg;
-
-	if (conn == NULL || conn->pre_shared_secret == 0)
-		return 0;
-
-	os_memcpy(secret, conn->pre_shared_secret,
-		  conn->pre_shared_secret_len);
-	*secret_len = conn->pre_shared_secret_len;
-
-	return 1;
-}
-
-
-int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
-				  const u8 *key, size_t key_len)
-{
-	if (conn == NULL || key_len > SSL_MAX_MASTER_KEY_LENGTH)
-		return -1;
-
-	os_free(conn->pre_shared_secret);
-	conn->pre_shared_secret = NULL;
-	conn->pre_shared_secret_len = 0;
-
-	if (key) {
-		conn->pre_shared_secret = os_malloc(key_len);
-		if (conn->pre_shared_secret) {
-			os_memcpy(conn->pre_shared_secret, key, key_len);
-			conn->pre_shared_secret_len = key_len;
-		}
-		if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
-					      conn) != 1)
-			return -1;
-	} else {
-		if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
-			return -1;
-	}
-
-	return 0;
-}
-#endif /* EAP_FAST || EAP_FAST_DYNAMIC */
 
 
 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
@@ -2255,6 +2282,12 @@
 				   params->private_key_passwd))
 		return -1;
 
+	if (tls_global_dh(ssl_ctx, params->dh_file)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
+			   params->dh_file);
+		return -1;
+	}
+
 	return 0;
 }
 
@@ -2272,7 +2305,11 @@
 		return -1;
 
 	c = conn->ssl->enc_read_ctx->cipher;
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+	h = EVP_MD_CTX_md(conn->ssl->read_hash);
+#else
 	h = conn->ssl->read_hash;
+#endif
 
 	return 2 * (EVP_CIPHER_key_length(c) +
 		    EVP_MD_size(h) +
@@ -2315,3 +2352,131 @@
 {
 	return -1;
 }
+
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC)
+/* Pre-shared secred requires a patch to openssl, so this function is
+ * commented out unless explicitly needed for EAP-FAST in order to be able to
+ * build this file with unmodified openssl. */
+
+static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
+			   STACK_OF(SSL_CIPHER) *peer_ciphers,
+			   SSL_CIPHER **cipher, void *arg)
+{
+	struct tls_connection *conn = arg;
+	int ret;
+
+	if (conn == NULL || conn->session_ticket_cb == NULL)
+		return 0;
+
+	ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
+				      conn->session_ticket,
+				      conn->session_ticket_len,
+				      s->s3->client_random,
+				      s->s3->server_random, secret);
+	os_free(conn->session_ticket);
+	conn->session_ticket = NULL;
+
+	if (ret <= 0)
+		return 0;
+
+	*secret_len = SSL_MAX_MASTER_KEY_LENGTH;
+	return 1;
+}
+
+
+#ifdef SSL_OP_NO_TICKET
+static void tls_hello_ext_cb(SSL *s, int client_server, int type,
+			     unsigned char *data, int len, void *arg)
+{
+	struct tls_connection *conn = arg;
+
+	if (conn == NULL || conn->session_ticket_cb == NULL)
+		return;
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
+		   type, len);
+
+	if (type == TLSEXT_TYPE_session_ticket && !client_server) {
+		os_free(conn->session_ticket);
+		conn->session_ticket = NULL;
+
+		wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
+			    "extension", data, len);
+		conn->session_ticket = os_malloc(len);
+		if (conn->session_ticket == NULL)
+			return;
+
+		os_memcpy(conn->session_ticket, data, len);
+		conn->session_ticket_len = len;
+	}
+}
+#else /* SSL_OP_NO_TICKET */
+static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg)
+{
+	struct tls_connection *conn = arg;
+
+	if (conn == NULL || conn->session_ticket_cb == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
+		   ext->type, ext->length);
+
+	os_free(conn->session_ticket);
+	conn->session_ticket = NULL;
+
+	if (ext->type == 35) {
+		wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
+			    "extension", ext->data, ext->length);
+		conn->session_ticket = os_malloc(ext->length);
+		if (conn->session_ticket == NULL)
+			return SSL_AD_INTERNAL_ERROR;
+
+		os_memcpy(conn->session_ticket, ext->data, ext->length);
+		conn->session_ticket_len = ext->length;
+	}
+
+	return 0;
+}
+#endif /* SSL_OP_NO_TICKET */
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC */
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+					 struct tls_connection *conn,
+					 tls_session_ticket_cb cb,
+					 void *ctx)
+{
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC)
+	conn->session_ticket_cb = cb;
+	conn->session_ticket_cb_ctx = ctx;
+
+	if (cb) {
+		if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
+					      conn) != 1)
+			return -1;
+#ifdef SSL_OP_NO_TICKET
+		SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb);
+		SSL_set_tlsext_debug_arg(conn->ssl, conn);
+#else /* SSL_OP_NO_TICKET */
+		if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb,
+					       conn) != 1)
+			return -1;
+#endif /* SSL_OP_NO_TICKET */
+	} else {
+		if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
+			return -1;
+#ifdef SSL_OP_NO_TICKET
+		SSL_set_tlsext_debug_callback(conn->ssl, NULL);
+		SSL_set_tlsext_debug_arg(conn->ssl, conn);
+#else /* SSL_OP_NO_TICKET */
+		if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1)
+			return -1;
+#endif /* SSL_OP_NO_TICKET */
+	}
+
+	return 0;
+#else /* EAP_FAST || EAP_FAST_DYNAMIC */
+	return -1;
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC */
+}

Modified: wpasupplicant/branches/upstream/current/src/crypto/tls_schannel.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls_schannel.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_schannel.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_schannel.c Sat Nov  3 08:40:37 2007
@@ -654,13 +654,6 @@
 }
 
 
-int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
-				  const u8 *key, size_t key_len)
-{
-	return -1;
-}
-
-
 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
 				   u8 *ciphers)
 {

Added: wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h Sat Nov  3 08:40:37 2007
@@ -1,0 +1,156 @@
+#ifndef APPLE80211_H
+#define APPLE80211_H
+
+/*
+ * Apple80211 framework definitions
+ * This is an undocumented interface and the definitions here are based on
+ * information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and
+ * whatever related information can be found with google and experiments ;-).
+ */
+
+typedef struct __WirelessRef *WirelessRef;
+typedef SInt32 WirelessError;
+#define errWirelessNoError 0
+
+typedef struct WirelessInfo {
+	UInt16 link_qual;
+	UInt16 comms_qual;
+	UInt16 signal;
+	UInt16 noise;
+	UInt16 port_stat;
+	UInt16 client_mode;
+	UInt16 res1;
+	UInt16 power;
+	UInt16 res2;
+	UInt8 bssID[6];
+	UInt8 ssid[34];
+} WirelessInfo;
+
+typedef struct WirelessInfo2 {
+	/* TODO - these are probably not in correct order or complete */
+	WirelessInfo info1;
+	UInt8 macAddress[6];
+} WirelessInfo2;
+
+typedef struct WirelessNetworkInfo {
+	UInt16 channel;
+	UInt16 noise;
+	UInt16 signal;
+	UInt8 bssid[6];
+	UInt16 beacon_int;
+	UInt16 capability;
+	UInt16 ssid_len;
+	UInt8 ssid[32];
+} WirelessNetworkInfo;
+
+typedef int wirelessKeyType; /* TODO */
+
+int WirelessIsAvailable(void);
+WirelessError WirelessAttach(WirelessRef *ref, UInt32 res);
+WirelessError WirelessDetach(WirelessRef ref);
+WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes,
+			      void *out_ptr, int out_bytes);
+WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled);
+WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled);
+WirelessError WirelessSetPower(WirelessRef ref, UInt8 power);
+WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power);
+WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info);
+WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info);
+WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results,
+			   UInt32 strip_dups);
+WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results,
+				CFArrayRef *ibss_results, UInt32 strip_dups);
+WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results,
+				   UInt32 strip_dups, CFStringRef ssid);
+WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid,
+				    UInt32 strip_dups, CFArrayRef *results);
+WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid);
+WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid,
+			      CFStringRef passwd);
+WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid);
+/*
+ * Set WEP key
+ * ref: wireless reference from WirelessAttach()
+ * type: ?
+ * key_idx: 0..3
+ * key_len: 13 for WEP-104 or 0 for clearing the key
+ * key: Pointer to the key or %NULL if key_len = 0
+ */
+WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type,
+			     int key_idx, int key_len,
+			     const unsigned char *key);
+/*
+ * Set WPA key (e.g., PMK for 4-way handshake)
+ * ref: wireless reference from WirelessAttach()
+ * type: 0..4; 1 = PMK
+ * key_len: 16, 32, or 0
+ * key: Pointer to the key or %NULL if key_len = 0
+ */
+WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type,
+				int key_len, const unsigned char *key);
+WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid,
+				CFStringRef key);
+WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res,
+				 CFStringRef key);
+WirelessError WirelessDisassociate(WirelessRef ref);
+
+/*
+ * Get a copy of scan results for the given SSID
+ * The returned dictionary includes following entries:
+ * beaconInterval: CFNumber(kCFNumberSInt32Type)
+ * SSID: CFData buffer of the SSID
+ * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2
+ * name: Name of the network (SSID string)
+ * BSSID: CFData buffer of the BSSID
+ * channel: CFNumber(kCFNumberSInt32Type)
+ * signal: CFNumber(kCFNumberSInt32Type)
+ * appleIE: CFData
+ * WPSNOPINRequired: CFBoolean
+ * noise: CFNumber(kCFNumberSInt32Type)
+ * capability: CFNumber(kCFNumberSInt32Type)
+ * uniCipher: CFArray of CFNumber(kCFNumberSInt32Type)
+ * appleIE_Version: CFNumber(kCFNumberSInt32Type)
+ * appleIE_Robust: CFBoolean
+ * WPSConfigured: CFBoolean
+ * scanWasDirected: CFBoolean
+ * appleIE_Product: CFNumber(kCFNumberSInt32Type)
+ * authModes: CFArray of CFNumber(kCFNumberSInt32Type)
+ * multiCipher: CFNumber(kCFNumberSInt32Type)
+ */
+CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid);
+
+/*
+ * Get information about the current association
+ * The returned dictionary includes following entries:
+ * keyData: CFData buffer of the key (e.g., 32-octet PSK)
+ * multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP?
+ * channel: CFNumber(kCFNumberSInt32Type)
+ * isIBSS: CFBoolean
+ * authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open,
+ *	129 = WPA2-Enterprise
+ * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2
+ * SSID: CFData buffer of the SSID
+ * cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP?
+ */
+CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref);
+
+WirelessError WirelessConfigure(WirelessRef ref);
+
+/*
+ * Get ASP information
+ * The returned dictionary includes following entries:
+ * Version: version number (e.g., 3.0)
+ * Channel: channel (e.g., 1)
+ * Vendor: vendor (e.g., 2)
+ */
+CFDictionaryRef WirelessGetInfoASP(void);
+
+/*
+ * Get a copy of the interface dictionary
+ * The returned dictionary has a key,value pairs for wireless interfaces.
+ * The key is the interface name and the value is the driver identifier, e.g.,
+ * en1: com.apple.driver.AirPort.Atheros
+ */
+CFDictionaryRef WirelessCopyInterfaceDict(void);
+
+#endif /* APPLE80211_H */

Added: wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.c (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.c Sat Nov  3 08:40:37 2007
@@ -1,0 +1,189 @@
+#include "includes.h"
+#include <dlfcn.h>
+
+#include "common.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include "MobileApple80211.h"
+
+/*
+ * Code for dynamically loading Apple80211 functions from Aeropuerto to avoid
+ * having to link with full Preferences.framework.
+ */
+
+static void *aeropuerto = NULL;
+
+
+int _Apple80211Initialized(void)
+{
+	return aeropuerto ? 1 : 0;
+}
+
+
+static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL;
+
+int Apple80211Open(Apple80211Ref *ctx)
+{
+	return __Apple80211Open(ctx);
+}
+
+
+static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL;
+
+int Apple80211Close(Apple80211Ref ctx)
+{
+	return __Apple80211Close(ctx);
+}
+
+
+static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list)
+	= NULL;
+
+int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list)
+{
+	return __Apple80211GetIfListCopy(handle, list);
+}
+
+
+static int (*__Apple80211BindToInterface)(Apple80211Ref handle,
+					  CFStringRef interface) = NULL;
+
+int Apple80211BindToInterface(Apple80211Ref handle,
+			      CFStringRef interface)
+{
+	return __Apple80211BindToInterface(handle, interface);
+}
+
+
+static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle,
+					       CFStringRef *name) = NULL;
+
+int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
+				   CFStringRef *name)
+{
+	return __Apple80211GetInterfaceNameCopy(handle, name);
+}
+
+
+static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle,
+				      CFDictionaryRef *info) = NULL;
+
+int Apple80211GetInfoCopy(Apple80211Ref handle,
+			  CFDictionaryRef *info)
+{
+	return __Apple80211GetInfoCopy(handle, info);
+}
+
+
+static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL;
+
+int Apple80211GetPower(Apple80211Ref handle, char *pwr)
+{
+	return __Apple80211GetPower(handle, pwr);
+}
+
+
+static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL;
+
+int Apple80211SetPower(Apple80211Ref handle, char pwr)
+{
+	return __Apple80211SetPower(handle, pwr);
+}
+
+
+static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list,
+			       CFDictionaryRef parameters) = NULL;
+
+int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
+		   CFDictionaryRef parameters)
+{
+	return __Apple80211Scan(handle, list, parameters);
+}
+
+
+static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss,
+				    CFStringRef arg) = NULL;
+
+int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
+			CFStringRef arg)
+{
+	return __Apple80211Associate(handle, bss, arg);
+}
+
+
+static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle,
+					       CFDictionaryRef bss,
+					       CFStringRef arg,
+					       CFDictionaryRef *info) =
+	NULL;
+
+int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
+				   CFStringRef arg, CFDictionaryRef *info)
+{
+	return __Apple80211AssociateAndCopyInfo(handle, bss, arg, info);
+}
+
+
+static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field,
+				    int unused, void *value) = NULL;
+
+int Apple80211CopyValue(Apple80211Ref handle, int field, int unused,
+			void *value)
+{
+	return __Apple80211CopyValue(handle, field, unused, value);
+}
+
+
+#define DLSYM(s) \
+do { \
+	__ ## s = dlsym(aeropuerto, #s); \
+	if (__ ## s == NULL) { \
+		wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \
+			   "symbol '" #s "' (%s)", dlerror()); \
+		err = 1; \
+	} \
+} while (0)
+
+
+__attribute__ ((constructor))
+void _Apple80211_constructor(void)
+{
+	const char *fname = "/System/Library/SystemConfiguration/"
+		"Aeropuerto.bundle/Aeropuerto";
+	int err = 0;
+
+	aeropuerto = dlopen(fname, RTLD_LAZY);
+	if (!aeropuerto) {
+		wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s "
+			   "for symbols", fname);
+		return;
+	}
+
+	DLSYM(Apple80211Open);
+	DLSYM(Apple80211Close);
+	DLSYM(Apple80211GetIfListCopy);
+	DLSYM(Apple80211BindToInterface);
+	DLSYM(Apple80211GetInterfaceNameCopy);
+	DLSYM(Apple80211GetInfoCopy);
+	DLSYM(Apple80211GetPower);
+	DLSYM(Apple80211SetPower);
+	DLSYM(Apple80211Scan);
+	DLSYM(Apple80211Associate);
+	DLSYM(Apple80211AssociateAndCopyInfo);
+	DLSYM(Apple80211CopyValue);
+
+	if (err) {
+		dlclose(aeropuerto);
+		aeropuerto = NULL;
+	}
+}
+
+
+__attribute__ ((destructor))
+void _Apple80211_destructor(void)
+{
+	if (aeropuerto) {
+		dlclose(aeropuerto);
+		aeropuerto = NULL;
+	}
+}

Added: wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.h (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.h Sat Nov  3 08:40:37 2007
@@ -1,0 +1,42 @@
+#ifndef MOBILEAPPLE80211_H
+#define MOBILEAPPLE80211_H
+
+/*
+ * MobileApple80211 interface for iPhone/iPod touch
+ * These functions are available from Aeropuerto.
+ */
+
+struct Apple80211;
+typedef struct Apple80211 *Apple80211Ref;
+
+int Apple80211Open(Apple80211Ref *ctx);
+int Apple80211Close(Apple80211Ref ctx);
+int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list);
+int Apple80211BindToInterface(Apple80211Ref handle,
+			      CFStringRef interface);
+int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
+				   CFStringRef *name);
+int Apple80211GetInfoCopy(Apple80211Ref handle,
+			  CFDictionaryRef *info);
+int Apple80211GetPower(Apple80211Ref handle, char *pwr);
+int Apple80211SetPower(Apple80211Ref handle, char pwr);
+
+/* parameters can be NULL; returns scan results in CFArrayRef *list;
+ * caller will need to free with CFRelease() */
+int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
+		   CFDictionaryRef parameters);
+
+int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
+			CFStringRef arg);
+int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
+				   CFStringRef arg, CFDictionaryRef *info);
+
+enum {
+	APPLE80211_VALUE_SSID = 1,
+	APPLE80211_VALUE_BSSID = 9
+};
+
+int Apple80211CopyValue(Apple80211Ref handle, int field, int unused,
+			void *value);
+
+#endif /* MOBILEAPPLE80211_H */

Modified: wpasupplicant/branches/upstream/current/src/drivers/driver.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver.h (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver.h Sat Nov  3 08:40:37 2007
@@ -197,6 +197,14 @@
 	 * mobility domain is currently active.
 	 */
 	const u8 *ft_md;
+
+	/**
+	 * passphrase - RSN passphrase for PSK
+	 *
+	 * This value is made available only for WPA/WPA2-Personal (PSK) and
+	 * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE.
+	 */
+	const char *passphrase;
 };
 
 /**
@@ -227,6 +235,9 @@
 #define WPA_DRIVER_FLAGS_DRIVER_IE	0x00000001
 #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
 #define WPA_DRIVER_FLAGS_USER_SPACE_MLME 0x00000004
+/* Driver takes care of RSN 4-way handshake internally; PMK is configured with
+ * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
+#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
 	unsigned int flags;
 };
 
@@ -347,7 +358,8 @@
 	 * set_key - Configure encryption key
 	 * @priv: private driver interface data
 	 * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
-	 *	%WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_DHV);
+	 *	%WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_DHV,
+	 *	%WPA_ALG_PMK);
 	 *	%WPA_ALG_NONE clears the key.
 	 * @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for
 	 *	broadcast/default keys

Added: wpasupplicant/branches/upstream/current/src/drivers/driver_iphone.m
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_iphone.m?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_iphone.m (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_iphone.m Sat Nov  3 08:40:37 2007
@@ -1,0 +1,466 @@
+/*
+ * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
+ * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#define Boolean __DummyBoolean
+#include <CoreFoundation/CoreFoundation.h>
+#undef Boolean
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+
+#include "MobileApple80211.h"
+
+struct wpa_driver_iphone_data {
+	void *ctx;
+	Apple80211Ref wireless_ctx;
+	CFArrayRef scan_results;
+	int ctrl_power;
+};
+
+
+static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
+{
+	const void *res;
+	CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
+						    kCFStringEncodingMacRoman);
+	if (str == NULL)
+		return NULL;
+
+	res = CFDictionaryGetValue(dict, str);
+	CFRelease(str);
+	return res;
+}
+
+
+static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
+{
+	struct wpa_driver_iphone_data *drv = priv;
+	CFDataRef data;
+	int err, len;
+
+	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
+				  &data);
+	if (err != 0) {
+		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
+			   "failed: %d", err);
+		return -1;
+	}
+
+	len = CFDataGetLength(data);
+	if (len > 32) {
+		CFRelease(data);
+		return -1;
+	}
+	os_memcpy(ssid, CFDataGetBytePtr(data), len);
+	CFRelease(data);
+
+	return len;
+}
+
+
+static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
+{
+	struct wpa_driver_iphone_data *drv = priv;
+	CFStringRef data;
+	int err;
+	int a1, a2, a3, a4, a5, a6;
+
+	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
+				  &data);
+	if (err != 0) {
+		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
+			   "failed: %d", err);
+		return -1;
+	}
+
+	sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
+	       "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
+	bssid[0] = a1;
+	bssid[1] = a2;
+	bssid[2] = a3;
+	bssid[3] = a4;
+	bssid[4] = a5;
+	bssid[5] = a6;
+
+	CFRelease(data);
+
+	return 0;
+}
+
+
+static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+	struct wpa_driver_iphone_data *drv = priv;
+	int err;
+
+	if (drv->scan_results) {
+		CFRelease(drv->scan_results);
+		drv->scan_results = NULL;
+	}
+
+	err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
+	if (err) {
+		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
+			   err);
+		return -1;
+	}
+
+	eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
+			       drv->ctx);
+	return 0;
+}
+
+
+static int wpa_driver_iphone_get_scan_results(void *priv,
+					      struct wpa_scan_result *results,
+					      size_t max_size)
+{
+	struct wpa_driver_iphone_data *drv = priv;
+	size_t i, num;
+
+	if (drv->scan_results == NULL)
+		return 0;
+
+	num = CFArrayGetCount(drv->scan_results);
+	if (num > max_size)
+		num = max_size;
+	os_memset(results, 0, num * sizeof(struct wpa_scan_result));
+
+	for (i = 0; i < num; i++) {
+		struct wpa_scan_result *res = &results[i];
+		CFDictionaryRef dict =
+			CFArrayGetValueAtIndex(drv->scan_results, i);
+		CFDataRef data;
+		CFStringRef str;
+		CFNumberRef num;
+		int val;
+
+		data = cfdict_get_key_str(dict, "SSID");
+		if (data) {
+			res->ssid_len = CFDataGetLength(data);
+			if (res->ssid_len > 32)
+				res->ssid_len = 32;
+			os_memcpy(res->ssid, CFDataGetBytePtr(data),
+				  res->ssid_len);
+		}
+
+		str = cfdict_get_key_str(dict, "BSSID");
+		if (str) {
+			int a1, a2, a3, a4, a5, a6;
+			sscanf(CFStringGetCStringPtr(
+				       str, kCFStringEncodingMacRoman),
+			       "%x:%x:%x:%x:%x:%x",
+			       &a1, &a2, &a3, &a4, &a5, &a6);
+			res->bssid[0] = a1;
+			res->bssid[1] = a2;
+			res->bssid[2] = a3;
+			res->bssid[3] = a4;
+			res->bssid[4] = a5;
+			res->bssid[5] = a6;
+		}
+
+		num = cfdict_get_key_str(dict, "CAPABILITIES");
+		if (num) {
+			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+				res->caps = val;
+		}
+
+		num = cfdict_get_key_str(dict, "CHANNEL");
+		if (num) {
+			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+				res->freq = 2407 + val * 5;
+		}
+
+		num = cfdict_get_key_str(dict, "RSSI");
+		if (num) {
+			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+				res->level = val;
+		}
+
+		num = cfdict_get_key_str(dict, "NOISE");
+		if (num) {
+			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+				res->noise = val;
+		}
+
+		data = cfdict_get_key_str(dict, "IE");
+		if (data) {
+			u8 *ptr = (u8 *) CFDataGetBytePtr(data);
+			int len = CFDataGetLength(data);
+			u8 *pos = ptr, *end = ptr + len;
+
+			while (pos + 2 < end) {
+				if (pos + 2 + pos[1] > end)
+					break;
+				if (pos[0] == WLAN_EID_RSN &&
+				    pos[1] <= SSID_MAX_WPA_IE_LEN) {
+					os_memcpy(res->rsn_ie, pos,
+						  2 + pos[1]);
+					res->rsn_ie_len = 2 + pos[1];
+				}
+				if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+				    pos[1] > 4 && pos[2] == 0x00 &&
+				    pos[3] == 0x50 && pos[4] == 0xf2 &&
+				    pos[5] == 0x01) {
+					os_memcpy(res->wpa_ie, pos,
+						  2 + pos[1]);
+					res->wpa_ie_len = 2 + pos[1];
+				}
+
+				pos = pos + 2 + pos[1];
+			}
+		}
+	}
+
+	return num;
+}
+
+
+static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_driver_iphone_data *drv = eloop_ctx;
+	u8 bssid[ETH_ALEN];
+
+	if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
+		eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
+				       drv, drv->ctx);
+		return;
+	}
+
+	wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
+}
+
+
+static int wpa_driver_iphone_associate(
+	void *priv, struct wpa_driver_associate_params *params)
+{
+	struct wpa_driver_iphone_data *drv = priv;
+	int i, num, err;
+	size_t ssid_len;
+	CFDictionaryRef bss = NULL;
+
+	/*
+	 * TODO: Consider generating parameters instead of just using an entry
+	 * from scan results in order to support ap_scan=2.
+	 */
+
+	if (drv->scan_results == NULL) {
+		wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
+			   "associate");
+		return -1;
+	}
+
+	num = CFArrayGetCount(drv->scan_results);
+
+	for (i = 0; i < num; i++) {
+		CFDictionaryRef dict =
+			CFArrayGetValueAtIndex(drv->scan_results, i);
+		CFDataRef data;
+
+		data = cfdict_get_key_str(dict, "SSID");
+		if (data == NULL)
+			continue;
+
+		ssid_len = CFDataGetLength(data);
+		if (ssid_len != params->ssid_len ||
+		    os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
+		    != 0)
+			continue;
+
+		bss = dict;
+		break;
+	}
+
+	if (bss == NULL) {
+		wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
+			   "results - cannot associate");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
+		   "from scan results");
+
+	err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
+	if (err) {
+		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
+			   "%d", err);
+		return -1;
+	}
+
+	/*
+	 * Driver is actually already associated; report association from an
+	 * eloop callback.
+	 */
+	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
+	eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
+			       drv->ctx);
+
+	return 0;
+}
+
+
+static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr,
+				     int key_idx, int set_tx, const u8 *seq,
+				     size_t seq_len, const u8 *key,
+				     size_t key_len)
+{
+	/*
+	 * TODO: Need to either support configuring PMK for 4-way handshake or
+	 * PTK for TKIP/CCMP.
+	 */
+	return -1;
+}
+
+
+static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+	os_memset(capa, 0, sizeof(*capa));
+
+	capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+	capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
+		WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
+	capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
+		WPA_DRIVER_AUTH_LEAP;
+	capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+
+	return 0;
+}
+
+
+static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
+{
+	struct wpa_driver_iphone_data *drv;
+	int err;
+	char power;
+	CFStringRef name;
+	CFDictionaryRef dict;
+
+	drv = os_zalloc(sizeof(*drv));
+	if (drv == NULL)
+		return NULL;
+	drv->ctx = ctx;
+	err = Apple80211Open(&drv->wireless_ctx);
+	if (err) {
+		wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
+			   err);
+		os_free(drv);
+		return NULL;
+	}
+
+	name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
+					 kCFStringEncodingISOLatin1);
+	if (name == NULL) {
+		wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
+		Apple80211Close(drv->wireless_ctx);
+		os_free(drv);
+		return NULL;
+	}
+
+	err = Apple80211BindToInterface(drv->wireless_ctx, name);
+	CFRelease(name);
+
+	if (err) {
+		wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
+			   "failed: %d", err);
+		Apple80211Close(drv->wireless_ctx);
+		os_free(drv);
+		return NULL;
+	}
+
+	err = Apple80211GetPower(drv->wireless_ctx, &power);
+	if (err)
+		wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
+			   err);
+
+	wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
+
+	if (!power) {
+		drv->ctrl_power = 1;
+		err = Apple80211SetPower(drv->wireless_ctx, 1);
+		if (err) {
+			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
+				   "failed: %d", err);
+			Apple80211Close(drv->wireless_ctx);
+			os_free(drv);
+			return NULL;
+		}
+	}
+
+	err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
+	if (err == 0) {
+		CFShow(dict);
+		CFRelease(dict);
+	} else {
+		printf("Apple80211GetInfoCopy: %d\n", err);
+	}
+
+	return drv;
+}
+
+
+static void wpa_driver_iphone_deinit(void *priv)
+{
+	struct wpa_driver_iphone_data *drv = priv;
+	int err;
+
+	eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
+	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
+
+	if (drv->ctrl_power) {
+		wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
+		err = Apple80211SetPower(drv->wireless_ctx, 0);
+		if (err) {
+			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
+				   "failed: %d", err);
+		}
+	}
+
+	err = Apple80211Close(drv->wireless_ctx);
+	if (err) {
+		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
+			   err);
+	}
+
+	if (drv->scan_results)
+		CFRelease(drv->scan_results);
+
+	os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_iphone_ops = {
+	.name = "iphone",
+	.desc = "iPhone/iPod touch Apple80211 driver",
+	.get_ssid = wpa_driver_iphone_get_ssid,
+	.get_bssid = wpa_driver_iphone_get_bssid,
+	.init = wpa_driver_iphone_init,
+	.deinit = wpa_driver_iphone_deinit,
+	.scan = wpa_driver_iphone_scan,
+	.get_scan_results = wpa_driver_iphone_get_scan_results,
+	.associate = wpa_driver_iphone_associate,
+	.set_key = wpa_driver_iphone_set_key,
+	.get_capa = wpa_driver_iphone_get_capa,
+};

Added: wpasupplicant/branches/upstream/current/src/drivers/driver_osx.m
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_osx.m?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_osx.m (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_osx.m Sat Nov  3 08:40:37 2007
@@ -1,0 +1,432 @@
+/*
+ * WPA Supplicant - Mac OS X Apple80211 driver interface
+ * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#define Boolean __DummyBoolean
+#include <CoreFoundation/CoreFoundation.h>
+#undef Boolean
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+
+#include "Apple80211.h"
+
+struct wpa_driver_osx_data {
+	void *ctx;
+	WirelessRef wireless_ctx;
+	CFArrayRef scan_results;
+};
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+extern int wpa_debug_level;
+
+static void dump_dict_cb(const void *key, const void *value, void *context)
+{
+        if (MSG_DEBUG < wpa_debug_level)
+                return;
+
+	wpa_printf(MSG_DEBUG, "Key:");
+	CFShow(key);
+	wpa_printf(MSG_DEBUG, "Value:");
+	CFShow(value);
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries",
+		   title, (unsigned int) CFDictionaryGetCount(dict));
+	CFDictionaryApplyFunction(dict, dump_dict_cb, NULL);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid)
+{
+	struct wpa_driver_osx_data *drv = priv;
+	WirelessError err;
+	WirelessInfo info;
+	int len;
+
+	err = WirelessGetInfo(drv->wireless_ctx, &info);
+	if (err) {
+		wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
+			   (int) err);
+		return -1;
+	}
+	if (!info.power) {
+		wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
+		return -1;
+	}
+
+	for (len = 0; len < 32; len++)
+		if (info.ssid[len] == 0)
+			break;
+
+	os_memcpy(ssid, info.ssid, len);
+	return len;
+}
+
+
+static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid)
+{
+	struct wpa_driver_osx_data *drv = priv;
+	WirelessError err;
+	WirelessInfo info;
+
+	err = WirelessGetInfo(drv->wireless_ctx, &info);
+	if (err) {
+		wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
+			   (int) err);
+		return -1;
+	}
+	if (!info.power) {
+		wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
+		return -1;
+	}
+
+	os_memcpy(bssid, info.bssID, ETH_ALEN);
+	return 0;
+}
+
+
+static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static int wpa_driver_osx_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+	struct wpa_driver_osx_data *drv = priv;
+	WirelessError err;
+
+	if (drv->scan_results) {
+		CFRelease(drv->scan_results);
+		drv->scan_results = NULL;
+	}
+
+	if (ssid) {
+		CFStringRef data;
+		data = CFStringCreateWithBytes(kCFAllocatorDefault,
+					       ssid, ssid_len,
+					       kCFStringEncodingISOLatin1,
+					       FALSE);
+		if (data == NULL) {
+			wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes "
+				   "failed");
+			return -1;
+		}
+
+		err = WirelessDirectedScan(drv->wireless_ctx,
+					   &drv->scan_results, 0, data);
+		CFRelease(data);
+		if (err) {
+			wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan "
+				   "failed: 0x%08x", (unsigned int) err);
+			return -1;
+		}
+	} else {
+		err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0);
+		if (err) {
+			wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: "
+				   "0x%08x", (unsigned int) err);
+			return -1;
+		}
+	}
+
+	eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv,
+			       drv->ctx);
+	return 0;
+}
+
+
+static int wpa_driver_osx_get_scan_results(void *priv,
+					   struct wpa_scan_result *results,
+					   size_t max_size)
+{
+	struct wpa_driver_osx_data *drv = priv;
+	size_t i, num;
+
+	if (drv->scan_results == NULL)
+		return 0;
+
+	num = CFArrayGetCount(drv->scan_results);
+	if (num > max_size)
+		num = max_size;
+	os_memset(results, 0, num * sizeof(struct wpa_scan_result));
+
+	for (i = 0; i < num; i++) {
+		struct wpa_scan_result *res = &results[i];
+		WirelessNetworkInfo *info;
+		info = (WirelessNetworkInfo *)
+			CFDataGetBytePtr(CFArrayGetValueAtIndex(
+						 drv->scan_results, i));
+
+		os_memcpy(res->bssid, info->bssid, ETH_ALEN);
+		if (info->ssid_len > 32) {
+			wpa_printf(MSG_DEBUG, "OSX: Invalid SSID length %d in "
+				   "scan results", (int) info->ssid_len);
+			continue;
+		}
+		os_memcpy(res->ssid, info->ssid, info->ssid_len);
+		res->ssid_len = info->ssid_len;
+		res->caps = info->capability;
+		res->freq = 2407 + info->channel * 5;
+		res->level = info->signal;
+		res->noise = info->noise;
+	}
+
+	return num;
+}
+
+
+static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_driver_osx_data *drv = eloop_ctx;
+	u8 bssid[ETH_ALEN];
+	CFDictionaryRef ai;
+
+	if (wpa_driver_osx_get_bssid(drv, bssid) != 0) {
+		eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout,
+				       drv, drv->ctx);
+		return;
+	}
+
+	ai = WirelessGetAssociationInfo(drv->wireless_ctx);
+	if (ai) {
+		wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo");
+		CFRelease(ai);
+	} else {
+		wpa_printf(MSG_DEBUG, "OSX: Failed to get association info");
+	}
+
+	wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
+}
+
+
+static int wpa_driver_osx_associate(void *priv,
+				    struct wpa_driver_associate_params *params)
+{
+	struct wpa_driver_osx_data *drv = priv;
+	WirelessError err;
+	CFDataRef ssid;
+	CFStringRef key;
+	int assoc_type;
+
+	ssid = CFDataCreate(kCFAllocatorDefault, params->ssid,
+			    params->ssid_len);
+	if (ssid == NULL)
+		return -1;
+
+	/* TODO: support for WEP */
+	if (params->key_mgmt_suite == KEY_MGMT_PSK) {
+		if (params->passphrase == NULL)
+			return -1;
+		key = CFStringCreateWithCString(kCFAllocatorDefault,
+						params->passphrase,
+						kCFStringEncodingISOLatin1);
+		if (key == NULL) {
+			CFRelease(ssid);
+			return -1;
+		}
+	} else
+		key = NULL;
+
+	if (params->key_mgmt_suite == KEY_MGMT_NONE)
+		assoc_type = 0;
+	else
+		assoc_type = 4;
+
+	wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)",
+		   assoc_type, key);
+	err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key);
+	CFRelease(ssid);
+	if (key)
+		CFRelease(key);
+	if (err) {
+		wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x",
+			   (unsigned int) err);
+		return -1;
+	}
+
+	/*
+	 * Driver is actually already associated; report association from an
+	 * eloop callback.
+	 */
+	eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
+	eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv,
+			       drv->ctx);
+
+	return 0;
+}
+
+
+static int wpa_driver_osx_set_key(void *priv, wpa_alg alg, const u8 *addr,
+				  int key_idx, int set_tx, const u8 *seq,
+				  size_t seq_len, const u8 *key,
+				  size_t key_len)
+{
+	struct wpa_driver_osx_data *drv = priv;
+	WirelessError err;
+
+	if (alg == WPA_ALG_WEP) {
+		err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len,
+				     key);
+		if (err != 0) {
+			wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: "
+				   "0x%08x", (unsigned int) err);
+			return -1;
+		}
+
+		return 0;
+	}
+
+	if (alg == WPA_ALG_PMK) {
+		err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key);
+		if (err != 0) {
+			wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: "
+				   "0x%08x", (unsigned int) err);
+			return -1;
+		}
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg);
+	return -1;
+}
+
+
+static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+	os_memset(capa, 0, sizeof(*capa));
+
+	capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+	capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
+		WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
+	capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
+		WPA_DRIVER_AUTH_LEAP;
+	capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+
+	return 0;
+}
+
+
+static void * wpa_driver_osx_init(void *ctx, const char *ifname)
+{
+	struct wpa_driver_osx_data *drv;
+	WirelessError err;
+	u8 enabled, power;
+
+	if (!WirelessIsAvailable()) {
+		wpa_printf(MSG_ERROR, "OSX: No wireless interface available");
+		return NULL;
+	}
+
+	drv = os_zalloc(sizeof(*drv));
+	if (drv == NULL)
+		return NULL;
+	drv->ctx = ctx;
+	err = WirelessAttach(&drv->wireless_ctx, 0);
+	if (err) {
+		wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d",
+			   (int) err);
+		os_free(drv);
+		return NULL;
+	}
+
+	err = WirelessGetEnabled(drv->wireless_ctx, &enabled);
+	if (err)
+		wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x",
+			   (unsigned int) err);
+	err = WirelessGetPower(drv->wireless_ctx, &power);
+	if (err)
+		wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x",
+			   (unsigned int) err);
+
+	wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power);
+
+	if (!enabled) {
+		err = WirelessSetEnabled(drv->wireless_ctx, 1);
+		if (err) {
+			wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:"
+				   " 0x%08x", (unsigned int) err);
+			WirelessDetach(drv->wireless_ctx);
+			os_free(drv);
+			return NULL;
+		}
+	}
+
+	if (!power) {
+		err = WirelessSetPower(drv->wireless_ctx, 1);
+		if (err) {
+			wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: "
+				   "0x%08x", (unsigned int) err);
+			WirelessDetach(drv->wireless_ctx);
+			os_free(drv);
+			return NULL;
+		}
+	}
+
+	return drv;
+}
+
+
+static void wpa_driver_osx_deinit(void *priv)
+{
+	struct wpa_driver_osx_data *drv = priv;
+	WirelessError err;
+
+	eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx);
+	eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
+
+	err = WirelessSetPower(drv->wireless_ctx, 0);
+	if (err) {
+		wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: "
+			   "0x%08x", (unsigned int) err);
+	}
+
+	err = WirelessDetach(drv->wireless_ctx);
+	if (err) {
+		wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x",
+			   (unsigned int) err);
+	}
+
+	if (drv->scan_results)
+		CFRelease(drv->scan_results);
+
+	os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_osx_ops = {
+	.name = "osx",
+	.desc = "Mac OS X Apple80211 driver",
+	.get_ssid = wpa_driver_osx_get_ssid,
+	.get_bssid = wpa_driver_osx_get_bssid,
+	.init = wpa_driver_osx_init,
+	.deinit = wpa_driver_osx_deinit,
+	.scan = wpa_driver_osx_scan,
+	.get_scan_results = wpa_driver_osx_get_scan_results,
+	.associate = wpa_driver_osx_associate,
+	.set_key = wpa_driver_osx_set_key,
+	.get_capa = wpa_driver_osx_get_capa,
+};

Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c Sat Nov  3 08:40:37 2007
@@ -1380,6 +1380,7 @@
 			wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes);
 			return;
 		}
+		bytes /= 2;
 		hexstr2bin(spos, bin, bytes);
 		res->tsf += WPA_GET_BE64(bin);
 	}

Modified: wpasupplicant/branches/upstream/current/src/drivers/drivers.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/drivers.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/drivers.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/drivers.c Sat Nov  3 08:40:37 2007
@@ -58,6 +58,12 @@
 #ifdef CONFIG_DRIVER_RALINK
 extern struct wpa_driver_ops wpa_driver_ralink_ops; /* driver_ralink.c */
 #endif /* CONFIG_DRIVER_RALINK */
+#ifdef CONFIG_DRIVER_OSX
+extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */
+#endif /* CONFIG_DRIVER_OSX */
+#ifdef CONFIG_DRIVER_IPHONE
+extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */
+#endif /* CONFIG_DRIVER_IPHONE */
 
 
 struct wpa_driver_ops *wpa_supplicant_drivers[] =
@@ -104,5 +110,11 @@
 #ifdef CONFIG_DRIVER_RALINK
 	&wpa_driver_ralink_ops,
 #endif /* CONFIG_DRIVER_RALINK */
+#ifdef CONFIG_DRIVER_OSX
+	&wpa_driver_osx_ops,
+#endif /* CONFIG_DRIVER_OSX */
+#ifdef CONFIG_DRIVER_IPHONE
+	&wpa_driver_iphone_ops,
+#endif /* CONFIG_DRIVER_IPHONE */
 	NULL
 };

Added: wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h (added)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h Sat Nov  3 08:40:37 2007
@@ -1,0 +1,85 @@
+/*
+ * EAP-FAST definitions (RFC 4851)
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef EAP_FAST_H
+#define EAP_FAST_H
+
+#define EAP_FAST_VERSION 1
+#define EAP_FAST_KEY_LEN 64
+#define EAP_FAST_SIMCK_LEN 40
+#define EAP_FAST_SKS_LEN 40
+
+#define TLS_EXT_PAC_OPAQUE 35
+
+/*
+ * draft-cam-winget-eap-fast-provisioning-04.txt:
+ * Section 4.2.1 - Formats for PAC TLV Attributes / Type Field
+ * Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined
+ * in the general PAC TLV format (Section 4.2).
+ */
+#define PAC_TYPE_PAC_KEY 1
+#define PAC_TYPE_PAC_OPAQUE 2
+#define PAC_TYPE_CRED_LIFETIME 3
+#define PAC_TYPE_A_ID 4
+#define PAC_TYPE_I_ID 5
+/*
+ * 6 was previous assigned for SERVER_PROTECTED_DATA, but
+ * draft-cam-winget-eap-fast-provisioning-02.txt changed this to Reserved.
+ */
+#define PAC_TYPE_A_ID_INFO 7
+#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8
+#define PAC_TYPE_PAC_INFO 9
+#define PAC_TYPE_PAC_TYPE 10
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct pac_tlv_hdr {
+	be16 type;
+	be16 len;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+#define EAP_FAST_PAC_KEY_LEN 32
+
+/* draft-cam-winget-eap-fast-provisioning-04.txt: 4.2.6 PAC-Type TLV
+ * Note: Machine Authentication PAC and User Authorization PAC were removed in
+ * draft-cam-winget-eap-fast-provisioning-03.txt
+ */
+#define PAC_TYPE_TUNNEL_PAC 1
+/* Application Specific Short Lived PACs (only in volatile storage) */
+/* User Authorization PAC */
+#define PAC_TYPE_USER_AUTHORIZATION 3
+/* Application Specific Long Lived PACs */
+/* Machine Authentication PAC */
+#define PAC_TYPE_MACHINE_AUTHENTICATION 2
+
+
+/*
+ * draft-cam-winget-eap-fast-provisioning-04.txt:
+ * Section 3.4 - Key Derivations Used in the EAP-FAST Provisioning Exchange
+ */
+struct eap_fast_key_block_provisioning {
+	/* Extra key material after TLS key_block */
+	u8 session_key_seed[EAP_FAST_SKS_LEN];
+	u8 server_challenge[16]; /* MSCHAPv2 ServerChallenge */
+	u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */
+};
+
+#endif /* EAP_FAST_H */

Modified: wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.c Sat Nov  3 08:40:37 2007
@@ -18,7 +18,9 @@
 #include "eap_defs.h"
 #include "aes_wrap.h"
 #include "crypto.h"
+#ifdef EAP_GPSK_SHA256
 #include "sha256.h"
+#endif /* EAP_GPSK_SHA256 */
 #include "eap_gpsk_common.h"
 
 
@@ -42,31 +44,29 @@
 }
 
 
-static int eap_gpsk_gkdf(const u8 *psk /* Y */, size_t psk_len,
-			 const u8 *data /* Z */, size_t data_len,
-			 u8 *buf, size_t len /* X */)
+static int eap_gpsk_gkdf_cmac(const u8 *psk /* Y */,
+			      const u8 *data /* Z */, size_t data_len,
+			      u8 *buf, size_t len /* X */)
 {
 	u8 *opos;
 	size_t i, n, hashlen, left, clen;
-	u8 ibuf[2], hash[SHA256_MAC_LEN];
-	const u8 *addr[3];
-	size_t vlen[3];
-
-	hashlen = SHA256_MAC_LEN;
-	/* M_i = Hash-Function (i || Y || Z); */
+	u8 ibuf[2], hash[16];
+	const u8 *addr[2];
+	size_t vlen[2];
+
+	hashlen = sizeof(hash);
+	/* M_i = MAC_Y (i || Z); (MAC = AES-CMAC-128) */
 	addr[0] = ibuf;
 	vlen[0] = sizeof(ibuf);
-	addr[1] = psk;
-	vlen[1] = psk_len;
-	addr[2] = data;
-	vlen[2] = data_len;
+	addr[1] = data;
+	vlen[1] = data_len;
 
 	opos = buf;
 	left = len;
 	n = (len + hashlen - 1) / hashlen;
 	for (i = 1; i <= n; i++) {
 		WPA_PUT_BE16(ibuf, i);
-		sha256_vector(3, addr, vlen, hash);
+		omac1_aes_128_vector(psk, 2, addr, vlen, hash);
 		clen = left > hashlen ? hashlen : left;
 		os_memcpy(opos, hash, clen);
 		opos += clen;
@@ -77,7 +77,42 @@
 }
 
 
-static int eap_gpsk_derive_keys_helper(u32 csuite_specified,
+#ifdef EAP_GPSK_SHA256
+static int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */,
+				const u8 *data /* Z */, size_t data_len,
+				u8 *buf, size_t len /* X */)
+{
+	u8 *opos;
+	size_t i, n, hashlen, left, clen;
+	u8 ibuf[2], hash[SHA256_MAC_LEN];
+	const u8 *addr[2];
+	size_t vlen[2];
+
+	hashlen = SHA256_MAC_LEN;
+	/* M_i = MAC_Y (i || Z); (MAC = HMAC-SHA256) */
+	addr[0] = ibuf;
+	vlen[0] = sizeof(ibuf);
+	addr[1] = data;
+	vlen[1] = data_len;
+
+	opos = buf;
+	left = len;
+	n = (len + hashlen - 1) / hashlen;
+	for (i = 1; i <= n; i++) {
+		WPA_PUT_BE16(ibuf, i);
+		hmac_sha256_vector(psk, 32, 2, addr, vlen, hash);
+		clen = left > hashlen ? hashlen : left;
+		os_memcpy(opos, hash, clen);
+		opos += clen;
+		left -= clen;
+	}
+
+	return 0;
+}
+#endif /* EAP_GPSK_SHA256 */
+
+
+static int eap_gpsk_derive_keys_helper(u32 csuite_specifier,
 				       u8 *kdf_out, size_t kdf_out_len,
 				       const u8 *psk, size_t psk_len,
 				       const u8 *seed, size_t seed_len,
@@ -85,10 +120,28 @@
 				       u8 *sk, size_t sk_len,
 				       u8 *pk, size_t pk_len)
 {
-	u8 zero, mk[32], *pos, *data;
-	size_t data_len;
-
-	zero = 0;
+	u8 zero[32], mk[32], *pos, *data;
+	size_t data_len, mk_len;
+	int (*gkdf)(const u8 *psk, const u8 *data, size_t data_len,
+		    u8 *buf, size_t len);
+
+	gkdf = NULL;
+	switch (csuite_specifier) {
+	case EAP_GPSK_CIPHER_AES:
+		gkdf = eap_gpsk_gkdf_cmac;
+		mk_len = 16;
+		break;
+#ifdef EAP_GPSK_SHA256
+	case EAP_GPSK_CIPHER_SHA256:
+		gkdf = eap_gpsk_gkdf_sha256;
+		mk_len = SHA256_MAC_LEN;
+		break;
+#endif /* EAP_GPSK_SHA256 */
+	default:
+		return -1;
+	}
+
+	os_memset(zero, 0, sizeof(zero));
 
 	data_len = 2 + psk_len + 6 + seed_len;
 	data = os_malloc(data_len);
@@ -99,23 +152,22 @@
 	pos += 2;
 	os_memcpy(pos, psk, psk_len);
 	pos += psk_len;
-	WPA_PUT_BE24(pos, 0); /* CSuite/Vendor = IETF */
-	pos += 3;
-	WPA_PUT_BE24(pos, csuite_specified); /* CSuite/Specifier */
-	pos += 3;
+	WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */
+	pos += 4;
+	WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */
+	pos += 2;
 	os_memcpy(pos, seed, seed_len); /* inputString */
 	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation",
 			data, data_len);
 
-	if (eap_gpsk_gkdf(&zero, 1, data, data_len, mk, sizeof(mk)) < 0) {
+	if (gkdf(zero, data, data_len, mk, mk_len) < 0) {
 		os_free(data);
 		return -1;
 	}
 	os_free(data);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, sizeof(mk));
-
-	if (eap_gpsk_gkdf(mk, sizeof(mk), seed, seed_len,
-			  kdf_out, kdf_out_len) < 0)
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, mk_len);
+
+	if (gkdf(mk, seed, seed_len, kdf_out, kdf_out_len) < 0)
 		return -1;
 
 	pos = kdf_out;
@@ -153,16 +205,15 @@
 	/*
 	 * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
 	 *            (= seed)
-	 * KS = 16, PL = psk_len, CSuite_Sel = 0x000000 0x000001
-	 * MK = GKDF-32 (0x00, PL || PSK || CSuite_Sel || inputString)
+	 * KS = 16, PL = psk_len, CSuite_Sel = 0x00000000 0x0001
+	 * zero = 0x00 || 0x00 || ... || 0x00 (16 times)
+	 * MK = GKDF-16 (zero, PL || PSK || CSuite_Sel || inputString)
 	 * MSK = GKDF-160 (MK, inputString)[0..63]
 	 * EMSK = GKDF-160 (MK, inputString)[64..127]
 	 * SK = GKDF-160 (MK, inputString)[128..143]
 	 * PK = GKDF-160 (MK, inputString)[144..159]
-	 * MID = GKDF-16(0x00, "Method ID" || EAP_Method_Type || CSuite_Sel ||
-	 *               inputString)
-	 * Hash-Function = SHA256 (see [RFC4634])
-	 * hashlen = 32 octets (256 bits)
+	 * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
+	 *                      CSuite_Sel || inputString)
 	 */
 
 	*sk_len = EAP_GPSK_SK_LEN_AES;
@@ -190,15 +241,14 @@
 	/*
 	 * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
 	 *            (= seed)
-	 * KS = 32, PL = psk_len, CSuite_Sel = 0x000000 0x000002
-	 * MK = GKDF-32 (0x00, PL || PSK || CSuite_Sel || inputString)
-	 * MSK = GKDF-192 (MK, inputString)[0..63]
-	 * EMSK = GKDF-192 (MK, inputString)[64..127]
-	 * SK = GKDF-192 (MK, inputString)[128..159]
-	 * MID = GKDF-16(0x00, "Method ID" || EAP_Method_Type || CSuite_Sel ||
-	 *               inputString)
-	 * Hash-Function = SHA256 (see [RFC4634])
-	 * hashlen = 32 octets (256 bits)
+	 * KS = 32, PL = psk_len, CSuite_Sel = 0x00000000 0x0002
+	 * zero = 0x00 || 0x00 || ... || 0x00 (32 times)
+	 * MK = GKDF-32 (zero, PL || PSK || CSuite_Sel || inputString)
+	 * MSK = GKDF-160 (MK, inputString)[0..63]
+	 * EMSK = GKDF-160 (MK, inputString)[64..127]
+	 * SK = GKDF-160 (MK, inputString)[128..159]
+	 * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
+	 *                      CSuite_Sel || inputString)
 	 */
 
 	*sk_len = EAP_GPSK_SK_LEN_SHA256;

Modified: wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.h Sat Nov  3 08:40:37 2007
@@ -32,7 +32,7 @@
 #define EAP_GPSK_MAX_PK_LEN 32
 #define EAP_GPSK_MAX_MIC_LEN 32
 
-#define EAP_GPSK_VENDOR_IETF		0x000000
+#define EAP_GPSK_VENDOR_IETF		0x00000000
 #define EAP_GPSK_CIPHER_RESERVED	0x000000
 #define EAP_GPSK_CIPHER_AES		0x000001
 #define EAP_GPSK_CIPHER_SHA256		0x000002
@@ -43,8 +43,8 @@
 #endif /* _MSC_VER */
 
 struct eap_gpsk_csuite {
-	u8 vendor[3];
-	u8 specifier[3];
+	u8 vendor[4];
+	u8 specifier[2];
 } STRUCT_PACKED;
 
 #ifdef _MSC_VER

Added: wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h (added)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h Sat Nov  3 08:40:37 2007
@@ -1,0 +1,116 @@
+/*
+ * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-07.txt)
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef EAP_TLV_COMMON_H
+#define EAP_TLV_COMMON_H
+
+/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-07.txt) */
+#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
+#define EAP_TLV_NAK_TLV 4
+/* Note: RFC 4851, Section 4.2.4 defines 5 as Error TLV */
+#define EAP_TLV_CRYPTO_BINDING_TLV 5
+#define EAP_TLV_CONNECTION_BINDING_TLV 6
+#define EAP_TLV_VENDOR_SPECIFIC_TLV 7
+#define EAP_TLV_URI_TLV 8
+#define EAP_TLV_EAP_PAYLOAD_TLV 9
+#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
+#define EAP_TLV_PAC_TLV 11 /* draft-cam-winget-eap-fast-provisioning-04.txt,
+			    * Section 4.2 */
+#define EAP_TLV_CRYPTO_BINDING_TLV_ 12 /* RFC 4851, Section 4.2.8 */
+/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.3.1 */
+#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18
+#define EAP_TLV_REQUEST_ACTION_TLV 19 /* RFC 4851, Section 4.2.9 */
+/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.3.2 */
+#define EAP_TLV_PKCS7_TLV 20
+
+#define EAP_TLV_RESULT_SUCCESS 1
+#define EAP_TLV_RESULT_FAILURE 2
+
+#define EAP_TLV_TYPE_MANDATORY 0x8000
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_tlv_hdr {
+	be16 tlv_type;
+	be16 length;
+} STRUCT_PACKED;
+
+struct eap_tlv_nak_tlv {
+	be16 tlv_type;
+	be16 length;
+	be32 vendor_id;
+	be16 nak_type;
+} STRUCT_PACKED;
+
+struct eap_tlv_result_tlv {
+	be16 tlv_type;
+	be16 length;
+	be16 status;
+} STRUCT_PACKED;
+
+/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */
+struct eap_tlv_intermediate_result_tlv {
+	be16 tlv_type;
+	be16 length;
+	be16 status;
+	/* Followed by optional TLVs */
+} STRUCT_PACKED;
+
+/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */
+struct eap_tlv_crypto_binding__tlv {
+	be16 tlv_type;
+	be16 length;
+	u8 reserved;
+	u8 version;
+	u8 received_version;
+	u8 subtype;
+	u8 nonce[32];
+	u8 compound_mac[20];
+} STRUCT_PACKED;
+
+struct eap_tlv_pac_ack_tlv {
+	be16 tlv_type;
+	be16 length;
+	be16 pac_type;
+	be16 pac_len;
+	be16 result;
+} STRUCT_PACKED;
+
+/* RFC 4851, Section 4.2.9 - Request-Action TLV */
+struct eap_tlv_request_action_tlv {
+	be16 tlv_type;
+	be16 length;
+	be16 action;
+} STRUCT_PACKED;
+
+/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.2.6 - PAC-Type TLV */
+struct eap_tlv_pac_type_tlv {
+	be16 tlv_type; /* PAC_TYPE_PAC_TYPE */
+	be16 length;
+	be16 pac_type;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0
+#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
+
+#define EAP_TLV_ACTION_PROCESS_TLV 1
+#define EAP_TLV_ACTION_NEGOTIATE_EAP 2
+
+#endif /* EAP_TLV_COMMON_H */

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap.c Sat Nov  3 08:40:37 2007
@@ -1,6 +1,6 @@
 /*
  * EAP peer state machines (RFC 4137)
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -1788,6 +1788,27 @@
 
 
 /**
+ * eap_get_config_password2 - Get password from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Buffer for the length of the password
+ * @hash: Buffer for returning whether the password is stored as a
+ * NtPasswordHash instead of plaintext password; can be %NULL if this
+ * information is not needed
+ * Returns: Pointer to the password or %NULL if not found
+ */
+const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
+{
+	struct wpa_ssid *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+	*len = config->password_len;
+	if (hash)
+		*hash = !!(config->flags & WPA_CONFIG_FLAGS_PASSWORD_NTHASH);
+	return config->password;
+}
+
+
+/**
  * eap_get_config_new_password - Get new password from network configuration
  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
  * @len: Buffer for the length of the new password

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c Sat Nov  3 08:40:37 2007
@@ -32,27 +32,8 @@
  * - password change (pending mschapv2 packet; replay decrypted packet)
  */
 
-#define EAP_FAST_VERSION 1
-#define EAP_FAST_KEY_LEN 64
-#define EAP_FAST_SIMCK_LEN 40
-#define EAP_FAST_SKS_LEN 40
-
-#define TLS_EXT_PAC_OPAQUE 35
-
 
 static void eap_fast_deinit(struct eap_sm *sm, void *priv);
-
-
-/*
- * draft-cam-winget-eap-fast-provisioning-04.txt:
- * Section 3.4 - Key Derivations Used in the EAP-FAST Provisioning Exchange
- */
-struct eap_fast_key_block_provisioning {
-	/* Extra key material after TLS key_block */
-	u8 session_key_seed[EAP_FAST_SKS_LEN];
-	u8 server_challenge[16]; /* MSCHAPv2 ServerChallenge */
-	u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */
-};
 
 
 struct eap_fast_data {
@@ -75,6 +56,7 @@
 	int provisioning; /* doing PAC provisioning (not the normal auth) */
 	int anon_provisioning; /* doing anonymous (unauthenticated)
 				* provisioning */
+	int session_ticket_used;
 
 	u8 key_data[EAP_FAST_KEY_LEN];
 	u8 emsk[EAP_EMSK_LEN];
@@ -85,14 +67,71 @@
 	size_t max_pac_list_len;
 	int use_pac_binary_format;
 
-	int tls_master_secret_set;
-
 	u8 simck[EAP_FAST_SIMCK_LEN];
 	int simck_idx;
 
 	u8 *pending_phase2_req;
 	size_t pending_phase2_req_len;
 };
+
+
+static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
+				      const u8 *client_random,
+				      const u8 *server_random,
+				      u8 *master_secret)
+{
+	struct eap_fast_data *data = ctx;
+#define TLS_RANDOM_LEN 32
+#define TLS_MASTER_SECRET_LEN 48
+	u8 seed[2 * TLS_RANDOM_LEN];
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
+
+	if (client_random == NULL || server_random == NULL ||
+	    master_secret == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket failed - fall "
+			   "back to full TLS handshake");
+		data->session_ticket_used = 0;
+		if (data->provisioning_allowed) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Try to provision a "
+				   "new PAC-Key");
+			data->provisioning = 1;
+			data->current_pac = NULL;
+		}
+		return 0;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket", ticket, len);
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
+		    client_random, TLS_RANDOM_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
+		    server_random, TLS_RANDOM_LEN);
+
+	if (data->current_pac == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key available for "
+			   "using SessionTicket");
+		data->session_ticket_used = 0;
+		return 0;
+	}
+
+	/*
+	 * RFC 4851, Section 5.1:
+	 * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", 
+	 *                       server_random + client_random, 48)
+	 */
+	os_memcpy(seed, server_random, TLS_RANDOM_LEN);
+	os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
+	sha1_t_prf(data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN,
+		   "PAC to master secret label hash",
+		   seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
+			master_secret, TLS_MASTER_SECRET_LEN);
+
+	data->session_ticket_used = 1;
+
+	return 1;
+}
 
 
 static int eap_fast_parse_phase1(struct eap_fast_data *data,
@@ -160,6 +199,15 @@
 		return NULL;
 	}
 
+	if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+						 eap_fast_session_ticket_cb,
+						 data) < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
+			   "callback");
+		eap_fast_deinit(sm, data);
+		return NULL;
+	}
+
 	/*
 	 * The local RADIUS server in a Cisco AP does not seem to like empty
 	 * fragments before data, so disable that workaround for CBC.
@@ -234,83 +282,6 @@
 	data->success = 1;
 
 	return 0;
-}
-
-
-static int eap_fast_set_tls_master_secret(struct eap_sm *sm,
-					  struct eap_fast_data *data,
-					  const u8 *tls, size_t tls_len)
-{
-	struct tls_keys keys;
-	u8 master_secret[48], *seed;
-	const u8 *server_random;
-	size_t seed_len, server_random_len;
-
-	if (data->tls_master_secret_set || !data->current_pac ||
-	    tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-	    keys.client_random == NULL) {
-		return 0;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
-		    keys.client_random, keys.client_random_len);
-
-	/*
-	 * TLS master secret is needed before TLS library has processed this
-	 * message which includes both ServerHello and an encrypted handshake
-	 * message, so we need to parse server_random from this message before
-	 * passing it to TLS library.
-	 *
-	 * Example TLS packet header:
-	 * (16 03 01 00 2a 02 00 00 26 03 01 <32 bytes server_random>)
-	 * Content Type: Handshake: 0x16
-	 * Version: TLS 1.0 (0x0301)
-	 * Lenghth: 42 (0x002a)
-	 * Handshake Type: Server Hello: 0x02
-	 * Length: 38 (0x000026)
-	 * Version TLS 1.0 (0x0301)
-	 * Random: 32 bytes
-	 */
-	if (tls_len < 43 || tls[0] != 0x16 ||
-	    tls[1] != 0x03 || tls[2] != 0x01 ||
-	    tls[5] != 0x02 || tls[9] != 0x03 || tls[10] != 0x01) {
-		wpa_hexdump(MSG_DEBUG, "EAP-FAST: unrecognized TLS "
-			    "ServerHello", tls, tls_len);
-		return -1;
-	}
-	server_random = tls + 11;
-	server_random_len = 32;
-	wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
-		    server_random, server_random_len);
-
-	seed_len = keys.client_random_len + server_random_len;
-	seed = os_malloc(seed_len);
-	if (seed == NULL)
-		return -1;
-	os_memcpy(seed, server_random, server_random_len);
-	os_memcpy(seed + server_random_len,
-		  keys.client_random, keys.client_random_len);
-
-	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: T-PRF seed", seed, seed_len);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: PAC-Key",
-			data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN);
-	/*
-	 * RFC 4851, Section 5.1:
-	 * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", 
-	 *                       server_random + client_random, 48)
-	 */
-	sha1_t_prf(data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN,
-		   "PAC to master secret label hash",
-		   seed, seed_len, master_secret, sizeof(master_secret));
-	os_free(seed);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: TLS pre-master-secret",
-			master_secret, sizeof(master_secret));
-
-	data->tls_master_secret_set = 1;
-
-	return tls_connection_set_master_key(sm->ssl_ctx, data->ssl.conn,
-					     master_secret,
-					     sizeof(master_secret));
 }
 
 
@@ -1719,21 +1690,6 @@
 			res = 1;
 		}
 	} else {
-		/*
-		 * Try to configure the TLS master secret based on PAC-Key
-		 * and server/client random values. If the needed values are
-		 * not yet available, the function returns 0, so we only abort
-		 * on failure case when configuring the TLS library fails, not
-		 * if the key material is not yet available.
-		 */
-		if (eap_fast_set_tls_master_secret(sm, data, pos, left) < 0) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to configure "
-				   "TLS master secret");
-			ret->methodState = METHOD_DONE;
-			ret->decision = DECISION_FAIL;
-			return NULL;
-		}
-
 		/* Continue processing TLS handshake (phase 1). */
 		res = eap_peer_tls_process_helper(sm, &data->ssl,
 						  EAP_TYPE_FAST,

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast_pac.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast_pac.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast_pac.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast_pac.h Sat Nov  3 08:40:37 2007
@@ -15,54 +15,7 @@
 #ifndef EAP_FAST_PAC_H
 #define EAP_FAST_PAC_H
 
-/*
- * draft-cam-winget-eap-fast-provisioning-04.txt:
- * Section 4.2.1 - Formats for PAC TLV Attributes / Type Field
- * Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined
- * in the general PAC TLV format (Section 4.2).
- */
-#define PAC_TYPE_PAC_KEY 1
-#define PAC_TYPE_PAC_OPAQUE 2
-#define PAC_TYPE_CRED_LIFETIME 3
-#define PAC_TYPE_A_ID 4
-#define PAC_TYPE_I_ID 5
-/*
- * 6 was previous assigned for SERVER_PROTECTED_DATA, but
- * draft-cam-winget-eap-fast-provisioning-02.txt changed this to Reserved.
- */
-#define PAC_TYPE_A_ID_INFO 7
-#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8
-#define PAC_TYPE_PAC_INFO 9
-#define PAC_TYPE_PAC_TYPE 10
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct pac_tlv_hdr {
-	be16 type;
-	be16 len;
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-
-#define EAP_FAST_PAC_KEY_LEN 32
-
-/* draft-cam-winget-eap-fast-provisioning-04.txt: 4.2.6 PAC-Type TLV
- * Note: Machine Authentication PAC and User Authorization PAC were removed in
- * draft-cam-winget-eap-fast-provisioning-03.txt
- */
-#define PAC_TYPE_TUNNEL_PAC 1
-/* Application Specific Short Lived PACs (only in volatile storage) */
-/* User Authorization PAC */
-#define PAC_TYPE_USER_AUTHORIZATION 3
-/* Application Specific Long Lived PACs */
-/* Machine Authentication PAC */
-#define PAC_TYPE_MACHINE_AUTHENTICATION 2
-
+#include "eap_common/eap_fast_common.h"
 
 struct eap_fast_pac {
 	struct eap_fast_pac *next;

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c Sat Nov  3 08:40:37 2007
@@ -1,5 +1,5 @@
 /*
- * EAP peer method: EAP-GPSK (draft-ietf-emu-eap-gpsk-04.txt)
+ * EAP peer method: EAP-GPSK (draft-ietf-emu-eap-gpsk-06.txt)
  * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -196,8 +196,8 @@
 	csuite = (struct eap_gpsk_csuite *) csuite_list;
 	for (i = 0; i < count; i++) {
 		int vendor, specifier;
-		vendor = WPA_GET_BE24(csuite->vendor);
-		specifier = WPA_GET_BE24(csuite->specifier);
+		vendor = WPA_GET_BE32(csuite->vendor);
+		specifier = WPA_GET_BE16(csuite->specifier);
 		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
 			   i, vendor, specifier);
 		if (data->vendor == EAP_GPSK_VENDOR_IETF &&
@@ -356,8 +356,8 @@
 	rpos += csuite_list_len;
 
 	csuite = (struct eap_gpsk_csuite *) rpos;
-	WPA_PUT_BE24(csuite->vendor, data->vendor);
-	WPA_PUT_BE24(csuite->specifier, data->specifier);
+	WPA_PUT_BE32(csuite->vendor, data->vendor);
+	WPA_PUT_BE16(csuite->specifier, data->specifier);
 	rpos = (u8 *) (csuite + 1);
 
 	if (eap_gpsk_derive_keys(data->psk, data->psk_len,
@@ -444,8 +444,8 @@
 		return NULL;
 	}
 	csuite = (const struct eap_gpsk_csuite *) pos;
-	vendor = WPA_GET_BE24(csuite->vendor);
-	specifier = WPA_GET_BE24(csuite->specifier);
+	vendor = WPA_GET_BE32(csuite->vendor);
+	specifier = WPA_GET_BE16(csuite->specifier);
 	pos += sizeof(*csuite);
 	if (vendor != data->vendor || specifier != data->specifier) {
 		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_gtc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_gtc.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_gtc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_gtc.c Sat Nov  3 08:40:37 2007
@@ -30,7 +30,8 @@
 	if (data == NULL)
 		return NULL;
 
-	if (sm->m && sm->m->method == EAP_TYPE_FAST) {
+	if (sm->m && sm->m->vendor == EAP_VENDOR_IETF &&
+	    sm->m->method == EAP_TYPE_FAST) {
 		wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
 			   "with challenge/response");
 		data->prefix = 1;

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h Sat Nov  3 08:40:37 2007
@@ -340,6 +340,7 @@
 
 const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
 const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len);
+const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash);
 const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len);
 const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len);
 void eap_clear_config_otp(struct eap_sm *sm);

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_leap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_leap.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_leap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_leap.c Sat Nov  3 08:40:37 2007
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: LEAP
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -72,11 +72,12 @@
 	const u8 *pos, *challenge, *identity, *password;
 	u8 challenge_len, *rpos;
 	size_t identity_len, password_len;
+	int pwhash;
 
 	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
 
 	identity = eap_get_config_identity(sm, &identity_len);
-	password = eap_get_config_password(sm, &password_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
 	if (identity == NULL || password == NULL)
 		return NULL;
 
@@ -123,7 +124,10 @@
 	*rpos++ = LEAP_VERSION;
 	*rpos++ = 0; /* unused */
 	*rpos++ = LEAP_RESPONSE_LEN;
-	nt_challenge_response(challenge, password, password_len, rpos);
+	if (pwhash)
+		challenge_response(challenge, password, rpos);
+	else
+		nt_challenge_response(challenge, password, password_len, rpos);
 	os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
 	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response",
 		    rpos, LEAP_RESPONSE_LEN);
@@ -199,10 +203,11 @@
 	u8 response_len, pw_hash[16], pw_hash_hash[16],
 		expected[LEAP_RESPONSE_LEN];
 	size_t password_len;
+	int pwhash;
 
 	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
 
-	password = eap_get_config_password(sm, &password_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
 	if (password == NULL)
 		return NULL;
 
@@ -239,8 +244,12 @@
 		    pos, LEAP_RESPONSE_LEN);
 	os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN);
 
-	nt_password_hash(password, password_len, pw_hash);
-	hash_nt_password_hash(pw_hash, pw_hash_hash);
+	if (pwhash) {
+		hash_nt_password_hash(password, pw_hash_hash);
+	} else {
+		nt_password_hash(password, password_len, pw_hash);
+		hash_nt_password_hash(pw_hash, pw_hash_hash);
+	}
 	challenge_response(data->ap_challenge, pw_hash_hash, expected);
 
 	ret->methodState = METHOD_DONE;
@@ -333,11 +342,12 @@
 	u8 *key, pw_hash_hash[16], pw_hash[16];
 	const u8 *addr[5], *password;
 	size_t elen[5], password_len;
+	int pwhash;
 
 	if (data->state != LEAP_DONE)
 		return NULL;
 
-	password = eap_get_config_password(sm, &password_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
 	if (password == NULL)
 		return NULL;
 
@@ -345,8 +355,12 @@
 	if (key == NULL)
 		return NULL;
 
-	nt_password_hash(password, password_len, pw_hash);
-	hash_nt_password_hash(pw_hash, pw_hash_hash);
+	if (pwhash)
+		hash_nt_password_hash(password, pw_hash_hash);
+	else {
+		nt_password_hash(password, password_len, pw_hash);
+		hash_nt_password_hash(pw_hash, pw_hash_hash);
+	}
 	wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash",
 			pw_hash_hash, 16);
 	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge",

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c Sat Nov  3 08:40:37 2007
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt)
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -180,7 +180,7 @@
 static void eap_mschapv2_derive_response(
 	struct eap_mschapv2_data *data,
 	const u8 *username, size_t username_len,
-	const u8 *password, size_t password_len,
+	const u8 *password, size_t password_len, int pwhash,
 	const u8 *auth_challenge, const u8 *peer_challenge,
 	u8 *nt_response)
 {
@@ -192,25 +192,45 @@
 		    peer_challenge, MSCHAPV2_CHAL_LEN);
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
 			  username, username_len);
-	wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: password",
-			      password, password_len);
-	generate_nt_response(auth_challenge, peer_challenge,
-			     username, username_len,
-			     password, password_len, nt_response);
+	if (pwhash) {
+		wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: password hash",
+				password, password_len);
+		generate_nt_response_pwhash(auth_challenge, peer_challenge,
+					    username, username_len,
+					    password, nt_response);
+	} else {
+		wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: password",
+				      password, password_len);
+		generate_nt_response(auth_challenge, peer_challenge,
+				     username, username_len,
+				     password, password_len, nt_response);
+	}
 	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: response", nt_response,
 		    MSCHAPV2_NT_RESPONSE_LEN);
 	/* Authenticator response is not really needed yet, but calculate it
 	 * here so that challenges need not be saved. */
-	generate_authenticator_response(password, password_len,
-					peer_challenge, auth_challenge,
-					username, username_len, nt_response,
-					data->auth_response);
+	if (pwhash) {
+		generate_authenticator_response_pwhash(
+			password, peer_challenge, auth_challenge,
+			username, username_len, nt_response,
+			data->auth_response);
+	} else {
+		generate_authenticator_response(password, password_len,
+						peer_challenge, auth_challenge,
+						username, username_len,
+						nt_response,
+						data->auth_response);
+	}
 	data->auth_response_valid = 1;
 
 	/* Likewise, generate master_key here since we have the needed data
 	 * available. */
-	nt_password_hash(password, password_len, password_hash);
-	hash_nt_password_hash(password_hash, password_hash_hash);
+	if (pwhash) {
+		hash_nt_password_hash(password, password_hash_hash);
+	} else {
+		nt_password_hash(password, password_len, password_hash);
+		hash_nt_password_hash(password_hash, password_hash_hash);
+	}
 	get_master_key(password_hash_hash, nt_response, data->master_key);
 	data->master_key_valid = 1;
 }
@@ -229,11 +249,12 @@
 	struct ms_response *r;
 	size_t username_len, identity_len, password_len;
 	const u8 *username, *identity, *password;
+	int pwhash;
 
 	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response");
 
 	identity = eap_get_config_identity(sm, &identity_len);
-	password = eap_get_config_password(sm, &password_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
 	if (identity == NULL || password == NULL)
 		return NULL;
 
@@ -281,7 +302,7 @@
 		auth_challenge = data->auth_challenge;
 	}
 	eap_mschapv2_derive_response(data, username, username_len,
-				     password, password_len,
+				     password, password_len, pwhash,
 				     auth_challenge, peer_challenge,
 				     r->nt_response);
 
@@ -375,9 +396,20 @@
 			"EAP-MSCHAPV2: Password changed successfully");
 		data->prev_error = 0;
 		os_free(config->password);
-		config->password = config->new_password;
+		if (config->flags & WPA_CONFIG_FLAGS_PASSWORD_NTHASH) {
+			config->password = os_malloc(16);
+			config->password_len = 16;
+			if (config->password) {
+				nt_password_hash(config->new_password,
+						 config->new_password_len,
+						 config->password);
+			}
+			os_free(config->new_password);
+		} else {
+			config->password = config->new_password;
+			config->password_len = config->new_password_len;
+		}
 		config->new_password = NULL;
-		config->password_len = config->new_password_len;
 		config->new_password_len = 0;
 	}
 }
@@ -574,9 +606,10 @@
 	struct eap_mschapv2_hdr *ms;
 	struct ms_change_password *cp;
 	u8 password_hash[16], password_hash_hash[16];
+	int pwhash;
 
 	username = eap_get_config_identity(sm, &username_len);
-	password = eap_get_config_password(sm, &password_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
 	new_password = eap_get_config_new_password(sm, &new_password_len);
 	if (username == NULL || password == NULL || new_password == NULL)
 		return NULL;
@@ -601,14 +634,29 @@
 	cp = (struct ms_change_password *) (ms + 1);
 
 	/* Encrypted-Password */
-	new_password_encrypted_with_old_nt_password_hash(
-		new_password, new_password_len,
-		password, password_len, cp->encr_password);
+	if (pwhash) {
+		encrypt_pw_block_with_password_hash(
+			new_password, new_password_len,
+			password, cp->encr_password);
+	} else {
+		new_password_encrypted_with_old_nt_password_hash(
+			new_password, new_password_len,
+			password, password_len, cp->encr_password);
+	}
 
 	/* Encrypted-Hash */
-	old_nt_password_hash_encrypted_with_new_nt_password_hash(
-		new_password, new_password_len,
-		password, password_len, cp->encr_hash);
+	if (pwhash) {
+		u8 new_password_hash[16];
+		nt_password_hash(new_password, new_password_len,
+				 new_password_hash);
+		nt_password_hash_encrypted_with_block(password,
+						      new_password_hash,
+						      cp->encr_hash);
+	} else {
+		old_nt_password_hash_encrypted_with_new_nt_password_hash(
+			new_password, new_password_len,
+			password, password_len, cp->encr_hash);
+	}
 
 	/* Peer-Challenge */
 	if (os_get_random(cp->peer_challenge, MSCHAPV2_CHAL_LEN)) {

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.h Sat Nov  3 08:40:37 2007
@@ -15,104 +15,7 @@
 #ifndef EAP_TLV_H
 #define EAP_TLV_H
 
-/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-07.txt) */
-#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
-#define EAP_TLV_NAK_TLV 4
-/* Note: RFC 4851, Section 4.2.4 defines 5 as Error TLV */
-#define EAP_TLV_CRYPTO_BINDING_TLV 5
-#define EAP_TLV_CONNECTION_BINDING_TLV 6
-#define EAP_TLV_VENDOR_SPECIFIC_TLV 7
-#define EAP_TLV_URI_TLV 8
-#define EAP_TLV_EAP_PAYLOAD_TLV 9
-#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
-#define EAP_TLV_PAC_TLV 11 /* draft-cam-winget-eap-fast-provisioning-04.txt,
-			    * Section 4.2 */
-#define EAP_TLV_CRYPTO_BINDING_TLV_ 12 /* RFC 4851, Section 4.2.8 */
-/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.3.1 */
-#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18
-#define EAP_TLV_REQUEST_ACTION_TLV 19 /* RFC 4851, Section 4.2.9 */
-/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.3.2 */
-#define EAP_TLV_PKCS7_TLV 20
-
-#define EAP_TLV_RESULT_SUCCESS 1
-#define EAP_TLV_RESULT_FAILURE 2
-
-#define EAP_TLV_TYPE_MANDATORY 0x8000
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct eap_tlv_hdr {
-	be16 tlv_type;
-	be16 length;
-} STRUCT_PACKED;
-
-struct eap_tlv_nak_tlv {
-	be16 tlv_type;
-	be16 length;
-	be32 vendor_id;
-	be16 nak_type;
-} STRUCT_PACKED;
-
-struct eap_tlv_result_tlv {
-	be16 tlv_type;
-	be16 length;
-	be16 status;
-} STRUCT_PACKED;
-
-/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */
-struct eap_tlv_intermediate_result_tlv {
-	be16 tlv_type;
-	be16 length;
-	be16 status;
-	/* Followed by optional TLVs */
-} STRUCT_PACKED;
-
-/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */
-struct eap_tlv_crypto_binding__tlv {
-	be16 tlv_type;
-	be16 length;
-	u8 reserved;
-	u8 version;
-	u8 received_version;
-	u8 subtype;
-	u8 nonce[32];
-	u8 compound_mac[20];
-} STRUCT_PACKED;
-
-struct eap_tlv_pac_ack_tlv {
-	be16 tlv_type;
-	be16 length;
-	be16 pac_type;
-	be16 pac_len;
-	be16 result;
-} STRUCT_PACKED;
-
-/* RFC 4851, Section 4.2.9 - Request-Action TLV */
-struct eap_tlv_request_action_tlv {
-	be16 tlv_type;
-	be16 length;
-	be16 action;
-} STRUCT_PACKED;
-
-/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.2.6 - PAC-Type TLV */
-struct eap_tlv_pac_type_tlv {
-	be16 tlv_type; /* PAC_TYPE_PAC_TYPE */
-	be16 length;
-	be16 pac_type;
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0
-#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
-
-#define EAP_TLV_ACTION_PROCESS_TLV 1
-#define EAP_TLV_ACTION_NEGOTIATE_EAP 2
-
+#include "eap_common/eap_tlv_common.h"
 
 u8 * eap_tlv_build_nak(int id, u16 nak_type, size_t *resp_len);
 u8 * eap_tlv_build_result(int id, u16 status, size_t *resp_len);

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c Sat Nov  3 08:40:37 2007
@@ -198,7 +198,7 @@
 
 static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code,
 			     u32 vendor_id, int mandatory,
-			     u8 *data, size_t len)
+			     const u8 *data, size_t len)
 {
 	u8 *pos;
 	pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len);
@@ -615,13 +615,23 @@
 #if EAP_TTLS_VERSION > 0
 	u8 pw_hash[16], pw_hash_hash[16], master_key[16];
 	u8 session_key[2 * MSCHAPV2_KEY_LEN];
-	struct wpa_ssid *config = eap_get_config(sm);
+	const u8 *password;
+	size_t password_len;
+	int pwhash;
 
 	if (data->ttls_version == 0)
 		return;
 
-	nt_password_hash(config->password, config->password_len, pw_hash);
-	hash_nt_password_hash(pw_hash, pw_hash_hash);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
+	if (password == NULL)
+		return;
+
+	if (pwhash)
+		hash_nt_password_hash(password, pw_hash_hash);
+	else {
+		nt_password_hash(password, password_len, pw_hash);
+		hash_nt_password_hash(pw_hash, pw_hash_hash);
+	}
 	get_master_key(pw_hash_hash, nt_response, master_key);
 	get_asymetric_start_key(master_key, session_key,
 				MSCHAPV2_KEY_LEN, 0, 0);
@@ -638,18 +648,22 @@
 					    struct eap_method_ret *ret,
 					    u8 **resp, size_t *resp_len)
 {
-	struct wpa_ssid *config = eap_get_config(sm);
-	u8 *buf, *pos, *challenge, *username, *peer_challenge;
-	size_t username_len, i;
+	u8 *buf, *pos, *challenge, *peer_challenge;
+	const u8 *identity, *username, *password;
+	size_t identity_len, password_len, username_len, i;
+	int pwhash;
 
 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request");
 
 	/* MSCHAPv2 does not include optional domain name in the
 	 * challenge-response calculation, so remove domain prefix
 	 * (if present). */
-	username = config->identity;
-	username_len = config->identity_len;
-	pos = username;
+	identity = eap_get_config_identity(sm, &identity_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
+	if (identity == NULL || password == NULL)
+		return -1;
+	username = identity;
+	username_len = identity_len;
 	for (i = 0; i < username_len; i++) {
 		if (username[i] == '\\') {
 			username_len -= i + 1;
@@ -658,7 +672,7 @@
 		}
 	}
 
-	pos = buf = os_malloc(config->identity_len + 1000);
+	pos = buf = os_malloc(identity_len + 1000);
 	if (buf == NULL) {
 		wpa_printf(MSG_ERROR,
 			   "EAP-TTLS/MSCHAPV2: Failed to allocate memory");
@@ -667,7 +681,7 @@
 
 	/* User-Name */
 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
-			       config->identity, config->identity_len);
+			       identity, identity_len);
 
 	/* MS-CHAP-Challenge */
 	challenge = eap_ttls_implicit_challenge(
@@ -701,17 +715,28 @@
 		    peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 username",
 			  username, username_len);
-	wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 password",
-			      config->password, config->password_len);
-	generate_nt_response(challenge, peer_challenge,
-			     username, username_len,
-			     config->password, config->password_len,
-			     pos);
-	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 response", pos, 24);
-	generate_authenticator_response(config->password, config->password_len,
-					peer_challenge, challenge,
-					username, username_len,
-					pos, data->auth_response);
+	if (pwhash) {
+		wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 password hash",
+				password, 16);
+		generate_nt_response_pwhash(challenge, peer_challenge,
+					    username, username_len,
+					    password, pos);
+		wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 response", pos, 24);
+		generate_authenticator_response_pwhash(
+			password, peer_challenge, challenge,
+			username, username_len, pos, data->auth_response);
+	} else {
+		wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 password",
+				      password, password_len);
+		generate_nt_response(challenge, peer_challenge,
+				     username, username_len,
+				     password, password_len, pos);
+		wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 response", pos, 24);
+		generate_authenticator_response(password, password_len,
+						peer_challenge, challenge,
+						username, username_len,
+						pos, data->auth_response);
+	}
 	data->auth_response_valid = 1;
 
 	eap_ttlsv1_permute_inner(sm, data, pos);
@@ -742,12 +767,19 @@
 					  struct eap_method_ret *ret,
 					  u8 **resp, size_t *resp_len)
 {
-	struct wpa_ssid *config = eap_get_config(sm);
 	u8 *buf, *pos, *challenge;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
+	int pwhash;
 
 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request");
 
-	pos = buf = os_malloc(config->identity_len + 1000);
+	identity = eap_get_config_identity(sm, &identity_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
+	if (identity == NULL || password == NULL)
+		return -1;
+
+	pos = buf = os_malloc(identity_len + 1000);
 	if (buf == NULL) {
 		wpa_printf(MSG_ERROR,
 			   "EAP-TTLS/MSCHAP: Failed to allocate memory");
@@ -756,7 +788,7 @@
 
 	/* User-Name */
 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
-			       config->identity, config->identity_len);
+			       identity, identity_len);
 
 	/* MS-CHAP-Challenge */
 	challenge = eap_ttls_implicit_challenge(sm, data, EAP_TLS_KEY_LEN);
@@ -780,11 +812,16 @@
 	*pos++ = 1; /* Flags: Use NT style passwords */
 	os_memset(pos, 0, 24); /* LM-Response */
 	pos += 24;
-	nt_challenge_response(challenge,
-			      config->password, config->password_len,
-			      pos); /* NT-Response */
-	wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password",
-			      config->password, config->password_len);
+	if (pwhash) {
+		challenge_response(challenge, password, pos); /* NT-Response */
+		wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash",
+				password, 16);
+	} else {
+		nt_challenge_response(challenge, password, password_len,
+				      pos); /* NT-Response */
+		wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password",
+				      password, password_len);
+	}
 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge",
 		    challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24);
@@ -816,14 +853,19 @@
 				       struct eap_method_ret *ret,
 				       u8 **resp, size_t *resp_len)
 {
-	struct wpa_ssid *config = eap_get_config(sm);
 	u8 *buf, *pos;
 	size_t pad;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
 
 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request");
 
-	pos = buf = os_malloc(config->identity_len + config->password_len +
-			      100);
+	identity = eap_get_config_identity(sm, &identity_len);
+	password = eap_get_config_password(sm, &password_len);
+	if (identity == NULL || password == NULL)
+		return -1;
+
+	pos = buf = os_malloc(identity_len + password_len + 100);
 	if (buf == NULL) {
 		wpa_printf(MSG_ERROR,
 			   "EAP-TTLS/PAP: Failed to allocate memory");
@@ -832,16 +874,16 @@
 
 	/* User-Name */
 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
-			       config->identity, config->identity_len);
+			       identity, identity_len);
 
 	/* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts
 	 * the data, so no separate encryption is used in the AVP itself.
 	 * However, the password is padded to obfuscate its length. */
-	pad = (16 - (config->password_len & 15)) & 15;
+	pad = (16 - (password_len & 15)) & 15;
 	pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1,
-			       config->password_len + pad);
-	os_memcpy(pos, config->password, config->password_len);
-	pos += config->password_len;
+			       password_len + pad);
+	os_memcpy(pos, password, password_len);
+	pos += password_len;
 	os_memset(pos, 0, pad);
 	pos += pad;
 	AVP_PAD(buf, pos);
@@ -870,14 +912,20 @@
 					struct eap_method_ret *ret,
 					u8 **resp, size_t *resp_len)
 {
-	struct wpa_ssid *config = eap_get_config(sm);
 	u8 *buf, *pos, *challenge;
 	const u8 *addr[3];
 	size_t len[3];
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
 
 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request");
 
-	pos = buf = os_malloc(config->identity_len + 1000);
+	identity = eap_get_config_identity(sm, &identity_len);
+	password = eap_get_config_password(sm, &password_len);
+	if (identity == NULL || password == NULL)
+		return -1;
+
+	pos = buf = os_malloc(identity_len + 1000);
 	if (buf == NULL) {
 		wpa_printf(MSG_ERROR,
 			   "EAP-TTLS/CHAP: Failed to allocate memory");
@@ -886,7 +934,7 @@
 
 	/* User-Name */
 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
-			       config->identity, config->identity_len);
+			       identity, identity_len);
 
 	/* CHAP-Challenge */
 	challenge = eap_ttls_implicit_challenge(sm, data, EAP_TLS_KEY_LEN);
@@ -909,16 +957,16 @@
 	/* MD5(Ident + Password + Challenge) */
 	addr[0] = &data->ident;
 	len[0] = 1;
-	addr[1] = config->password;
-	len[1] = config->password_len;
+	addr[1] = password;
+	len[1] = password_len;
 	addr[2] = challenge;
 	len[2] = EAP_TTLS_CHAP_CHALLENGE_LEN;
 	md5_vector(3, addr, len, pos);
 
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username",
-			  config->identity, config->identity_len);
+			  identity, identity_len);
 	wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password",
-			      config->password, config->password_len);
+			      password, password_len);
 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge",
 		    challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password",

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c Sat Nov  3 08:40:37 2007
@@ -684,9 +684,7 @@
 		}
 
 		pos += 6;
-		while (*pos == ' ')
-			pos++;
-		type = atoi(pos);
+		type = strtoul(pos, NULL, 16);
 		wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
 
 		pos = os_strstr(start, "<Base64>");

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap.c Sat Nov  3 08:40:37 2007
@@ -941,6 +941,15 @@
 	sm->ssl_ctx = conf->ssl_ctx;
 	sm->eap_sim_db_priv = conf->eap_sim_db_priv;
 	sm->backend_auth = conf->backend_auth;
+	if (conf->pac_opaque_encr_key) {
+		sm->pac_opaque_encr_key = os_malloc(16);
+		if (sm->pac_opaque_encr_key) {
+			os_memcpy(sm->pac_opaque_encr_key,
+				  conf->pac_opaque_encr_key, 16);
+		}
+	}
+	if (conf->eap_fast_a_id)
+		sm->eap_fast_a_id = strdup(conf->eap_fast_a_id);
 
 	wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
 
@@ -967,6 +976,8 @@
 	free(sm->lastReqData);
 	free(sm->eapRespData);
 	free(sm->identity);
+	free(sm->pac_opaque_encr_key);
+	free(sm->eap_fast_a_id);
 	eap_user_free(sm->user);
 	free(sm);
 }

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap.h Sat Nov  3 08:40:37 2007
@@ -57,6 +57,8 @@
 	void *ssl_ctx;
 	void *eap_sim_db_priv;
 	Boolean backend_auth;
+	u8 *pac_opaque_encr_key;
+	char *eap_fast_a_id;
 };
 
 

Added: wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c (added)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c Sat Nov  3 08:40:37 2007
@@ -1,0 +1,1715 @@
+/*
+ * EAP-FAST server (RFC 4851)
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes_wrap.h"
+#include "sha1.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "tls.h"
+#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_fast_common.h"
+
+
+static void eap_fast_reset(struct eap_sm *sm, void *priv);
+
+
+/* Private PAC-Opaque TLV types */
+#define PAC_OPAQUE_TYPE_PAD 0
+#define PAC_OPAQUE_TYPE_KEY 1
+#define PAC_OPAQUE_TYPE_LIFETIME 2
+
+/* PAC-Key lifetime in seconds (hard limit) */
+#define PAC_KEY_LIFETIME (7 * 24 * 60 * 60)
+
+/*
+ * PAC-Key refresh time in seconds (soft limit on remaining hard limit). The
+ * server will generate a new PAC-Key when this number of seconds (or fewer)
+ * of the lifetime.
+ */
+#define PAC_KEY_REFRESH_TIME (1 * 24 * 60 * 60)
+
+
+struct eap_fast_data {
+	struct eap_ssl_data ssl;
+	enum {
+		START, PHASE1, PHASE2_START, PHASE2_ID, PHASE2_METHOD,
+		CRYPTO_BINDING, REQUEST_PAC, SUCCESS, FAILURE
+	} state;
+
+	int fast_version;
+	const struct eap_method *phase2_method;
+	void *phase2_priv;
+	int force_version;
+	int peer_version;
+
+	u8 crypto_binding_nonce[32];
+	int final_result;
+
+	struct eap_fast_key_block_provisioning *key_block_p;
+
+	u8 simck[EAP_FAST_SIMCK_LEN];
+	u8 cmk[20];
+	int simck_idx;
+
+	u8 pac_opaque_encr[16];
+	char *srv_id;
+
+	int anon_provisioning;
+	int send_new_pac; /* server triggered re-keying of Tunnel PAC */
+};
+
+
+static const char * eap_fast_state_txt(int state)
+{
+	switch (state) {
+	case START:
+		return "START";
+	case PHASE1:
+		return "PHASE1";
+	case PHASE2_START:
+		return "PHASE2_START";
+	case PHASE2_ID:
+		return "PHASE2_ID";
+	case PHASE2_METHOD:
+		return "PHASE2_METHOD";
+	case CRYPTO_BINDING:
+		return "CRYPTO_BINDING";
+	case REQUEST_PAC:
+		return "REQUEST_PAC";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "Unknown?!";
+	}
+}
+
+
+static void eap_fast_state(struct eap_fast_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-FAST: %s -> %s",
+		   eap_fast_state_txt(data->state),
+		   eap_fast_state_txt(state));
+	data->state = state;
+}
+
+
+static EapType eap_fast_req_failure(struct eap_sm *sm,
+				    struct eap_fast_data *data)
+{
+	/* TODO: send Result TLV(FAILURE) */
+	eap_fast_state(data, FAILURE);
+	return EAP_TYPE_NONE;
+}
+
+
+static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
+				      const u8 *client_random,
+				      const u8 *server_random,
+				      u8 *master_secret)
+{
+	struct eap_fast_data *data = ctx;
+#define TLS_RANDOM_LEN 32
+#define TLS_MASTER_SECRET_LEN 48
+	u8 seed[2 * TLS_RANDOM_LEN];
+	const u8 *pac_opaque;
+	size_t pac_opaque_len;
+	u8 *buf, *pos, *end, *pac_key = NULL;
+	os_time_t lifetime = 0;
+	struct os_time now;
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket (PAC-Opaque)",
+		    ticket, len);
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
+		    client_random, TLS_RANDOM_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
+		    server_random, TLS_RANDOM_LEN);
+
+	if (len < 4 || WPA_GET_BE16(ticket) != PAC_TYPE_PAC_OPAQUE) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid "
+			   "SessionTicket");
+		return 0;
+	}
+
+	pac_opaque_len = WPA_GET_BE16(ticket + 2);
+	pac_opaque = ticket + 4;
+	if (pac_opaque_len < 8 || pac_opaque_len % 8 ||
+	    pac_opaque_len > len - 4) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid PAC-Opaque "
+			   "(len=%lu left=%lu)",
+			   (unsigned long) pac_opaque_len,
+			   (unsigned long) len);
+		return 0;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: Received PAC-Opaque",
+		    pac_opaque, pac_opaque_len);
+
+	buf = os_malloc(pac_opaque_len - 8);
+	if (buf == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
+			   "for decrypting PAC-Opaque");
+		return 0;
+	}
+
+	if (aes_unwrap(data->pac_opaque_encr, (pac_opaque_len - 8) / 8,
+		       pac_opaque, buf) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to decrypt "
+			   "PAC-Opaque");
+		os_free(buf);
+		/*
+		 * This may have been caused by server changing the PAC-Opaque
+		 * encryption key, so just ignore this PAC-Opaque instead of
+		 * failing the authentication completely. Provisioning can now
+		 * be used to provision a new PAC.
+		 */
+		return 0;
+	}
+
+	end = buf + pac_opaque_len - 8;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Decrypted PAC-Opaque",
+			buf, end - buf);
+
+	pos = buf;
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+
+		switch (*pos) {
+		case PAC_OPAQUE_TYPE_PAD:
+			pos = end;
+			break;
+		case PAC_OPAQUE_TYPE_KEY:
+			if (pos[1] != EAP_FAST_PAC_KEY_LEN) {
+				wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
+					   "PAC-Key length %d", pos[1]);
+				os_free(buf);
+				return -1;
+			}
+			pac_key = pos + 2;
+			wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key from "
+					"decrypted PAC-Opaque",
+					pac_key, EAP_FAST_PAC_KEY_LEN);
+			break;
+		case PAC_OPAQUE_TYPE_LIFETIME:
+			if (pos[1] != 4) {
+				wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
+					   "PAC-Key lifetime length %d",
+					   pos[1]);
+				os_free(buf);
+				return -1;
+			}
+			lifetime = WPA_GET_BE32(pos + 2);
+			break;
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	if (pac_key == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key included in "
+			   "PAC-Opaque");
+		os_free(buf);
+		return -1;
+	}
+
+	if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key not valid anymore "
+			   "(lifetime=%ld now=%ld)", lifetime, now.sec);
+		os_free(buf);
+		return 0;
+	}
+
+	if (lifetime - now.sec < PAC_KEY_REFRESH_TIME)
+		data->send_new_pac = 1;
+
+	/*
+	 * RFC 4851, Section 5.1:
+	 * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", 
+	 *                       server_random + client_random, 48)
+	 */
+	os_memcpy(seed, server_random, TLS_RANDOM_LEN);
+	os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
+	sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN,
+		   "PAC to master secret label hash",
+		   seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
+			master_secret, TLS_MASTER_SECRET_LEN);
+
+	os_free(buf);
+
+	return 1;
+}
+
+
+static u8 * eap_fast_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
+				char *label, size_t len)
+{
+	struct tls_keys keys;
+	u8 *rnd = NULL, *out;
+	int block_size;
+
+	block_size = tls_connection_get_keyblock_size(sm->ssl_ctx, data->conn);
+	if (block_size < 0)
+		return NULL;
+
+	out = os_malloc(block_size + len);
+	if (out == NULL)
+		return NULL;
+
+	if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 1, out,
+			       block_size + len) == 0) {
+		os_memmove(out, out + block_size, len);
+		return out;
+	}
+
+	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+		goto fail;
+
+	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
+	if (rnd == NULL)
+		goto fail;
+
+	os_memcpy(rnd, keys.server_random, keys.server_random_len);
+	os_memcpy(rnd + keys.server_random_len, keys.client_random,
+		  keys.client_random_len);
+
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
+			"expansion", keys.master_key, keys.master_key_len);
+	if (tls_prf(keys.master_key, keys.master_key_len,
+		    label, rnd, keys.client_random_len +
+		    keys.server_random_len, out, block_size + len))
+		goto fail;
+	os_free(rnd);
+	os_memmove(out, out + block_size, len);
+	return out;
+
+fail:
+	os_free(rnd);
+	os_free(out);
+	return NULL;
+}
+
+
+static void eap_fast_derive_key_auth(struct eap_sm *sm,
+				     struct eap_fast_data *data)
+{
+	u8 *sks;
+
+	/* RFC 4851, Section 5.1:
+	 * Extra key material after TLS key_block: session_key_seed[40]
+	 */
+
+	sks = eap_fast_derive_key(sm, &data->ssl, "key expansion",
+				  EAP_FAST_SKS_LEN);
+	if (sks == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
+			   "session_key_seed");
+		return;
+	}
+
+	/*
+	 * RFC 4851, Section 5.2:
+	 * S-IMCK[0] = session_key_seed
+	 */
+	wpa_hexdump_key(MSG_DEBUG,
+			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
+			sks, EAP_FAST_SKS_LEN);
+	data->simck_idx = 0;
+	os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
+	os_free(sks);
+}
+
+
+static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
+					     struct eap_fast_data *data)
+{
+	os_free(data->key_block_p);
+	data->key_block_p = (struct eap_fast_key_block_provisioning *)
+		eap_fast_derive_key(sm, &data->ssl, "key expansion",
+				    sizeof(*data->key_block_p));
+	if (data->key_block_p == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
+		return;
+	}
+	/*
+	 * RFC 4851, Section 5.2:
+	 * S-IMCK[0] = session_key_seed
+	 */
+	wpa_hexdump_key(MSG_DEBUG,
+			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
+			data->key_block_p->session_key_seed,
+			sizeof(data->key_block_p->session_key_seed));
+	data->simck_idx = 0;
+	os_memcpy(data->simck, data->key_block_p->session_key_seed,
+		  EAP_FAST_SIMCK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",
+			data->key_block_p->server_challenge,
+			sizeof(data->key_block_p->server_challenge));
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",
+			data->key_block_p->client_challenge,
+			sizeof(data->key_block_p->client_challenge));
+}
+
+
+static int eap_fast_get_phase2_key(struct eap_sm *sm,
+				   struct eap_fast_data *data,
+				   u8 *isk, size_t isk_len)
+{
+	u8 *key;
+	size_t key_len;
+
+	os_memset(isk, 0, isk_len);
+
+	if (data->phase2_method == NULL || data->phase2_priv == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
+			   "available");
+		return -1;
+	}
+
+	if (data->phase2_method->getKey == NULL)
+		return 0;
+
+	if ((key = data->phase2_method->getKey(sm, data->phase2_priv,
+					       &key_len)) == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material "
+			   "from Phase 2");
+		return -1;
+	}
+
+	if (key_len > isk_len)
+		key_len = isk_len;
+	os_memcpy(isk, key, key_len);
+	os_free(key);
+
+	return 0;
+}
+
+
+static int eap_fast_update_icmk(struct eap_sm *sm, struct eap_fast_data *data)
+{
+	u8 isk[32], imck[60];
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Deriving ICMK[%d] (S-IMCK and CMK)",
+		   data->simck_idx + 1);
+
+	/*
+	 * RFC 4851, Section 5.2:
+	 * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
+	 *                 MSK[j], 60)
+	 * S-IMCK[j] = first 40 octets of IMCK[j]
+	 * CMK[j] = last 20 octets of IMCK[j]
+	 */
+
+	if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk));
+	sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+		   "Inner Methods Compound Keys",
+		   isk, sizeof(isk), imck, sizeof(imck));
+	data->simck_idx++;
+	os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
+			data->simck, EAP_FAST_SIMCK_LEN);
+	os_memcpy(data->cmk, imck + EAP_FAST_SIMCK_LEN, 20);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", data->cmk, 20);
+
+	return 0;
+}
+
+
+static void * eap_fast_init(struct eap_sm *sm)
+{
+	struct eap_fast_data *data;
+	u8 ciphers[5] = {
+		TLS_CIPHER_ANON_DH_AES128_SHA,
+		TLS_CIPHER_AES128_SHA,
+		TLS_CIPHER_RSA_DHE_AES128_SHA,
+		TLS_CIPHER_RC4_SHA,
+		TLS_CIPHER_NONE
+	};
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->fast_version = EAP_FAST_VERSION;
+	data->force_version = -1;
+	if (sm->user && sm->user->force_version >= 0) {
+		data->force_version = sm->user->force_version;
+		wpa_printf(MSG_DEBUG, "EAP-FAST: forcing version %d",
+			   data->force_version);
+		data->fast_version = data->force_version;
+	}
+	data->state = START;
+
+	if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+
+	if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn,
+					   ciphers) < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to set TLS cipher "
+			   "suites");
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+
+	if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+						 eap_fast_session_ticket_cb,
+						 data) < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
+			   "callback");
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+
+	if (sm->pac_opaque_encr_key == NULL) {
+		wpa_printf(MSG_INFO, "EAP-FAST: No PAC-Opaque encryption key "
+			   "configured");
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+	os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key,
+		  sizeof(data->pac_opaque_encr));
+
+	if (sm->eap_fast_a_id == NULL) {
+		wpa_printf(MSG_INFO, "EAP-FAST: No A-ID configured");
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+	data->srv_id = os_strdup(sm->eap_fast_a_id);
+	if (data->srv_id == NULL) {
+		eap_fast_reset(sm, data);
+		return NULL;
+	}
+
+	return data;
+}
+
+
+static void eap_fast_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_fast_data *data = priv;
+	if (data == NULL)
+		return;
+	if (data->phase2_priv && data->phase2_method)
+		data->phase2_method->reset(sm, data->phase2_priv);
+	eap_server_tls_ssl_deinit(sm, &data->ssl);
+	free(data->srv_id);
+	free(data);
+}
+
+
+static u8 * eap_fast_build_start(struct eap_sm *sm, struct eap_fast_data *data,
+				 int id, size_t *reqDataLen)
+{
+	struct eap_hdr *req;
+	u8 *pos;
+	struct pac_tlv_hdr *a_id;
+	size_t srv_id_len = os_strlen(data->srv_id);
+
+	*reqDataLen = sizeof(*req) + 2 + sizeof(*a_id) + srv_id_len;
+	req = malloc(*reqDataLen);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-FAST: Failed to allocate memory for"
+			   " request");
+		eap_fast_state(data, FAILURE);
+		return NULL;
+	}
+
+	req->code = EAP_CODE_REQUEST;
+	req->identifier = id;
+	req->length = host_to_be16(*reqDataLen);
+	pos = (u8 *) (req + 1);
+	*pos++ = EAP_TYPE_FAST;
+	*pos++ = EAP_TLS_FLAGS_START | data->fast_version;
+	a_id = (struct pac_tlv_hdr *) pos;
+	a_id->type = host_to_be16(PAC_TYPE_A_ID);
+	a_id->len = host_to_be16(srv_id_len);
+	pos = (u8 *) (a_id + 1);
+	os_memcpy(pos, data->srv_id, srv_id_len);
+
+	eap_fast_state(data, PHASE1);
+
+	return (u8 *) req;
+}
+
+
+static int eap_fast_phase1_done(struct eap_sm *sm, struct eap_fast_data *data)
+{
+	char cipher[64];
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Phase1 done, starting Phase2");
+
+	if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher))
+	    < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to get cipher "
+			   "information");
+		eap_fast_state(data, FAILURE);
+		return -1;
+	}
+	data->anon_provisioning = os_strstr(cipher, "ADH") != NULL;
+		    
+	if (data->anon_provisioning) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Anonymous provisioning");
+		eap_fast_derive_key_provisioning(sm, data);
+	} else
+		eap_fast_derive_key_auth(sm, data);
+
+	eap_fast_state(data, PHASE2_START);
+
+	return 0;
+}
+
+
+static u8 * eap_fast_build_req(struct eap_sm *sm, struct eap_fast_data *data,
+			       int id, size_t *reqDataLen)
+{
+	int res;
+	u8 *req;
+
+	res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_FAST,
+					     data->fast_version, id, &req,
+					     reqDataLen);
+
+	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+		if (eap_fast_phase1_done(sm, data) < 0) {
+			os_free(req);
+			return NULL;
+		}
+	}
+
+	if (res == 1)
+		return eap_server_tls_build_ack(reqDataLen, id, EAP_TYPE_FAST,
+						data->fast_version);
+	return req;
+}
+
+
+static u8 * eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data,
+			     int id, u8 *plain, size_t plain_len,
+			     size_t *out_len)
+{
+	int res;
+	u8 *pos;
+	struct eap_hdr *req;
+
+	/* TODO: add support for fragmentation, if needed. This will need to
+	 * add TLS Message Length field, if the frame is fragmented. */
+	req = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
+	if (req == NULL)
+		return NULL;
+
+	req->code = EAP_CODE_REQUEST;
+	req->identifier = id;
+
+	pos = (u8 *) (req + 1);
+	*pos++ = EAP_TYPE_FAST;
+	*pos++ = data->fast_version;
+
+	res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
+				     plain, plain_len,
+				     pos, data->ssl.tls_out_limit);
+	if (res < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt Phase 2 "
+			   "data");
+		free(req);
+		return NULL;
+	}
+
+	*out_len = sizeof(struct eap_hdr) + 2 + res;
+	req->length = host_to_be16(*out_len);
+	return (u8 *) req;
+}
+
+
+static u8 * eap_fast_tlv_eap_payload(u8 *buf, size_t *len)
+{
+	struct eap_tlv_hdr *tlv;
+
+	if (buf == NULL)
+		return NULL;
+
+	/* Encapsulate EAP packet in EAP-Payload TLV */
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV");
+	tlv = os_malloc(sizeof(*tlv) + *len);
+	if (tlv == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
+			   "allocate memory for TLV "
+			   "encapsulation");
+		os_free(buf);
+		return NULL;
+	}
+	tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+				     EAP_TLV_EAP_PAYLOAD_TLV);
+	tlv->length = host_to_be16(*len);
+	os_memcpy(tlv + 1, buf, *len);
+	os_free(buf);
+	*len += sizeof(*tlv);
+	return (u8 *) tlv;
+}
+
+
+static u8 * eap_fast_build_phase2_req(struct eap_sm *sm,
+				      struct eap_fast_data *data,
+				      int id, size_t *req_len)
+{
+	u8 *req;
+
+	req = data->phase2_method->buildReq(sm, data->phase2_priv, id,
+					    req_len);
+	if (req == NULL)
+		return NULL;
+
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: Phase 2 EAP-Request",
+			req, *req_len);
+	return eap_fast_tlv_eap_payload(req, req_len);
+}
+
+
+static u8 * eap_fast_build_crypto_binding(struct eap_sm *sm,
+					  struct eap_fast_data *data,
+					  size_t *req_len)
+{
+	struct eap_tlv_result_tlv *result;
+	struct eap_tlv_crypto_binding__tlv *binding;
+	int type;
+
+	*req_len = sizeof(*result) + sizeof(*binding);
+	result = os_zalloc(*req_len);
+	if (result == NULL)
+		return NULL;
+	binding = (struct eap_tlv_crypto_binding__tlv *) (result + 1);
+
+	if (data->send_new_pac || data->anon_provisioning) {
+		type = EAP_TLV_INTERMEDIATE_RESULT_TLV;
+		data->final_result = 0;
+	} else {
+		type = EAP_TLV_RESULT_TLV;
+		data->final_result = 1;
+	}
+
+	/* Result TLV */
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)");
+	result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | type);
+	result->length = host_to_be16(2);
+	result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
+
+	/* Crypto-Binding TLV */
+	binding->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+					 EAP_TLV_CRYPTO_BINDING_TLV_);
+	binding->length = host_to_be16(sizeof(*binding) -
+				       sizeof(struct eap_tlv_hdr));
+	binding->version = EAP_FAST_VERSION;
+	binding->received_version = data->peer_version;
+	binding->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST;
+	if (os_get_random(binding->nonce, sizeof(binding->nonce)) < 0) {
+		os_free(result);
+		return NULL;
+	}
+
+	/*
+	 * RFC 4851, Section 4.2.8:
+	 * The nonce in a request MUST have its least significant bit set to 0.
+	 */
+	binding->nonce[sizeof(binding->nonce) - 1] &= ~0x01;
+
+	os_memcpy(data->crypto_binding_nonce, binding->nonce,
+		  sizeof(binding->nonce));
+
+	/*
+	 * RFC 4851, Section 5.3:
+	 * CMK = CMK[j]
+	 * Compound-MAC = HMAC-SHA1( CMK, Crypto-Binding TLV )
+	 */
+
+	hmac_sha1(data->cmk, 20, (u8 *) binding, sizeof(*binding),
+		  binding->compound_mac);
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Add Crypto-Binding TLV: Version %d "
+		   "Received Version %d SubType %d",
+		   binding->version, binding->received_version,
+		   binding->subtype);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
+		    binding->nonce, sizeof(binding->nonce));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
+		    binding->compound_mac, sizeof(binding->compound_mac));
+
+	return (u8 *) result;
+}
+
+
+static u8 * eap_fast_build_pac(struct eap_sm *sm,
+			       struct eap_fast_data *data,
+			       size_t *reqDataLen)
+{
+	u8 pac_key[2 + EAP_FAST_PAC_KEY_LEN + 6];
+	u8 pac_opaque[8 + EAP_FAST_PAC_KEY_LEN + 8];
+	u8 *buf, *pos;
+	size_t buf_len, srv_id_len;
+	struct eap_tlv_hdr *pac_tlv;
+	struct pac_tlv_hdr *hdr, *pac_info;
+	struct eap_tlv_result_tlv *result;
+	struct os_time now;
+
+	srv_id_len = os_strlen(data->srv_id);
+
+	pac_key[0] = PAC_OPAQUE_TYPE_KEY;
+	pac_key[1] = EAP_FAST_PAC_KEY_LEN;
+	if (os_get_random(pac_key + 2, EAP_FAST_PAC_KEY_LEN) < 0)
+		return NULL;
+	if (os_get_time(&now) < 0)
+		return NULL;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key",
+			pac_key + 2, EAP_FAST_PAC_KEY_LEN);
+	pos = pac_key + 2 + EAP_FAST_PAC_KEY_LEN;
+	*pos++ = PAC_OPAQUE_TYPE_LIFETIME;
+	*pos++ = 4;
+	WPA_PUT_BE32(pos, now.sec + PAC_KEY_LIFETIME);
+
+	if (aes_wrap(data->pac_opaque_encr, sizeof(pac_key) / 8, pac_key,
+		     pac_opaque) < 0)
+		return NULL;
+
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
+		    pac_opaque, sizeof(pac_opaque));
+
+	buf_len = sizeof(*pac_tlv) +
+		sizeof(*hdr) + EAP_FAST_PAC_KEY_LEN +
+		sizeof(*hdr) + sizeof(pac_opaque) +
+		2 * srv_id_len + 100 + sizeof(*result);
+	buf = os_zalloc(buf_len);
+	if (buf == NULL)
+		return NULL;
+
+	pos = buf;
+
+	/* PAC TLV */
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV");
+	pac_tlv = (struct eap_tlv_hdr *) pos;
+	pac_tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+					 EAP_TLV_PAC_TLV);
+	pos = (u8 *) (pac_tlv + 1);
+
+	/* PAC-Key */
+	hdr = (struct pac_tlv_hdr *) pos;
+	hdr->type = host_to_be16(PAC_TYPE_PAC_KEY);
+	hdr->len = host_to_be16(EAP_FAST_PAC_KEY_LEN);
+	pos = (u8 *) (hdr + 1);
+	os_memcpy(pos, pac_key + 2, EAP_FAST_PAC_KEY_LEN);
+	pos += EAP_FAST_PAC_KEY_LEN;
+
+	/* PAC-Opaque */
+	hdr = (struct pac_tlv_hdr *) pos;
+	hdr->type = host_to_be16(PAC_TYPE_PAC_OPAQUE);
+	hdr->len = host_to_be16(sizeof(pac_opaque));
+	pos = (u8 *) (hdr + 1);
+	os_memcpy(pos, pac_opaque, sizeof(pac_opaque));
+	pos += sizeof(pac_opaque);
+
+	/* PAC-Info */
+	pac_info = (struct pac_tlv_hdr *) pos;
+	pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO);
+	pos = (u8 *) (pac_info + 1);
+
+	/* PAC-Lifetime (inside PAC-Info) */
+	hdr = (struct pac_tlv_hdr *) pos;
+	hdr->type = host_to_be16(PAC_TYPE_CRED_LIFETIME);
+	hdr->len = host_to_be16(4);
+	pos = (u8 *) (hdr + 1);
+	WPA_PUT_BE32(pos, now.sec + PAC_KEY_LIFETIME);
+	pos += 4;
+
+	/* A-ID (inside PAC-Info) */
+	hdr = (struct pac_tlv_hdr *) pos;
+	hdr->type = host_to_be16(PAC_TYPE_A_ID);
+	hdr->len = host_to_be16(srv_id_len);
+	pos = (u8 *) (hdr + 1);
+	os_memcpy(pos, data->srv_id, srv_id_len);
+	pos += srv_id_len;
+	
+	/* Note: headers may be misaligned after A-ID */
+
+	/* A-ID-Info (inside PAC-Info) */
+	hdr = (struct pac_tlv_hdr *) pos;
+	WPA_PUT_BE16((u8 *) &hdr->type, PAC_TYPE_A_ID_INFO);
+	WPA_PUT_BE16((u8 *) &hdr->len, srv_id_len);
+	pos = (u8 *) (hdr + 1);
+	os_memcpy(pos, data->srv_id, srv_id_len);
+	pos += srv_id_len;
+
+	/* PAC-Type (inside PAC-Info) */
+	hdr = (struct pac_tlv_hdr *) pos;
+	WPA_PUT_BE16((u8 *) &hdr->type, PAC_TYPE_PAC_TYPE);
+	WPA_PUT_BE16((u8 *) &hdr->len, 2);
+	pos = (u8 *) (hdr + 1);
+	WPA_PUT_BE16(pos, PAC_TYPE_TUNNEL_PAC);
+	pos += 2;
+
+	/* Update PAC-Info and PAC TLV Length fields */
+	pac_info->len = host_to_be16(pos - (u8 *) (pac_info + 1));
+	pac_tlv->length = host_to_be16(pos - (u8 *) (pac_tlv + 1));
+
+	/* Result TLV */
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)");
+	result = (struct eap_tlv_result_tlv *) pos;
+	WPA_PUT_BE16((u8 *) &result->tlv_type,
+		     EAP_TLV_TYPE_MANDATORY | EAP_TLV_RESULT_TLV);
+	WPA_PUT_BE16((u8 *) &result->length, 2);
+	WPA_PUT_BE16((u8 *) &result->status, EAP_TLV_RESULT_SUCCESS);
+	pos = (u8 *) (result + 1);
+
+	*reqDataLen = pos - buf;
+
+	return buf;
+}
+
+
+static u8 * eap_fast_buildReq(struct eap_sm *sm, void *priv, int id,
+			      size_t *reqDataLen)
+{
+	struct eap_fast_data *data = priv;
+	u8 *req, *encr;
+	size_t req_len;
+
+	if (data->state == START)
+		return eap_fast_build_start(sm, data, id, reqDataLen);
+
+	if (data->state == PHASE1)
+		return eap_fast_build_req(sm, data, id, reqDataLen);
+
+	switch (data->state) {
+	case PHASE2_ID:
+	case PHASE2_METHOD:
+		req = eap_fast_build_phase2_req(sm, data, id, &req_len);
+		break;
+	case CRYPTO_BINDING:
+		req = eap_fast_build_crypto_binding(sm, data, &req_len);
+		break;
+	case REQUEST_PAC:
+		req = eap_fast_build_pac(sm, data, &req_len);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d",
+			   __func__, data->state);
+		return NULL;
+	}
+
+	if (req == NULL)
+		return NULL;
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs",
+			(u8 *) req, req_len);
+	encr = eap_fast_encrypt(sm, data, id, req, req_len, reqDataLen);
+	free(req);
+
+	return encr;
+}
+
+
+static Boolean eap_fast_check(struct eap_sm *sm, void *priv,
+			      u8 *respData, size_t respDataLen)
+{
+	struct eap_hdr *resp;
+	u8 *pos;
+
+	resp = (struct eap_hdr *) respData;
+	pos = (u8 *) (resp + 1);
+	if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_FAST ||
+	    (be_to_host16(resp->length)) > respDataLen) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data,
+				EapType eap_type)
+{
+	if (data->phase2_priv && data->phase2_method) {
+		data->phase2_method->reset(sm, data->phase2_priv);
+		data->phase2_method = NULL;
+		data->phase2_priv = NULL;
+	}
+	data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
+							eap_type);
+	if (!data->phase2_method)
+		return -1;
+
+	if (data->key_block_p) {
+		sm->auth_challenge = data->key_block_p->server_challenge;
+		sm->peer_challenge = data->key_block_p->client_challenge;
+	}
+	sm->init_phase2 = 1;
+	data->phase2_priv = data->phase2_method->init(sm);
+	sm->init_phase2 = 0;
+	sm->auth_challenge = NULL;
+	sm->peer_challenge = NULL;
+
+	return data->phase2_priv == NULL ? -1 : 0;
+}
+
+
+static void eap_fast_process_phase2_response(struct eap_sm *sm,
+					     struct eap_fast_data *data,
+					     u8 *in_data, size_t in_len)
+{
+	u8 next_type = EAP_TYPE_NONE;
+	struct eap_hdr *hdr;
+	u8 *pos;
+	size_t left;
+
+	if (data->phase2_priv == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - Phase2 not "
+			   "initialized?!", __func__);
+		return;
+	}
+
+	hdr = (struct eap_hdr *) in_data;
+	pos = (u8 *) (hdr + 1);
+
+	if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
+		left = in_len - sizeof(*hdr);
+		wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; "
+			    "allowed types", pos + 1, left - 1);
+		eap_sm_process_nak(sm, pos + 1, left - 1);
+		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
+		    sm->user->methods[sm->user_eap_method_index].method !=
+		    EAP_TYPE_NONE) {
+			next_type = sm->user->methods[
+				sm->user_eap_method_index++].method;
+			wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d",
+				   next_type);
+		} else {
+			next_type = eap_fast_req_failure(sm, data);
+		}
+		eap_fast_phase2_init(sm, data, next_type);
+		return;
+	}
+
+	if (data->phase2_method->check(sm, data->phase2_priv, in_data,
+				       in_len)) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to "
+			   "ignore the packet");
+		next_type = eap_fast_req_failure(sm, data);
+		return;
+	}
+
+	data->phase2_method->process(sm, data->phase2_priv, in_data, in_len);
+
+	if (!data->phase2_method->isDone(sm, data->phase2_priv))
+		return;
+
+	if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed");
+		next_type = eap_fast_req_failure(sm, data);
+		eap_fast_phase2_init(sm, data, next_type);
+		return;
+	}
+
+	switch (data->state) {
+	case PHASE2_ID:
+		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+			wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Phase2 "
+					  "Identity not found in the user "
+					  "database",
+					  sm->identity, sm->identity_len);
+			next_type = eap_fast_req_failure(sm, data);
+			break;
+		}
+
+		eap_fast_state(data, PHASE2_METHOD);
+		if (data->anon_provisioning) {
+			/*
+			 * Only EAP-MSCHAPv2 is allowed for anonymous
+			 * provisioning.
+			 */
+			next_type = EAP_TYPE_MSCHAPV2;
+			sm->user_eap_method_index = 0;
+		} else {
+			next_type = sm->user->methods[0].method;
+			sm->user_eap_method_index = 1;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type);
+		break;
+	case PHASE2_METHOD:
+		eap_fast_update_icmk(sm, data);
+		eap_fast_state(data, CRYPTO_BINDING);
+		next_type = EAP_TYPE_NONE;
+		break;
+	case FAILURE:
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d",
+			   __func__, data->state);
+		break;
+	}
+
+	eap_fast_phase2_init(sm, data, next_type);
+}
+
+
+static void eap_fast_process_phase2_eap(struct eap_sm *sm,
+					struct eap_fast_data *data,
+					u8 *in_data, size_t in_len)
+{
+	struct eap_hdr *hdr;
+	size_t len;
+
+	hdr = (struct eap_hdr *) in_data;
+	if (in_len < (int) sizeof(*hdr)) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
+			   "EAP frame (len=%d)", in_len);
+		eap_fast_req_failure(sm, data);
+		return;
+	}
+	len = be_to_host16(hdr->length);
+	if (len > in_len) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Length mismatch in "
+			   "Phase 2 EAP frame (len=%d hdr->length=%d)",
+			   in_len, len);
+		eap_fast_req_failure(sm, data);
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: code=%d "
+		   "identifier=%d length=%d", hdr->code, hdr->identifier, len);
+	switch (hdr->code) {
+	case EAP_CODE_RESPONSE:
+		eap_fast_process_phase2_response(sm, data, (u8 *) hdr, len);
+		break;
+	default:
+		wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
+			   "Phase 2 EAP header", hdr->code);
+		break;
+	}
+}
+
+
+struct eap_fast_tlv_parse {
+	u8 *eap_payload_tlv;
+	size_t eap_payload_tlv_len;
+	struct eap_tlv_crypto_binding__tlv *crypto_binding;
+	size_t crypto_binding_len;
+	int iresult;
+	int result;
+	int request_action;
+	u8 *pac;
+	size_t pac_len;
+};
+
+
+static int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
+			      int tlv_type, u8 *pos, int len)
+{
+	switch (tlv_type) {
+	case EAP_TLV_EAP_PAYLOAD_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV",
+			    pos, len);
+		if (tlv->eap_payload_tlv) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "EAP-Payload TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->eap_payload_tlv = pos;
+		tlv->eap_payload_tlv_len = len;
+		break;
+	case EAP_TLV_RESULT_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len);
+		if (tlv->result) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "Result TLV in the message");
+			tlv->result = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+				   "Result TLV");
+			tlv->result = EAP_TLV_RESULT_FAILURE;
+			break;
+		}
+		tlv->result = WPA_GET_BE16(pos);
+		if (tlv->result != EAP_TLV_RESULT_SUCCESS &&
+		    tlv->result != EAP_TLV_RESULT_FAILURE) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d",
+				   tlv->result);
+			tlv->result = EAP_TLV_RESULT_FAILURE;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
+			   tlv->result == EAP_TLV_RESULT_SUCCESS ?
+			   "Success" : "Failure");
+		break;
+	case EAP_TLV_INTERMEDIATE_RESULT_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV",
+			    pos, len);
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+				   "Intermediate-Result TLV");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			break;
+		}
+		if (tlv->iresult) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "Intermediate-Result TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->iresult = WPA_GET_BE16(pos);
+		if (tlv->iresult != EAP_TLV_RESULT_SUCCESS &&
+		    tlv->iresult != EAP_TLV_RESULT_FAILURE) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate "
+				   "Result %d", tlv->iresult);
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s",
+			   tlv->iresult == EAP_TLV_RESULT_SUCCESS ?
+			   "Success" : "Failure");
+		break;
+	case EAP_TLV_CRYPTO_BINDING_TLV_:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV",
+			    pos, len);
+		if (tlv->crypto_binding) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "Crypto-Binding TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
+		if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+				   "Crypto-Binding TLV");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->crypto_binding = (struct eap_tlv_crypto_binding__tlv *)
+			(pos - sizeof(struct eap_tlv_hdr));
+		break;
+	case EAP_TLV_REQUEST_ACTION_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV",
+			    pos, len);
+		if (tlv->request_action) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "Request-Action TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+				   "Request-Action TLV");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			break;
+		}
+		tlv->request_action = WPA_GET_BE16(pos);
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d",
+			   tlv->request_action);
+		break;
+	case EAP_TLV_PAC_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len);
+		if (tlv->pac) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "PAC TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->pac = pos;
+		tlv->pac_len = len;
+		break;
+	default:
+		/* Unknown TLV */
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eap_fast_parse_tlvs(u8 *data, size_t data_len,
+			       struct eap_fast_tlv_parse *tlv)
+{
+	int mandatory, tlv_type, len, res;
+	u8 *pos, *end;
+
+	os_memset(tlv, 0, sizeof(*tlv));
+
+	pos = data;
+	end = data + data_len;
+	while (pos + 4 < end) {
+		mandatory = pos[0] & 0x80;
+		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
+		pos += 2;
+		len = WPA_GET_BE16(pos);
+		pos += 2;
+		if (pos + len > end) {
+			wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
+			   "TLV type %d length %d%s",
+			   tlv_type, len, mandatory ? " (mandatory)" : "");
+
+		res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
+		if (res == -2)
+			break;
+		if (res < 0) {
+			if (mandatory) {
+				wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown "
+					   "mandatory TLV type %d", tlv_type);
+				/* TODO: generate Nak TLV */
+				break;
+			} else {
+				wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored "
+					   "unknown optional TLV type %d",
+					   tlv_type);
+			}
+		}
+
+		pos += len;
+	}
+
+	return 0;
+}
+
+
+static int eap_fast_validate_crypto_binding(
+	struct eap_fast_data *data, struct eap_tlv_crypto_binding__tlv *b,
+	size_t bind_len)
+{
+	u8 cmac[20];
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: "
+		   "Version %d Received Version %d SubType %d",
+		   b->version, b->received_version, b->subtype);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
+		    b->nonce, sizeof(b->nonce));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
+		    b->compound_mac, sizeof(b->compound_mac));
+
+	if (b->version != EAP_FAST_VERSION ||
+	    b->received_version != EAP_FAST_VERSION) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected version "
+			   "in Crypto-Binding: version %d "
+			   "received_version %d", b->version,
+			   b->received_version);
+		return -1;
+	}
+
+	if (b->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected subtype in "
+			   "Crypto-Binding: %d", b->subtype);
+		return -1;
+	}
+
+	if (os_memcmp(data->crypto_binding_nonce, b->nonce, 31) != 0 ||
+	    (data->crypto_binding_nonce[31] | 1) != b->nonce[31]) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in "
+			   "Crypto-Binding");
+		return -1;
+	}
+
+	os_memcpy(cmac, b->compound_mac, sizeof(cmac));
+	os_memset(b->compound_mac, 0, sizeof(cmac));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for "
+		    "Compound MAC calculation",
+		    (u8 *) b, bind_len);
+	hmac_sha1(data->cmk, 20, (u8 *) b, bind_len, b->compound_mac);
+	if (os_memcmp(cmac, b->compound_mac, sizeof(cmac)) != 0) {
+		wpa_hexdump(MSG_MSGDUMP,
+			    "EAP-FAST: Calculated Compound MAC",
+			    b->compound_mac, sizeof(cmac));
+		wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not "
+			   "match");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eap_fast_pac_type(u8 *pac, size_t len, u16 type)
+{
+	struct eap_tlv_pac_type_tlv *tlv;
+
+	if (pac == NULL || len != sizeof(*tlv))
+		return 0;
+
+	tlv = (struct eap_tlv_pac_type_tlv *) pac;
+
+	return be_to_host16(tlv->tlv_type) == PAC_TYPE_PAC_TYPE &&
+		be_to_host16(tlv->length) == 2 &&
+		be_to_host16(tlv->pac_type) == type;
+}
+
+
+static void eap_fast_process_phase2_tlvs(struct eap_sm *sm,
+					 struct eap_fast_data *data,
+					 u8 *in_data, size_t in_len)
+{
+	struct eap_fast_tlv_parse tlv;
+	int check_crypto_binding = data->state == CRYPTO_BINDING;
+
+	if (eap_fast_parse_tlvs(in_data, in_len, &tlv) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to parse receivede "
+			   "Phase 2 TLVs");
+		return;
+	}
+
+	if (tlv.result == EAP_TLV_RESULT_FAILURE) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Result TLV indicated "
+			   "failure");
+		eap_fast_state(data, FAILURE);
+		return;
+	}
+
+	if (data->state == REQUEST_PAC) {
+		u16 type, len, res;
+		if (tlv.pac == NULL || tlv.pac_len < 6) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC "
+				   "Acknowledgement received");
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		type = WPA_GET_BE16(tlv.pac);
+		len = WPA_GET_BE16(tlv.pac + 2);
+		res = WPA_GET_BE16(tlv.pac + 4);
+
+		if (type != PAC_TYPE_PAC_ACKNOWLEDGEMENT || len != 2 ||
+		    res != EAP_TLV_RESULT_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV did not "
+				   "contain acknowledgement");
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Acknowledgement received "
+			   "- PAC provisioning succeeded");
+		eap_fast_state(data, data->anon_provisioning ?
+			       FAILURE : SUCCESS);
+		return;
+	}
+
+	if (tlv.eap_payload_tlv) {
+		eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv,
+					    tlv.eap_payload_tlv_len);
+	}
+
+	if (check_crypto_binding) {
+		if (tlv.crypto_binding == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: No Crypto-Binding "
+				   "TLV received");
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		if (data->final_result &&
+		    tlv.result != EAP_TLV_RESULT_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV "
+				   "without Success Result");
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		if (!data->final_result &&
+		    tlv.iresult != EAP_TLV_RESULT_SUCCESS) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV "
+				   "without intermediate Success Result");
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		if (eap_fast_validate_crypto_binding(data, tlv.crypto_binding,
+						     tlv.crypto_binding_len)) {
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Valid Crypto-Binding TLV "
+			   "received - authentication completed successfully");
+
+		if (data->anon_provisioning ||
+		    (tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
+		     eap_fast_pac_type(tlv.pac, tlv.pac_len,
+				       PAC_TYPE_TUNNEL_PAC))) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Requested a new "
+				   "Tunnel PAC");
+			eap_fast_state(data, REQUEST_PAC);
+		} else if (data->send_new_pac) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Server triggered "
+				   "re-keying of Tunnel PAC");
+			eap_fast_state(data, REQUEST_PAC);
+		} else
+			eap_fast_state(data, SUCCESS);
+	}
+}
+
+
+static void eap_fast_process_phase2(struct eap_sm *sm,
+				    struct eap_fast_data *data,
+				    struct eap_hdr *resp,
+				    u8 *in_data, size_t in_len)
+{
+	u8 *in_decrypted;
+	int len_decrypted, res;
+	size_t buf_len;
+
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for"
+		   " Phase 2", (unsigned long) in_len);
+
+	res = eap_server_tls_data_reassemble(sm, &data->ssl, &in_data,
+					     &in_len);
+	if (res < 0 || res == 1)
+		return;
+
+	buf_len = in_len;
+	if (data->ssl.tls_in_total > buf_len)
+		buf_len = data->ssl.tls_in_total;
+	in_decrypted = malloc(buf_len);
+	if (in_decrypted == NULL) {
+		free(data->ssl.tls_in);
+		data->ssl.tls_in = NULL;
+		data->ssl.tls_in_len = 0;
+		wpa_printf(MSG_WARNING, "EAP-FAST: Failed to allocate memory "
+			   "for decryption");
+		return;
+	}
+
+	len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+					       in_data, in_len,
+					       in_decrypted, buf_len);
+	free(data->ssl.tls_in);
+	data->ssl.tls_in = NULL;
+	data->ssl.tls_in_len = 0;
+	if (len_decrypted < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
+			   "data");
+		free(in_decrypted);
+		eap_fast_state(data, FAILURE);
+		return;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Decrypted Phase 2 TLVs",
+			in_decrypted, len_decrypted);
+
+	eap_fast_process_phase2_tlvs(sm, data, in_decrypted, len_decrypted);
+
+	free(in_decrypted);
+}
+
+
+static void eap_fast_process(struct eap_sm *sm, void *priv,
+			     u8 *respData, size_t respDataLen)
+{
+	struct eap_fast_data *data = priv;
+	struct eap_hdr *resp;
+	u8 *pos, flags;
+	int left;
+	unsigned int tls_msg_len;
+	int peer_version;
+
+	resp = (struct eap_hdr *) respData;
+	pos = (u8 *) (resp + 1);
+	pos++;
+	flags = *pos++;
+	left = be_to_host16(resp->length) - sizeof(struct eap_hdr) - 2;
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Received packet(len=%lu) - "
+		   "Flags 0x%02x", (unsigned long) respDataLen, flags);
+	data->peer_version = peer_version = flags & EAP_PEAP_VERSION_MASK;
+	if (data->force_version >= 0 && peer_version != data->force_version) {
+		wpa_printf(MSG_INFO, "EAP-FAST: peer did not select the forced"
+			   " version (forced=%d peer=%d) - reject",
+			   data->force_version, peer_version);
+		eap_fast_state(data, FAILURE);
+		return;
+	}
+	if (peer_version < data->fast_version) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: peer ver=%d, own ver=%d; "
+			   "use version %d",
+			   peer_version, data->fast_version, peer_version);
+		data->fast_version = peer_version;
+	}
+	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+		if (left < 4) {
+			wpa_printf(MSG_INFO, "EAP-FAST: Short frame with TLS "
+				   "length");
+			eap_fast_state(data, FAILURE);
+			return;
+		}
+		tls_msg_len = WPA_GET_BE32(pos);
+		wpa_printf(MSG_DEBUG, "EAP-FAST: TLS Message Length: %d",
+			   tls_msg_len);
+		if (data->ssl.tls_in_left == 0) {
+			data->ssl.tls_in_total = tls_msg_len;
+			data->ssl.tls_in_left = tls_msg_len;
+			free(data->ssl.tls_in);
+			data->ssl.tls_in = NULL;
+			data->ssl.tls_in_len = 0;
+		}
+		pos += 4;
+		left -= 4;
+	}
+
+	switch (data->state) {
+	case PHASE1:
+		if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) <
+		    0) {
+			wpa_printf(MSG_INFO, "EAP-FAST: TLS processing "
+				   "failed");
+			eap_fast_state(data, FAILURE);
+		}
+
+		if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+		    data->ssl.tls_out_len > 0)
+			break;
+
+		/*
+		 * Phase 1 was completed with the received message (e.g., when
+		 * using abbreviated handshake), so Phase 2 can be started
+		 * immediately without having to send through an empty message
+		 * to the peer.
+		 */
+
+		if (eap_fast_phase1_done(sm, data) < 0)
+			break;
+
+		/* fall through to PHASE2_START */
+	case PHASE2_START:
+		eap_fast_state(data, PHASE2_ID);
+		eap_fast_phase2_init(sm, data, EAP_TYPE_IDENTITY);
+		break;
+	case PHASE2_ID:
+	case PHASE2_METHOD:
+	case CRYPTO_BINDING:
+	case REQUEST_PAC:
+		eap_fast_process_phase2(sm, data, resp, pos, left);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected state %d in %s",
+			   data->state, __func__);
+		break;
+	}
+
+	if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
+		wpa_printf(MSG_INFO, "EAP-FAST: Locally detected fatal error "
+			   "in TLS processing");
+		eap_fast_state(data, FAILURE);
+	}
+}
+
+
+static Boolean eap_fast_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_fast_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_fast_data *data = priv;
+	u8 *eapKeyData;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	/*
+	 * RFC 4851, Section 5.4: EAP Master Session Key Genreration
+	 * MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64)
+	 */
+
+	eapKeyData = os_malloc(EAP_FAST_KEY_LEN);
+	if (eapKeyData == NULL)
+		return NULL;
+
+	sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+		   "Session Key Generating Function", (u8 *) "", 0,
+		   eapKeyData, EAP_FAST_KEY_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
+			eapKeyData, EAP_FAST_KEY_LEN);
+	*len = EAP_FAST_KEY_LEN;
+
+	return eapKeyData;
+}
+
+
+static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_fast_data *data = priv;
+	u8 *eapKeyData;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	/*
+	 * RFC 4851, Section 5.4: EAP Master Session Key Genreration
+	 * EMSK = T-PRF(S-IMCK[j],
+	 *        "Extended Session Key Generating Function", 64)
+	 */
+
+	eapKeyData = os_malloc(EAP_EMSK_LEN);
+	if (eapKeyData == NULL)
+		return NULL;
+
+	sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+		   "Extended Session Key Generating Function",
+		   (u8 *) "", 0, eapKeyData, EAP_EMSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
+			eapKeyData, EAP_EMSK_LEN);
+
+	*len = EAP_EMSK_LEN;
+
+	return eapKeyData;
+}
+
+
+static Boolean eap_fast_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_fast_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+int eap_server_fast_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_fast_init;
+	eap->reset = eap_fast_reset;
+	eap->buildReq = eap_fast_buildReq;
+	eap->check = eap_fast_check;
+	eap->process = eap_fast_process;
+	eap->isDone = eap_fast_isDone;
+	eap->getKey = eap_fast_getKey;
+	eap->get_emsk = eap_fast_get_emsk;
+	eap->isSuccess = eap_fast_isSuccess;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_gpsk.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_gpsk.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_gpsk.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_gpsk.c Sat Nov  3 08:40:37 2007
@@ -1,5 +1,5 @@
 /*
- * hostapd / EAP-GPSK (draft-ietf-emu-eap-gpsk-04.txt) server
+ * hostapd / EAP-GPSK (draft-ietf-emu-eap-gpsk-06.txt) server
  * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -84,17 +84,17 @@
 	data->csuite_count = 0;
 	if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
 					   EAP_GPSK_CIPHER_AES)) {
-		WPA_PUT_BE24(data->csuite_list[data->csuite_count].vendor,
+		WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor,
 			     EAP_GPSK_VENDOR_IETF);
-		WPA_PUT_BE24(data->csuite_list[data->csuite_count].specifier,
+		WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier,
 			     EAP_GPSK_CIPHER_AES);
 		data->csuite_count++;
 	}
 	if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
 					   EAP_GPSK_CIPHER_SHA256)) {
-		WPA_PUT_BE24(data->csuite_list[data->csuite_count].vendor,
+		WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor,
 			     EAP_GPSK_VENDOR_IETF);
-		WPA_PUT_BE24(data->csuite_list[data->csuite_count].specifier,
+		WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier,
 			     EAP_GPSK_CIPHER_SHA256);
 		data->csuite_count++;
 	}
@@ -192,8 +192,8 @@
 	memcpy(pos, data->rand_server, EAP_GPSK_RAND_LEN);
 	pos += EAP_GPSK_RAND_LEN;
 	csuite = (struct eap_gpsk_csuite *) pos;
-	WPA_PUT_BE24(csuite->vendor, data->vendor);
-	WPA_PUT_BE24(csuite->specifier, data->specifier);
+	WPA_PUT_BE32(csuite->vendor, data->vendor);
+	WPA_PUT_BE16(csuite->specifier, data->specifier);
 	pos += sizeof(*csuite);
 
 	/* no PD_Payload_2 */
@@ -396,13 +396,13 @@
 	if (i == data->csuite_count) {
 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported "
 			   "ciphersuite %d:%d",
-			   WPA_GET_BE24(csuite->vendor),
-			   WPA_GET_BE24(csuite->specifier));
-		eap_gpsk_state(data, FAILURE);
-		return;
-	}
-	data->vendor = WPA_GET_BE24(csuite->vendor);
-	data->specifier = WPA_GET_BE24(csuite->specifier);
+			   WPA_GET_BE32(csuite->vendor),
+			   WPA_GET_BE16(csuite->specifier));
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	data->vendor = WPA_GET_BE32(csuite->vendor);
+	data->specifier = WPA_GET_BE16(csuite->specifier);
 	wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d",
 		   data->vendor, data->specifier);
 	pos += sizeof(*csuite);	

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c Sat Nov  3 08:40:37 2007
@@ -20,6 +20,7 @@
 
 struct eap_gtc_data {
 	enum { CONTINUE, SUCCESS, FAILURE } state;
+	int prefix;
 };
 
 
@@ -32,6 +33,15 @@
 		return NULL;
 	data->state = CONTINUE;
 
+#ifdef EAP_FAST
+	if (sm->m && sm->m->vendor == EAP_VENDOR_IETF &&
+	    sm->m->method == EAP_TYPE_FAST) {
+		wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
+			   "with challenge/response");
+		data->prefix = 1;
+	}
+#endif /* EAP_FAST */
+
 	return data;
 }
 
@@ -49,8 +59,10 @@
 	struct eap_gtc_data *data = priv;
 	struct eap_hdr *req;
 	u8 *pos;
-	char *msg = "Password";
+	char *msg;
 	size_t msg_len;
+
+	msg = data->prefix ? "CHALLENGE=Password" : "Password";
 
 	msg_len = strlen(msg);
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqDataLen,
@@ -94,6 +106,64 @@
 	const u8 *pos;
 	size_t rlen;
 
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC,
+			       respData, respDataLen, &rlen);
+	if (pos == NULL || rlen < 1)
+		return; /* Should not happen - frame already validated */
+
+	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen);
+
+#ifdef EAP_FAST
+	if (data->prefix) {
+		const u8 *pos2, *end;
+		/* "RESPONSE=<user>\0<password>" */
+		if (rlen < 10) {
+			wpa_printf(MSG_DEBUG, "EAP-GTC: Too short response "
+				   "for EAP-FAST prefix");
+			data->state = FAILURE;
+			return;
+		}
+
+		end = pos + rlen;
+		pos += 9;
+		pos2 = pos;
+		while (pos2 < end && *pos2)
+			pos2++;
+		if (pos2 == end) {
+			wpa_printf(MSG_DEBUG, "EAP-GTC: No password in "
+				   "response to EAP-FAST prefix");
+			data->state = FAILURE;
+			return;
+		}
+
+		wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Response user",
+				  pos, pos2 - pos);
+		os_free(sm->identity);
+		sm->identity_len = pos2 - pos;
+		sm->identity = os_malloc(sm->identity_len);
+		if (sm->identity == NULL) {
+			data->state = FAILURE;
+			return;
+		}
+		os_memcpy(sm->identity, pos, sm->identity_len);
+
+		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+			wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 "
+					  "Identity not found in the user "
+					  "database",
+					  sm->identity, sm->identity_len);
+			data->state = FAILURE;
+			return;
+		}
+
+		pos = pos2 + 1;
+		rlen = end - pos;
+		wpa_hexdump_ascii_key(MSG_MSGDUMP,
+				      "EAP-GTC: Response password",
+				      pos, rlen);
+	}
+#endif /* EAP_FAST */
+
 	if (sm->user == NULL || sm->user->password == NULL ||
 	    sm->user->password_hash) {
 		wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not "
@@ -101,13 +171,6 @@
 		data->state = FAILURE;
 		return;
 	}
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC,
-			       respData, respDataLen, &rlen);
-	if (pos == NULL || rlen < 1)
-		return; /* Should not happen - frame already validated */
-
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen);
 
 	if (rlen != sm->user->password_len ||
 	    memcmp(pos, sm->user->password, rlen) != 0) {

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h Sat Nov  3 08:40:37 2007
@@ -179,6 +179,12 @@
 	enum {
 		METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT
 	} method_pending;
+
+	u8 *auth_challenge;
+	u8 *peer_challenge;
+
+	u8 *pac_opaque_encr_key;
+	char *eap_fast_a_id;
 };
 
 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c Sat Nov  3 08:40:37 2007
@@ -247,6 +247,13 @@
 	}
 #endif /* EAP_VENDOR_TEST */
 
+#ifdef EAP_FAST
+	if (ret == 0) {
+		int eap_server_fast_register(void);
+		ret = eap_server_fast_register();
+	}
+#endif /* EAP_FAST */
+
 	return ret;
 }
 

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c Sat Nov  3 08:40:37 2007
@@ -50,6 +50,8 @@
 
 struct eap_mschapv2_data {
 	u8 auth_challenge[CHALLENGE_LEN];
+	int auth_challenge_from_tls;
+	u8 *peer_challenge;
 	u8 auth_response[20];
 	enum { CHALLENGE, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE } state;
 	u8 resp_mschapv2_id;
@@ -67,6 +69,22 @@
 		return NULL;
 	data->state = CHALLENGE;
 
+	if (sm->auth_challenge) {
+		os_memcpy(data->auth_challenge, sm->auth_challenge,
+			  CHALLENGE_LEN);
+		data->auth_challenge_from_tls = 1;
+	}
+
+	if (sm->peer_challenge) {
+		data->peer_challenge = os_malloc(CHALLENGE_LEN);
+		if (data->peer_challenge == NULL) {
+			os_free(data);
+			return NULL;
+		}
+		os_memcpy(data->peer_challenge, sm->peer_challenge,
+			  CHALLENGE_LEN);
+	}
+
 	return data;
 }
 
@@ -74,6 +92,10 @@
 static void eap_mschapv2_reset(struct eap_sm *sm, void *priv)
 {
 	struct eap_mschapv2_data *data = priv;
+	if (data == NULL)
+		return;
+
+	free(data->peer_challenge);
 	free(data);
 }
 
@@ -88,7 +110,8 @@
 	char *name = "hostapd"; /* TODO: make this configurable */
 	size_t ms_len;
 
-	if (hostapd_get_rand(data->auth_challenge, CHALLENGE_LEN)) {
+	if (!data->auth_challenge_from_tls &&
+	    hostapd_get_rand(data->auth_challenge, CHALLENGE_LEN)) {
 		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random "
 			   "data");
 		data->state = FAILURE;
@@ -112,7 +135,8 @@
 
 	pos = (u8 *) (ms + 1);
 	*pos++ = CHALLENGE_LEN;
-	memcpy(pos, data->auth_challenge, CHALLENGE_LEN);
+	if (!data->auth_challenge_from_tls)
+		memcpy(pos, data->auth_challenge, CHALLENGE_LEN);
 	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge", pos,
 		    CHALLENGE_LEN);
 	pos += CHALLENGE_LEN;
@@ -306,6 +330,11 @@
 	name = pos;
 	name_len = end - name;
 
+	if (data->peer_challenge) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using pre-configured "
+			   "Peer-Challenge");
+		peer_challenge = data->peer_challenge;
+	}
 	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge",
 		    peer_challenge, 16);
 	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: NT-Response", nt_response, 24);

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_tlv.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_tlv.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_tlv.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_tlv.c Sat Nov  3 08:40:37 2007
@@ -16,20 +16,7 @@
 
 #include "common.h"
 #include "eap_i.h"
-
-
-/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-07.txt) */
-#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
-#define EAP_TLV_NAK_TLV 4
-#define EAP_TLV_CRYPTO_BINDING_TLV 5
-#define EAP_TLV_CONNECTION_BINDING_TLV 6
-#define EAP_TLV_VENDOR_SPECIFIC_TLV 7
-#define EAP_TLV_URI_TLV 8
-#define EAP_TLV_EAP_PAYLOAD_TLV 9
-#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
-
-#define EAP_TLV_RESULT_SUCCESS 1
-#define EAP_TLV_RESULT_FAILURE 2
+#include "eap_common/eap_tlv_common.h"
 
 
 struct eap_tlv_data {

Modified: wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_freebsd.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_freebsd.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_freebsd.c (original)
+++ wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_freebsd.c Sat Nov  3 08:40:37 2007
@@ -14,6 +14,9 @@
  */
 
 #include "includes.h"
+#ifdef __APPLE__
+#include <net/bpf.h>
+#endif /* __APPLE__ */
 #include <pcap.h>
 
 #include <sys/ioctl.h>
@@ -231,8 +234,11 @@
 void l2_packet_deinit(struct l2_packet_data *l2)
 {
 	if (l2 != NULL) {
-		if (l2->pcap)
+		if (l2->pcap) {
+			eloop_unregister_read_sock(
+				pcap_get_selectable_fd(l2->pcap));
 			pcap_close(l2->pcap);
+		}
 		os_free(l2);
 	}
 }

Modified: wpasupplicant/branches/upstream/current/src/radius/radius_client.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius_client.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_client.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_client.c Sat Nov  3 08:40:37 2007
@@ -142,7 +142,8 @@
 #ifndef CONFIG_NATIVE_WINDOWS
 	int _errno = errno;
 	perror("send[RADIUS]");
-	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL) {
+	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
+	    _errno == EBADF) {
 		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 			       HOSTAPD_LEVEL_INFO,
 			       "Send failed - maybe interface status changed -"

Modified: wpasupplicant/branches/upstream/current/src/radius/radius_server.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius_server.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_server.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_server.c Sat Nov  3 08:40:37 2007
@@ -87,6 +87,8 @@
 	int num_sess;
 	void *eap_sim_db_priv;
 	void *ssl_ctx;
+	u8 *pac_opaque_encr_key;
+	char *eap_fast_a_id;
 	int ipv6;
 	struct os_time start_time;
 	struct radius_server_counters counters;
@@ -309,6 +311,8 @@
 	eap_conf.ssl_ctx = data->ssl_ctx;
 	eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
 	eap_conf.backend_auth = TRUE;
+	eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
+	eap_conf.eap_fast_a_id = data->eap_fast_a_id;
 	sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
 				       &eap_conf);
 	if (sess->eap == NULL) {
@@ -999,6 +1003,13 @@
 	data->eap_sim_db_priv = conf->eap_sim_db_priv;
 	data->ssl_ctx = conf->ssl_ctx;
 	data->ipv6 = conf->ipv6;
+	if (conf->pac_opaque_encr_key) {
+		data->pac_opaque_encr_key = os_malloc(16);
+		os_memcpy(data->pac_opaque_encr_key, conf->pac_opaque_encr_key,
+			  16);
+	}
+	if (conf->eap_fast_a_id)
+		data->eap_fast_a_id = os_strdup(conf->eap_fast_a_id);
 	data->get_eap_user = conf->get_eap_user;
 
 	data->clients = radius_server_read_clients(conf->client_file,

Modified: wpasupplicant/branches/upstream/current/src/radius/radius_server.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius_server.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_server.h (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_server.h Sat Nov  3 08:40:37 2007
@@ -24,6 +24,8 @@
 	void *conf_ctx;
 	void *eap_sim_db_priv;
 	void *ssl_ctx;
+	u8 *pac_opaque_encr_key;
+	char *eap_fast_a_id;
 	int ipv6;
 	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
 			    int phase2, struct eap_user *user);

Modified: wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c Sat Nov  3 08:40:37 2007
@@ -229,7 +229,7 @@
 	pos += sizeof(*mdie);
 	os_memcpy(mdie->mobility_domain, sm->mobility_domain,
 		  MOBILITY_DOMAIN_ID_LEN);
-	mdie->ft_capab = RSN_FT_CAPAB_FT_OVER_AIR;
+	mdie->ft_capab = 0; /* FIX: copy from the target AP's MDIE */
 
 	/* FTIE[SNonce, R0KH-ID] */
 	*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
@@ -747,7 +747,8 @@
 
 	if (parse.gtk[1] != keylen) {
 		wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d "
-			   "negotiated %d", parse.gtk[1], keylen);
+			   "negotiated %lu",
+			   parse.gtk[1], (unsigned long) keylen);
 		return -1;
 	}
 

Modified: wpasupplicant/branches/upstream/current/src/tls/asn1.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/asn1.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/asn1.c (original)
+++ wpasupplicant/branches/upstream/current/src/tls/asn1.c Sat Nov  3 08:40:37 2007
@@ -58,6 +58,10 @@
 		}
 		tmp &= 0x7f; /* number of subsequent octets */
 		hdr->length = 0;
+		if (tmp > 4) {
+			wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
+			return -1;
+		}
 		while (tmp--) {
 			if (pos >= end) {
 				wpa_printf(MSG_DEBUG, "ASN.1: Length "
@@ -71,7 +75,7 @@
 		hdr->length = tmp;
 	}
 
-	if (pos + hdr->length > end) {
+	if (end < pos || hdr->length > (unsigned int) (end - pos)) {
 		wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
 		return -1;
 	}

Modified: wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c (original)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c Sat Nov  3 08:40:37 2007
@@ -1,6 +1,6 @@
 /*
- * wpa_supplicant: TLSv1 client (RFC 2246)
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ * TLSv1 client (RFC 2246)
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -15,614 +15,26 @@
 #include "includes.h"
 
 #include "common.h"
-#include "base64.h"
-#include "md5.h"
 #include "sha1.h"
-#include "crypto.h"
 #include "tls.h"
 #include "tlsv1_common.h"
+#include "tlsv1_record.h"
 #include "tlsv1_client.h"
-#include "x509v3.h"
+#include "tlsv1_client_i.h"
 
 /* TODO:
  * Support for a message fragmented across several records (RFC 2246, 6.2.1)
  */
 
-struct tlsv1_client {
-	enum {
-		CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,
-		SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,
-		SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,
-		SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,
-		ESTABLISHED, FAILED
-	} state;
-
-	struct tlsv1_record_layer rl;
-
-	u8 session_id[TLS_SESSION_ID_MAX_LEN];
-	size_t session_id_len;
-	u8 client_random[TLS_RANDOM_LEN];
-	u8 server_random[TLS_RANDOM_LEN];
-	u8 master_secret[TLS_MASTER_SECRET_LEN];
-
-	u8 alert_level;
-	u8 alert_description;
-
-	unsigned int certificate_requested:1;
-	unsigned int session_resumed:1;
-	unsigned int ticket:1;
-	unsigned int ticket_key:1;
-
-	struct crypto_public_key *server_rsa_key;
-
-	struct crypto_hash *verify_md5_client;
-	struct crypto_hash *verify_sha1_client;
-	struct crypto_hash *verify_md5_server;
-	struct crypto_hash *verify_sha1_server;
-	struct crypto_hash *verify_md5_cert;
-	struct crypto_hash *verify_sha1_cert;
-
-#define MAX_CIPHER_COUNT 30
-	u16 cipher_suites[MAX_CIPHER_COUNT];
-	size_t num_cipher_suites;
-
-	u16 prev_cipher_suite;
-
-	u8 *client_hello_ext;
-	size_t client_hello_ext_len;
-
-	/* The prime modulus used for Diffie-Hellman */
-	u8 *dh_p;
-	size_t dh_p_len;
-	/* The generator used for Diffie-Hellman */
-	u8 *dh_g;
-	size_t dh_g_len;
-	/* The server's Diffie-Hellman public value */
-	u8 *dh_ys;
-	size_t dh_ys_len;
-
-	struct x509_certificate *trusted_certs;
-	struct x509_certificate *client_cert;
-	struct crypto_private_key *client_key;
-};
-
-
-static int tls_derive_keys(struct tlsv1_client *conn,
-			   const u8 *pre_master_secret,
-			   size_t pre_master_secret_len);
-static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
-					   const u8 *in_data, size_t *in_len);
-static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
-					   const u8 *in_data, size_t *in_len);
-static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
-					 const u8 *in_data, size_t *in_len);
-
-
-static void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)
+
+void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)
 {
 	conn->alert_level = level;
 	conn->alert_description = description;
 }
 
 
-static void tls_verify_hash_add(struct tlsv1_client *conn, const u8 *buf,
-				size_t len)
-{
-	if (conn->verify_md5_client && conn->verify_sha1_client) {
-		crypto_hash_update(conn->verify_md5_client, buf, len);
-		crypto_hash_update(conn->verify_sha1_client, buf, len);
-	}
-	if (conn->verify_md5_server && conn->verify_sha1_server) {
-		crypto_hash_update(conn->verify_md5_server, buf, len);
-		crypto_hash_update(conn->verify_sha1_server, buf, len);
-	}
-	if (conn->verify_md5_cert && conn->verify_sha1_cert) {
-		crypto_hash_update(conn->verify_md5_cert, buf, len);
-		crypto_hash_update(conn->verify_sha1_cert, buf, len);
-	}
-}
-
-
-static u8 * tls_send_alert(struct tlsv1_client *conn,
-			   u8 level, u8 description,
-			   size_t *out_len)
-{
-	u8 *alert, *pos, *length;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
-	*out_len = 0;
-
-	alert = os_malloc(10);
-	if (alert == NULL)
-		return NULL;
-
-	pos = alert;
-
-	/* TLSPlaintext */
-	/* ContentType type */
-	*pos++ = TLS_CONTENT_TYPE_ALERT;
-	/* ProtocolVersion version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
-	pos += 2;
-	/* uint16 length (to be filled) */
-	length = pos;
-	pos += 2;
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Alert */
-	/* AlertLevel level */
-	*pos++ = level;
-	/* AlertDescription description */
-	*pos++ = description;
-
-	WPA_PUT_BE16(length, pos - length - 2);
-	*out_len = pos - alert;
-
-	return alert;
-}
-
-
-static u8 * tls_send_client_hello(struct tlsv1_client *conn,
-				  size_t *out_len)
-{
-	u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
-	struct os_time now;
-	size_t len, i;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
-	*out_len = 0;
-
-	os_get_time(&now);
-	WPA_PUT_BE32(conn->client_random, now.sec);
-	if (os_get_random(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
-		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
-			   "client_random");
-		return NULL;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
-		    conn->client_random, TLS_RANDOM_LEN);
-
-	len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
-	hello = os_malloc(len);
-	if (hello == NULL)
-		return NULL;
-	end = hello + len;
-
-	rhdr = hello;
-	pos = rhdr + TLS_RECORD_HEADER_LEN;
-
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-	/* body - ClientHello */
-	/* ProtocolVersion client_version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
-	pos += 2;
-	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
-	os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN);
-	pos += TLS_RANDOM_LEN;
-	/* SessionID session_id */
-	*pos++ = conn->session_id_len;
-	os_memcpy(pos, conn->session_id, conn->session_id_len);
-	pos += conn->session_id_len;
-	/* CipherSuite cipher_suites<2..2^16-1> */
-	WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites);
-	pos += 2;
-	for (i = 0; i < conn->num_cipher_suites; i++) {
-		WPA_PUT_BE16(pos, conn->cipher_suites[i]);
-		pos += 2;
-	}
-	/* CompressionMethod compression_methods<1..2^8-1> */
-	*pos++ = 1;
-	*pos++ = TLS_COMPRESSION_NULL;
-
-	if (conn->client_hello_ext) {
-		os_memcpy(pos, conn->client_hello_ext,
-			  conn->client_hello_ext_len);
-		pos += conn->client_hello_ext_len;
-	}
-
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-	tls_verify_hash_add(conn, hs_start, pos - hs_start);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, out_len) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(hello);
-		return NULL;
-	}
-
-	conn->state = SERVER_HELLO;
-
-	return hello;
-}
-
-
-static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
-				    const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len, i;
-	u16 cipher_suite;
-
-	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
-			   "received content type 0x%x", ct);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	pos = in_data;
-	left = *in_len;
-
-	if (left < 4)
-		goto decode_error;
-
-	/* HandshakeType msg_type */
-	if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected ServerHello)", *pos);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello");
-	pos++;
-	/* uint24 length */
-	len = WPA_GET_BE24(pos);
-	pos += 3;
-	left -= 4;
-
-	if (len > left)
-		goto decode_error;
-
-	/* body - ServerHello */
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len);
-	end = pos + len;
-
-	/* ProtocolVersion server_version */
-	if (end - pos < 2)
-		goto decode_error;
-	if (WPA_GET_BE16(pos) != TLS_VERSION) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
-			   "ServerHello");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_PROTOCOL_VERSION);
-		return -1;
-	}
-	pos += 2;
-
-	/* Random random */
-	if (end - pos < TLS_RANDOM_LEN)
-		goto decode_error;
-
-	os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN);
-	pos += TLS_RANDOM_LEN;
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
-		    conn->server_random, TLS_RANDOM_LEN);
-
-	/* SessionID session_id */
-	if (end - pos < 1)
-		goto decode_error;
-	if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
-		goto decode_error;
-	if (conn->session_id_len && conn->session_id_len == *pos &&
-	    os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) {
-		pos += 1 + conn->session_id_len;
-		wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session");
-		conn->session_resumed = 1;
-	} else {
-		conn->session_id_len = *pos;
-		pos++;
-		os_memcpy(conn->session_id, pos, conn->session_id_len);
-		pos += conn->session_id_len;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
-		    conn->session_id, conn->session_id_len);
-
-	/* CipherSuite cipher_suite */
-	if (end - pos < 2)
-		goto decode_error;
-	cipher_suite = WPA_GET_BE16(pos);
-	pos += 2;
-	for (i = 0; i < conn->num_cipher_suites; i++) {
-		if (cipher_suite == conn->cipher_suites[i])
-			break;
-	}
-	if (i == conn->num_cipher_suites) {
-		wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
-			   "cipher suite 0x%04x", cipher_suite);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_ILLEGAL_PARAMETER);
-		return -1;
-	}
-
-	if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different "
-			   "cipher suite for a resumed connection (0x%04x != "
-			   "0x%04x)", cipher_suite, conn->prev_cipher_suite);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_ILLEGAL_PARAMETER);
-		return -1;
-	}
-
-	if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
-			   "record layer");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	conn->prev_cipher_suite = cipher_suite;
-
-	if (conn->session_resumed || conn->ticket_key)
-		tls_derive_keys(conn, NULL, 0);
-
-	/* CompressionMethod compression_method */
-	if (end - pos < 1)
-		goto decode_error;
-	if (*pos != TLS_COMPRESSION_NULL) {
-		wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
-			   "compression 0x%02x", *pos);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_ILLEGAL_PARAMETER);
-		return -1;
-	}
-	pos++;
-
-	if (end != pos) {
-		wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
-			    "end of ServerHello", pos, end - pos);
-		goto decode_error;
-	}
-
-	*in_len = end - in_data;
-
-	conn->state = (conn->session_resumed || conn->ticket) ?
-		SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE;
-
-	return 0;
-
-decode_error:
-	wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello");
-	tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-	return -1;
-}
-
-
-static int tls_server_key_exchange_allowed(struct tlsv1_client *conn)
-{
-	const struct tls_cipher_suite *suite;
-
-	/* RFC 2246, Section 7.4.3 */
-	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
-	if (suite == NULL)
-		return 0;
-
-	switch (suite->key_exchange) {
-	case TLS_KEY_X_DHE_DSS:
-	case TLS_KEY_X_DHE_DSS_EXPORT:
-	case TLS_KEY_X_DHE_RSA:
-	case TLS_KEY_X_DHE_RSA_EXPORT:
-	case TLS_KEY_X_DH_anon_EXPORT:
-	case TLS_KEY_X_DH_anon:
-		return 1;
-	case TLS_KEY_X_RSA_EXPORT:
-		return 1 /* FIX: public key len > 512 bits */;
-	default:
-		return 0;
-	}
-}
-
-
-static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
-				   const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len, list_len, cert_len, idx;
-	u8 type;
-	struct x509_certificate *chain = NULL, *last = NULL, *cert;
-	int reason;
-
-	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
-			   "received content type 0x%x", ct);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	pos = in_data;
-	left = *in_len;
-
-	if (left < 4) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
-			   "(len=%lu)", (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	type = *pos++;
-	len = WPA_GET_BE24(pos);
-	pos += 3;
-	left -= 4;
-
-	if (len > left) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
-			   "length (len=%lu != left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	if (type == TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE)
-		return tls_process_server_key_exchange(conn, ct, in_data,
-						       in_len);
-	if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
-		return tls_process_certificate_request(conn, ct, in_data,
-						       in_len);
-	if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
-		return tls_process_server_hello_done(conn, ct, in_data,
-						     in_len);
-	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected Certificate/"
-			   "ServerKeyExchange/CertificateRequest/"
-			   "ServerHelloDone)", type);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG,
-		   "TLSv1: Received Certificate (certificate_list len %lu)",
-		   (unsigned long) len);
-
-	/*
-	 * opaque ASN.1Cert<2^24-1>;
-	 *
-	 * struct {
-	 *     ASN.1Cert certificate_list<1..2^24-1>;
-	 * } Certificate;
-	 */
-
-	end = pos + len;
-
-	if (end - pos < 3) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
-			   "(left=%lu)", (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	list_len = WPA_GET_BE24(pos);
-	pos += 3;
-
-	if ((size_t) (end - pos) != list_len) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
-			   "length (len=%lu left=%lu)",
-			   (unsigned long) list_len,
-			   (unsigned long) (end - pos));
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	idx = 0;
-	while (pos < end) {
-		if (end - pos < 3) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
-				   "certificate_list");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_DECODE_ERROR);
-			x509_certificate_chain_free(chain);
-			return -1;
-		}
-
-		cert_len = WPA_GET_BE24(pos);
-		pos += 3;
-
-		if ((size_t) (end - pos) < cert_len) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
-				   "length (len=%lu left=%lu)",
-				   (unsigned long) cert_len,
-				   (unsigned long) (end - pos));
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_DECODE_ERROR);
-			x509_certificate_chain_free(chain);
-			return -1;
-		}
-
-		wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
-			   (unsigned long) idx, (unsigned long) cert_len);
-
-		if (idx == 0) {
-			crypto_public_key_free(conn->server_rsa_key);
-			if (tls_parse_cert(pos, cert_len,
-					   &conn->server_rsa_key)) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
-					   "the certificate");
-				tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-					  TLS_ALERT_BAD_CERTIFICATE);
-				x509_certificate_chain_free(chain);
-				return -1;
-			}
-		}
-
-		cert = x509_certificate_parse(pos, cert_len);
-		if (cert == NULL) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
-				   "the certificate");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_BAD_CERTIFICATE);
-			x509_certificate_chain_free(chain);
-			return -1;
-		}
-
-		if (last == NULL)
-			chain = cert;
-		else
-			last->next = cert;
-		last = cert;
-
-		idx++;
-		pos += cert_len;
-	}
-
-	if (x509_certificate_chain_validate(conn->trusted_certs, chain,
-					    &reason) < 0) {
-		int tls_reason;
-		wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
-			   "validation failed (reason=%d)", reason);
-		switch (reason) {
-		case X509_VALIDATE_BAD_CERTIFICATE:
-			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
-			break;
-		case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
-			tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
-			break;
-		case X509_VALIDATE_CERTIFICATE_REVOKED:
-			tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
-			break;
-		case X509_VALIDATE_CERTIFICATE_EXPIRED:
-			tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
-			break;
-		case X509_VALIDATE_CERTIFICATE_UNKNOWN:
-			tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
-			break;
-		case X509_VALIDATE_UNKNOWN_CA:
-			tls_reason = TLS_ALERT_UNKNOWN_CA;
-			break;
-		default:
-			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
-			break;
-		}
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
-		x509_certificate_chain_free(chain);
-		return -1;
-	}
-
-	x509_certificate_chain_free(chain);
-
-	*in_len = end - in_data;
-
-	conn->state = SERVER_KEY_EXCHANGE;
-
-	return 0;
-}
-
-
-static void tlsv1_client_free_dh(struct tlsv1_client *conn)
+void tlsv1_client_free_dh(struct tlsv1_client *conn)
 {
 	os_free(conn->dh_p);
 	os_free(conn->dh_g);
@@ -631,438 +43,7 @@
 }
 
 
-static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
-					const u8 *buf, size_t len)
-{
-	const u8 *pos, *end;
-
-	tlsv1_client_free_dh(conn);
-
-	pos = buf;
-	end = buf + len;
-
-	if (end - pos < 3)
-		goto fail;
-	conn->dh_p_len = WPA_GET_BE16(pos);
-	pos += 2;
-	if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len)
-		goto fail;
-	conn->dh_p = os_malloc(conn->dh_p_len);
-	if (conn->dh_p == NULL)
-		goto fail;
-	os_memcpy(conn->dh_p, pos, conn->dh_p_len);
-	pos += conn->dh_p_len;
-	wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
-		    conn->dh_p, conn->dh_p_len);
-
-	if (end - pos < 3)
-		goto fail;
-	conn->dh_g_len = WPA_GET_BE16(pos);
-	pos += 2;
-	if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
-		goto fail;
-	conn->dh_g = os_malloc(conn->dh_g_len);
-	if (conn->dh_g == NULL)
-		goto fail;
-	os_memcpy(conn->dh_g, pos, conn->dh_g_len);
-	pos += conn->dh_g_len;
-	wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
-		    conn->dh_g, conn->dh_g_len);
-	if (conn->dh_g_len == 1 && conn->dh_g[0] < 2)
-		goto fail;
-
-	if (end - pos < 3)
-		goto fail;
-	conn->dh_ys_len = WPA_GET_BE16(pos);
-	pos += 2;
-	if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
-		goto fail;
-	conn->dh_ys = os_malloc(conn->dh_ys_len);
-	if (conn->dh_ys == NULL)
-		goto fail;
-	os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
-	pos += conn->dh_ys_len;
-	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
-		    conn->dh_ys, conn->dh_ys_len);
-
-	return 0;
-
-fail:
-	tlsv1_client_free_dh(conn);
-	return -1;
-}
-
-
-static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
-					   const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len;
-	u8 type;
-	const struct tls_cipher_suite *suite;
-
-	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
-			   "received content type 0x%x", ct);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	pos = in_data;
-	left = *in_len;
-
-	if (left < 4) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerKeyExchange "
-			   "(Left=%lu)", (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	type = *pos++;
-	len = WPA_GET_BE24(pos);
-	pos += 3;
-	left -= 4;
-
-	if (len > left) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerKeyExchange "
-			   "length (len=%lu != left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	end = pos + len;
-
-	if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
-		return tls_process_certificate_request(conn, ct, in_data,
-						       in_len);
-	if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
-		return tls_process_server_hello_done(conn, ct, in_data,
-						     in_len);
-	if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected ServerKeyExchange/"
-			   "CertificateRequest/ServerHelloDone)", type);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange");
-
-	if (!tls_server_key_exchange_allowed(conn)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed "
-			   "with the selected cipher suite");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
-	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
-	if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
-		if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_DECODE_ERROR);
-			return -1;
-		}
-	} else {
-		wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	*in_len = end - in_data;
-
-	conn->state = SERVER_CERTIFICATE_REQUEST;
-
-	return 0;
-}
-
-
-static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
-					   const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len;
-	u8 type;
-
-	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
-			   "received content type 0x%x", ct);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	pos = in_data;
-	left = *in_len;
-
-	if (left < 4) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateRequest "
-			   "(left=%lu)", (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	type = *pos++;
-	len = WPA_GET_BE24(pos);
-	pos += 3;
-	left -= 4;
-
-	if (len > left) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in CertificateRequest "
-			   "length (len=%lu != left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	end = pos + len;
-
-	if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
-		return tls_process_server_hello_done(conn, ct, in_data,
-						     in_len);
-	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected CertificateRequest/"
-			   "ServerHelloDone)", type);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateRequest");
-
-	conn->certificate_requested = 1;
-
-	*in_len = end - in_data;
-
-	conn->state = SERVER_HELLO_DONE;
-
-	return 0;
-}
-
-
-static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
-					 const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len;
-	u8 type;
-
-	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
-			   "received content type 0x%x", ct);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	pos = in_data;
-	left = *in_len;
-
-	if (left < 4) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerHelloDone "
-			   "(left=%lu)", (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	type = *pos++;
-	len = WPA_GET_BE24(pos);
-	pos += 3;
-	left -= 4;
-
-	if (len > left) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerHelloDone "
-			   "length (len=%lu != left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-	end = pos + len;
-
-	if (type != TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
-			   "message %d (expected ServerHelloDone)", type);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
-
-	*in_len = end - in_data;
-
-	conn->state = CLIENT_KEY_EXCHANGE;
-
-	return 0;
-}
-
-
-static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,
-						 u8 ct, const u8 *in_data,
-						 size_t *in_len)
-{
-	const u8 *pos;
-	size_t left;
-
-	if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
-			   "received content type 0x%x", ct);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	pos = in_data;
-	left = *in_len;
-
-	if (left < 1) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	if (*pos != TLS_CHANGE_CIPHER_SPEC) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
-			   "received data 0x%x", *pos);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
-	if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
-			   "for record layer");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	*in_len = pos + 1 - in_data;
-
-	conn->state = SERVER_FINISHED;
-
-	return 0;
-}
-
-
-static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
-				       const u8 *in_data, size_t *in_len)
-{
-	const u8 *pos, *end;
-	size_t left, len, hlen;
-	u8 verify_data[TLS_VERIFY_DATA_LEN];
-	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
-
-	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
-			   "received content type 0x%x", ct);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	pos = in_data;
-	left = *in_len;
-
-	if (left < 4) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
-			   "Finished",
-			   (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-
-	if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
-			   "type 0x%x", pos[0]);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	len = WPA_GET_BE24(pos + 1);
-
-	pos += 4;
-	left -= 4;
-
-	if (len > left) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
-			   "(len=%lu > left=%lu)",
-			   (unsigned long) len, (unsigned long) left);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-	end = pos + len;
-	if (len != TLS_VERIFY_DATA_LEN) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
-			   "in Finished: %lu (expected %d)",
-			   (unsigned long) len, TLS_VERIFY_DATA_LEN);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_DECODE_ERROR);
-		return -1;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
-		    pos, TLS_VERIFY_DATA_LEN);
-
-	hlen = MD5_MAC_LEN;
-	if (conn->verify_md5_server == NULL ||
-	    crypto_hash_finish(conn->verify_md5_server, hash, &hlen) < 0) {
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		conn->verify_md5_server = NULL;
-		crypto_hash_finish(conn->verify_sha1_server, NULL, NULL);
-		conn->verify_sha1_server = NULL;
-		return -1;
-	}
-	conn->verify_md5_server = NULL;
-	hlen = SHA1_MAC_LEN;
-	if (conn->verify_sha1_server == NULL ||
-	    crypto_hash_finish(conn->verify_sha1_server, hash + MD5_MAC_LEN,
-			       &hlen) < 0) {
-		conn->verify_sha1_server = NULL;
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	conn->verify_sha1_server = NULL;
-
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
-		    verify_data, TLS_VERIFY_DATA_LEN)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_DECRYPT_ERROR);
-		return -1;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
-			verify_data, TLS_VERIFY_DATA_LEN);
-
-	if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
-		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
-
-	*in_len = end - in_data;
-
-	conn->state = (conn->session_resumed || conn->ticket) ?
-		CHANGE_CIPHER_SPEC : ACK_FINISHED;
-
-	return 0;
-}
-
-
-static int tls_derive_pre_master_secret(u8 *pre_master_secret)
+int tls_derive_pre_master_secret(u8 *pre_master_secret)
 {
 	WPA_PUT_BE16(pre_master_secret, TLS_VERSION);
 	if (os_get_random(pre_master_secret + 2,
@@ -1072,9 +53,8 @@
 }
 
 
-static int tls_derive_keys(struct tlsv1_client *conn,
-			   const u8 *pre_master_secret,
-			   size_t pre_master_secret_len)
+int tls_derive_keys(struct tlsv1_client *conn,
+		    const u8 *pre_master_secret, size_t pre_master_secret_len)
 {
 	u8 seed[2 * TLS_RANDOM_LEN];
 	u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
@@ -1138,718 +118,6 @@
 }
 
 
-static int tls_write_client_certificate(struct tlsv1_client *conn,
-					u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
-	size_t rlen;
-	struct x509_certificate *cert;
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-	/* body - Certificate */
-	/* uint24 length (to be filled) */
-	cert_start = pos;
-	pos += 3;
-	cert = conn->client_cert;
-	while (cert) {
-		if (pos + 3 + cert->cert_len > end) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
-				   "for Certificate (cert_len=%lu left=%lu)",
-				   (unsigned long) cert->cert_len,
-				   (unsigned long) (end - pos));
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_INTERNAL_ERROR);
-			return -1;
-		}
-		WPA_PUT_BE24(pos, cert->cert_len);
-		pos += 3;
-		os_memcpy(pos, cert->cert_start, cert->cert_len);
-		pos += cert->cert_len;
-
-		if (x509_certificate_self_signed(cert))
-			break;
-		cert = x509_certificate_get_subject(conn->trusted_certs,
-						    &cert->issuer);
-	}
-	if (cert == conn->client_cert || cert == NULL) {
-		/*
-		 * Client was not configured with all the needed certificates
-		 * to form a full certificate chain. The server may fail to
-		 * validate the chain unless it is configured with all the
-		 * missing CA certificates.
-		 */
-		wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain "
-			   "not configured - validation may fail");
-	}
-	WPA_PUT_BE24(cert_start, pos - cert_start - 3);
-
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	pos = rhdr + rlen;
-
-	tls_verify_hash_add(conn, hs_start, pos - hs_start);
-
-	*msgpos = pos;
-
-	return 0;
-}
-
-
-static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
-{
-#ifdef EAP_FAST
-	/* ClientDiffieHellmanPublic */
-	u8 *csecret, *csecret_start, *dh_yc, *shared;
-	size_t csecret_len, dh_yc_len, shared_len;
-
-	csecret_len = conn->dh_p_len;
-	csecret = os_malloc(csecret_len);
-	if (csecret == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
-			   "memory for Yc (Diffie-Hellman)");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	if (os_get_random(csecret, csecret_len)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
-			   "data for Diffie-Hellman");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(csecret);
-		return -1;
-	}
-
-	if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0)
-		csecret[0] = 0; /* make sure Yc < p */
-
-	csecret_start = csecret;
-	while (csecret_len > 1 && *csecret_start == 0) {
-		csecret_start++;
-		csecret_len--;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value",
-			csecret_start, csecret_len);
-
-	/* Yc = g^csecret mod p */
-	dh_yc_len = conn->dh_p_len;
-	dh_yc = os_malloc(dh_yc_len);
-	if (dh_yc == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
-			   "memory for Diffie-Hellman");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(csecret);
-		return -1;
-	}
-	crypto_mod_exp(conn->dh_g, conn->dh_g_len,
-		       csecret_start, csecret_len,
-		       conn->dh_p, conn->dh_p_len,
-		       dh_yc, &dh_yc_len);
-
-	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
-		    dh_yc, dh_yc_len);
-
-	WPA_PUT_BE16(*pos, dh_yc_len);
-	*pos += 2;
-	if (*pos + dh_yc_len > end) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
-			   "message buffer for Yc");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(csecret);
-		os_free(dh_yc);
-		return -1;
-	}
-	os_memcpy(*pos, dh_yc, dh_yc_len);
-	*pos += dh_yc_len;
-	os_free(dh_yc);
-
-	shared_len = conn->dh_p_len;
-	shared = os_malloc(shared_len);
-	if (shared == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
-			   "DH");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(csecret);
-		return -1;
-	}
-
-	/* shared = Ys^csecret mod p */
-	crypto_mod_exp(conn->dh_ys, conn->dh_ys_len,
-		       csecret_start, csecret_len,
-		       conn->dh_p, conn->dh_p_len,
-		       shared, &shared_len);
-	wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
-			shared, shared_len);
-
-	os_memset(csecret_start, 0, csecret_len);
-	os_free(csecret);
-	if (tls_derive_keys(conn, shared, shared_len)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		os_free(shared);
-		return -1;
-	}
-	os_memset(shared, 0, shared_len);
-	os_free(shared);
-	tlsv1_client_free_dh(conn);
-	return 0;
-#else /* EAP_FAST */
-	tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR);
-	return -1;
-#endif /* EAP_FAST */
-}
-
-
-static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)
-{
-	u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN];
-	size_t clen;
-	int res;
-
-	if (tls_derive_pre_master_secret(pre_master_secret) < 0 ||
-	    tls_derive_keys(conn, pre_master_secret,
-			    TLS_PRE_MASTER_SECRET_LEN)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	/* EncryptedPreMasterSecret */
-	if (conn->server_rsa_key == NULL) {
-		wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to "
-			   "use for encrypting pre-master secret");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	/* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */
-	*pos += 2;
-	clen = end - *pos;
-	res = crypto_public_key_encrypt_pkcs1_v15(
-		conn->server_rsa_key,
-		pre_master_secret, TLS_PRE_MASTER_SECRET_LEN,
-		*pos, &clen);
-	os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN);
-	if (res < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	WPA_PUT_BE16(*pos - 2, clen);
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret",
-		    *pos, clen);
-	*pos += clen;
-
-	return 0;
-}
-
-
-static int tls_write_client_key_exchange(struct tlsv1_client *conn,
-					 u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr, *hs_start, *hs_length;
-	size_t rlen;
-	tls_key_exchange keyx;
-	const struct tls_cipher_suite *suite;
-
-	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
-	if (suite == NULL)
-		keyx = TLS_KEY_X_NULL;
-	else
-		keyx = suite->key_exchange;
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange");
-
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-
-	/* opaque fragment[TLSPlaintext.length] */
-
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-	/* body - ClientKeyExchange */
-	if (keyx == TLS_KEY_X_DH_anon) {
-		if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
-			return -1;
-	} else {
-		if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
-			return -1;
-	}
-
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	pos = rhdr + rlen;
-	tls_verify_hash_add(conn, hs_start, pos - hs_start);
-
-	*msgpos = pos;
-
-	return 0;
-}
-
-
-static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
-					       u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
-	size_t rlen, hlen, clen;
-	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
-	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-
-	/*
-	 * RFC 2246: 7.4.3 and 7.4.8:
-	 * Signature signature
-	 *
-	 * RSA:
-	 * digitally-signed struct {
-	 *     opaque md5_hash[16];
-	 *     opaque sha_hash[20];
-	 * };
-	 *
-	 * DSA:
-	 * digitally-signed struct {
-	 *     opaque sha_hash[20];
-	 * };
-	 *
-	 * The hash values are calculated over all handshake messages sent or
-	 * received starting at ClientHello up to, but not including, this
-	 * CertificateVerify message, including the type and length fields of
-	 * the handshake messages.
-	 */
-
-	hpos = hash;
-
-	if (alg == SIGN_ALG_RSA) {
-		hlen = MD5_MAC_LEN;
-		if (conn->verify_md5_cert == NULL ||
-		    crypto_hash_finish(conn->verify_md5_cert, hpos, &hlen) < 0)
-		{
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_INTERNAL_ERROR);
-			conn->verify_md5_cert = NULL;
-			crypto_hash_finish(conn->verify_sha1_cert, NULL, NULL);
-			conn->verify_sha1_cert = NULL;
-			return -1;
-		}
-		hpos += MD5_MAC_LEN;
-	} else
-		crypto_hash_finish(conn->verify_md5_cert, NULL, NULL);
-
-	conn->verify_md5_cert = NULL;
-	hlen = SHA1_MAC_LEN;
-	if (conn->verify_sha1_cert == NULL ||
-	    crypto_hash_finish(conn->verify_sha1_cert, hpos, &hlen) < 0) {
-		conn->verify_sha1_cert = NULL;
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	conn->verify_sha1_cert = NULL;
-
-	if (alg == SIGN_ALG_RSA)
-		hlen += MD5_MAC_LEN;
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
-
-	/*
-	 * RFC 2246, 4.7:
-	 * In digital signing, one-way hash functions are used as input for a
-	 * signing algorithm. A digitally-signed element is encoded as an
-	 * opaque vector <0..2^16-1>, where the length is specified by the
-	 * signing algorithm and key.
-	 *
-	 * In RSA signing, a 36-byte structure of two hashes (one SHA and one
-	 * MD5) is signed (encrypted with the private key). It is encoded with
-	 * PKCS #1 block type 0 or type 1 as described in [PKCS1].
-	 */
-	signed_start = pos; /* length to be filled */
-	pos += 2;
-	clen = end - pos;
-	if (crypto_private_key_sign_pkcs1(conn->client_key, hash, hlen,
-					  pos, &clen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	WPA_PUT_BE16(signed_start, clen);
-
-	pos += clen;
-
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	pos = rhdr + rlen;
-
-	tls_verify_hash_add(conn, hs_start, pos - hs_start);
-
-	*msgpos = pos;
-
-	return 0;
-}
-
-
-static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
-					       u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr;
-	size_t rlen;
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-	*pos = TLS_CHANGE_CIPHER_SPEC;
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
-			      rhdr, end - rhdr, 1, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
-			   "record layer");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	*msgpos = rhdr + rlen;
-
-	return 0;
-}
-
-
-static int tls_write_client_finished(struct tlsv1_client *conn,
-				     u8 **msgpos, u8 *end)
-{
-	u8 *pos, *rhdr, *hs_start, *hs_length;
-	size_t rlen, hlen;
-	u8 verify_data[TLS_VERIFY_DATA_LEN];
-	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
-
-	pos = *msgpos;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
-
-	/* Encrypted Handshake Message: Finished */
-
-	hlen = MD5_MAC_LEN;
-	if (conn->verify_md5_client == NULL ||
-	    crypto_hash_finish(conn->verify_md5_client, hash, &hlen) < 0) {
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		conn->verify_md5_client = NULL;
-		crypto_hash_finish(conn->verify_sha1_client, NULL, NULL);
-		conn->verify_sha1_client = NULL;
-		return -1;
-	}
-	conn->verify_md5_client = NULL;
-	hlen = SHA1_MAC_LEN;
-	if (conn->verify_sha1_client == NULL ||
-	    crypto_hash_finish(conn->verify_sha1_client, hash + MD5_MAC_LEN,
-			       &hlen) < 0) {
-		conn->verify_sha1_client = NULL;
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	conn->verify_sha1_client = NULL;
-
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
-		    verify_data, TLS_VERIFY_DATA_LEN)) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
-			verify_data, TLS_VERIFY_DATA_LEN);
-
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-	/* Handshake */
-	hs_start = pos;
-	/* HandshakeType msg_type */
-	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
-	pos += 3;
-	os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
-	pos += TLS_VERIFY_DATA_LEN;
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-	tls_verify_hash_add(conn, hs_start, pos - hs_start);
-
-	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_INTERNAL_ERROR);
-		return -1;
-	}
-
-	pos = rhdr + rlen;
-
-	*msgpos = pos;
-
-	return 0;
-}
-
-
-static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)
-{
-	size_t len = 0;
-	struct x509_certificate *cert;
-
-	cert = conn->client_cert;
-	while (cert) {
-		len += 3 + cert->cert_len;
-		if (x509_certificate_self_signed(cert))
-			break;
-		cert = x509_certificate_get_subject(conn->trusted_certs,
-						    &cert->issuer);
-	}
-
-	return len;
-}
-
-
-static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,
-					 size_t *out_len)
-{
-	u8 *msg, *end, *pos;
-	size_t msglen;
-
-	*out_len = 0;
-
-	msglen = 1000;
-	if (conn->certificate_requested)
-		msglen += tls_client_cert_chain_der_len(conn);
-
-	msg = os_malloc(msglen);
-	if (msg == NULL)
-		return NULL;
-
-	pos = msg;
-	end = msg + msglen;
-
-	if (conn->certificate_requested) {
-		if (tls_write_client_certificate(conn, &pos, end) < 0) {
-			os_free(msg);
-			return NULL;
-		}
-	}
-
-	if (tls_write_client_key_exchange(conn, &pos, end) < 0 ||
-	    (conn->certificate_requested && conn->client_key &&
-	     tls_write_client_certificate_verify(conn, &pos, end) < 0) ||
-	    tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
-	    tls_write_client_finished(conn, &pos, end) < 0) {
-		os_free(msg);
-		return NULL;
-	}
-
-	*out_len = pos - msg;
-
-	conn->state = SERVER_CHANGE_CIPHER_SPEC;
-
-	return msg;
-}
-
-
-static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
-					size_t *out_len)
-{
-	u8 *msg, *end, *pos;
-
-	*out_len = 0;
-
-	msg = os_malloc(1000);
-	if (msg == NULL)
-		return NULL;
-
-	pos = msg;
-	end = msg + 1000;
-
-	if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
-	    tls_write_client_finished(conn, &pos, end) < 0) {
-		os_free(msg);
-		return NULL;
-	}
-
-	*out_len = pos - msg;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
-		   "successfully");
-	conn->state = ESTABLISHED;
-
-	return msg;
-}
-
-
-static int tls_process_application_data(struct tlsv1_client *conn, u8 ct,
-					const u8 *in_data, size_t *in_len,
-					u8 **out_data, size_t *out_len)
-{
-	const u8 *pos;
-	size_t left;
-
-	if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Expected Application Data; "
-			   "received content type 0x%x", ct);
-		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-			  TLS_ALERT_UNEXPECTED_MESSAGE);
-		return -1;
-	}
-
-	pos = in_data;
-	left = *in_len;
-
-	wpa_hexdump(MSG_DEBUG, "TLSv1: Application Data included in Handshake",
-		    pos, left);
-
-	*out_data = os_malloc(left);
-	if (*out_data) {
-		os_memcpy(*out_data, pos, left);
-		*out_len = left;
-	}
-
-	return 0;
-}
-
-
-static int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
-					  const u8 *buf, size_t *len,
-					  u8 **out_data, size_t *out_len)
-{
-	if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 &&
-	    buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) {
-		size_t hr_len = WPA_GET_BE24(buf + 1);
-		if (hr_len > *len - 4) {
-			wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_DECODE_ERROR);
-			return -1;
-		}
-		wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest");
-		*len = 4 + hr_len;
-		return 0;
-	}
-
-	switch (conn->state) {
-	case SERVER_HELLO:
-		if (tls_process_server_hello(conn, ct, buf, len))
-			return -1;
-		break;
-	case SERVER_CERTIFICATE:
-		if (tls_process_certificate(conn, ct, buf, len))
-			return -1;
-		break;
-	case SERVER_KEY_EXCHANGE:
-		if (tls_process_server_key_exchange(conn, ct, buf, len))
-			return -1;
-		break;
-	case SERVER_CERTIFICATE_REQUEST:
-		if (tls_process_certificate_request(conn, ct, buf, len))
-			return -1;
-		break;
-	case SERVER_HELLO_DONE:
-		if (tls_process_server_hello_done(conn, ct, buf, len))
-			return -1;
-		break;
-	case SERVER_CHANGE_CIPHER_SPEC:
-		if (tls_process_server_change_cipher_spec(conn, ct, buf, len))
-			return -1;
-		break;
-	case SERVER_FINISHED:
-		if (tls_process_server_finished(conn, ct, buf, len))
-			return -1;
-		break;
-	case ACK_FINISHED:
-		if (out_data &&
-		    tls_process_application_data(conn, ct, buf, len, out_data,
-						 out_len))
-			return -1;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
-			   "while processing received message",
-			   conn->state);
-		return -1;
-	}
-
-	if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
-		tls_verify_hash_add(conn, buf, *len);
-
-	return 0;
-}
-
-
 /**
  * tlsv1_client_handshake - Process TLS handshake
  * @conn: TLSv1 client connection data from tlsv1_client_init()
@@ -1866,6 +134,7 @@
 	const u8 *pos, *end;
 	u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
 	size_t in_msg_len;
+	int no_appl_data;
 
 	if (conn->state == CLIENT_HELLO) {
 		if (in_len)
@@ -1915,36 +184,20 @@
 	os_free(in_msg);
 	in_msg = NULL;
 
-	switch (conn->state) {
-	case CLIENT_KEY_EXCHANGE:
-		msg = tls_send_client_key_exchange(conn, out_len);
-		break;
-	case CHANGE_CIPHER_SPEC:
-		msg = tls_send_change_cipher_spec(conn, out_len);
-		break;
-	case ACK_FINISHED:
-		wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed "
-			   "successfully");
-		conn->state = ESTABLISHED;
-		if (appl_data == NULL || *appl_data == NULL) {
-			/* Need to return something to get final TLS ACK. */
-			msg = os_malloc(1);
-		}
-		*out_len = 0;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
-			   "generating reply", conn->state);
-		break;
-	}
+	no_appl_data = appl_data == NULL || *appl_data == NULL;
+	msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data);
 
 failed:
 	os_free(in_msg);
 	if (conn->alert_level) {
 		conn->state = FAILED;
 		os_free(msg);
-		msg = tls_send_alert(conn, conn->alert_level,
-				     conn->alert_description, out_len);
+		msg = tlsv1_client_send_alert(conn, conn->alert_level,
+					      conn->alert_description,
+					      out_len);
+	} else if (msg == NULL) {
+		msg = os_zalloc(1);
+		*out_len = 0;
 	}
 
 	return msg;
@@ -2071,49 +324,6 @@
 }
 
 
-static void tlsv1_client_free_verify_hashes(struct tlsv1_client *conn)
-{
-	crypto_hash_finish(conn->verify_md5_client, NULL, NULL);
-	crypto_hash_finish(conn->verify_md5_server, NULL, NULL);
-	crypto_hash_finish(conn->verify_md5_cert, NULL, NULL);
-	crypto_hash_finish(conn->verify_sha1_client, NULL, NULL);
-	crypto_hash_finish(conn->verify_sha1_server, NULL, NULL);
-	crypto_hash_finish(conn->verify_sha1_cert, NULL, NULL);
-	conn->verify_md5_client = NULL;
-	conn->verify_md5_server = NULL;
-	conn->verify_md5_cert = NULL;
-	conn->verify_sha1_client = NULL;
-	conn->verify_sha1_server = NULL;
-	conn->verify_sha1_cert = NULL;
-}
-
-
-static int tlsv1_client_init_verify_hashes(struct tlsv1_client *conn)
-{
-	conn->verify_md5_client = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL,
-						   0);
-	conn->verify_md5_server = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL,
-						   0);
-	conn->verify_md5_cert = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
-	conn->verify_sha1_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL,
-						    0);
-	conn->verify_sha1_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL,
-						    0);
-	conn->verify_sha1_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL,
-						  0);
-	if (conn->verify_md5_client == NULL ||
-	    conn->verify_md5_server == NULL ||
-	    conn->verify_md5_cert == NULL ||
-	    conn->verify_sha1_client == NULL ||
-	    conn->verify_sha1_server == NULL ||
-	    conn->verify_sha1_cert == NULL) {
-		tlsv1_client_free_verify_hashes(conn);
-		return -1;
-	}
-	return 0;
-}
-
-
 /**
  * tlsv1_client_init - Initialize TLSv1 client connection
  * Returns: Pointer to TLSv1 client connection data or %NULL on failure
@@ -2130,7 +340,7 @@
 
 	conn->state = CLIENT_HELLO;
 
-	if (tlsv1_client_init_verify_hashes(conn) < 0) {
+	if (tls_verify_hash_init(&conn->verify) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
 			   "hash");
 		os_free(conn);
@@ -2162,12 +372,10 @@
 	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
 	tlsv1_record_change_write_cipher(&conn->rl);
 	tlsv1_record_change_read_cipher(&conn->rl);
-	tlsv1_client_free_verify_hashes(conn);
+	tls_verify_hash_free(&conn->verify);
 	os_free(conn->client_hello_ext);
 	tlsv1_client_free_dh(conn);
-	x509_certificate_chain_free(conn->trusted_certs);
-	x509_certificate_chain_free(conn->client_cert);
-	crypto_private_key_free(conn->client_key);
+	tlsv1_cred_free(conn->cred);
 	os_free(conn);
 }
 
@@ -2271,8 +479,7 @@
 {
 	conn->state = CLIENT_HELLO;
 
-	tlsv1_client_free_verify_hashes(conn);
-	if (tlsv1_client_init_verify_hashes(conn) < 0) {
+	if (tls_verify_hash_init(&conn->verify) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
 			   "hash");
 		return -1;
@@ -2315,7 +522,7 @@
 {
 	u8 *pos;
 
-	conn->ticket = 0;
+	conn->session_ticket_included = 0;
 	os_free(conn->client_hello_ext);
 	conn->client_hello_ext = NULL;
 	conn->client_hello_ext_len = 0;
@@ -2337,7 +544,7 @@
 	conn->client_hello_ext_len = 6 + data_len;
 
 	if (ext_type == TLS_EXT_PAC_OPAQUE) {
-		conn->ticket = 1;
+		conn->session_ticket_included = 1;
 		wpa_printf(MSG_DEBUG, "TLSv1: Using session ticket");
 	}
 
@@ -2372,27 +579,6 @@
 
 
 /**
- * tlsv1_client_set_master_key - Configure master secret for TLS connection
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @key: TLS pre-master-secret
- * @key_len: length of key in bytes
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_client_set_master_key(struct tlsv1_client *conn,
-				const u8 *key, size_t key_len)
-{
-	if (key_len > TLS_MASTER_SECRET_LEN)
-		return -1;
-	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret from session "
-			"ticket", key, key_len);
-	os_memcpy(conn->master_secret, key, key_len);
-	conn->ticket_key = 1;
-
-	return 0;
-}
-
-
-/**
  * tlsv1_client_get_keyblock_size - Get TLS key_block size
  * @conn: TLSv1 client connection data from tlsv1_client_init()
  * Returns: Size of the key_block for the negotiated cipher suite or -1 on
@@ -2425,7 +611,9 @@
 	if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
 		count = 0;
 		suites = conn->cipher_suites;
+#ifndef CONFIG_CRYPTO_INTERNAL
 		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
+#endif /* CONFIG_CRYPTO_INTERNAL */
 		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
 		suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
 		suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
@@ -2440,223 +628,31 @@
 }
 
 
-static int tlsv1_client_add_cert_der(struct x509_certificate **chain,
-				     const u8 *buf, size_t len)
-{
-	struct x509_certificate *cert;
-	char name[128];
-
-	cert = x509_certificate_parse(buf, len);
-	if (cert == NULL) {
-		wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
-			   __func__);
-		return -1;
-	}
-
-	cert->next = *chain;
-	*chain = cert;
-
-	x509_name_string(&cert->subject, name, sizeof(name));
-	wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
-
-	return 0;
-}
-
-
-static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
-static const char *pem_cert_end = "-----END CERTIFICATE-----";
-
-
-static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
-{
-	size_t i, plen;
-
-	plen = os_strlen(tag);
-	if (len < plen)
-		return NULL;
-
-	for (i = 0; i < len - plen; i++) {
-		if (os_memcmp(buf + i, tag, plen) == 0)
-			return buf + i;
-	}
-
-	return NULL;
-}
-
-
-static int tlsv1_client_add_cert(struct x509_certificate **chain,
-				 const u8 *buf, size_t len)
-{
-	const u8 *pos, *end;
-	unsigned char *der;
-	size_t der_len;
-
-	pos = search_tag(pem_cert_begin, buf, len);
-	if (!pos) {
-		wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
-			   "assume DER format");
-		return tlsv1_client_add_cert_der(chain, buf, len);
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
-		   "DER format");
-
-	while (pos) {
-		pos += os_strlen(pem_cert_begin);
-		end = search_tag(pem_cert_end, pos, buf + len - pos);
-		if (end == NULL) {
-			wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
-				   "certificate end tag (%s)", pem_cert_end);
-			return -1;
-		}
-
-		der = base64_decode(pos, end - pos, &der_len);
-		if (der == NULL) {
-			wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
-				   "certificate");
-			return -1;
-		}
-
-		if (tlsv1_client_add_cert_der(chain, der, der_len) < 0) {
-			wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
-				   "certificate after DER conversion");
-			os_free(der);
-			return -1;
-		}
-
-		os_free(der);
-
-		end += os_strlen(pem_cert_end);
-		pos = search_tag(pem_cert_begin, end, buf + len - end);
-	}
-
-	return 0;
-}
-
-
-static int tlsv1_client_set_cert_chain(struct x509_certificate **chain,
-				       const char *cert, const u8 *cert_blob,
-				       size_t cert_blob_len)
-{
-	if (cert_blob)
-		return tlsv1_client_add_cert(chain, cert_blob, cert_blob_len);
-
-	if (cert) {
-		u8 *buf;
-		size_t len;
-		int ret;
-
-		buf = (u8 *) os_readfile(cert, &len);
-		if (buf == NULL) {
-			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
-				   cert);
-			return -1;
-		}
-
-		ret = tlsv1_client_add_cert(chain, buf, len);
-		os_free(buf);
-		return ret;
-	}
-
-	return 0;
-}
-
-
-/**
- * tlsv1_client_set_ca_cert - Set trusted CA certificate(s)
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @cert: File or reference name for X.509 certificate in PEM or DER format
- * @cert_blob: cert as inlined data or %NULL if not used
- * @cert_blob_len: ca_cert_blob length
- * @path: Path to CA certificates (not yet supported)
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_client_set_ca_cert(struct tlsv1_client *conn, const char *cert,
-			     const u8 *cert_blob, size_t cert_blob_len,
-			     const char *path)
-{
-	if (tlsv1_client_set_cert_chain(&conn->trusted_certs, cert,
-					cert_blob, cert_blob_len) < 0)
-		return -1;
-
-	if (path) {
-		/* TODO: add support for reading number of certificate files */
-		wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
-			   "not yet supported");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/**
- * tlsv1_client_set_client_cert - Set client certificate
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @cert: File or reference name for X.509 certificate in PEM or DER format
- * @cert_blob: cert as inlined data or %NULL if not used
- * @cert_blob_len: ca_cert_blob length
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_client_set_client_cert(struct tlsv1_client *conn, const char *cert,
-				 const u8 *cert_blob, size_t cert_blob_len)
-{
-	return tlsv1_client_set_cert_chain(&conn->client_cert, cert,
-					   cert_blob, cert_blob_len);
-}
-
-
-static int tlsv1_client_set_key(struct tlsv1_client *conn,
-				const u8 *key, size_t len)
-{
-	conn->client_key = crypto_private_key_import(key, len);
-	if (conn->client_key == NULL) {
-		wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
-		return -1;
-	}
-	return 0;
-}
-
-
-/**
- * tlsv1_client_set_private_key - Set client private key
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @private_key: File or reference name for the key in PEM or DER format
- * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
- * passphrase is used.
- * @private_key_blob: private_key as inlined data or %NULL if not used
- * @private_key_blob_len: private_key_blob length
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_client_set_private_key(struct tlsv1_client *conn,
-				 const char *private_key,
-				 const char *private_key_passwd,
-				 const u8 *private_key_blob,
-				 size_t private_key_blob_len)
-{
-	crypto_private_key_free(conn->client_key);
-	conn->client_key = NULL;
-
-	if (private_key_blob)
-		return tlsv1_client_set_key(conn, private_key_blob,
-					    private_key_blob_len);
-
-	if (private_key) {
-		u8 *buf;
-		size_t len;
-		int ret;
-
-		buf = (u8 *) os_readfile(private_key, &len);
-		if (buf == NULL) {
-			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
-				   private_key);
-			return -1;
-		}
-
-		ret = tlsv1_client_set_key(conn, buf, len);
-		os_free(buf);
-		return ret;
-	}
-
-	return 0;
-}
+/**
+ * tlsv1_client_set_cred - Set client credentials
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @cred: Credentials from tlsv1_cred_alloc()
+ * Returns: 0 on success, -1 on failure
+ *
+ * On success, the client takes ownership of the credentials block and caller
+ * must not free it. On failure, caller is responsible for freeing the
+ * credential block.
+ */
+int tlsv1_client_set_cred(struct tlsv1_client *conn,
+			  struct tlsv1_credentials *cred)
+{
+	tlsv1_cred_free(conn->cred);
+	conn->cred = cred;
+	return 0;
+}
+
+
+void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
+					tlsv1_client_session_ticket_cb cb,
+					void *ctx)
+{
+	wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
+		   cb, ctx);
+	conn->session_ticket_cb = cb;
+	conn->session_ticket_cb_ctx = ctx;
+}

Modified: wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.h (original)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.h Sat Nov  3 08:40:37 2007
@@ -1,6 +1,6 @@
 /*
- * wpa_supplicant: TLSv1 client (RFC 2246)
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ * TLSv1 client (RFC 2246)
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -14,6 +14,8 @@
 
 #ifndef TLSV1_CLIENT_H
 #define TLSV1_CLIENT_H
+
+#include "tlsv1_cred.h"
 
 struct tlsv1_client;
 
@@ -41,19 +43,17 @@
 int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
 			   const u8 *data, size_t data_len);
 int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys);
-int tlsv1_client_set_master_key(struct tlsv1_client *conn,
-				const u8 *key, size_t key_len);
 int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn);
 int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers);
-int tlsv1_client_set_ca_cert(struct tlsv1_client *conn, const char *cert,
-			     const u8 *cert_blob, size_t cert_blob_len,
-			     const char *path);
-int tlsv1_client_set_client_cert(struct tlsv1_client *conn, const char *cert,
-				 const u8 *cert_blob, size_t cert_blob_len);
-int tlsv1_client_set_private_key(struct tlsv1_client *conn,
-				 const char *private_key,
-				 const char *private_key_passwd,
-				 const u8 *private_key_blob,
-				 size_t private_key_blob_len);
+int tlsv1_client_set_cred(struct tlsv1_client *conn,
+			  struct tlsv1_credentials *cred);
+
+typedef int (*tlsv1_client_session_ticket_cb)
+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
+ const u8 *server_random, u8 *master_secret);
+
+void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
+					tlsv1_client_session_ticket_cb cb,
+					void *ctx);
 
 #endif /* TLSV1_CLIENT_H */

Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_i.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_i.h (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_i.h Sat Nov  3 08:40:37 2007
@@ -1,0 +1,87 @@
+/*
+ * TLSv1 client - internal structures
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef TLSV1_CLIENT_I_H
+#define TLSV1_CLIENT_I_H
+
+struct tlsv1_client {
+	enum {
+		CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,
+		SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,
+		SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,
+		SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,
+		ESTABLISHED, FAILED
+	} state;
+
+	struct tlsv1_record_layer rl;
+
+	u8 session_id[TLS_SESSION_ID_MAX_LEN];
+	size_t session_id_len;
+	u8 client_random[TLS_RANDOM_LEN];
+	u8 server_random[TLS_RANDOM_LEN];
+	u8 master_secret[TLS_MASTER_SECRET_LEN];
+
+	u8 alert_level;
+	u8 alert_description;
+
+	unsigned int certificate_requested:1;
+	unsigned int session_resumed:1;
+	unsigned int session_ticket_included:1;
+	unsigned int use_session_ticket:1;
+
+	struct crypto_public_key *server_rsa_key;
+
+	struct tls_verify_hash verify;
+
+#define MAX_CIPHER_COUNT 30
+	u16 cipher_suites[MAX_CIPHER_COUNT];
+	size_t num_cipher_suites;
+
+	u16 prev_cipher_suite;
+
+	u8 *client_hello_ext;
+	size_t client_hello_ext_len;
+
+	/* The prime modulus used for Diffie-Hellman */
+	u8 *dh_p;
+	size_t dh_p_len;
+	/* The generator used for Diffie-Hellman */
+	u8 *dh_g;
+	size_t dh_g_len;
+	/* The server's Diffie-Hellman public value */
+	u8 *dh_ys;
+	size_t dh_ys_len;
+
+	struct tlsv1_credentials *cred;
+
+	tlsv1_client_session_ticket_cb session_ticket_cb;
+	void *session_ticket_cb_ctx;
+};
+
+
+void tls_alert(struct tlsv1_client *conn, u8 level, u8 description);
+void tlsv1_client_free_dh(struct tlsv1_client *conn);
+int tls_derive_pre_master_secret(u8 *pre_master_secret);
+int tls_derive_keys(struct tlsv1_client *conn,
+		    const u8 *pre_master_secret, size_t pre_master_secret_len);
+u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len);
+u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
+			     u8 description, size_t *out_len);
+u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,
+				  int no_appl_data);
+int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
+				   const u8 *buf, size_t *len,
+				   u8 **out_data, size_t *out_len);
+
+#endif /* TLSV1_CLIENT_I_H */

Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_read.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_read.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_read.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_read.c Sat Nov  3 08:40:37 2007
@@ -1,0 +1,976 @@
+/*
+ * TLSv1 client - read handshake message
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "x509v3.h"
+#include "tls.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
+
+static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
+					   const u8 *in_data, size_t *in_len);
+static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
+					   const u8 *in_data, size_t *in_len);
+static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
+					 const u8 *in_data, size_t *in_len);
+
+
+static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
+				    const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len, i;
+	u16 cipher_suite;
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+			   "received content type 0x%x", ct);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 4)
+		goto decode_error;
+
+	/* HandshakeType msg_type */
+	if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected ServerHello)", *pos);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello");
+	pos++;
+	/* uint24 length */
+	len = WPA_GET_BE24(pos);
+	pos += 3;
+	left -= 4;
+
+	if (len > left)
+		goto decode_error;
+
+	/* body - ServerHello */
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len);
+	end = pos + len;
+
+	/* ProtocolVersion server_version */
+	if (end - pos < 2)
+		goto decode_error;
+	if (WPA_GET_BE16(pos) != TLS_VERSION) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
+			   "ServerHello");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_PROTOCOL_VERSION);
+		return -1;
+	}
+	pos += 2;
+
+	/* Random random */
+	if (end - pos < TLS_RANDOM_LEN)
+		goto decode_error;
+
+	os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN);
+	pos += TLS_RANDOM_LEN;
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
+		    conn->server_random, TLS_RANDOM_LEN);
+
+	/* SessionID session_id */
+	if (end - pos < 1)
+		goto decode_error;
+	if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
+		goto decode_error;
+	if (conn->session_id_len && conn->session_id_len == *pos &&
+	    os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) {
+		pos += 1 + conn->session_id_len;
+		wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session");
+		conn->session_resumed = 1;
+	} else {
+		conn->session_id_len = *pos;
+		pos++;
+		os_memcpy(conn->session_id, pos, conn->session_id_len);
+		pos += conn->session_id_len;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
+		    conn->session_id, conn->session_id_len);
+
+	/* CipherSuite cipher_suite */
+	if (end - pos < 2)
+		goto decode_error;
+	cipher_suite = WPA_GET_BE16(pos);
+	pos += 2;
+	for (i = 0; i < conn->num_cipher_suites; i++) {
+		if (cipher_suite == conn->cipher_suites[i])
+			break;
+	}
+	if (i == conn->num_cipher_suites) {
+		wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
+			   "cipher suite 0x%04x", cipher_suite);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_ILLEGAL_PARAMETER);
+		return -1;
+	}
+
+	if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different "
+			   "cipher suite for a resumed connection (0x%04x != "
+			   "0x%04x)", cipher_suite, conn->prev_cipher_suite);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_ILLEGAL_PARAMETER);
+		return -1;
+	}
+
+	if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
+			   "record layer");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	conn->prev_cipher_suite = cipher_suite;
+
+	/* CompressionMethod compression_method */
+	if (end - pos < 1)
+		goto decode_error;
+	if (*pos != TLS_COMPRESSION_NULL) {
+		wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
+			   "compression 0x%02x", *pos);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_ILLEGAL_PARAMETER);
+		return -1;
+	}
+	pos++;
+
+	if (end != pos) {
+		/* TODO: ServerHello extensions */
+		wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
+			    "end of ServerHello", pos, end - pos);
+		goto decode_error;
+	}
+
+	if (conn->session_ticket_included && conn->session_ticket_cb) {
+		/* TODO: include SessionTicket extension if one was included in
+		 * ServerHello */
+		int res = conn->session_ticket_cb(
+			conn->session_ticket_cb_ctx, NULL, 0,
+			conn->client_random, conn->server_random,
+			conn->master_secret);
+		if (res < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
+				   "indicated failure");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_HANDSHAKE_FAILURE);
+			return -1;
+		}
+		conn->use_session_ticket = !!res;
+	}
+
+	if ((conn->session_resumed || conn->use_session_ticket) &&
+	    tls_derive_keys(conn, NULL, 0)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	*in_len = end - in_data;
+
+	conn->state = (conn->session_resumed || conn->use_session_ticket) ?
+		SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE;
+
+	return 0;
+
+decode_error:
+	wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello");
+	tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+	return -1;
+}
+
+
+static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
+				   const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len, list_len, cert_len, idx;
+	u8 type;
+	struct x509_certificate *chain = NULL, *last = NULL, *cert;
+	int reason;
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+			   "received content type 0x%x", ct);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 4) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
+			   "(len=%lu)", (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	type = *pos++;
+	len = WPA_GET_BE24(pos);
+	pos += 3;
+	left -= 4;
+
+	if (len > left) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
+			   "length (len=%lu != left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	if (type == TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE)
+		return tls_process_server_key_exchange(conn, ct, in_data,
+						       in_len);
+	if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
+		return tls_process_certificate_request(conn, ct, in_data,
+						       in_len);
+	if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
+		return tls_process_server_hello_done(conn, ct, in_data,
+						     in_len);
+	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected Certificate/"
+			   "ServerKeyExchange/CertificateRequest/"
+			   "ServerHelloDone)", type);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "TLSv1: Received Certificate (certificate_list len %lu)",
+		   (unsigned long) len);
+
+	/*
+	 * opaque ASN.1Cert<2^24-1>;
+	 *
+	 * struct {
+	 *     ASN.1Cert certificate_list<1..2^24-1>;
+	 * } Certificate;
+	 */
+
+	end = pos + len;
+
+	if (end - pos < 3) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
+			   "(left=%lu)", (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	list_len = WPA_GET_BE24(pos);
+	pos += 3;
+
+	if ((size_t) (end - pos) != list_len) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
+			   "length (len=%lu left=%lu)",
+			   (unsigned long) list_len,
+			   (unsigned long) (end - pos));
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	idx = 0;
+	while (pos < end) {
+		if (end - pos < 3) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+				   "certificate_list");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_DECODE_ERROR);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+
+		cert_len = WPA_GET_BE24(pos);
+		pos += 3;
+
+		if ((size_t) (end - pos) < cert_len) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
+				   "length (len=%lu left=%lu)",
+				   (unsigned long) cert_len,
+				   (unsigned long) (end - pos));
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_DECODE_ERROR);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+
+		wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
+			   (unsigned long) idx, (unsigned long) cert_len);
+
+		if (idx == 0) {
+			crypto_public_key_free(conn->server_rsa_key);
+			if (tls_parse_cert(pos, cert_len,
+					   &conn->server_rsa_key)) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+					   "the certificate");
+				tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					  TLS_ALERT_BAD_CERTIFICATE);
+				x509_certificate_chain_free(chain);
+				return -1;
+			}
+		}
+
+		cert = x509_certificate_parse(pos, cert_len);
+		if (cert == NULL) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+				   "the certificate");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_BAD_CERTIFICATE);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+
+		if (last == NULL)
+			chain = cert;
+		else
+			last->next = cert;
+		last = cert;
+
+		idx++;
+		pos += cert_len;
+	}
+
+	if (conn->cred &&
+	    x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
+					    &reason) < 0) {
+		int tls_reason;
+		wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
+			   "validation failed (reason=%d)", reason);
+		switch (reason) {
+		case X509_VALIDATE_BAD_CERTIFICATE:
+			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+			break;
+		case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
+			tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
+			break;
+		case X509_VALIDATE_CERTIFICATE_REVOKED:
+			tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
+			break;
+		case X509_VALIDATE_CERTIFICATE_EXPIRED:
+			tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
+			break;
+		case X509_VALIDATE_CERTIFICATE_UNKNOWN:
+			tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
+			break;
+		case X509_VALIDATE_UNKNOWN_CA:
+			tls_reason = TLS_ALERT_UNKNOWN_CA;
+			break;
+		default:
+			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+			break;
+		}
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
+		x509_certificate_chain_free(chain);
+		return -1;
+	}
+
+	x509_certificate_chain_free(chain);
+
+	*in_len = end - in_data;
+
+	conn->state = SERVER_KEY_EXCHANGE;
+
+	return 0;
+}
+
+
+static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
+					const u8 *buf, size_t len)
+{
+	const u8 *pos, *end;
+
+	tlsv1_client_free_dh(conn);
+
+	pos = buf;
+	end = buf + len;
+
+	if (end - pos < 3)
+		goto fail;
+	conn->dh_p_len = WPA_GET_BE16(pos);
+	pos += 2;
+	if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %d",
+			   conn->dh_p_len);
+		goto fail;
+	}
+	conn->dh_p = os_malloc(conn->dh_p_len);
+	if (conn->dh_p == NULL)
+		goto fail;
+	os_memcpy(conn->dh_p, pos, conn->dh_p_len);
+	pos += conn->dh_p_len;
+	wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
+		    conn->dh_p, conn->dh_p_len);
+
+	if (end - pos < 3)
+		goto fail;
+	conn->dh_g_len = WPA_GET_BE16(pos);
+	pos += 2;
+	if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
+		goto fail;
+	conn->dh_g = os_malloc(conn->dh_g_len);
+	if (conn->dh_g == NULL)
+		goto fail;
+	os_memcpy(conn->dh_g, pos, conn->dh_g_len);
+	pos += conn->dh_g_len;
+	wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
+		    conn->dh_g, conn->dh_g_len);
+	if (conn->dh_g_len == 1 && conn->dh_g[0] < 2)
+		goto fail;
+
+	if (end - pos < 3)
+		goto fail;
+	conn->dh_ys_len = WPA_GET_BE16(pos);
+	pos += 2;
+	if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
+		goto fail;
+	conn->dh_ys = os_malloc(conn->dh_ys_len);
+	if (conn->dh_ys == NULL)
+		goto fail;
+	os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
+	pos += conn->dh_ys_len;
+	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
+		    conn->dh_ys, conn->dh_ys_len);
+
+	return 0;
+
+fail:
+	wpa_printf(MSG_DEBUG, "TLSv1: Processing DH params failed");
+	tlsv1_client_free_dh(conn);
+	return -1;
+}
+
+
+static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
+					   const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len;
+	u8 type;
+	const struct tls_cipher_suite *suite;
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+			   "received content type 0x%x", ct);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 4) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerKeyExchange "
+			   "(Left=%lu)", (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	type = *pos++;
+	len = WPA_GET_BE24(pos);
+	pos += 3;
+	left -= 4;
+
+	if (len > left) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerKeyExchange "
+			   "length (len=%lu != left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	end = pos + len;
+
+	if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
+		return tls_process_certificate_request(conn, ct, in_data,
+						       in_len);
+	if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
+		return tls_process_server_hello_done(conn, ct, in_data,
+						     in_len);
+	if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected ServerKeyExchange/"
+			   "CertificateRequest/ServerHelloDone)", type);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange");
+
+	if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed "
+			   "with the selected cipher suite");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
+	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+	if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
+		if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_DECODE_ERROR);
+			return -1;
+		}
+	} else {
+		wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	*in_len = end - in_data;
+
+	conn->state = SERVER_CERTIFICATE_REQUEST;
+
+	return 0;
+}
+
+
+static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
+					   const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len;
+	u8 type;
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+			   "received content type 0x%x", ct);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 4) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateRequest "
+			   "(left=%lu)", (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	type = *pos++;
+	len = WPA_GET_BE24(pos);
+	pos += 3;
+	left -= 4;
+
+	if (len > left) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in CertificateRequest "
+			   "length (len=%lu != left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	end = pos + len;
+
+	if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
+		return tls_process_server_hello_done(conn, ct, in_data,
+						     in_len);
+	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected CertificateRequest/"
+			   "ServerHelloDone)", type);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateRequest");
+
+	conn->certificate_requested = 1;
+
+	*in_len = end - in_data;
+
+	conn->state = SERVER_HELLO_DONE;
+
+	return 0;
+}
+
+
+static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
+					 const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len;
+	u8 type;
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+			   "received content type 0x%x", ct);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 4) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerHelloDone "
+			   "(left=%lu)", (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	type = *pos++;
+	len = WPA_GET_BE24(pos);
+	pos += 3;
+	left -= 4;
+
+	if (len > left) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerHelloDone "
+			   "length (len=%lu != left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+	end = pos + len;
+
+	if (type != TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected ServerHelloDone)", type);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
+
+	*in_len = end - in_data;
+
+	conn->state = CLIENT_KEY_EXCHANGE;
+
+	return 0;
+}
+
+
+static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,
+						 u8 ct, const u8 *in_data,
+						 size_t *in_len)
+{
+	const u8 *pos;
+	size_t left;
+
+	if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+			   "received content type 0x%x", ct);
+		if (conn->use_session_ticket) {
+			int res;
+			wpa_printf(MSG_DEBUG, "TLSv1: Server may have "
+				   "rejected SessionTicket");
+			conn->use_session_ticket = 0;
+
+			/* Notify upper layers that SessionTicket failed */
+			res = conn->session_ticket_cb(
+				conn->session_ticket_cb_ctx, NULL, 0, NULL,
+				NULL, NULL);
+			if (res < 0) {
+				wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket "
+					   "callback indicated failure");
+				tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					  TLS_ALERT_HANDSHAKE_FAILURE);
+				return -1;
+			}
+
+			conn->state = SERVER_CERTIFICATE;
+			return tls_process_certificate(conn, ct, in_data,
+						       in_len);
+		}
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 1) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	if (*pos != TLS_CHANGE_CIPHER_SPEC) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+			   "received data 0x%x", *pos);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
+	if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
+			   "for record layer");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	*in_len = pos + 1 - in_data;
+
+	conn->state = SERVER_FINISHED;
+
+	return 0;
+}
+
+
+static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
+				       const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len, hlen;
+	u8 verify_data[TLS_VERIFY_DATA_LEN];
+	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
+			   "received content type 0x%x", ct);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 4) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
+			   "Finished",
+			   (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
+			   "type 0x%x", pos[0]);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	len = WPA_GET_BE24(pos + 1);
+
+	pos += 4;
+	left -= 4;
+
+	if (len > left) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
+			   "(len=%lu > left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+	end = pos + len;
+	if (len != TLS_VERIFY_DATA_LEN) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
+			   "in Finished: %lu (expected %d)",
+			   (unsigned long) len, TLS_VERIFY_DATA_LEN);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
+		    pos, TLS_VERIFY_DATA_LEN);
+
+	hlen = MD5_MAC_LEN;
+	if (conn->verify.md5_server == NULL ||
+	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		conn->verify.md5_server = NULL;
+		crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
+		conn->verify.sha1_server = NULL;
+		return -1;
+	}
+	conn->verify.md5_server = NULL;
+	hlen = SHA1_MAC_LEN;
+	if (conn->verify.sha1_server == NULL ||
+	    crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
+			       &hlen) < 0) {
+		conn->verify.sha1_server = NULL;
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	conn->verify.sha1_server = NULL;
+
+	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+		    verify_data, TLS_VERIFY_DATA_LEN)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_DECRYPT_ERROR);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
+			verify_data, TLS_VERIFY_DATA_LEN);
+
+	if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
+
+	*in_len = end - in_data;
+
+	conn->state = (conn->session_resumed || conn->use_session_ticket) ?
+		CHANGE_CIPHER_SPEC : ACK_FINISHED;
+
+	return 0;
+}
+
+
+static int tls_process_application_data(struct tlsv1_client *conn, u8 ct,
+					const u8 *in_data, size_t *in_len,
+					u8 **out_data, size_t *out_len)
+{
+	const u8 *pos;
+	size_t left;
+
+	if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Application Data; "
+			   "received content type 0x%x", ct);
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	wpa_hexdump(MSG_DEBUG, "TLSv1: Application Data included in Handshake",
+		    pos, left);
+
+	*out_data = os_malloc(left);
+	if (*out_data) {
+		os_memcpy(*out_data, pos, left);
+		*out_len = left;
+	}
+
+	return 0;
+}
+
+
+int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
+				   const u8 *buf, size_t *len,
+				   u8 **out_data, size_t *out_len)
+{
+	if (ct == TLS_CONTENT_TYPE_ALERT) {
+		if (*len < 2) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_DECODE_ERROR);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+			   buf[0], buf[1]);
+		*len = 2;
+		conn->state = FAILED;
+		return -1;
+	}
+
+	if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 &&
+	    buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) {
+		size_t hr_len = WPA_GET_BE24(buf + 1);
+		if (hr_len > *len - 4) {
+			wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_DECODE_ERROR);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest");
+		*len = 4 + hr_len;
+		return 0;
+	}
+
+	switch (conn->state) {
+	case SERVER_HELLO:
+		if (tls_process_server_hello(conn, ct, buf, len))
+			return -1;
+		break;
+	case SERVER_CERTIFICATE:
+		if (tls_process_certificate(conn, ct, buf, len))
+			return -1;
+		break;
+	case SERVER_KEY_EXCHANGE:
+		if (tls_process_server_key_exchange(conn, ct, buf, len))
+			return -1;
+		break;
+	case SERVER_CERTIFICATE_REQUEST:
+		if (tls_process_certificate_request(conn, ct, buf, len))
+			return -1;
+		break;
+	case SERVER_HELLO_DONE:
+		if (tls_process_server_hello_done(conn, ct, buf, len))
+			return -1;
+		break;
+	case SERVER_CHANGE_CIPHER_SPEC:
+		if (tls_process_server_change_cipher_spec(conn, ct, buf, len))
+			return -1;
+		break;
+	case SERVER_FINISHED:
+		if (tls_process_server_finished(conn, ct, buf, len))
+			return -1;
+		break;
+	case ACK_FINISHED:
+		if (out_data &&
+		    tls_process_application_data(conn, ct, buf, len, out_data,
+						 out_len))
+			return -1;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
+			   "while processing received message",
+			   conn->state);
+		return -1;
+	}
+
+	if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
+		tls_verify_hash_add(&conn->verify, buf, *len);
+
+	return 0;
+}

Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_write.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_write.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_write.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_write.c Sat Nov  3 08:40:37 2007
@@ -1,0 +1,790 @@
+/*
+ * TLSv1 client - write handshake message
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "x509v3.h"
+#include "tls.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
+
+
+static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)
+{
+	size_t len = 0;
+	struct x509_certificate *cert;
+
+	if (conn->cred == NULL)
+		return 0;
+
+	cert = conn->cred->cert;
+	while (cert) {
+		len += 3 + cert->cert_len;
+		if (x509_certificate_self_signed(cert))
+			break;
+		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
+						    &cert->issuer);
+	}
+
+	return len;
+}
+
+
+u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
+{
+	u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
+	struct os_time now;
+	size_t len, i;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
+	*out_len = 0;
+
+	os_get_time(&now);
+	WPA_PUT_BE32(conn->client_random, now.sec);
+	if (os_get_random(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
+		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
+			   "client_random");
+		return NULL;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
+		    conn->client_random, TLS_RANDOM_LEN);
+
+	len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
+	hello = os_malloc(len);
+	if (hello == NULL)
+		return NULL;
+	end = hello + len;
+
+	rhdr = hello;
+	pos = rhdr + TLS_RECORD_HEADER_LEN;
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	/* body - ClientHello */
+	/* ProtocolVersion client_version */
+	WPA_PUT_BE16(pos, TLS_VERSION);
+	pos += 2;
+	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
+	os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN);
+	pos += TLS_RANDOM_LEN;
+	/* SessionID session_id */
+	*pos++ = conn->session_id_len;
+	os_memcpy(pos, conn->session_id, conn->session_id_len);
+	pos += conn->session_id_len;
+	/* CipherSuite cipher_suites<2..2^16-1> */
+	WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites);
+	pos += 2;
+	for (i = 0; i < conn->num_cipher_suites; i++) {
+		WPA_PUT_BE16(pos, conn->cipher_suites[i]);
+		pos += 2;
+	}
+	/* CompressionMethod compression_methods<1..2^8-1> */
+	*pos++ = 1;
+	*pos++ = TLS_COMPRESSION_NULL;
+
+	if (conn->client_hello_ext) {
+		os_memcpy(pos, conn->client_hello_ext,
+			  conn->client_hello_ext_len);
+		pos += conn->client_hello_ext_len;
+	}
+
+	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      rhdr, end - rhdr, pos - hs_start, out_len) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(hello);
+		return NULL;
+	}
+
+	conn->state = SERVER_HELLO;
+
+	return hello;
+}
+
+
+static int tls_write_client_certificate(struct tlsv1_client *conn,
+					u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
+	size_t rlen;
+	struct x509_certificate *cert;
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	/* body - Certificate */
+	/* uint24 length (to be filled) */
+	cert_start = pos;
+	pos += 3;
+	cert = conn->cred ? conn->cred->cert : NULL;
+	while (cert) {
+		if (pos + 3 + cert->cert_len > end) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
+				   "for Certificate (cert_len=%lu left=%lu)",
+				   (unsigned long) cert->cert_len,
+				   (unsigned long) (end - pos));
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		WPA_PUT_BE24(pos, cert->cert_len);
+		pos += 3;
+		os_memcpy(pos, cert->cert_start, cert->cert_len);
+		pos += cert->cert_len;
+
+		if (x509_certificate_self_signed(cert))
+			break;
+		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
+						    &cert->issuer);
+	}
+	if (conn->cred == NULL || cert == conn->cred->cert || cert == NULL) {
+		/*
+		 * Client was not configured with all the needed certificates
+		 * to form a full certificate chain. The server may fail to
+		 * validate the chain unless it is configured with all the
+		 * missing CA certificates.
+		 */
+		wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain "
+			   "not configured - validation may fail");
+	}
+	WPA_PUT_BE24(cert_start, pos - cert_start - 3);
+
+	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	pos = rhdr + rlen;
+
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	*msgpos = pos;
+
+	return 0;
+}
+
+
+static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
+{
+#ifdef EAP_FAST
+	/* ClientDiffieHellmanPublic */
+	u8 *csecret, *csecret_start, *dh_yc, *shared;
+	size_t csecret_len, dh_yc_len, shared_len;
+
+	csecret_len = conn->dh_p_len;
+	csecret = os_malloc(csecret_len);
+	if (csecret == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+			   "memory for Yc (Diffie-Hellman)");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	if (os_get_random(csecret, csecret_len)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
+			   "data for Diffie-Hellman");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(csecret);
+		return -1;
+	}
+
+	if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0)
+		csecret[0] = 0; /* make sure Yc < p */
+
+	csecret_start = csecret;
+	while (csecret_len > 1 && *csecret_start == 0) {
+		csecret_start++;
+		csecret_len--;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value",
+			csecret_start, csecret_len);
+
+	/* Yc = g^csecret mod p */
+	dh_yc_len = conn->dh_p_len;
+	dh_yc = os_malloc(dh_yc_len);
+	if (dh_yc == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+			   "memory for Diffie-Hellman");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(csecret);
+		return -1;
+	}
+	crypto_mod_exp(conn->dh_g, conn->dh_g_len,
+		       csecret_start, csecret_len,
+		       conn->dh_p, conn->dh_p_len,
+		       dh_yc, &dh_yc_len);
+
+	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
+		    dh_yc, dh_yc_len);
+
+	WPA_PUT_BE16(*pos, dh_yc_len);
+	*pos += 2;
+	if (*pos + dh_yc_len > end) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
+			   "message buffer for Yc");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(csecret);
+		os_free(dh_yc);
+		return -1;
+	}
+	os_memcpy(*pos, dh_yc, dh_yc_len);
+	*pos += dh_yc_len;
+	os_free(dh_yc);
+
+	shared_len = conn->dh_p_len;
+	shared = os_malloc(shared_len);
+	if (shared == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
+			   "DH");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(csecret);
+		return -1;
+	}
+
+	/* shared = Ys^csecret mod p */
+	crypto_mod_exp(conn->dh_ys, conn->dh_ys_len,
+		       csecret_start, csecret_len,
+		       conn->dh_p, conn->dh_p_len,
+		       shared, &shared_len);
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
+			shared, shared_len);
+
+	os_memset(csecret_start, 0, csecret_len);
+	os_free(csecret);
+	if (tls_derive_keys(conn, shared, shared_len)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		os_free(shared);
+		return -1;
+	}
+	os_memset(shared, 0, shared_len);
+	os_free(shared);
+	tlsv1_client_free_dh(conn);
+	return 0;
+#else /* EAP_FAST */
+	tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR);
+	return -1;
+#endif /* EAP_FAST */
+}
+
+
+static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)
+{
+	u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN];
+	size_t clen;
+	int res;
+
+	if (tls_derive_pre_master_secret(pre_master_secret) < 0 ||
+	    tls_derive_keys(conn, pre_master_secret,
+			    TLS_PRE_MASTER_SECRET_LEN)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	/* EncryptedPreMasterSecret */
+	if (conn->server_rsa_key == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to "
+			   "use for encrypting pre-master secret");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	/* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */
+	*pos += 2;
+	clen = end - *pos;
+	res = crypto_public_key_encrypt_pkcs1_v15(
+		conn->server_rsa_key,
+		pre_master_secret, TLS_PRE_MASTER_SECRET_LEN,
+		*pos, &clen);
+	os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	WPA_PUT_BE16(*pos - 2, clen);
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret",
+		    *pos, clen);
+	*pos += clen;
+
+	return 0;
+}
+
+
+static int tls_write_client_key_exchange(struct tlsv1_client *conn,
+					 u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length;
+	size_t rlen;
+	tls_key_exchange keyx;
+	const struct tls_cipher_suite *suite;
+
+	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+	if (suite == NULL)
+		keyx = TLS_KEY_X_NULL;
+	else
+		keyx = suite->key_exchange;
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange");
+
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	/* body - ClientKeyExchange */
+	if (keyx == TLS_KEY_X_DH_anon) {
+		if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
+			return -1;
+	} else {
+		if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
+			return -1;
+	}
+
+	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	pos = rhdr + rlen;
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	*msgpos = pos;
+
+	return 0;
+}
+
+
+static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
+					       u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
+	size_t rlen, hlen, clen;
+	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
+	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+
+	/*
+	 * RFC 2246: 7.4.3 and 7.4.8:
+	 * Signature signature
+	 *
+	 * RSA:
+	 * digitally-signed struct {
+	 *     opaque md5_hash[16];
+	 *     opaque sha_hash[20];
+	 * };
+	 *
+	 * DSA:
+	 * digitally-signed struct {
+	 *     opaque sha_hash[20];
+	 * };
+	 *
+	 * The hash values are calculated over all handshake messages sent or
+	 * received starting at ClientHello up to, but not including, this
+	 * CertificateVerify message, including the type and length fields of
+	 * the handshake messages.
+	 */
+
+	hpos = hash;
+
+	if (alg == SIGN_ALG_RSA) {
+		hlen = MD5_MAC_LEN;
+		if (conn->verify.md5_cert == NULL ||
+		    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
+		{
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			conn->verify.md5_cert = NULL;
+			crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+			conn->verify.sha1_cert = NULL;
+			return -1;
+		}
+		hpos += MD5_MAC_LEN;
+	} else
+		crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+
+	conn->verify.md5_cert = NULL;
+	hlen = SHA1_MAC_LEN;
+	if (conn->verify.sha1_cert == NULL ||
+	    crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
+		conn->verify.sha1_cert = NULL;
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	conn->verify.sha1_cert = NULL;
+
+	if (alg == SIGN_ALG_RSA)
+		hlen += MD5_MAC_LEN;
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
+
+	/*
+	 * RFC 2246, 4.7:
+	 * In digital signing, one-way hash functions are used as input for a
+	 * signing algorithm. A digitally-signed element is encoded as an
+	 * opaque vector <0..2^16-1>, where the length is specified by the
+	 * signing algorithm and key.
+	 *
+	 * In RSA signing, a 36-byte structure of two hashes (one SHA and one
+	 * MD5) is signed (encrypted with the private key). It is encoded with
+	 * PKCS #1 block type 0 or type 1 as described in [PKCS1].
+	 */
+	signed_start = pos; /* length to be filled */
+	pos += 2;
+	clen = end - pos;
+	if (conn->cred == NULL ||
+	    crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
+					  pos, &clen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	WPA_PUT_BE16(signed_start, clen);
+
+	pos += clen;
+
+	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	pos = rhdr + rlen;
+
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	*msgpos = pos;
+
+	return 0;
+}
+
+
+static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
+					       u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr;
+	size_t rlen;
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+	*pos = TLS_CHANGE_CIPHER_SPEC;
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
+			      rhdr, end - rhdr, 1, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
+			   "record layer");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	*msgpos = rhdr + rlen;
+
+	return 0;
+}
+
+
+static int tls_write_client_finished(struct tlsv1_client *conn,
+				     u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length;
+	size_t rlen, hlen;
+	u8 verify_data[TLS_VERIFY_DATA_LEN];
+	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
+
+	/* Encrypted Handshake Message: Finished */
+
+	hlen = MD5_MAC_LEN;
+	if (conn->verify.md5_client == NULL ||
+	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		conn->verify.md5_client = NULL;
+		crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
+		conn->verify.sha1_client = NULL;
+		return -1;
+	}
+	conn->verify.md5_client = NULL;
+	hlen = SHA1_MAC_LEN;
+	if (conn->verify.sha1_client == NULL ||
+	    crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
+			       &hlen) < 0) {
+		conn->verify.sha1_client = NULL;
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	conn->verify.sha1_client = NULL;
+
+	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+		    verify_data, TLS_VERIFY_DATA_LEN)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
+			verify_data, TLS_VERIFY_DATA_LEN);
+
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
+	pos += TLS_VERIFY_DATA_LEN;
+	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			  TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	pos = rhdr + rlen;
+
+	*msgpos = pos;
+
+	return 0;
+}
+
+
+static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,
+					 size_t *out_len)
+{
+	u8 *msg, *end, *pos;
+	size_t msglen;
+
+	*out_len = 0;
+
+	msglen = 1000;
+	if (conn->certificate_requested)
+		msglen += tls_client_cert_chain_der_len(conn);
+
+	msg = os_malloc(msglen);
+	if (msg == NULL)
+		return NULL;
+
+	pos = msg;
+	end = msg + msglen;
+
+	if (conn->certificate_requested) {
+		if (tls_write_client_certificate(conn, &pos, end) < 0) {
+			os_free(msg);
+			return NULL;
+		}
+	}
+
+	if (tls_write_client_key_exchange(conn, &pos, end) < 0 ||
+	    (conn->certificate_requested && conn->cred && conn->cred->key &&
+	     tls_write_client_certificate_verify(conn, &pos, end) < 0) ||
+	    tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
+	    tls_write_client_finished(conn, &pos, end) < 0) {
+		os_free(msg);
+		return NULL;
+	}
+
+	*out_len = pos - msg;
+
+	conn->state = SERVER_CHANGE_CIPHER_SPEC;
+
+	return msg;
+}
+
+
+static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
+					size_t *out_len)
+{
+	u8 *msg, *end, *pos;
+
+	*out_len = 0;
+
+	msg = os_malloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	pos = msg;
+	end = msg + 1000;
+
+	if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
+	    tls_write_client_finished(conn, &pos, end) < 0) {
+		os_free(msg);
+		return NULL;
+	}
+
+	*out_len = pos - msg;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
+		   "successfully");
+	conn->state = ESTABLISHED;
+
+	return msg;
+}
+
+
+u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,
+				  int no_appl_data)
+{
+	switch (conn->state) {
+	case CLIENT_KEY_EXCHANGE:
+		return tls_send_client_key_exchange(conn, out_len);
+	case CHANGE_CIPHER_SPEC:
+		return tls_send_change_cipher_spec(conn, out_len);
+	case ACK_FINISHED:
+		wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed "
+			   "successfully");
+		conn->state = ESTABLISHED;
+		*out_len = 0;
+		if (no_appl_data) {
+			/* Need to return something to get final TLS ACK. */
+			return os_malloc(1);
+		}
+		return NULL;
+	default:
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
+			   "generating reply", conn->state);
+		return NULL;
+	}
+}
+
+
+u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
+			     u8 description, size_t *out_len)
+{
+	u8 *alert, *pos, *length;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
+	*out_len = 0;
+
+	alert = os_malloc(10);
+	if (alert == NULL)
+		return NULL;
+
+	pos = alert;
+
+	/* TLSPlaintext */
+	/* ContentType type */
+	*pos++ = TLS_CONTENT_TYPE_ALERT;
+	/* ProtocolVersion version */
+	WPA_PUT_BE16(pos, TLS_VERSION);
+	pos += 2;
+	/* uint16 length (to be filled) */
+	length = pos;
+	pos += 2;
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Alert */
+	/* AlertLevel level */
+	*pos++ = level;
+	/* AlertDescription description */
+	*pos++ = description;
+
+	WPA_PUT_BE16(length, pos - length - 2);
+	*out_len = pos - alert;
+
+	return alert;
+}

Modified: wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.c Sat Nov  3 08:40:37 2007
@@ -1,6 +1,6 @@
 /*
- * wpa_supplicant/hostapd: TLSv1 common routines
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ * TLSv1 common routines
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -15,9 +15,6 @@
 #include "includes.h"
 
 #include "common.h"
-#include "md5.h"
-#include "sha1.h"
-#include "crypto.h"
 #include "x509v3.h"
 #include "tlsv1_common.h"
 
@@ -101,13 +98,38 @@
 }
 
 
-static const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher)
+const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher)
 {
 	size_t i;
 	for (i = 0; i < NUM_TLS_CIPHER_DATA; i++)
 		if (tls_ciphers[i].cipher == cipher)
 			return &tls_ciphers[i];
 	return NULL;
+}
+
+
+int tls_server_key_exchange_allowed(tls_cipher cipher)
+{
+	const struct tls_cipher_suite *suite;
+
+	/* RFC 2246, Section 7.4.3 */
+	suite = tls_get_cipher_suite(cipher);
+	if (suite == NULL)
+		return 0;
+
+	switch (suite->key_exchange) {
+	case TLS_KEY_X_DHE_DSS:
+	case TLS_KEY_X_DHE_DSS_EXPORT:
+	case TLS_KEY_X_DHE_RSA:
+	case TLS_KEY_X_DHE_RSA_EXPORT:
+	case TLS_KEY_X_DH_anon_EXPORT:
+	case TLS_KEY_X_DH_anon:
+		return 1;
+	case TLS_KEY_X_RSA_EXPORT:
+		return 1 /* FIX: public key len > 512 bits */;
+	default:
+		return 0;
+	}
 }
 
 
@@ -165,388 +187,55 @@
 }
 
 
-/**
- * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite
- * @rl: Pointer to TLS record layer data
- * @cipher_suite: New cipher suite
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to prepare TLS record layer for cipher suite change.
- * tlsv1_record_change_write_cipher() and
- * tlsv1_record_change_read_cipher() functions can then be used to change the
- * currently used ciphers.
- */
-int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
-				  u16 cipher_suite)
-{
-	const struct tls_cipher_suite *suite;
-	const struct tls_cipher_data *data;
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x",
-		   cipher_suite);
-	rl->cipher_suite = cipher_suite;
-
-	suite = tls_get_cipher_suite(cipher_suite);
-	if (suite == NULL)
+int tls_verify_hash_init(struct tls_verify_hash *verify)
+{
+	tls_verify_hash_free(verify);
+	verify->md5_client = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+	verify->md5_server = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+	verify->md5_cert = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+	verify->sha1_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
+	verify->sha1_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
+	verify->sha1_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
+	if (verify->md5_client == NULL || verify->md5_server == NULL ||
+	    verify->md5_cert == NULL || verify->sha1_client == NULL ||
+	    verify->sha1_server == NULL || verify->sha1_cert == NULL) {
+		tls_verify_hash_free(verify);
 		return -1;
-
-	if (suite->hash == TLS_HASH_MD5) {
-		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5;
-		rl->hash_size = MD5_MAC_LEN;
-	} else if (suite->hash == TLS_HASH_SHA) {
-		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
-		rl->hash_size = SHA1_MAC_LEN;
-	}
-
-	data = tls_get_cipher_data(suite->cipher);
-	if (data == NULL)
-		return -1;
-
-	rl->key_material_len = data->key_material;
-	rl->iv_size = data->block_size;
-	rl->cipher_alg = data->alg;
-
+	}
 	return 0;
 }
 
 
-/**
- * tlsv1_record_change_write_cipher - TLS record layer: Change write cipher
- * @rl: Pointer to TLS record layer data
- * Returns: 0 on success (cipher changed), -1 on failure
- *
- * This function changes TLS record layer to use the new cipher suite
- * configured with tlsv1_record_set_cipher_suite() for writing.
- */
-int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
-{
-	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite "
-		   "0x%04x", rl->cipher_suite);
-	rl->write_cipher_suite = rl->cipher_suite;
-	os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN);
-
-	if (rl->write_cbc) {
-		crypto_cipher_deinit(rl->write_cbc);
-		rl->write_cbc = NULL;
-	}
-	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
-		rl->write_cbc = crypto_cipher_init(rl->cipher_alg,
-						   rl->write_iv, rl->write_key,
-						   rl->key_material_len);
-		if (rl->write_cbc == NULL) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
-				   "cipher");
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-/**
- * tlsv1_record_change_read_cipher - TLS record layer: Change read cipher
- * @rl: Pointer to TLS record layer data
- * Returns: 0 on success (cipher changed), -1 on failure
- *
- * This function changes TLS record layer to use the new cipher suite
- * configured with tlsv1_record_set_cipher_suite() for reading.
- */
-int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
-{
-	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
-		   "0x%04x", rl->cipher_suite);
-	rl->read_cipher_suite = rl->cipher_suite;
-	os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
-
-	if (rl->read_cbc) {
-		crypto_cipher_deinit(rl->read_cbc);
-		rl->read_cbc = NULL;
-	}
-	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
-		rl->read_cbc = crypto_cipher_init(rl->cipher_alg,
-						  rl->read_iv, rl->read_key,
-						  rl->key_material_len);
-		if (rl->read_cbc == NULL) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
-				   "cipher");
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-/**
- * tlsv1_record_send - TLS record layer: Send a message
- * @rl: Pointer to TLS record layer data
- * @content_type: Content type (TLS_CONTENT_TYPE_*)
- * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the
- * beginning for record layer to fill in; payload filled in after this and
- * extra space in the end for HMAC).
- * @buf_size: Maximum buf size
- * @payload_len: Length of the payload
- * @out_len: Buffer for returning the used buf length
- * Returns: 0 on success, -1 on failure
- *
- * This function fills in the TLS record layer header, adds HMAC, and encrypts
- * the data using the current write cipher.
- */
-int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
-		      size_t buf_size, size_t payload_len, size_t *out_len)
-{
-	u8 *pos, *ct_start, *length, *payload;
-	struct crypto_hash *hmac;
-	size_t clen;
-
-	pos = buf;
-	/* ContentType type */
-	ct_start = pos;
-	*pos++ = content_type;
-	/* ProtocolVersion version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
-	pos += 2;
-	/* uint16 length */
-	length = pos;
-	WPA_PUT_BE16(length, payload_len);
-	pos += 2;
-
-	/* opaque fragment[TLSPlaintext.length] */
-	payload = pos;
-	pos += payload_len;
-
-	if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
-		hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
-					rl->hash_size);
-		if (hmac == NULL) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
-				   "to initialize HMAC");
-			return -1;
-		}
-		crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
-		/* type + version + length + fragment */
-		crypto_hash_update(hmac, ct_start, pos - ct_start);
-		clen = buf + buf_size - pos;
-		if (clen < rl->hash_size) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
-				   "enough room for MAC");
-			crypto_hash_finish(hmac, NULL, NULL);
-			return -1;
-		}
-
-		if (crypto_hash_finish(hmac, pos, &clen) < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
-				   "to calculate HMAC");
-			return -1;
-		}
-		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
-			    pos, clen);
-		pos += clen;
-		if (rl->iv_size) {
-			size_t len = pos - payload;
-			size_t pad;
-			pad = (len + 1) % rl->iv_size;
-			if (pad)
-				pad = rl->iv_size - pad;
-			if (pos + pad + 1 > buf + buf_size) {
-				wpa_printf(MSG_DEBUG, "TLSv1: No room for "
-					   "block cipher padding");
-				return -1;
-			}
-			os_memset(pos, pad, pad + 1);
-			pos += pad + 1;
-		}
-
-		if (crypto_cipher_encrypt(rl->write_cbc, payload,
-					  payload, pos - payload) < 0)
-			return -1;
-	}
-
-	WPA_PUT_BE16(length, pos - length - 2);
-	inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);
-
-	*out_len = pos - buf;
-
-	return 0;
-}
-
-
-/**
- * tlsv1_record_receive - TLS record layer: Process a received message
- * @rl: Pointer to TLS record layer data
- * @in_data: Received data
- * @in_len: Length of the received data
- * @out_data: Buffer for output data (must be at least as long as in_data)
- * @out_len: Set to maximum out_data length by caller; used to return the
- * length of the used data
- * @alert: Buffer for returning an alert value on failure
- * Returns: 0 on success, -1 on failure
- *
- * This function decrypts the received message, verifies HMAC and TLS record
- * layer header.
- */
-int tlsv1_record_receive(struct tlsv1_record_layer *rl,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t *out_len, u8 *alert)
-{
-	size_t i, rlen, hlen;
-	u8 padlen;
-	struct crypto_hash *hmac;
-	u8 len[2], hash[100];
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
-		    in_data, in_len);
-
-	if (in_len < TLS_RECORD_HEADER_LEN) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
-			   (unsigned long) in_len);
-		*alert = TLS_ALERT_DECODE_ERROR;
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
-		   "length %d", in_data[0], in_data[1], in_data[2],
-		   WPA_GET_BE16(in_data + 3));
-
-	if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
-	    in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
-	    in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
-			   in_data[0]);
-		*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
-		return -1;
-	}
-
-	if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
-			   "%d.%d", in_data[1], in_data[2]);
-		*alert = TLS_ALERT_PROTOCOL_VERSION;
-		return -1;
-	}
-
-	rlen = WPA_GET_BE16(in_data + 3);
-
-	/* TLSCiphertext must not be more than 2^14+2048 bytes */
-	if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
-			   (unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
-		*alert = TLS_ALERT_RECORD_OVERFLOW;
-		return -1;
-	}
-
-	in_data += TLS_RECORD_HEADER_LEN;
-	in_len -= TLS_RECORD_HEADER_LEN;
-
-	if (rlen > in_len) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
-			   "(rlen=%lu > in_len=%lu)",
-			   (unsigned long) rlen, (unsigned long) in_len);
-		*alert = TLS_ALERT_DECODE_ERROR;
-		return -1;
-	}
-
-	in_len = rlen;
-
-	if (*out_len < in_len) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
-			   "processing received record");
-		*alert = TLS_ALERT_INTERNAL_ERROR;
-		return -1;
-	}
-
-	os_memcpy(out_data, in_data, in_len);
-	*out_len = in_len;
-
-	if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
-		if (crypto_cipher_decrypt(rl->read_cbc, out_data,
-					  out_data, in_len) < 0) {
-			*alert = TLS_ALERT_DECRYPTION_FAILED;
-			return -1;
-		}
-		if (rl->iv_size) {
-			if (in_len == 0) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
-					   " (no pad)");
-				*alert = TLS_ALERT_DECODE_ERROR;
-				return -1;
-			}
-			padlen = out_data[in_len - 1];
-			if (padlen >= in_len) {
-				wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
-					   "length (%u, in_len=%lu) in "
-					   "received record",
-					   padlen, (unsigned long) in_len);
-				*alert = TLS_ALERT_DECRYPTION_FAILED;
-				return -1;
-			}
-			for (i = in_len - padlen; i < in_len; i++) {
-				if (out_data[i] != padlen) {
-					wpa_hexdump(MSG_DEBUG,
-						    "TLSv1: Invalid pad in "
-						    "received record",
-						    out_data + in_len - padlen,
-						    padlen);
-					*alert = TLS_ALERT_DECRYPTION_FAILED;
-					return -1;
-				}
-			}
-
-			*out_len -= padlen + 1;
-		}
-
-		wpa_hexdump(MSG_MSGDUMP,
-			    "TLSv1: Record Layer - Decrypted data",
-			    out_data, in_len);
-
-		if (*out_len < rl->hash_size) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
-				   "hash value");
-			*alert = TLS_ALERT_INTERNAL_ERROR;
-			return -1;
-		}
-
-		*out_len -= rl->hash_size;
-
-		hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
-					rl->hash_size);
-		if (hmac == NULL) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
-				   "to initialize HMAC");
-			*alert = TLS_ALERT_INTERNAL_ERROR;
-			return -1;
-		}
-
-		crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
-		/* type + version + length + fragment */
-		crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
-		WPA_PUT_BE16(len, *out_len);
-		crypto_hash_update(hmac, len, 2);
-		crypto_hash_update(hmac, out_data, *out_len);
-		hlen = sizeof(hash);
-		if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
-				   "to calculate HMAC");
-			return -1;
-		}
-		if (hlen != rl->hash_size ||
-		    os_memcmp(hash, out_data + *out_len, hlen) != 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
-				   "received message");
-			*alert = TLS_ALERT_BAD_RECORD_MAC;
-			return -1;
-		}
-	}
-
-	/* TLSCompressed must not be more than 2^14+1024 bytes */
-	if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
-			   (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
-		*alert = TLS_ALERT_RECORD_OVERFLOW;
-		return -1;
-	}
-
-	inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
-
-	return 0;
-}
+void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
+			 size_t len)
+{
+	if (verify->md5_client && verify->sha1_client) {
+		crypto_hash_update(verify->md5_client, buf, len);
+		crypto_hash_update(verify->sha1_client, buf, len);
+	}
+	if (verify->md5_server && verify->sha1_server) {
+		crypto_hash_update(verify->md5_server, buf, len);
+		crypto_hash_update(verify->sha1_server, buf, len);
+	}
+	if (verify->md5_cert && verify->sha1_cert) {
+		crypto_hash_update(verify->md5_cert, buf, len);
+		crypto_hash_update(verify->sha1_cert, buf, len);
+	}
+}
+
+
+void tls_verify_hash_free(struct tls_verify_hash *verify)
+{
+	crypto_hash_finish(verify->md5_client, NULL, NULL);
+	crypto_hash_finish(verify->md5_server, NULL, NULL);
+	crypto_hash_finish(verify->md5_cert, NULL, NULL);
+	crypto_hash_finish(verify->sha1_client, NULL, NULL);
+	crypto_hash_finish(verify->sha1_server, NULL, NULL);
+	crypto_hash_finish(verify->sha1_cert, NULL, NULL);
+	verify->md5_client = NULL;
+	verify->md5_server = NULL;
+	verify->md5_cert = NULL;
+	verify->sha1_client = NULL;
+	verify->sha1_server = NULL;
+	verify->sha1_cert = NULL;
+}

Modified: wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.h Sat Nov  3 08:40:37 2007
@@ -1,6 +1,6 @@
 /*
- * wpa_supplicant/hostapd: TLSv1 common definitions
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ * TLSv1 common definitions
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -12,8 +12,10 @@
  * See README and COPYING for more details.
  */
 
-#ifndef TLSV1_COMMON
-#define TLSV1_COMMON
+#ifndef TLSV1_COMMON_H
+#define TLSV1_COMMON_H
+
+#include "crypto.h"
 
 #define TLS_VERSION 0x0301 /* TLSv1 */
 #define TLS_RANDOM_LEN 32
@@ -21,34 +23,22 @@
 #define TLS_MASTER_SECRET_LEN 48
 #define TLS_SESSION_ID_MAX_LEN 32
 #define TLS_VERIFY_DATA_LEN 12
-#define TLS_MAX_WRITE_MAC_SECRET_LEN 20
-#define TLS_MAX_WRITE_KEY_LEN 32
-#define TLS_MAX_IV_LEN 16
-#define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \
-				    TLS_MAX_WRITE_KEY_LEN + TLS_MAX_IV_LEN))
-#define TLS_SEQ_NUM_LEN 8
-#define TLS_RECORD_HEADER_LEN 5
-
-/* ContentType */
-enum {
-	TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20,
-	TLS_CONTENT_TYPE_ALERT = 21,
-	TLS_CONTENT_TYPE_HANDSHAKE = 22,
-	TLS_CONTENT_TYPE_APPLICATION_DATA = 23
-};
 
 /* HandshakeType */
 enum {
 	TLS_HANDSHAKE_TYPE_HELLO_REQUEST = 0,
 	TLS_HANDSHAKE_TYPE_CLIENT_HELLO = 1,
 	TLS_HANDSHAKE_TYPE_SERVER_HELLO = 2,
+	TLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET = 4 /* RFC 4507 */,
 	TLS_HANDSHAKE_TYPE_CERTIFICATE = 11,
 	TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE = 12,
 	TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST = 13,
 	TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE = 14,
 	TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY = 15,
 	TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE = 16,
-	TLS_HANDSHAKE_TYPE_FINISHED = 20
+	TLS_HANDSHAKE_TYPE_FINISHED = 20,
+	TLS_HANDSHAKE_TYPE_CERTIFICATE_URL = 21 /* RFC 4366 */,
+	TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS = 22 /* RFC 4366 */
 };
 
 /* CipherSuite */
@@ -124,6 +114,11 @@
 #define TLS_ALERT_INTERNAL_ERROR		80
 #define TLS_ALERT_USER_CANCELED			90
 #define TLS_ALERT_NO_RENEGOTIATION		100
+#define TLS_ALERT_UNSUPPORTED_EXTENSION		110 /* RFC 4366 */
+#define TLS_ALERT_CERTIFICATE_UNOBTAINABLE	111 /* RFC 4366 */
+#define TLS_ALERT_UNRECOGNIZED_NAME		112 /* RFC 4366 */
+#define TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE	113 /* RFC 4366 */
+#define TLS_ALERT_BAD_CERTIFICATE_HASH_VALUE	114 /* RFC 4366 */
 
 /* ChangeCipherSpec */
 enum {
@@ -131,7 +126,15 @@
 };
 
 /* TLS Extensions */
-#define TLS_EXT_PAC_OPAQUE 35
+#define TLS_EXT_SERVER_NAME			0 /* RFC 4366 */
+#define TLS_EXT_MAX_FRAGMENT_LENGTH		1 /* RFC 4366 */
+#define TLS_EXT_CLIENT_CERTIFICATE_URL		2 /* RFC 4366 */
+#define TLS_EXT_TRUSTED_CA_KEYS			3 /* RFC 4366 */
+#define TLS_EXT_TRUNCATED_HMAC			4 /* RFC 4366 */
+#define TLS_EXT_STATUS_REQUEST			5 /* RFC 4366 */
+#define TLS_EXT_SESSION_TICKET			35 /* RFC 4507 */
+
+#define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */
 
 
 typedef enum {
@@ -191,43 +194,23 @@
 };
 
 
-struct tlsv1_record_layer {
-	u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
-	u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
-	u8 write_key[TLS_MAX_WRITE_KEY_LEN];
-	u8 read_key[TLS_MAX_WRITE_KEY_LEN];
-	u8 write_iv[TLS_MAX_IV_LEN];
-	u8 read_iv[TLS_MAX_IV_LEN];
-
-	size_t hash_size;
-	size_t key_material_len;
-	size_t iv_size; /* also block_size */
-
-	enum crypto_hash_alg hash_alg;
-	enum crypto_cipher_alg cipher_alg;
-
-	u8 write_seq_num[TLS_SEQ_NUM_LEN];
-	u8 read_seq_num[TLS_SEQ_NUM_LEN];
-
-	u16 cipher_suite;
-	u16 write_cipher_suite;
-	u16 read_cipher_suite;
-
-	struct crypto_cipher *write_cbc;
-	struct crypto_cipher *read_cbc;
+struct tls_verify_hash {
+	struct crypto_hash *md5_client;
+	struct crypto_hash *sha1_client;
+	struct crypto_hash *md5_server;
+	struct crypto_hash *sha1_server;
+	struct crypto_hash *md5_cert;
+	struct crypto_hash *sha1_cert;
 };
 
 
 const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite);
+const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher);
+int tls_server_key_exchange_allowed(tls_cipher cipher);
 int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk);
-int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
-				  u16 cipher_suite);
-int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl);
-int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl);
-int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
-		      size_t buf_size, size_t payload_len, size_t *out_len);
-int tlsv1_record_receive(struct tlsv1_record_layer *rl,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t *out_len, u8 *alert);
+int tls_verify_hash_init(struct tls_verify_hash *verify);
+void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
+			 size_t len);
+void tls_verify_hash_free(struct tls_verify_hash *verify);
 
 #endif /* TLSV1_COMMON_H */

Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.c Sat Nov  3 08:40:37 2007
@@ -1,0 +1,422 @@
+/*
+ * TLSv1 credentials
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "base64.h"
+#include "crypto.h"
+#include "x509v3.h"
+#include "tlsv1_cred.h"
+
+
+struct tlsv1_credentials * tlsv1_cred_alloc(void)
+{
+	struct tlsv1_credentials *cred;
+	cred = os_zalloc(sizeof(*cred));
+	return cred;
+}
+
+
+void tlsv1_cred_free(struct tlsv1_credentials *cred)
+{
+	if (cred == NULL)
+		return;
+
+	x509_certificate_chain_free(cred->trusted_certs);
+	x509_certificate_chain_free(cred->cert);
+	crypto_private_key_free(cred->key);
+	os_free(cred->dh_p);
+	os_free(cred->dh_g);
+	os_free(cred);
+}
+
+
+static int tlsv1_add_cert_der(struct x509_certificate **chain,
+			      const u8 *buf, size_t len)
+{
+	struct x509_certificate *cert;
+	char name[128];
+
+	cert = x509_certificate_parse(buf, len);
+	if (cert == NULL) {
+		wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
+			   __func__);
+		return -1;
+	}
+
+	cert->next = *chain;
+	*chain = cert;
+
+	x509_name_string(&cert->subject, name, sizeof(name));
+	wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
+
+	return 0;
+}
+
+
+static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
+static const char *pem_cert_end = "-----END CERTIFICATE-----";
+
+
+static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
+{
+	size_t i, plen;
+
+	plen = os_strlen(tag);
+	if (len < plen)
+		return NULL;
+
+	for (i = 0; i < len - plen; i++) {
+		if (os_memcmp(buf + i, tag, plen) == 0)
+			return buf + i;
+	}
+
+	return NULL;
+}
+
+
+static int tlsv1_add_cert(struct x509_certificate **chain,
+			  const u8 *buf, size_t len)
+{
+	const u8 *pos, *end;
+	unsigned char *der;
+	size_t der_len;
+
+	pos = search_tag(pem_cert_begin, buf, len);
+	if (!pos) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
+			   "assume DER format");
+		return tlsv1_add_cert_der(chain, buf, len);
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
+		   "DER format");
+
+	while (pos) {
+		pos += os_strlen(pem_cert_begin);
+		end = search_tag(pem_cert_end, pos, buf + len - pos);
+		if (end == NULL) {
+			wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
+				   "certificate end tag (%s)", pem_cert_end);
+			return -1;
+		}
+
+		der = base64_decode(pos, end - pos, &der_len);
+		if (der == NULL) {
+			wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
+				   "certificate");
+			return -1;
+		}
+
+		if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
+			wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
+				   "certificate after DER conversion");
+			os_free(der);
+			return -1;
+		}
+
+		os_free(der);
+
+		end += os_strlen(pem_cert_end);
+		pos = search_tag(pem_cert_begin, end, buf + len - end);
+	}
+
+	return 0;
+}
+
+
+static int tlsv1_set_cert_chain(struct x509_certificate **chain,
+				const char *cert, const u8 *cert_blob,
+				size_t cert_blob_len)
+{
+	if (cert_blob)
+		return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
+
+	if (cert) {
+		u8 *buf;
+		size_t len;
+		int ret;
+
+		buf = (u8 *) os_readfile(cert, &len);
+		if (buf == NULL) {
+			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
+				   cert);
+			return -1;
+		}
+
+		ret = tlsv1_add_cert(chain, buf, len);
+		os_free(buf);
+		return ret;
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_set_ca_cert - Set trusted CA certificate(s)
+ * @cred: TLSv1 credentials from tlsv1_cred_alloc()
+ * @cert: File or reference name for X.509 certificate in PEM or DER format
+ * @cert_blob: cert as inlined data or %NULL if not used
+ * @cert_blob_len: ca_cert_blob length
+ * @path: Path to CA certificates (not yet supported)
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
+		      const u8 *cert_blob, size_t cert_blob_len,
+		      const char *path)
+{
+	if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
+				 cert_blob, cert_blob_len) < 0)
+		return -1;
+
+	if (path) {
+		/* TODO: add support for reading number of certificate files */
+		wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
+			   "not yet supported");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_set_cert - Set certificate
+ * @cred: TLSv1 credentials from tlsv1_cred_alloc()
+ * @cert: File or reference name for X.509 certificate in PEM or DER format
+ * @cert_blob: cert as inlined data or %NULL if not used
+ * @cert_blob_len: cert_blob length
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
+		   const u8 *cert_blob, size_t cert_blob_len)
+{
+	return tlsv1_set_cert_chain(&cred->cert, cert,
+				    cert_blob, cert_blob_len);
+}
+
+
+static int tlsv1_set_key(struct tlsv1_credentials *cred,
+			 const u8 *key, size_t len)
+{
+	cred->key = crypto_private_key_import(key, len);
+	if (cred->key == NULL) {
+		wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
+		return -1;
+	}
+	return 0;
+}
+
+
+/**
+ * tlsv1_set_private_key - Set private key
+ * @cred: TLSv1 credentials from tlsv1_cred_alloc()
+ * @private_key: File or reference name for the key in PEM or DER format
+ * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
+ * passphrase is used.
+ * @private_key_blob: private_key as inlined data or %NULL if not used
+ * @private_key_blob_len: private_key_blob length
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_set_private_key(struct tlsv1_credentials *cred,
+			  const char *private_key,
+			  const char *private_key_passwd,
+			  const u8 *private_key_blob,
+			  size_t private_key_blob_len)
+{
+	crypto_private_key_free(cred->key);
+	cred->key = NULL;
+
+	if (private_key_blob)
+		return tlsv1_set_key(cred, private_key_blob,
+				     private_key_blob_len);
+
+	if (private_key) {
+		u8 *buf;
+		size_t len;
+		int ret;
+
+		buf = (u8 *) os_readfile(private_key, &len);
+		if (buf == NULL) {
+			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
+				   private_key);
+			return -1;
+		}
+
+		ret = tlsv1_set_key(cred, buf, len);
+		os_free(buf);
+		return ret;
+	}
+
+	return 0;
+}
+
+
+static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
+				  const u8 *dh, size_t len)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+
+	pos = dh;
+	end = dh + len;
+
+	/*
+	 * DHParameter ::= SEQUENCE {
+	 *   prime INTEGER, -- p
+	 *   base INTEGER, -- g
+	 *   privateValueLength INTEGER OPTIONAL }
+	 */
+
+	/* DHParamer ::= SEQUENCE */
+	if (asn1_get_next(pos, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
+			   "valid SEQUENCE - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return -1;
+	}
+	pos = hdr.payload;
+
+	/* prime INTEGER */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0)
+		return -1;
+
+	if (hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_INTEGER) {
+		wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
+			   "class=%d tag=0x%x", hdr.class, hdr.tag);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
+	if (hdr.length == 0)
+		return -1;
+	os_free(cred->dh_p);
+	cred->dh_p = os_malloc(hdr.length);
+	if (cred->dh_p == NULL)
+		return -1;
+	os_memcpy(cred->dh_p, hdr.payload, hdr.length);
+	cred->dh_p_len = hdr.length;
+	pos = hdr.payload + hdr.length;
+
+	/* base INTEGER */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0)
+		return -1;
+
+	if (hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_INTEGER) {
+		wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
+			   "class=%d tag=0x%x", hdr.class, hdr.tag);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
+	if (hdr.length == 0)
+		return -1;
+	os_free(cred->dh_g);
+	cred->dh_g = os_malloc(hdr.length);
+	if (cred->dh_g == NULL)
+		return -1;
+	os_memcpy(cred->dh_g, hdr.payload, hdr.length);
+	cred->dh_g_len = hdr.length;
+
+	return 0;
+}
+
+
+static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
+static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
+
+
+static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
+				   const u8 *buf, size_t len)
+{
+	const u8 *pos, *end;
+	unsigned char *der;
+	size_t der_len;
+
+	pos = search_tag(pem_dhparams_begin, buf, len);
+	if (!pos) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
+			   "assume DER format");
+		return tlsv1_set_dhparams_der(cred, buf, len);
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
+		   "format");
+
+	pos += os_strlen(pem_dhparams_begin);
+	end = search_tag(pem_dhparams_end, pos, buf + len - pos);
+	if (end == NULL) {
+		wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
+			   "tag (%s)", pem_dhparams_end);
+		return -1;
+	}
+
+	der = base64_decode(pos, end - pos, &der_len);
+	if (der == NULL) {
+		wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
+		return -1;
+	}
+
+	if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
+		wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
+			   "DER conversion");
+		os_free(der);
+		return -1;
+	}
+
+	os_free(der);
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_set_dhparams - Set Diffie-Hellman parameters
+ * @cred: TLSv1 credentials from tlsv1_cred_alloc()
+ * @dh_file: File or reference name for the DH params in PEM or DER format
+ * @dh_blob: DH params as inlined data or %NULL if not used
+ * @dh_blob_len: dh_blob length
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
+		       const u8 *dh_blob, size_t dh_blob_len)
+{
+	if (dh_blob)
+		return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
+
+	if (dh_file) {
+		u8 *buf;
+		size_t len;
+		int ret;
+
+		buf = (u8 *) os_readfile(dh_file, &len);
+		if (buf == NULL) {
+			wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
+				   dh_file);
+			return -1;
+		}
+
+		ret = tlsv1_set_dhparams_blob(cred, buf, len);
+		os_free(buf);
+		return ret;
+	}
+
+	return 0;
+}

Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.h (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.h Sat Nov  3 08:40:37 2007
@@ -1,0 +1,46 @@
+/*
+ * TLSv1 credentials
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef TLSV1_CRED_H
+#define TLSV1_CRED_H
+
+struct tlsv1_credentials {
+	struct x509_certificate *trusted_certs;
+	struct x509_certificate *cert;
+	struct crypto_private_key *key;
+
+	/* Diffie-Hellman parameters */
+	u8 *dh_p; /* prime */
+	size_t dh_p_len;
+	u8 *dh_g; /* generator */
+	size_t dh_g_len;
+};
+
+
+struct tlsv1_credentials * tlsv1_cred_alloc(void);
+void tlsv1_cred_free(struct tlsv1_credentials *cred);
+int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
+		      const u8 *cert_blob, size_t cert_blob_len,
+		      const char *path);
+int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
+		   const u8 *cert_blob, size_t cert_blob_len);
+int tlsv1_set_private_key(struct tlsv1_credentials *cred,
+			  const char *private_key,
+			  const char *private_key_passwd,
+			  const u8 *private_key_blob,
+			  size_t private_key_blob_len);
+int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
+		       const u8 *dh_blob, size_t dh_blob_len);
+
+#endif /* TLSV1_CRED_H */

Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.c Sat Nov  3 08:40:37 2007
@@ -1,0 +1,409 @@
+/*
+ * TLSv1 Record Protocol
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+
+
+/**
+ * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite
+ * @rl: Pointer to TLS record layer data
+ * @cipher_suite: New cipher suite
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to prepare TLS record layer for cipher suite change.
+ * tlsv1_record_change_write_cipher() and
+ * tlsv1_record_change_read_cipher() functions can then be used to change the
+ * currently used ciphers.
+ */
+int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
+				  u16 cipher_suite)
+{
+	const struct tls_cipher_suite *suite;
+	const struct tls_cipher_data *data;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x",
+		   cipher_suite);
+	rl->cipher_suite = cipher_suite;
+
+	suite = tls_get_cipher_suite(cipher_suite);
+	if (suite == NULL)
+		return -1;
+
+	if (suite->hash == TLS_HASH_MD5) {
+		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5;
+		rl->hash_size = MD5_MAC_LEN;
+	} else if (suite->hash == TLS_HASH_SHA) {
+		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
+		rl->hash_size = SHA1_MAC_LEN;
+	}
+
+	data = tls_get_cipher_data(suite->cipher);
+	if (data == NULL)
+		return -1;
+
+	rl->key_material_len = data->key_material;
+	rl->iv_size = data->block_size;
+	rl->cipher_alg = data->alg;
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_record_change_write_cipher - TLS record layer: Change write cipher
+ * @rl: Pointer to TLS record layer data
+ * Returns: 0 on success (cipher changed), -1 on failure
+ *
+ * This function changes TLS record layer to use the new cipher suite
+ * configured with tlsv1_record_set_cipher_suite() for writing.
+ */
+int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
+{
+	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite "
+		   "0x%04x", rl->cipher_suite);
+	rl->write_cipher_suite = rl->cipher_suite;
+	os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN);
+
+	if (rl->write_cbc) {
+		crypto_cipher_deinit(rl->write_cbc);
+		rl->write_cbc = NULL;
+	}
+	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
+		rl->write_cbc = crypto_cipher_init(rl->cipher_alg,
+						   rl->write_iv, rl->write_key,
+						   rl->key_material_len);
+		if (rl->write_cbc == NULL) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
+				   "cipher");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_record_change_read_cipher - TLS record layer: Change read cipher
+ * @rl: Pointer to TLS record layer data
+ * Returns: 0 on success (cipher changed), -1 on failure
+ *
+ * This function changes TLS record layer to use the new cipher suite
+ * configured with tlsv1_record_set_cipher_suite() for reading.
+ */
+int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
+{
+	wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
+		   "0x%04x", rl->cipher_suite);
+	rl->read_cipher_suite = rl->cipher_suite;
+	os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
+
+	if (rl->read_cbc) {
+		crypto_cipher_deinit(rl->read_cbc);
+		rl->read_cbc = NULL;
+	}
+	if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
+		rl->read_cbc = crypto_cipher_init(rl->cipher_alg,
+						  rl->read_iv, rl->read_key,
+						  rl->key_material_len);
+		if (rl->read_cbc == NULL) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
+				   "cipher");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_record_send - TLS record layer: Send a message
+ * @rl: Pointer to TLS record layer data
+ * @content_type: Content type (TLS_CONTENT_TYPE_*)
+ * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the
+ * beginning for record layer to fill in; payload filled in after this and
+ * extra space in the end for HMAC).
+ * @buf_size: Maximum buf size
+ * @payload_len: Length of the payload
+ * @out_len: Buffer for returning the used buf length
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function fills in the TLS record layer header, adds HMAC, and encrypts
+ * the data using the current write cipher.
+ */
+int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
+		      size_t buf_size, size_t payload_len, size_t *out_len)
+{
+	u8 *pos, *ct_start, *length, *payload;
+	struct crypto_hash *hmac;
+	size_t clen;
+
+	pos = buf;
+	/* ContentType type */
+	ct_start = pos;
+	*pos++ = content_type;
+	/* ProtocolVersion version */
+	WPA_PUT_BE16(pos, TLS_VERSION);
+	pos += 2;
+	/* uint16 length */
+	length = pos;
+	WPA_PUT_BE16(length, payload_len);
+	pos += 2;
+
+	/* opaque fragment[TLSPlaintext.length] */
+	payload = pos;
+	pos += payload_len;
+
+	if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
+		hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
+					rl->hash_size);
+		if (hmac == NULL) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+				   "to initialize HMAC");
+			return -1;
+		}
+		crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
+		/* type + version + length + fragment */
+		crypto_hash_update(hmac, ct_start, pos - ct_start);
+		clen = buf + buf_size - pos;
+		if (clen < rl->hash_size) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
+				   "enough room for MAC");
+			crypto_hash_finish(hmac, NULL, NULL);
+			return -1;
+		}
+
+		if (crypto_hash_finish(hmac, pos, &clen) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+				   "to calculate HMAC");
+			return -1;
+		}
+		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
+			    pos, clen);
+		pos += clen;
+		if (rl->iv_size) {
+			size_t len = pos - payload;
+			size_t pad;
+			pad = (len + 1) % rl->iv_size;
+			if (pad)
+				pad = rl->iv_size - pad;
+			if (pos + pad + 1 > buf + buf_size) {
+				wpa_printf(MSG_DEBUG, "TLSv1: No room for "
+					   "block cipher padding");
+				return -1;
+			}
+			os_memset(pos, pad, pad + 1);
+			pos += pad + 1;
+		}
+
+		if (crypto_cipher_encrypt(rl->write_cbc, payload,
+					  payload, pos - payload) < 0)
+			return -1;
+	}
+
+	WPA_PUT_BE16(length, pos - length - 2);
+	inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);
+
+	*out_len = pos - buf;
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_record_receive - TLS record layer: Process a received message
+ * @rl: Pointer to TLS record layer data
+ * @in_data: Received data
+ * @in_len: Length of the received data
+ * @out_data: Buffer for output data (must be at least as long as in_data)
+ * @out_len: Set to maximum out_data length by caller; used to return the
+ * length of the used data
+ * @alert: Buffer for returning an alert value on failure
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function decrypts the received message, verifies HMAC and TLS record
+ * layer header.
+ */
+int tlsv1_record_receive(struct tlsv1_record_layer *rl,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t *out_len, u8 *alert)
+{
+	size_t i, rlen, hlen;
+	u8 padlen;
+	struct crypto_hash *hmac;
+	u8 len[2], hash[100];
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+		    in_data, in_len);
+
+	if (in_len < TLS_RECORD_HEADER_LEN) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
+			   (unsigned long) in_len);
+		*alert = TLS_ALERT_DECODE_ERROR;
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
+		   "length %d", in_data[0], in_data[1], in_data[2],
+		   WPA_GET_BE16(in_data + 3));
+
+	if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
+	    in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
+	    in_data[0] != TLS_CONTENT_TYPE_ALERT &&
+	    in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
+			   in_data[0]);
+		*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
+		return -1;
+	}
+
+	if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
+			   "%d.%d", in_data[1], in_data[2]);
+		*alert = TLS_ALERT_PROTOCOL_VERSION;
+		return -1;
+	}
+
+	rlen = WPA_GET_BE16(in_data + 3);
+
+	/* TLSCiphertext must not be more than 2^14+2048 bytes */
+	if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
+			   (unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
+		*alert = TLS_ALERT_RECORD_OVERFLOW;
+		return -1;
+	}
+
+	in_data += TLS_RECORD_HEADER_LEN;
+	in_len -= TLS_RECORD_HEADER_LEN;
+
+	if (rlen > in_len) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
+			   "(rlen=%lu > in_len=%lu)",
+			   (unsigned long) rlen, (unsigned long) in_len);
+		*alert = TLS_ALERT_DECODE_ERROR;
+		return -1;
+	}
+
+	in_len = rlen;
+
+	if (*out_len < in_len) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
+			   "processing received record");
+		*alert = TLS_ALERT_INTERNAL_ERROR;
+		return -1;
+	}
+
+	os_memcpy(out_data, in_data, in_len);
+	*out_len = in_len;
+
+	if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
+		if (crypto_cipher_decrypt(rl->read_cbc, out_data,
+					  out_data, in_len) < 0) {
+			*alert = TLS_ALERT_DECRYPTION_FAILED;
+			return -1;
+		}
+		if (rl->iv_size) {
+			if (in_len == 0) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
+					   " (no pad)");
+				*alert = TLS_ALERT_DECODE_ERROR;
+				return -1;
+			}
+			padlen = out_data[in_len - 1];
+			if (padlen >= in_len) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
+					   "length (%u, in_len=%lu) in "
+					   "received record",
+					   padlen, (unsigned long) in_len);
+				*alert = TLS_ALERT_DECRYPTION_FAILED;
+				return -1;
+			}
+			for (i = in_len - padlen; i < in_len; i++) {
+				if (out_data[i] != padlen) {
+					wpa_hexdump(MSG_DEBUG,
+						    "TLSv1: Invalid pad in "
+						    "received record",
+						    out_data + in_len - padlen,
+						    padlen);
+					*alert = TLS_ALERT_DECRYPTION_FAILED;
+					return -1;
+				}
+			}
+
+			*out_len -= padlen + 1;
+		}
+
+		wpa_hexdump(MSG_MSGDUMP,
+			    "TLSv1: Record Layer - Decrypted data",
+			    out_data, in_len);
+
+		if (*out_len < rl->hash_size) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
+				   "hash value");
+			*alert = TLS_ALERT_INTERNAL_ERROR;
+			return -1;
+		}
+
+		*out_len -= rl->hash_size;
+
+		hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
+					rl->hash_size);
+		if (hmac == NULL) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+				   "to initialize HMAC");
+			*alert = TLS_ALERT_INTERNAL_ERROR;
+			return -1;
+		}
+
+		crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
+		/* type + version + length + fragment */
+		crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
+		WPA_PUT_BE16(len, *out_len);
+		crypto_hash_update(hmac, len, 2);
+		crypto_hash_update(hmac, out_data, *out_len);
+		hlen = sizeof(hash);
+		if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+				   "to calculate HMAC");
+			return -1;
+		}
+		if (hlen != rl->hash_size ||
+		    os_memcmp(hash, out_data + *out_len, hlen) != 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
+				   "received message");
+			*alert = TLS_ALERT_BAD_RECORD_MAC;
+			return -1;
+		}
+	}
+
+	/* TLSCompressed must not be more than 2^14+1024 bytes */
+	if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
+			   (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
+		*alert = TLS_ALERT_RECORD_OVERFLOW;
+		return -1;
+	}
+
+	inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
+
+	return 0;
+}

Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.h (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.h Sat Nov  3 08:40:37 2007
@@ -1,0 +1,74 @@
+/*
+ * TLSv1 Record Protocol
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef TLSV1_RECORD_H
+#define TLSV1_RECORD_H
+
+#include "crypto.h"
+
+#define TLS_MAX_WRITE_MAC_SECRET_LEN 20
+#define TLS_MAX_WRITE_KEY_LEN 32
+#define TLS_MAX_IV_LEN 16
+#define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \
+				    TLS_MAX_WRITE_KEY_LEN + TLS_MAX_IV_LEN))
+
+#define TLS_SEQ_NUM_LEN 8
+#define TLS_RECORD_HEADER_LEN 5
+
+/* ContentType */
+enum {
+	TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20,
+	TLS_CONTENT_TYPE_ALERT = 21,
+	TLS_CONTENT_TYPE_HANDSHAKE = 22,
+	TLS_CONTENT_TYPE_APPLICATION_DATA = 23
+};
+
+struct tlsv1_record_layer {
+	u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
+	u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
+	u8 write_key[TLS_MAX_WRITE_KEY_LEN];
+	u8 read_key[TLS_MAX_WRITE_KEY_LEN];
+	u8 write_iv[TLS_MAX_IV_LEN];
+	u8 read_iv[TLS_MAX_IV_LEN];
+
+	size_t hash_size;
+	size_t key_material_len;
+	size_t iv_size; /* also block_size */
+
+	enum crypto_hash_alg hash_alg;
+	enum crypto_cipher_alg cipher_alg;
+
+	u8 write_seq_num[TLS_SEQ_NUM_LEN];
+	u8 read_seq_num[TLS_SEQ_NUM_LEN];
+
+	u16 cipher_suite;
+	u16 write_cipher_suite;
+	u16 read_cipher_suite;
+
+	struct crypto_cipher *write_cbc;
+	struct crypto_cipher *read_cbc;
+};
+
+
+int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
+				  u16 cipher_suite);
+int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl);
+int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl);
+int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
+		      size_t buf_size, size_t payload_len, size_t *out_len);
+int tlsv1_record_receive(struct tlsv1_record_layer *rl,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t *out_len, u8 *alert);
+
+#endif /* TLSV1_RECORD_H */

Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.c Sat Nov  3 08:40:37 2007
@@ -1,0 +1,596 @@
+/*
+ * TLSv1 server (RFC 2246)
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "tls.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_server.h"
+#include "tlsv1_server_i.h"
+
+/* TODO:
+ * Support for a message fragmented across several records (RFC 2246, 6.2.1)
+ */
+
+
+void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)
+{
+	conn->alert_level = level;
+	conn->alert_description = description;
+}
+
+
+int tlsv1_server_derive_keys(struct tlsv1_server *conn,
+			     const u8 *pre_master_secret,
+			     size_t pre_master_secret_len)
+{
+	u8 seed[2 * TLS_RANDOM_LEN];
+	u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
+	u8 *pos;
+	size_t key_block_len;
+
+	if (pre_master_secret) {
+		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
+				pre_master_secret, pre_master_secret_len);
+		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
+		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
+			  TLS_RANDOM_LEN);
+		if (tls_prf(pre_master_secret, pre_master_secret_len,
+			    "master secret", seed, 2 * TLS_RANDOM_LEN,
+			    conn->master_secret, TLS_MASTER_SECRET_LEN)) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
+				   "master_secret");
+			return -1;
+		}
+		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
+				conn->master_secret, TLS_MASTER_SECRET_LEN);
+	}
+
+	os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
+	os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
+	key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
+			     conn->rl.iv_size);
+	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "key expansion", seed, 2 * TLS_RANDOM_LEN,
+		    key_block, key_block_len)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
+		return -1;
+	}
+	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
+			key_block, key_block_len);
+
+	pos = key_block;
+
+	/* client_write_MAC_secret */
+	os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
+	pos += conn->rl.hash_size;
+	/* server_write_MAC_secret */
+	os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
+	pos += conn->rl.hash_size;
+
+	/* client_write_key */
+	os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
+	pos += conn->rl.key_material_len;
+	/* server_write_key */
+	os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
+	pos += conn->rl.key_material_len;
+
+	/* client_write_IV */
+	os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
+	pos += conn->rl.iv_size;
+	/* server_write_IV */
+	os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
+	pos += conn->rl.iv_size;
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_server_handshake - Process TLS handshake
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @in_data: Input data from TLS peer
+ * @in_len: Input data length
+ * @out_len: Length of the output buffer.
+ * Returns: Pointer to output data, %NULL on failure
+ */
+u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
+			    const u8 *in_data, size_t in_len,
+			    size_t *out_len)
+{
+	const u8 *pos, *end;
+	u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
+	size_t in_msg_len;
+
+	if (in_data == NULL || in_len == 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No input data to server");
+		return NULL;
+	}
+
+	pos = in_data;
+	end = in_data + in_len;
+	in_msg = os_malloc(in_len);
+	if (in_msg == NULL)
+		return NULL;
+
+	/* Each received packet may include multiple records */
+	while (pos < end) {
+		in_msg_len = in_len;
+		if (tlsv1_record_receive(&conn->rl, pos, end - pos,
+					 in_msg, &in_msg_len, &alert)) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
+				   "record failed");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			goto failed;
+		}
+		ct = pos[0];
+
+		in_pos = in_msg;
+		in_end = in_msg + in_msg_len;
+
+		/* Each received record may include multiple messages of the
+		 * same ContentType. */
+		while (in_pos < in_end) {
+			in_msg_len = in_end - in_pos;
+			if (tlsv1_server_process_handshake(conn, ct, in_pos,
+							   &in_msg_len) < 0)
+				goto failed;
+			in_pos += in_msg_len;
+		}
+
+		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+	}
+
+	os_free(in_msg);
+	in_msg = NULL;
+
+	msg = tlsv1_server_handshake_write(conn, out_len);
+
+failed:
+	os_free(in_msg);
+	if (conn->alert_level) {
+		if (conn->state == FAILED) {
+			/* Avoid alert loops */
+			wpa_printf(MSG_DEBUG, "TLSv1: Drop alert loop");
+			os_free(msg);
+			return NULL;
+		}
+		conn->state = FAILED;
+		os_free(msg);
+		msg = tlsv1_server_send_alert(conn, conn->alert_level,
+					      conn->alert_description,
+					      out_len);
+	}
+
+	return msg;
+}
+
+
+/**
+ * tlsv1_server_encrypt - Encrypt data into TLS tunnel
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @in_data: Pointer to plaintext data to be encrypted
+ * @in_len: Input buffer length
+ * @out_data: Pointer to output buffer (encrypted TLS data)
+ * @out_len: Maximum out_data length 
+ * Returns: Number of bytes written to out_data, -1 on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * send data in the encrypted tunnel.
+ */
+int tlsv1_server_encrypt(struct tlsv1_server *conn,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t out_len)
+{
+	size_t rlen;
+
+	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
+			in_data, in_len);
+
+	os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
+			      out_data, out_len, in_len, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	return rlen;
+}
+
+
+/**
+ * tlsv1_server_decrypt - Decrypt data from TLS tunnel
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @in_data: Pointer to input buffer (encrypted TLS data)
+ * @in_len: Input buffer length
+ * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
+ * @out_len: Maximum out_data length
+ * Returns: Number of bytes written to out_data, -1 on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * receive data from the encrypted tunnel.
+ */
+int tlsv1_server_decrypt(struct tlsv1_server *conn,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t out_len)
+{
+	const u8 *in_end, *pos;
+	int res;
+	u8 alert, *out_end, *out_pos;
+	size_t olen;
+
+	pos = in_data;
+	in_end = in_data + in_len;
+	out_pos = out_data;
+	out_end = out_data + out_len;
+
+	while (pos < in_end) {
+		if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
+				   "0x%x", pos[0]);
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_UNEXPECTED_MESSAGE);
+			return -1;
+		}
+
+		olen = out_end - out_pos;
+		res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+					   out_pos, &olen, &alert);
+		if (res < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
+				   "failed");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			return -1;
+		}
+		out_pos += olen;
+		if (out_pos > out_end) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
+				   "for processing the received record");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+
+		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+	}
+
+	return out_pos - out_data;
+}
+
+
+/**
+ * tlsv1_server_global_init - Initialize TLSv1 server
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function must be called before using any other TLSv1 server functions.
+ */
+int tlsv1_server_global_init(void)
+{
+	return crypto_global_init();
+}
+
+
+/**
+ * tlsv1_server_global_deinit - Deinitialize TLSv1 server
+ *
+ * This function can be used to deinitialize the TLSv1 server that was
+ * initialized by calling tlsv1_server_global_init(). No TLSv1 server functions
+ * can be called after this before calling tlsv1_server_global_init() again.
+ */
+void tlsv1_server_global_deinit(void)
+{
+	crypto_global_deinit();
+}
+
+
+/**
+ * tlsv1_server_init - Initialize TLSv1 server connection
+ * @cred: Pointer to server credentials from tlsv1_server_cred_alloc()
+ * Returns: Pointer to TLSv1 server connection data or %NULL on failure
+ */
+struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
+{
+	struct tlsv1_server *conn;
+	size_t count;
+	u16 *suites;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+
+	conn->cred = cred;
+
+	conn->state = CLIENT_HELLO;
+
+	if (tls_verify_hash_init(&conn->verify) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
+			   "hash");
+		os_free(conn);
+		return NULL;
+	}
+
+	count = 0;
+	suites = conn->cipher_suites;
+#ifndef CONFIG_CRYPTO_INTERNAL
+	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+#endif /* CONFIG_CRYPTO_INTERNAL */
+	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
+	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
+	conn->num_cipher_suites = count;
+
+	return conn;
+}
+
+
+static void tlsv1_server_clear_data(struct tlsv1_server *conn)
+{
+	tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
+	tlsv1_record_change_write_cipher(&conn->rl);
+	tlsv1_record_change_read_cipher(&conn->rl);
+	tls_verify_hash_free(&conn->verify);
+
+	crypto_public_key_free(conn->client_rsa_key);
+	conn->client_rsa_key = NULL;
+
+	os_free(conn->session_ticket);
+	conn->session_ticket = NULL;
+	conn->session_ticket_len = 0;
+	conn->use_session_ticket = 0;
+
+	os_free(conn->dh_secret);
+	conn->dh_secret = NULL;
+	conn->dh_secret_len = 0;
+}
+
+
+/**
+ * tlsv1_server_deinit - Deinitialize TLSv1 server connection
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ */
+void tlsv1_server_deinit(struct tlsv1_server *conn)
+{
+	tlsv1_server_clear_data(conn);
+	os_free(conn);
+}
+
+
+/**
+ * tlsv1_server_established - Check whether connection has been established
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * Returns: 1 if connection is established, 0 if not
+ */
+int tlsv1_server_established(struct tlsv1_server *conn)
+{
+	return conn->state == ESTABLISHED;
+}
+
+
+/**
+ * tlsv1_server_prf - Use TLS-PRF to derive keying material
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @label: Label (e.g., description of the key) for PRF
+ * @server_random_first: seed is 0 = client_random|server_random,
+ * 1 = server_random|client_random
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
+		     int server_random_first, u8 *out, size_t out_len)
+{
+	u8 seed[2 * TLS_RANDOM_LEN];
+
+	if (conn->state != ESTABLISHED)
+		return -1;
+
+	if (server_random_first) {
+		os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
+		os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
+			  TLS_RANDOM_LEN);
+	} else {
+		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
+		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
+			  TLS_RANDOM_LEN);
+	}
+
+	return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+		       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
+}
+
+
+/**
+ * tlsv1_server_get_cipher - Get current cipher name
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @buf: Buffer for the cipher name
+ * @buflen: buf size
+ * Returns: 0 on success, -1 on failure
+ *
+ * Get the name of the currently used cipher.
+ */
+int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
+			    size_t buflen)
+{
+	char *cipher;
+
+	switch (conn->rl.cipher_suite) {
+	case TLS_RSA_WITH_RC4_128_MD5:
+		cipher = "RC4-MD5";
+		break;
+	case TLS_RSA_WITH_RC4_128_SHA:
+		cipher = "RC4-SHA";
+		break;
+	case TLS_RSA_WITH_DES_CBC_SHA:
+		cipher = "DES-CBC-SHA";
+		break;
+	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+		cipher = "DES-CBC3-SHA";
+		break;
+	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
+		cipher = "ADH-AES-128-SHA";
+		break;
+	case TLS_RSA_WITH_AES_256_CBC_SHA:
+		cipher = "AES-256-SHA";
+		break;
+	case TLS_RSA_WITH_AES_128_CBC_SHA:
+		cipher = "AES-128-SHA";
+		break;
+	default:
+		return -1;
+	}
+
+	if (os_strlcpy(buf, cipher, buflen) >= buflen)
+		return -1;
+	return 0;
+}
+
+
+/**
+ * tlsv1_server_shutdown - Shutdown TLS connection
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_server_shutdown(struct tlsv1_server *conn)
+{
+	conn->state = CLIENT_HELLO;
+
+	if (tls_verify_hash_init(&conn->verify) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
+			   "hash");
+		return -1;
+	}
+
+	tlsv1_server_clear_data(conn);
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_server_resumed - Was session resumption used
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * Returns: 1 if current session used session resumption, 0 if not
+ */
+int tlsv1_server_resumed(struct tlsv1_server *conn)
+{
+	return 0;
+}
+
+
+/**
+ * tlsv1_server_get_keys - Get master key and random data from TLS connection
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @keys: Structure of key/random data (filled on success)
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys)
+{
+	os_memset(keys, 0, sizeof(*keys));
+	if (conn->state == CLIENT_HELLO)
+		return -1;
+
+	keys->client_random = conn->client_random;
+	keys->client_random_len = TLS_RANDOM_LEN;
+
+	if (conn->state != SERVER_HELLO) {
+		keys->server_random = conn->server_random;
+		keys->server_random_len = TLS_RANDOM_LEN;
+		keys->master_key = conn->master_secret;
+		keys->master_key_len = TLS_MASTER_SECRET_LEN;
+	}
+
+	return 0;
+}
+
+
+/**
+ * tlsv1_server_get_keyblock_size - Get TLS key_block size
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * Returns: Size of the key_block for the negotiated cipher suite or -1 on
+ * failure
+ */
+int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn)
+{
+	if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
+		return -1;
+
+	return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
+		    conn->rl.iv_size);
+}
+
+
+/**
+ * tlsv1_server_set_cipher_list - Configure acceptable cipher suites
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
+ * (TLS_CIPHER_*).
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers)
+{
+#ifdef EAP_FAST
+	size_t count;
+	u16 *suites;
+
+	/* TODO: implement proper configuration of cipher suites */
+	if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
+		count = 0;
+		suites = conn->cipher_suites;
+#ifndef CONFIG_CRYPTO_INTERNAL
+		suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+#endif /* CONFIG_CRYPTO_INTERNAL */
+		suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+		suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+		suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
+		suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
+#ifndef CONFIG_CRYPTO_INTERNAL
+		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
+#endif /* CONFIG_CRYPTO_INTERNAL */
+		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
+		suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
+		suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
+		suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
+		conn->num_cipher_suites = count;
+	}
+
+	return 0;
+#else /* EAP_FAST */
+	return -1;
+#endif /* EAP_FAST */
+}
+
+
+int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer)
+{
+	conn->verify_peer = verify_peer;
+	return 0;
+}
+
+
+void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
+					tlsv1_server_session_ticket_cb cb,
+					void *ctx)
+{
+	wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
+		   cb, ctx);
+	conn->session_ticket_cb = cb;
+	conn->session_ticket_cb_ctx = ctx;
+}

Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.h (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.h Sat Nov  3 08:40:37 2007
@@ -1,0 +1,54 @@
+/*
+ * TLSv1 server (RFC 2246)
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef TLSV1_SERVER_H
+#define TLSV1_SERVER_H
+
+#include "tlsv1_cred.h"
+
+struct tlsv1_server;
+
+int tlsv1_server_global_init(void);
+void tlsv1_server_global_deinit(void);
+struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred);
+void tlsv1_server_deinit(struct tlsv1_server *conn);
+int tlsv1_server_established(struct tlsv1_server *conn);
+int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
+		     int server_random_first, u8 *out, size_t out_len);
+u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
+			    const u8 *in_data, size_t in_len, size_t *out_len);
+int tlsv1_server_encrypt(struct tlsv1_server *conn,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t out_len);
+int tlsv1_server_decrypt(struct tlsv1_server *conn,
+			 const u8 *in_data, size_t in_len,
+			 u8 *out_data, size_t out_len);
+int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
+			    size_t buflen);
+int tlsv1_server_shutdown(struct tlsv1_server *conn);
+int tlsv1_server_resumed(struct tlsv1_server *conn);
+int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys);
+int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn);
+int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers);
+int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer);
+
+typedef int (*tlsv1_server_session_ticket_cb)
+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
+ const u8 *server_random, u8 *master_secret);
+
+void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
+					tlsv1_server_session_ticket_cb cb,
+					void *ctx);
+
+#endif /* TLSV1_SERVER_H */

Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_i.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_i.h (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_i.h Sat Nov  3 08:40:37 2007
@@ -1,0 +1,77 @@
+/*
+ * TLSv1 server - internal structures
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef TLSV1_SERVER_I_H
+#define TLSV1_SERVER_I_H
+
+struct tlsv1_server {
+	enum {
+		CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,
+		SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,
+		SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE,
+		CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED,
+		SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED,
+		ESTABLISHED, FAILED
+	} state;
+
+	struct tlsv1_record_layer rl;
+
+	u8 session_id[TLS_SESSION_ID_MAX_LEN];
+	size_t session_id_len;
+	u8 client_random[TLS_RANDOM_LEN];
+	u8 server_random[TLS_RANDOM_LEN];
+	u8 master_secret[TLS_MASTER_SECRET_LEN];
+
+	u8 alert_level;
+	u8 alert_description;
+
+	struct crypto_public_key *client_rsa_key;
+
+	struct tls_verify_hash verify;
+
+#define MAX_CIPHER_COUNT 30
+	u16 cipher_suites[MAX_CIPHER_COUNT];
+	size_t num_cipher_suites;
+
+	u16 cipher_suite;
+
+	struct tlsv1_credentials *cred;
+
+	int verify_peer;
+	u16 client_version;
+
+	u8 *session_ticket;
+	size_t session_ticket_len;
+
+	tlsv1_server_session_ticket_cb session_ticket_cb;
+	void *session_ticket_cb_ctx;
+
+	int use_session_ticket;
+
+	u8 *dh_secret;
+	size_t dh_secret_len;
+};
+
+
+void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description);
+int tlsv1_server_derive_keys(struct tlsv1_server *conn,
+			     const u8 *pre_master_secret,
+			     size_t pre_master_secret_len);
+u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len);
+u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
+			     u8 description, size_t *out_len);
+int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
+				   const u8 *buf, size_t *len);
+
+#endif /* TLSV1_SERVER_I_H */

Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_read.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_read.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_read.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_read.c Sat Nov  3 08:40:37 2007
@@ -1,0 +1,1132 @@
+/*
+ * TLSv1 server - read handshake message
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "x509v3.h"
+#include "tls.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_server.h"
+#include "tlsv1_server_i.h"
+
+
+static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
+					   const u8 *in_data, size_t *in_len);
+static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
+					  u8 ct, const u8 *in_data,
+					  size_t *in_len);
+
+
+static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
+				    const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end, *c;
+	size_t left, len, i, j;
+	u16 cipher_suite;
+	u16 num_suites;
+	int compr_null_found;
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+			   "received content type 0x%x", ct);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 4)
+		goto decode_error;
+
+	/* HandshakeType msg_type */
+	if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected ClientHello)", *pos);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello");
+	pos++;
+	/* uint24 length */
+	len = WPA_GET_BE24(pos);
+	pos += 3;
+	left -= 4;
+
+	if (len > left)
+		goto decode_error;
+
+	/* body - ClientHello */
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len);
+	end = pos + len;
+
+	/* ProtocolVersion client_version */
+	if (end - pos < 2)
+		goto decode_error;
+	conn->client_version = WPA_GET_BE16(pos);
+	wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
+		   conn->client_version >> 8, conn->client_version & 0xff);
+	if (conn->client_version < TLS_VERSION) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
+			   "ClientHello");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_PROTOCOL_VERSION);
+		return -1;
+	}
+	pos += 2;
+
+	/* Random random */
+	if (end - pos < TLS_RANDOM_LEN)
+		goto decode_error;
+
+	os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN);
+	pos += TLS_RANDOM_LEN;
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
+		    conn->client_random, TLS_RANDOM_LEN);
+
+	/* SessionID session_id */
+	if (end - pos < 1)
+		goto decode_error;
+	if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
+		goto decode_error;
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos);
+	pos += 1 + *pos;
+	/* TODO: add support for session resumption */
+
+	/* CipherSuite cipher_suites<2..2^16-1> */
+	if (end - pos < 2)
+		goto decode_error;
+	num_suites = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < num_suites)
+		goto decode_error;
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites",
+		    pos, num_suites);
+	if (num_suites & 1)
+		goto decode_error;
+	num_suites /= 2;
+
+	cipher_suite = 0;
+	for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
+		c = pos;
+		for (j = 0; j < num_suites; j++) {
+			u16 tmp = WPA_GET_BE16(c);
+			c += 2;
+			if (!cipher_suite && tmp == conn->cipher_suites[i]) {
+				cipher_suite = tmp;
+				break;
+			}
+		}
+	}
+	pos += num_suites * 2;
+	if (!cipher_suite) {
+		wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite "
+			   "available");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_ILLEGAL_PARAMETER);
+		return -1;
+	}
+
+	if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
+			   "record layer");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	conn->cipher_suite = cipher_suite;
+
+	/* CompressionMethod compression_methods<1..2^8-1> */
+	if (end - pos < 1)
+		goto decode_error;
+	num_suites = *pos++;
+	if (end - pos < num_suites)
+		goto decode_error;
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods",
+		    pos, num_suites);
+	compr_null_found = 0;
+	for (i = 0; i < num_suites; i++) {
+		if (*pos++ == TLS_COMPRESSION_NULL)
+			compr_null_found = 1;
+	}
+	if (!compr_null_found) {
+		wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL "
+			   "compression");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_ILLEGAL_PARAMETER);
+		return -1;
+	}
+
+	if (end - pos == 1) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the "
+			    "end of ClientHello: 0x%02x", *pos);
+		goto decode_error;
+	}
+
+	if (end - pos >= 2) {
+		u16 ext_len;
+
+		/* Extension client_hello_extension_list<0..2^16-1> */
+
+		ext_len = WPA_GET_BE16(pos);
+		pos += 2;
+
+		wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello "
+			   "extensions", ext_len);
+		if (end - pos != ext_len) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello "
+				   "extension list length %u (expected %u)",
+				   ext_len, end - pos);
+			goto decode_error;
+		}
+
+		/*
+		 * struct {
+		 *   ExtensionType extension_type (0..65535)
+		 *   opaque extension_data<0..2^16-1>
+		 * } Extension;
+		 */
+
+		while (pos < end) {
+			u16 ext_type, ext_len;
+
+			if (end - pos < 2) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
+					   "extension_type field");
+				goto decode_error;
+			}
+
+			ext_type = WPA_GET_BE16(pos);
+			pos += 2;
+
+			if (end - pos < 2) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
+					   "extension_data length field");
+				goto decode_error;
+			}
+
+			ext_len = WPA_GET_BE16(pos);
+			pos += 2;
+
+			if (end - pos < ext_len) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
+					   "extension_data field");
+				goto decode_error;
+			}
+
+			wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension "
+				   "type %u", ext_type);
+			wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello "
+				    "Extension data", pos, ext_len);
+
+			if (ext_type == TLS_EXT_SESSION_TICKET) {
+				os_free(conn->session_ticket);
+				conn->session_ticket = os_malloc(ext_len);
+				if (conn->session_ticket) {
+					os_memcpy(conn->session_ticket, pos,
+						  ext_len);
+					conn->session_ticket_len = ext_len;
+				}
+			}
+
+			pos += ext_len;
+		}
+	}
+
+	*in_len = end - in_data;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to "
+		   "ServerHello");
+	conn->state = SERVER_HELLO;
+
+	return 0;
+
+decode_error:
+	wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello");
+	tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+			   TLS_ALERT_DECODE_ERROR);
+	return -1;
+}
+
+
+static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
+				   const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len, list_len, cert_len, idx;
+	u8 type;
+	struct x509_certificate *chain = NULL, *last = NULL, *cert;
+	int reason;
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+			   "received content type 0x%x", ct);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 4) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
+			   "(len=%lu)", (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	type = *pos++;
+	len = WPA_GET_BE24(pos);
+	pos += 3;
+	left -= 4;
+
+	if (len > left) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
+			   "length (len=%lu != left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
+		if (conn->verify_peer) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
+				   "Certificate");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_UNEXPECTED_MESSAGE);
+			return -1;
+		}
+
+		return tls_process_client_key_exchange(conn, ct, in_data,
+						       in_len);
+	}
+	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected Certificate/"
+			   "ClientKeyExchange)", type);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "TLSv1: Received Certificate (certificate_list len %lu)",
+		   (unsigned long) len);
+
+	/*
+	 * opaque ASN.1Cert<2^24-1>;
+	 *
+	 * struct {
+	 *     ASN.1Cert certificate_list<1..2^24-1>;
+	 * } Certificate;
+	 */
+
+	end = pos + len;
+
+	if (end - pos < 3) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
+			   "(left=%lu)", (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	list_len = WPA_GET_BE24(pos);
+	pos += 3;
+
+	if ((size_t) (end - pos) != list_len) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
+			   "length (len=%lu left=%lu)",
+			   (unsigned long) list_len,
+			   (unsigned long) (end - pos));
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	idx = 0;
+	while (pos < end) {
+		if (end - pos < 3) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+				   "certificate_list");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_DECODE_ERROR);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+
+		cert_len = WPA_GET_BE24(pos);
+		pos += 3;
+
+		if ((size_t) (end - pos) < cert_len) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
+				   "length (len=%lu left=%lu)",
+				   (unsigned long) cert_len,
+				   (unsigned long) (end - pos));
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_DECODE_ERROR);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+
+		wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
+			   (unsigned long) idx, (unsigned long) cert_len);
+
+		if (idx == 0) {
+			crypto_public_key_free(conn->client_rsa_key);
+			if (tls_parse_cert(pos, cert_len,
+					   &conn->client_rsa_key)) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+					   "the certificate");
+				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+						   TLS_ALERT_BAD_CERTIFICATE);
+				x509_certificate_chain_free(chain);
+				return -1;
+			}
+		}
+
+		cert = x509_certificate_parse(pos, cert_len);
+		if (cert == NULL) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+				   "the certificate");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_BAD_CERTIFICATE);
+			x509_certificate_chain_free(chain);
+			return -1;
+		}
+
+		if (last == NULL)
+			chain = cert;
+		else
+			last->next = cert;
+		last = cert;
+
+		idx++;
+		pos += cert_len;
+	}
+
+	if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
+					    &reason) < 0) {
+		int tls_reason;
+		wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
+			   "validation failed (reason=%d)", reason);
+		switch (reason) {
+		case X509_VALIDATE_BAD_CERTIFICATE:
+			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+			break;
+		case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
+			tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
+			break;
+		case X509_VALIDATE_CERTIFICATE_REVOKED:
+			tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
+			break;
+		case X509_VALIDATE_CERTIFICATE_EXPIRED:
+			tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
+			break;
+		case X509_VALIDATE_CERTIFICATE_UNKNOWN:
+			tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
+			break;
+		case X509_VALIDATE_UNKNOWN_CA:
+			tls_reason = TLS_ALERT_UNKNOWN_CA;
+			break;
+		default:
+			tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+			break;
+		}
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
+		x509_certificate_chain_free(chain);
+		return -1;
+	}
+
+	x509_certificate_chain_free(chain);
+
+	*in_len = end - in_data;
+
+	conn->state = CLIENT_KEY_EXCHANGE;
+
+	return 0;
+}
+
+
+static int tls_process_client_key_exchange_rsa(
+	struct tlsv1_server *conn, const u8 *pos, const u8 *end)
+{
+	u8 *out;
+	size_t outlen, outbuflen;
+	u16 encr_len;
+	int res;
+	int use_random = 0;
+
+	if (end - pos < 2) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	encr_len = WPA_GET_BE16(pos);
+	pos += 2;
+
+	outbuflen = outlen = end - pos;
+	out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ?
+			outlen : TLS_PRE_MASTER_SECRET_LEN);
+	if (out == NULL) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	/*
+	 * struct {
+	 *   ProtocolVersion client_version;
+	 *   opaque random[46];
+	 * } PreMasterSecret;
+	 *
+	 * struct {
+	 *   public-key-encrypted PreMasterSecret pre_master_secret;
+	 * } EncryptedPreMasterSecret;
+	 */
+
+	/*
+	 * Note: To avoid Bleichenbacher attack, we do not report decryption or
+	 * parsing errors from EncryptedPreMasterSecret processing to the
+	 * client. Instead, a random pre-master secret is used to force the
+	 * handshake to fail.
+	 */
+
+	if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key,
+						 pos, end - pos,
+						 out, &outlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
+			   "PreMasterSecret (encr_len=%d outlen=%lu)",
+			   end - pos, (unsigned long) outlen);
+		use_random = 1;
+	}
+
+	if (outlen != TLS_PRE_MASTER_SECRET_LEN) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
+			   "length %lu", (unsigned long) outlen);
+		use_random = 1;
+	}
+
+	if (WPA_GET_BE16(out) != conn->client_version) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
+			   "ClientKeyExchange does not match with version in "
+			   "ClientHello");
+		use_random = 1;
+	}
+
+	if (use_random) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Using random premaster secret "
+			   "to avoid revealing information about private key");
+		outlen = TLS_PRE_MASTER_SECRET_LEN;
+		if (os_get_random(out, outlen)) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
+				   "data");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			os_free(out);
+			return -1;
+		}
+	}
+
+	res = tlsv1_server_derive_keys(conn, out, outlen);
+
+	/* Clear the pre-master secret since it is not needed anymore */
+	os_memset(out, 0, outbuflen);
+	os_free(out);
+
+	if (res) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int tls_process_client_key_exchange_dh_anon(
+	struct tlsv1_server *conn, const u8 *pos, const u8 *end)
+{
+	const u8 *dh_yc;
+	u16 dh_yc_len;
+	u8 *shared;
+	size_t shared_len;
+	int res;
+
+	/*
+	 * struct {
+	 *   select (PublicValueEncoding) {
+	 *     case implicit: struct { };
+	 *     case explicit: opaque dh_Yc<1..2^16-1>;
+	 *   } dh_public;
+	 * } ClientDiffieHellmanPublic;
+	 */
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic",
+		    pos, end - pos);
+
+	if (end == pos) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Implicit public value encoding "
+			   "not supported");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	if (end - pos < 3) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value "
+			   "length");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	dh_yc_len = WPA_GET_BE16(pos);
+	dh_yc = pos + 2;
+
+	if (dh_yc + dh_yc_len > end) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow "
+			   "(length %d)", dh_yc_len);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
+		    dh_yc, dh_yc_len);
+
+	if (conn->cred == NULL || conn->cred->dh_p == NULL ||
+	    conn->dh_secret == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	shared_len = conn->cred->dh_p_len;
+	shared = os_malloc(shared_len);
+	if (shared == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
+			   "DH");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	/* shared = Yc^secret mod p */
+	crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret, conn->dh_secret_len,
+		       conn->cred->dh_p, conn->cred->dh_p_len,
+		       shared, &shared_len);
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
+			shared, shared_len);
+
+	os_memset(conn->dh_secret, 0, conn->dh_secret_len);
+	os_free(conn->dh_secret);
+	conn->dh_secret = NULL;
+
+	res = tlsv1_server_derive_keys(conn, shared, shared_len);
+
+	/* Clear the pre-master secret since it is not needed anymore */
+	os_memset(shared, 0, shared_len);
+	os_free(shared);
+
+	if (res) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
+					   const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len;
+	u8 type;
+	tls_key_exchange keyx;
+	const struct tls_cipher_suite *suite;
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+			   "received content type 0x%x", ct);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 4) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange "
+			   "(Left=%lu)", (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	type = *pos++;
+	len = WPA_GET_BE24(pos);
+	pos += 3;
+	left -= 4;
+
+	if (len > left) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange "
+			   "length (len=%lu != left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	end = pos + len;
+
+	if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected ClientKeyExchange)", type);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange");
+
+	wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len);
+
+	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+	if (suite == NULL)
+		keyx = TLS_KEY_X_NULL;
+	else
+		keyx = suite->key_exchange;
+
+	if (keyx == TLS_KEY_X_DH_anon &&
+	    tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0)
+		return -1;
+
+	if (keyx != TLS_KEY_X_DH_anon &&
+	    tls_process_client_key_exchange_rsa(conn, pos, end) < 0)
+		return -1;
+
+	*in_len = end - in_data;
+
+	conn->state = CERTIFICATE_VERIFY;
+
+	return 0;
+}
+
+
+static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
+					  const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len;
+	u8 type;
+	size_t hlen, buflen;
+	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;
+	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
+	u16 slen;
+
+	if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
+		if (conn->verify_peer) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
+				   "CertificateVerify");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_UNEXPECTED_MESSAGE);
+			return -1;
+		}
+
+		return tls_process_change_cipher_spec(conn, ct, in_data,
+						      in_len);
+	}
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+			   "received content type 0x%x", ct);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 4) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify "
+			   "message (len=%lu)", (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	type = *pos++;
+	len = WPA_GET_BE24(pos);
+	pos += 3;
+	left -= 4;
+
+	if (len > left) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify "
+			   "message length (len=%lu != left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	end = pos + len;
+
+	if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+			   "message %d (expected CertificateVerify)", type);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify");
+
+	/*
+	 * struct {
+	 *   Signature signature;
+	 * } CertificateVerify;
+	 */
+
+	hpos = hash;
+
+	if (alg == SIGN_ALG_RSA) {
+		hlen = MD5_MAC_LEN;
+		if (conn->verify.md5_cert == NULL ||
+		    crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
+		{
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			conn->verify.md5_cert = NULL;
+			crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+			conn->verify.sha1_cert = NULL;
+			return -1;
+		}
+		hpos += MD5_MAC_LEN;
+	} else
+		crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+
+	conn->verify.md5_cert = NULL;
+	hlen = SHA1_MAC_LEN;
+	if (conn->verify.sha1_cert == NULL ||
+	    crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
+		conn->verify.sha1_cert = NULL;
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	conn->verify.sha1_cert = NULL;
+
+	if (alg == SIGN_ALG_RSA)
+		hlen += MD5_MAC_LEN;
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
+
+	if (end - pos < 2) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+	slen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < slen) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
+	if (conn->client_rsa_key == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
+			   "signature");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	buflen = end - pos;
+	buf = os_malloc(end - pos);
+	if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
+					    pos, end - pos, buf, &buflen) < 0)
+	{
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
+		os_free(buf);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECRYPT_ERROR);
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
+			buf, buflen);
+
+	if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
+			   "CertificateVerify - did not match with calculated "
+			   "hash");
+		os_free(buf);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECRYPT_ERROR);
+		return -1;
+	}
+
+	os_free(buf);
+
+	*in_len = end - in_data;
+
+	conn->state = CHANGE_CIPHER_SPEC;
+
+	return 0;
+}
+
+
+static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
+					  u8 ct, const u8 *in_data,
+					  size_t *in_len)
+{
+	const u8 *pos;
+	size_t left;
+
+	if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+			   "received content type 0x%x", ct);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 1) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	if (*pos != TLS_CHANGE_CIPHER_SPEC) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+			   "received data 0x%x", *pos);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
+	if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
+			   "for record layer");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	*in_len = pos + 1 - in_data;
+
+	conn->state = CLIENT_FINISHED;
+
+	return 0;
+}
+
+
+static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
+				       const u8 *in_data, size_t *in_len)
+{
+	const u8 *pos, *end;
+	size_t left, len, hlen;
+	u8 verify_data[TLS_VERIFY_DATA_LEN];
+	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
+			   "received content type 0x%x", ct);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	pos = in_data;
+	left = *in_len;
+
+	if (left < 4) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
+			   "Finished",
+			   (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+
+	if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
+			   "type 0x%x", pos[0]);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_UNEXPECTED_MESSAGE);
+		return -1;
+	}
+
+	len = WPA_GET_BE24(pos + 1);
+
+	pos += 4;
+	left -= 4;
+
+	if (len > left) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
+			   "(len=%lu > left=%lu)",
+			   (unsigned long) len, (unsigned long) left);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+	end = pos + len;
+	if (len != TLS_VERIFY_DATA_LEN) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
+			   "in Finished: %lu (expected %d)",
+			   (unsigned long) len, TLS_VERIFY_DATA_LEN);
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
+		    pos, TLS_VERIFY_DATA_LEN);
+
+	hlen = MD5_MAC_LEN;
+	if (conn->verify.md5_client == NULL ||
+	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		conn->verify.md5_client = NULL;
+		crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
+		conn->verify.sha1_client = NULL;
+		return -1;
+	}
+	conn->verify.md5_client = NULL;
+	hlen = SHA1_MAC_LEN;
+	if (conn->verify.sha1_client == NULL ||
+	    crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
+			       &hlen) < 0) {
+		conn->verify.sha1_client = NULL;
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	conn->verify.sha1_client = NULL;
+
+	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+		    verify_data, TLS_VERIFY_DATA_LEN)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECRYPT_ERROR);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
+			verify_data, TLS_VERIFY_DATA_LEN);
+
+	if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+		wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
+
+	*in_len = end - in_data;
+
+	if (conn->use_session_ticket) {
+		/* Abbreviated handshake using session ticket; RFC 4507 */
+		wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed "
+			   "successfully");
+		conn->state = ESTABLISHED;
+	} else {
+		/* Full handshake */
+		conn->state = SERVER_CHANGE_CIPHER_SPEC;
+	}
+
+	return 0;
+}
+
+
+int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
+				   const u8 *buf, size_t *len)
+{
+	if (ct == TLS_CONTENT_TYPE_ALERT) {
+		if (*len < 2) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_DECODE_ERROR);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+			   buf[0], buf[1]);
+		*len = 2;
+		conn->state = FAILED;
+		return -1;
+	}
+
+	switch (conn->state) {
+	case CLIENT_HELLO:
+		if (tls_process_client_hello(conn, ct, buf, len))
+			return -1;
+		break;
+	case CLIENT_CERTIFICATE:
+		if (tls_process_certificate(conn, ct, buf, len))
+			return -1;
+		break;
+	case CLIENT_KEY_EXCHANGE:
+		if (tls_process_client_key_exchange(conn, ct, buf, len))
+			return -1;
+		break;
+	case CERTIFICATE_VERIFY:
+		if (tls_process_certificate_verify(conn, ct, buf, len))
+			return -1;
+		break;
+	case CHANGE_CIPHER_SPEC:
+		if (tls_process_change_cipher_spec(conn, ct, buf, len))
+			return -1;
+		break;
+	case CLIENT_FINISHED:
+		if (tls_process_client_finished(conn, ct, buf, len))
+			return -1;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
+			   "while processing received message",
+			   conn->state);
+		return -1;
+	}
+
+	if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
+		tls_verify_hash_add(&conn->verify, buf, *len);
+
+	return 0;
+}

Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_write.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_write.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_write.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_write.c Sat Nov  3 08:40:37 2007
@@ -1,0 +1,785 @@
+/*
+ * TLSv1 server - write handshake message
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "x509v3.h"
+#include "tls.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_server.h"
+#include "tlsv1_server_i.h"
+
+
+static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
+{
+	size_t len = 0;
+	struct x509_certificate *cert;
+
+	cert = conn->cred->cert;
+	while (cert) {
+		len += 3 + cert->cert_len;
+		if (x509_certificate_self_signed(cert))
+			break;
+		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
+						    &cert->issuer);
+	}
+
+	return len;
+}
+
+
+static int tls_write_server_hello(struct tlsv1_server *conn,
+				  u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length;
+	struct os_time now;
+	size_t rlen;
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	os_get_time(&now);
+	WPA_PUT_BE32(conn->server_random, now.sec);
+	if (os_get_random(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
+		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
+			   "server_random");
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
+		    conn->server_random, TLS_RANDOM_LEN);
+
+	conn->session_id_len = TLS_SESSION_ID_MAX_LEN;
+	if (os_get_random(conn->session_id, conn->session_id_len)) {
+		wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
+			   "session_id");
+		return -1;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
+		    conn->session_id, conn->session_id_len);
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	/* body - ServerHello */
+	/* ProtocolVersion server_version */
+	WPA_PUT_BE16(pos, TLS_VERSION);
+	pos += 2;
+	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
+	os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
+	pos += TLS_RANDOM_LEN;
+	/* SessionID session_id */
+	*pos++ = conn->session_id_len;
+	os_memcpy(pos, conn->session_id, conn->session_id_len);
+	pos += conn->session_id_len;
+	/* CipherSuite cipher_suite */
+	WPA_PUT_BE16(pos, conn->cipher_suite);
+	pos += 2;
+	/* CompressionMethod compression_method */
+	*pos++ = TLS_COMPRESSION_NULL;
+
+	if (conn->session_ticket && conn->session_ticket_cb) {
+		int res = conn->session_ticket_cb(
+			conn->session_ticket_cb_ctx,
+			conn->session_ticket, conn->session_ticket_len,
+			conn->client_random, conn->server_random,
+			conn->master_secret);
+		if (res < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
+				   "indicated failure");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_HANDSHAKE_FAILURE);
+			return -1;
+		}
+		conn->use_session_ticket = res;
+
+		if (conn->use_session_ticket) {
+			if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
+					   "derive keys");
+				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+						   TLS_ALERT_INTERNAL_ERROR);
+				return -1;
+			}
+		}
+
+		/*
+		 * RFC 4507 specifies that server would include an empty
+		 * SessionTicket extension in ServerHello and a
+		 * NewSessionTicket message after the ServerHello. However,
+		 * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket
+		 * extension at the moment, does not use such extensions.
+		 *
+		 * TODO: Add support for configuring RFC 4507 behavior and make
+		 * EAP-FAST disable it.
+		 */
+	}
+
+	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	pos = rhdr + rlen;
+
+	*msgpos = pos;
+
+	return 0;
+}
+
+
+static int tls_write_server_certificate(struct tlsv1_server *conn,
+					u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
+	size_t rlen;
+	struct x509_certificate *cert;
+	const struct tls_cipher_suite *suite;
+
+	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+	if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when "
+			   "using anonymous DH");
+		return 0;
+	}
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	/* body - Certificate */
+	/* uint24 length (to be filled) */
+	cert_start = pos;
+	pos += 3;
+	cert = conn->cred->cert;
+	while (cert) {
+		if (pos + 3 + cert->cert_len > end) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
+				   "for Certificate (cert_len=%lu left=%lu)",
+				   (unsigned long) cert->cert_len,
+				   (unsigned long) (end - pos));
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		WPA_PUT_BE24(pos, cert->cert_len);
+		pos += 3;
+		os_memcpy(pos, cert->cert_start, cert->cert_len);
+		pos += cert->cert_len;
+
+		if (x509_certificate_self_signed(cert))
+			break;
+		cert = x509_certificate_get_subject(conn->cred->trusted_certs,
+						    &cert->issuer);
+	}
+	if (cert == conn->cred->cert || cert == NULL) {
+		/*
+		 * Server was not configured with all the needed certificates
+		 * to form a full certificate chain. The client may fail to
+		 * validate the chain unless it is configured with all the
+		 * missing CA certificates.
+		 */
+		wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain "
+			   "not configured - validation may fail");
+	}
+	WPA_PUT_BE24(cert_start, pos - cert_start - 3);
+
+	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	pos = rhdr + rlen;
+
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	*msgpos = pos;
+
+	return 0;
+}
+
+
+static int tls_write_server_key_exchange(struct tlsv1_server *conn,
+					 u8 **msgpos, u8 *end)
+{
+	tls_key_exchange keyx;
+	const struct tls_cipher_suite *suite;
+	u8 *pos, *rhdr, *hs_start, *hs_length;
+	size_t rlen;
+	u8 *dh_ys;
+	size_t dh_ys_len;
+
+	suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+	if (suite == NULL)
+		keyx = TLS_KEY_X_NULL;
+	else
+		keyx = suite->key_exchange;
+
+	if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed");
+		return 0;
+	}
+
+	if (keyx != TLS_KEY_X_DH_anon) {
+		/* TODO? */
+		wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
+			   "supported with key exchange type %d", keyx);
+		return -1;
+	}
+
+	if (conn->cred == NULL || conn->cred->dh_p == NULL ||
+	    conn->cred->dh_g == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for "
+			   "ServerKeyExhcange");
+		return -1;
+	}
+
+	os_free(conn->dh_secret);
+	conn->dh_secret_len = conn->cred->dh_p_len;
+	conn->dh_secret = os_malloc(conn->dh_secret_len);
+	if (conn->dh_secret == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+			   "memory for secret (Diffie-Hellman)");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	if (os_get_random(conn->dh_secret, conn->dh_secret_len)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
+			   "data for Diffie-Hellman");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		os_free(conn->dh_secret);
+		conn->dh_secret = NULL;
+		return -1;
+	}
+
+	if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) >
+	    0)
+		conn->dh_secret[0] = 0; /* make sure secret < p */
+
+	pos = conn->dh_secret;
+	while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0)
+		pos++;
+	if (pos != conn->dh_secret) {
+		os_memmove(conn->dh_secret, pos,
+			   conn->dh_secret_len - (pos - conn->dh_secret));
+		conn->dh_secret_len -= pos - conn->dh_secret;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value",
+			conn->dh_secret, conn->dh_secret_len);
+
+	/* Ys = g^secret mod p */
+	dh_ys_len = conn->cred->dh_p_len;
+	dh_ys = os_malloc(dh_ys_len);
+	if (dh_ys == NULL) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
+			   "Diffie-Hellman");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
+		       conn->dh_secret, conn->dh_secret_len,
+		       conn->cred->dh_p, conn->cred->dh_p_len,
+		       dh_ys, &dh_ys_len);
+
+	wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
+		    dh_ys, dh_ys_len);
+
+	/*
+	 * struct {
+	 *    select (KeyExchangeAlgorithm) {
+	 *       case diffie_hellman:
+	 *          ServerDHParams params;
+	 *          Signature signed_params;
+	 *       case rsa:
+	 *          ServerRSAParams params;
+	 *          Signature signed_params;
+	 *    };
+	 * } ServerKeyExchange;
+	 *
+	 * struct {
+	 *    opaque dh_p<1..2^16-1>;
+	 *    opaque dh_g<1..2^16-1>;
+	 *    opaque dh_Ys<1..2^16-1>;
+	 * } ServerDHParams;
+	 */
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+
+	/* body - ServerDHParams */
+	/* dh_p */
+	if (pos + 2 + conn->cred->dh_p_len > end) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
+			   "dh_p");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		os_free(dh_ys);
+		return -1;
+	}
+	WPA_PUT_BE16(pos, conn->cred->dh_p_len);
+	pos += 2;
+	os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len);
+	pos += conn->cred->dh_p_len;
+
+	/* dh_g */
+	if (pos + 2 + conn->cred->dh_g_len > end) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
+			   "dh_g");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		os_free(dh_ys);
+		return -1;
+	}
+	WPA_PUT_BE16(pos, conn->cred->dh_g_len);
+	pos += 2;
+	os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len);
+	pos += conn->cred->dh_g_len;
+
+	/* dh_Ys */
+	if (pos + 2 + dh_ys_len > end) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
+			   "dh_Ys");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		os_free(dh_ys);
+		return -1;
+	}
+	WPA_PUT_BE16(pos, dh_ys_len);
+	pos += 2;
+	os_memcpy(pos, dh_ys, dh_ys_len);
+	pos += dh_ys_len;
+	os_free(dh_ys);
+
+	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	pos = rhdr + rlen;
+
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	*msgpos = pos;
+
+	return 0;
+}
+
+
+static int tls_write_server_certificate_request(struct tlsv1_server *conn,
+						u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length;
+	size_t rlen;
+
+	if (!conn->verify_peer) {
+		wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed");
+		return 0;
+	}
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	/* body - CertificateRequest */
+
+	/*
+	 * enum {
+	 *   rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
+	 *   (255)
+	 * } ClientCertificateType;
+	 * ClientCertificateType certificate_types<1..2^8-1>
+	 */
+	*pos++ = 1;
+	*pos++ = 1; /* rsa_sign */
+
+	/*
+	 * opaque DistinguishedName<1..2^16-1>
+	 * DistinguishedName certificate_authorities<3..2^16-1>
+	 */
+	/* TODO: add support for listing DNs for trusted CAs */
+	WPA_PUT_BE16(pos, 0);
+	pos += 2;
+
+	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	pos = rhdr + rlen;
+
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	*msgpos = pos;
+
+	return 0;
+}
+
+
+static int tls_write_server_hello_done(struct tlsv1_server *conn,
+				       u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length;
+	size_t rlen;
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	/* body - ServerHelloDone (empty) */
+
+	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	pos = rhdr + rlen;
+
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	*msgpos = pos;
+
+	return 0;
+}
+
+
+static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
+					       u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr;
+	size_t rlen;
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+	*pos = TLS_CHANGE_CIPHER_SPEC;
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
+			      rhdr, end - rhdr, 1, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
+			   "record layer");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	*msgpos = rhdr + rlen;
+
+	return 0;
+}
+
+
+static int tls_write_server_finished(struct tlsv1_server *conn,
+				     u8 **msgpos, u8 *end)
+{
+	u8 *pos, *rhdr, *hs_start, *hs_length;
+	size_t rlen, hlen;
+	u8 verify_data[TLS_VERIFY_DATA_LEN];
+	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+	pos = *msgpos;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
+
+	/* Encrypted Handshake Message: Finished */
+
+	hlen = MD5_MAC_LEN;
+	if (conn->verify.md5_server == NULL ||
+	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		conn->verify.md5_server = NULL;
+		crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
+		conn->verify.sha1_server = NULL;
+		return -1;
+	}
+	conn->verify.md5_server = NULL;
+	hlen = SHA1_MAC_LEN;
+	if (conn->verify.sha1_server == NULL ||
+	    crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
+			       &hlen) < 0) {
+		conn->verify.sha1_server = NULL;
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	conn->verify.sha1_server = NULL;
+
+	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+		    verify_data, TLS_VERIFY_DATA_LEN)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
+			verify_data, TLS_VERIFY_DATA_LEN);
+
+	rhdr = pos;
+	pos += TLS_RECORD_HEADER_LEN;
+	/* Handshake */
+	hs_start = pos;
+	/* HandshakeType msg_type */
+	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
+	/* uint24 length (to be filled) */
+	hs_length = pos;
+	pos += 3;
+	os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
+	pos += TLS_VERIFY_DATA_LEN;
+	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_INTERNAL_ERROR);
+		return -1;
+	}
+
+	pos = rhdr + rlen;
+
+	*msgpos = pos;
+
+	return 0;
+}
+
+
+static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
+{
+	u8 *msg, *end, *pos;
+	size_t msglen;
+
+	*out_len = 0;
+
+	msglen = 1000 + tls_server_cert_chain_der_len(conn);
+
+	msg = os_malloc(msglen);
+	if (msg == NULL)
+		return NULL;
+
+	pos = msg;
+	end = msg + msglen;
+
+	if (tls_write_server_hello(conn, &pos, end) < 0) {
+		os_free(msg);
+		return NULL;
+	}
+
+	if (conn->use_session_ticket) {
+		/* Abbreviated handshake using session ticket; RFC 4507 */
+		if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
+		    tls_write_server_finished(conn, &pos, end) < 0) {
+			os_free(msg);
+			return NULL;
+		}
+
+		*out_len = pos - msg;
+
+		conn->state = CHANGE_CIPHER_SPEC;
+
+		return msg;
+	}
+
+	/* Full handshake */
+	if (tls_write_server_certificate(conn, &pos, end) < 0 ||
+	    tls_write_server_key_exchange(conn, &pos, end) < 0 ||
+	    tls_write_server_certificate_request(conn, &pos, end) < 0 ||
+	    tls_write_server_hello_done(conn, &pos, end) < 0) {
+		os_free(msg);
+		return NULL;
+	}
+
+	*out_len = pos - msg;
+
+	conn->state = CLIENT_CERTIFICATE;
+
+	return msg;
+}
+
+
+static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
+					size_t *out_len)
+{
+	u8 *msg, *end, *pos;
+
+	*out_len = 0;
+
+	msg = os_malloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	pos = msg;
+	end = msg + 1000;
+
+	if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
+	    tls_write_server_finished(conn, &pos, end) < 0) {
+		os_free(msg);
+		return NULL;
+	}
+
+	*out_len = pos - msg;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully");
+	conn->state = ESTABLISHED;
+
+	return msg;
+}
+
+
+u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
+{
+	switch (conn->state) {
+	case SERVER_HELLO:
+		return tls_send_server_hello(conn, out_len);
+	case SERVER_CHANGE_CIPHER_SPEC:
+		return tls_send_change_cipher_spec(conn, out_len);
+	default:
+		if (conn->state == ESTABLISHED && conn->use_session_ticket) {
+			/* Abbreviated handshake was already completed. */
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
+			   "generating reply", conn->state);
+		return NULL;
+	}
+}
+
+
+u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
+			     u8 description, size_t *out_len)
+{
+	u8 *alert, *pos, *length;
+
+	wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
+	*out_len = 0;
+
+	alert = os_malloc(10);
+	if (alert == NULL)
+		return NULL;
+
+	pos = alert;
+
+	/* TLSPlaintext */
+	/* ContentType type */
+	*pos++ = TLS_CONTENT_TYPE_ALERT;
+	/* ProtocolVersion version */
+	WPA_PUT_BE16(pos, TLS_VERSION);
+	pos += 2;
+	/* uint16 length (to be filled) */
+	length = pos;
+	pos += 2;
+	/* opaque fragment[TLSPlaintext.length] */
+
+	/* Alert */
+	/* AlertLevel level */
+	*pos++ = level;
+	/* AlertDescription description */
+	*pos++ = description;
+
+	WPA_PUT_BE16(length, pos - length - 2);
+	*out_len = pos - alert;
+
+	return alert;
+}

Modified: wpasupplicant/branches/upstream/current/src/tls/x509v3.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/x509v3.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/x509v3.c (original)
+++ wpasupplicant/branches/upstream/current/src/tls/x509v3.c Sat Nov  3 08:40:37 2007
@@ -1,6 +1,6 @@
 /*
  * X.509v3 certificate parsing and processing (RFC 3280 profile)
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -75,8 +75,39 @@
 }
 
 
+static int x509_whitespace(char c)
+{
+	return c == ' ' || c == '\t';
+}
+
+
+static void x509_str_strip_whitespace(char *a)
+{
+	char *ipos, *opos;
+	int remove_whitespace = 1;
+
+	ipos = opos = a;
+
+	while (*ipos) {
+		if (remove_whitespace && x509_whitespace(*ipos))
+			ipos++;
+		else {
+			remove_whitespace = x509_whitespace(*ipos);
+			*opos++ = *ipos++;
+		}
+	}
+
+	*opos-- = '\0';
+	if (opos > a && x509_whitespace(*opos))
+		*opos = '\0';
+}
+
+
 static int x509_str_compare(const char *a, const char *b)
 {
+	char *aa, *bb;
+	int ret;
+
 	if (!a && b)
 		return -1;
 	if (a && !b)
@@ -84,14 +115,31 @@
 	if (!a && !b)
 		return 0;
 
-	return os_strcmp(a, b);
+	aa = os_strdup(a);
+	bb = os_strdup(b);
+
+	if (aa == NULL || bb == NULL) {
+		os_free(aa);
+		os_free(bb);
+		return os_strcasecmp(a, b);
+	}
+
+	x509_str_strip_whitespace(aa);
+	x509_str_strip_whitespace(bb);
+
+	ret = os_strcasecmp(aa, bb);
+
+	os_free(aa);
+	os_free(bb);
+
+	return ret;
 }
 
 
 /**
  * x509_name_compare - Compare X.509 certificate names
  * @a: Certificate name
- * @b: Certifiatte name
+ * @b: Certificate name
  * Returns: <0, 0, or >0 based on whether a is less than, equal to, or
  * greater than b
  */
@@ -553,6 +601,17 @@
 	if (os_mktime(year, month, day, hour, min, sec, val) < 0) {
 		wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time",
 				  buf, len);
+		if (year < 1970) {
+			/*
+			 * At least some test certificates have been configured
+			 * to use dates prior to 1970. Set the date to
+			 * beginning of 1970 to handle these case.
+			 */
+			wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - "
+				   "assume epoch as the time", year);
+			*val = 0;
+			return 0;
+		}
 		return -1;
 	}
 
@@ -720,7 +779,8 @@
 			return 0;
 		}
 
-		if (asn1_get_next(pos, len, &hdr) < 0 ||
+		if (asn1_get_next(hdr.payload + hdr.length, len - hdr.length,
+				  &hdr) < 0 ||
 		    hdr.class != ASN1_CLASS_UNIVERSAL) {
 			wpa_printf(MSG_DEBUG, "X509: Failed to parse "
 				   "BasicConstraints");
@@ -1443,6 +1503,13 @@
 		return -1;
 	}
 
+	if (cert->version == X509_CERT_V3 &&
+	    !(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) {
+		wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not "
+			   "include BasicConstraints extension");
+		return -1;
+	}
+
 	if ((cert->extensions_present & X509_EXT_KEY_USAGE) &&
 	    !(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) {
 		wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have "
@@ -1466,7 +1533,8 @@
 				    struct x509_certificate *chain,
 				    int *reason)
 {
-	int idx, chain_trusted = 0;
+	long unsigned idx;
+	int chain_trusted = 0;
 	struct x509_certificate *cert, *trust;
 	char buf[128];
 	struct os_time now;
@@ -1478,12 +1546,15 @@
 
 	for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
 		x509_name_string(&cert->subject, buf, sizeof(buf)); 
-		wpa_printf(MSG_DEBUG, "X509: %d: %s", idx, buf);
+		wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
 
 		if (chain_trusted)
 			continue;
 
-		if (now.sec < cert->not_before || now.sec > cert->not_after) {
+		if ((unsigned long) now.sec <
+		    (unsigned long) cert->not_before ||
+		    (unsigned long) now.sec >
+		    (unsigned long) cert->not_after) {
 			wpa_printf(MSG_INFO, "X509: Certificate not valid "
 				   "(now=%lu not_before=%lu not_after=%lu)",
 				   now.sec, cert->not_before, cert->not_after);
@@ -1505,7 +1576,16 @@
 				return -1;
 			}
 
-			/* TODO: validate pathLenConstraint */
+			if ((cert->next->extensions_present &
+			     X509_EXT_PATH_LEN_CONSTRAINT) &&
+			    idx > cert->next->path_len_constraint) {
+				wpa_printf(MSG_DEBUG, "X509: pathLenConstraint"
+					   " not met (idx=%lu issuer "
+					   "pathLenConstraint=%lu)", idx,
+					   cert->next->path_len_constraint);
+				*reason = X509_VALIDATE_BAD_CERTIFICATE;
+				return -1;
+			}
 
 			if (x509_certificate_check_signature(cert->next, cert)
 			    < 0) {

Modified: wpasupplicant/branches/upstream/current/src/utils/common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/common.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/common.h (original)
+++ wpasupplicant/branches/upstream/current/src/utils/common.h Sat Nov  3 08:40:37 2007
@@ -33,6 +33,24 @@
 #define bswap_64 bswap64
 #endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
 	* defined(__DragonFly__) */
+
+#ifdef __APPLE__
+#include <sys/types.h>
+#include <machine/endian.h>
+#define __BYTE_ORDER	_BYTE_ORDER
+#define __LITTLE_ENDIAN	_LITTLE_ENDIAN
+#define __BIG_ENDIAN	_BIG_ENDIAN
+static inline unsigned short bswap_16(unsigned short v)
+{
+	return ((v & 0xff) << 8) | (v >> 8);
+}
+
+static inline unsigned int bswap_32(unsigned int v)
+{
+	return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
+		((v & 0xff0000) >> 8) | (v >> 24);
+}
+#endif /* __APPLE__ */
 
 #ifdef CONFIG_TI_COMPILER
 #define __BIG_ENDIAN 4321

Modified: wpasupplicant/branches/upstream/current/src/utils/os_unix.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/os_unix.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/os_unix.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/os_unix.c Sat Nov  3 08:40:37 2007
@@ -175,7 +175,7 @@
 
 int os_unsetenv(const char *name)
 {
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
 	unsetenv(name);
 	return 0;
 #else

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog Sat Nov  3 08:40:37 2007
@@ -1,4 +1,26 @@
 ChangeLog for wpa_supplicant
+
+????-??-?? - v0.6.1
+	* added support for configuring password as NtPasswordHash
+	  (16-byte MD4 hash of password) in hash:<32 hex digits> format
+	* added support for fallback from abbreviated TLS handshake to
+	  full handshake when using EAP-FAST (e.g., due to an expired
+	  PAC-Opaque)
+	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+	  draft (draft-ietf-emu-eap-gpsk-06.txt)
+	* added support for drivers that take care of RSN 4-way handshake
+	  internally (WPA_DRIVER_FLAGS_4WAY_HANDSHAKE in get_capa flags and
+	  WPA_ALG_PMK in set_key)
+	* added an experimental port for Mac OS X (CONFIG_DRIVER_OSX=y in
+	  .config); this version supports only ap_scan=2 mode and allow the
+	  driver to take care of the 4-way handshake
+	* fixed a buffer overflow in parsing TSF from scan results when using
+	  driver_wext.c with a driver that includes the TSF (e.g., iwl4965)
+	  [Bug 232]
+	* updated FT support to use the latest draft, IEEE 802.11r/D8.0
+	* fixed an integer overflow issue in the ASN.1 parser used by the
+	  (experimental) internal TLS implementation to avoid a potential
+	  buffer read overflow
 
 2007-05-28 - v0.6.0
 	* added network configuration parameter 'frequency' for setting

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile Sat Nov  3 08:40:37 2007
@@ -189,6 +189,20 @@
 OBJS_d += ../src/drivers/driver_test.o
 endif
 
+ifdef CONFIG_DRIVER_OSX
+CFLAGS += -DCONFIG_DRIVER_OSX
+OBJS_d += ../src/drivers/driver_osx.o
+LDFLAGS += -framework CoreFoundation
+LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211
+endif
+
+ifdef CONFIG_DRIVER_IPHONE
+CFLAGS += -DCONFIG_DRIVER_IPHONE
+OBJS_d += ../src/drivers/driver_iphone.o
+OBJS_d += ../src/drivers/MobileApple80211.o
+LIBS += -framework CoreFoundation
+endif
+
 ifndef CONFIG_L2_PACKET
 CONFIG_L2_PACKET=linux
 endif
@@ -393,6 +407,7 @@
 else
 CFLAGS += -DEAP_FAST
 OBJS += ../src/eap_peer/eap_fast.o ../src/eap_peer/eap_fast_pac.o
+OBJS_h += ../src/eap_server/eap_fast.o
 endif
 TLS_FUNCS=y
 endif
@@ -555,12 +570,15 @@
 endif
 ifeq ($(CONFIG_TLS), internal)
 OBJS += ../src/crypto/tls_internal.o
-OBJS += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_client.o
+OBJS += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_record.o
+OBJS += ../src/tls/tlsv1_cred.o ../src/tls/tlsv1_client.o
+OBJS += ../src/tls/tlsv1_client_write.o ../src/tls/tlsv1_client_read.o
 OBJS += ../src/tls/asn1.o ../src/tls/x509v3.o
 OBJS_p += ../src/tls/asn1.o
 OBJS_p += ../src/crypto/rc4.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o
 NEED_BASE64=y
 CFLAGS += -DCONFIG_TLS_INTERNAL
+CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
 ifeq ($(CONFIG_CRYPTO), internal)
 ifdef CONFIG_INTERNAL_LIBTOMMATH
 CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config.c Sat Nov  3 08:40:37 2007
@@ -949,6 +949,86 @@
 
 	return buf;
 }
+
+
+static int wpa_config_parse_password(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	u8 *hash;
+
+	if (os_strncmp(value, "hash:", 5) != 0) {
+		char *tmp;
+		size_t res_len;
+
+		tmp = wpa_config_parse_string(value, &res_len);
+		if (tmp == NULL) {
+			wpa_printf(MSG_ERROR, "Line %d: failed to parse "
+				   "password.", line);
+			return -1;
+		}
+		wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
+				  (u8 *) tmp, res_len);
+
+		os_free(ssid->password);
+		ssid->password = (u8 *) tmp;
+		ssid->password_len = res_len;
+		ssid->flags &= ~WPA_CONFIG_FLAGS_PASSWORD_NTHASH;
+
+		return 0;
+	}
+
+
+	/* NtPasswordHash: hash:<32 hex digits> */
+	if (os_strlen(value + 5) != 2 * 16) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
+			   "(expected 32 hex digits)", line);
+		return -1;
+	}
+
+	hash = os_malloc(16);
+	if (hash == NULL)
+		return -1;
+
+	if (hexstr2bin(value + 5, hash, 16)) {
+		os_free(hash);
+		wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line);
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
+
+	os_free(ssid->password);
+	ssid->password = hash;
+	ssid->password_len = 16;
+	ssid->flags |= WPA_CONFIG_FLAGS_PASSWORD_NTHASH;
+
+	return 0;
+}
+
+
+static char * wpa_config_write_password(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	char *buf;
+
+	if (ssid->password == NULL)
+		return NULL;
+
+	if (!(ssid->flags & WPA_CONFIG_FLAGS_PASSWORD_NTHASH)) {
+		return wpa_config_write_string(
+			ssid->password, ssid->password_len);
+	}
+
+	buf = os_malloc(5 + 32 + 1);
+	if (buf == NULL)
+		return NULL;
+
+	os_memcpy(buf, "hash:", 5);
+	wpa_snprintf_hex(buf + 5, 32 + 1, ssid->password, 16);
+
+	return buf;
+}
 #endif /* IEEE8021X_EAPOL */
 
 
@@ -1137,7 +1217,7 @@
 	{ STR_LEN(anonymous_identity) },
 	{ STR_RANGE_KEY(eappsk, EAP_PSK_LEN_MIN, EAP_PSK_LEN_MAX) },
 	{ STR_LEN(nai) },
-	{ STR_LEN_KEY(password) },
+	{ FUNC(password) },
 	{ STR(ca_cert) },
 	{ STR(ca_path) },
 	{ STR(client_cert) },

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config_ssid.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config_ssid.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config_ssid.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config_ssid.h Sat Nov  3 08:40:37 2007
@@ -226,6 +226,14 @@
 
 	/**
 	 * password - Password string for EAP
+	 *
+	 * This field can include either the plaintext password (default
+	 * option) or a NtPasswordHash (16-byte MD4 hash of the unicode
+	 * presentation of the password) if flags field has
+	 * WPA_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can
+	 * only be used with authentication mechanism that use this hash as the
+	 * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2,
+	 * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
 	 */
 	u8 *password;
 
@@ -849,6 +857,17 @@
 	 * will be used instead of this configured value.
 	 */
 	int frequency;
+
+#define WPA_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
+	/**
+	 * flags - Network configuration flags (bitfield)
+	 *
+	 * This variable is used for internal flags to describe further details
+	 * for the network parameters.
+	 * bit 0 = password is represented as a 16-byte NtPasswordHash value
+	 *         instead of plaintext password
+	 */
+	u32 flags;
 };
 
 int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int vendor,

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c Sat Nov  3 08:40:37 2007
@@ -1225,6 +1225,12 @@
 		wpa_s->disconnected = 0;
 		wpa_s->reassociate = 1;
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
+	} else if (os_strcmp(buf, "RECONNECT") == 0) {
+		if (wpa_s->disconnected) {
+			wpa_s->disconnected = 0;
+			wpa_s->reassociate = 1;
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
+		}
 	} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
 		if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
 			reply_len = -1;
@@ -1257,6 +1263,7 @@
 		reply_len = wpa_supplicant_ctrl_iface_list_networks(
 			wpa_s, reply, reply_size);
 	} else if (os_strcmp(buf, "DISCONNECT") == 0) {
+		wpa_s->reassociate = 0;
 		wpa_s->disconnected = 1;
 		wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
 	} else if (os_strcmp(buf, "SCAN") == 0) {

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/ctrl_iface.doxygen
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/ctrl_iface.doxygen?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/ctrl_iface.doxygen (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/ctrl_iface.doxygen Sat Nov  3 08:40:37 2007
@@ -203,6 +203,12 @@
 Force reassociation.
 
 
+\subsection ctrl_iface_RECONNECT RECONNECT
+
+Connect if disconnected (i.e., like \c REASSOCIATE, but only connect
+if in disconnected state).
+
+
 \subsection ctrl_iface_PREAUTH PREAUTH <BSSID>
 
 Start pre-authentication with the given BSSID.
@@ -255,7 +261,8 @@
 
 \subsection ctrl_iface_DISCONNECT DISCONNECT
 
-Disconnect and wait for \c REASSOCIATE command before connecting.
+Disconnect and wait for \c REASSOCIATE or \c RECONNECT command before
+connecting.
 
 
 \subsection ctrl_iface_SCAN SCAN

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml Sat Nov  3 08:40:37 2007
@@ -140,7 +140,7 @@
 	<listitem><para>Run in daemon mode executing the action file
         based on events from wpa_supplicant.  The specified file will
 	be executed with the first argument set to interface name and
-	second to "CONNECT" or "DISCONNECT" depending on the event.
+	second to "CONNECTED" or "DISCONNECTED" depending on the event.
 	This can be used to execute networking tools required to configure
 	the interface.</para>
 

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt Sat Nov  3 08:40:37 2007
@@ -79,12 +79,12 @@
 EAP-PAX			-   -   -   -   -   +   -   -   -   -   +   -
 EAP-SAKE		-   -   -   -   -   -   -   -   -   -   +   -
 EAP-GPSK		-   -   -   -   -   -   -   -   -   -   +   -
-EAP-FAST/MSCHAPv2(prov)	-   -   -   +   -   -   -   -   -   +   -   +
-EAP-FAST/GTC(auth)	-   -   -   +   -   -   -   -   -   +   -   +
-EAP-FAST/MSCHAPv2(aprov)-   -   -   -   -   -   -   -   -   -   -   +
-EAP-FAST/GTC(aprov)	-   -   -   -   -   -   -   -   -   -   -   +
+EAP-FAST/MSCHAPv2(prov)	-   -   -   +   -   -   -   -   -   +   +   +
+EAP-FAST/GTC(auth)	-   -   -   +   -   -   -   -   -   +   +   +
+EAP-FAST/MSCHAPv2(aprov)-   -   -   -   -   -   -   -   -   -   +   +
+EAP-FAST/GTC(aprov)	-   -   -   -   -   -   -   -   -   -   +   +
 EAP-FAST/TLS(aprov)	-   -   -   -   -   -   -   -   -   -   -   +
-EAP-FAST/MSCHAPv2(auth)	-   -   -   -   -   -   -   -   -   -   -   +
+EAP-FAST/MSCHAPv2(auth)	-   -   -   -   -   -   -   -   -   -   +   +
 EAP-FAST/TLS(auth)	-   -   -   -   -   -   -   -   -   -   -   +
 LEAP			+   -   +   +   +   +   F   +6  -   +   -   +
 EAP-TNC			-   -   -   -   -   +   -   -   -   -   -   -

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c Sat Nov  3 08:40:37 2007
@@ -199,7 +199,8 @@
 				 size_t len)
 {
 	/* struct wpa_supplicant *wpa_s = ctx; */
-	printf("WPA: eapol_test_eapol_send(type=%d len=%d)\n", type, len);
+	printf("WPA: eapol_test_eapol_send(type=%d len=%lu)\n",
+	       type, (unsigned long) len);
 	if (type == IEEE802_1X_TYPE_EAP_PACKET) {
 		wpa_hexdump(MSG_DEBUG, "TX EAP -> RADIUS", buf, len);
 		ieee802_1x_encapsulate_radius(&eapol_test, buf, len);

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/events.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/events.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/events.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/events.c Sat Nov  3 08:40:37 2007
@@ -444,9 +444,10 @@
 				wpa_printf(MSG_DEBUG, "   skip - disabled");
 				continue;
 			}
-			if (bss->ssid_len != ssid->ssid_len ||
-			    os_memcmp(bss->ssid, ssid->ssid,
-				      bss->ssid_len) != 0) {
+			if (ssid->ssid_len != 0 &&
+			    (bss->ssid_len != ssid->ssid_len ||
+			     os_memcmp(bss->ssid, ssid->ssid,
+				       bss->ssid_len) != 0)) {
 				wpa_printf(MSG_DEBUG, "   skip - "
 					   "SSID mismatch");
 				continue;
@@ -520,7 +521,7 @@
 
 	wpa_supplicant_dbus_notify_scan_results(wpa_s);
 
-	if (wpa_s->conf->ap_scan == 2)
+	if (wpa_s->conf->ap_scan == 2 || wpa_s->disconnected)
 		return;
 	results = wpa_s->scan_results;
 	num = wpa_s->num_scan_results;
@@ -733,6 +734,19 @@
 		wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
 	}
 	wpa_supplicant_cancel_scan(wpa_s);
+
+	if (wpa_s->driver_4way_handshake &&
+	    (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK ||
+	     wpa_s->key_mgmt == WPA_KEY_MGMT_FT_PSK)) {
+		/*
+		 * We are done; the driver will take care of RSN 4-way
+		 * handshake.
+		 */
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+	}
 }
 
 

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c Sat Nov  3 08:40:37 2007
@@ -460,8 +460,7 @@
 			mdie = (struct rsn_mdie *) (bss->mdie + 2);
 		if (mdie &&
 		    os_memcmp(mdie->mobility_domain, wpa_s->mlme.current_md,
-			      MOBILITY_DOMAIN_ID_LEN) == 0 &&
-		    (mdie->ft_capab & RSN_FT_CAPAB_FT_OVER_AIR)) {
+			      MOBILITY_DOMAIN_ID_LEN) == 0) {
 			wpa_printf(MSG_DEBUG, "MLME: Trying to use FT "
 				   "over-the-air");
 			wpa_s->mlme.auth_alg = WLAN_AUTH_FT;
@@ -586,15 +585,14 @@
 	    wpa_s->mlme.auth_alg != WLAN_AUTH_FT &&
 	    bss && bss->mdie &&
 	    bss->mdie_len >= 2 + sizeof(struct rsn_mdie) &&
-	    bss->mdie[1] >= sizeof(struct rsn_mdie) &&
-	    bss->mdie[2 + MOBILITY_DOMAIN_ID_LEN] & RSN_FT_CAPAB_FT_OVER_AIR) {
+	    bss->mdie[1] >= sizeof(struct rsn_mdie)) {
 		pos = buf + blen;
 		blen += 2 + sizeof(struct rsn_mdie);
 		*pos++ = WLAN_EID_MOBILITY_DOMAIN;
 		*pos++ = sizeof(struct rsn_mdie);
 		os_memcpy(pos, bss->mdie + 2, MOBILITY_DOMAIN_ID_LEN);
 		pos += MOBILITY_DOMAIN_ID_LEN;
-		*pos++ = RSN_FT_CAPAB_FT_OVER_AIR;
+		*pos++ = 0; /* FIX: copy from the target AP's MDIE */
 	}
 
 	if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X ||

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_aes.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_aes.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_aes.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_aes.c Sat Nov  3 08:40:37 2007
@@ -277,6 +277,23 @@
 			printf("OMAC1-AES-128 test vector %d failed\n", i);
 			ret++;
 		}
+
+		if (tv->msg_len > 1) {
+			const u8 *addr[2];
+			size_t len[2];
+
+			addr[0] = tv->msg;
+			len[0] = 1;
+			addr[1] = tv->msg + 1;
+			len[1] = tv->msg_len - 1;
+
+			omac1_aes_128_vector(tv->k, 2, addr, len, result);
+			if (memcmp(result, tv->tag, 16) != 0) {
+				printf("OMAC1-AES-128(vector) test vector %d "
+				       "failed\n", i);
+				ret++;
+			}
+		}
 	}
 
 	ret += test_eax();

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3.c Sat Nov  3 08:40:37 2007
@@ -1,6 +1,6 @@
 /*
  * Testing tool for X.509v3 routines
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -15,8 +15,8 @@
 #include "includes.h"
 
 #include "common.h"
-#include "asn1.h"
-#include "x509v3.h"
+#include "tls/asn1.h"
+#include "tls/x509v3.h"
 
 extern int wpa_debug_level;
 
@@ -43,7 +43,7 @@
 			return -1;
 		}
 
-		cert = x509_certificate_parse(buf, len);
+		cert = x509_certificate_parse((u8 *) buf, len);
 		if (cert == NULL) {
 			printf("Failed to parse X.509 certificate\n");
 			return -1;

Added: wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist.sh
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist.sh?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist.sh (added)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist.sh Sat Nov  3 08:40:37 2007
@@ -1,0 +1,144 @@
+#!/bin/sh
+
+# X.509 Path Validation Test Suite, Version 1.07
+# http://csrc.nist.gov/pki/testing/x509paths_old.html
+# http://csrc.nist.gov/pki/testing/x509tests.tgz
+
+if [ -z "$1" ]; then
+    echo "usage: $0 <path to X509tests directory>"
+    exit 1
+fi
+
+TESTS=$1
+
+if [ ! -d $TESTS ]; then
+    echo "Not a directory: $TESTS"
+    exit 1
+fi
+
+X509TEST="./test_x509v3 -v"
+TMPOUT=test_x509v3_nist.out
+
+# TODO: add support for validating CRLs
+
+END="End Certificate "
+ROOT="Trust Anchor "
+ICA="Intermediate Certificate "
+
+SUCCESS=""
+FAILURE=""
+
+function run_test
+{
+    NUM=$1
+    RES=$2
+    shift 2
+    $X509TEST "$@" > $TMPOUT.$NUM
+    VALRES=$?
+    OK=0
+    if [ $RES -eq 0 ]; then
+	# expecting success
+	if [ $VALRES -eq 0 ]; then
+	    OK=1
+	else
+	    echo "test$NUM failed - expected validation success"
+	    OK=0
+	fi
+    else
+	# expecting failure
+	if [ $VALRES -eq 0 ]; then
+	    echo "test$NUM failed - expected validation failure"
+	    OK=0
+	else
+	    REASON=`grep "Certificate chain validation failed: " $TMPOUT.$NUM`
+	    if [ $? -eq 0 ]; then
+		REASONNUM=`echo "$REASON" | colrm 1 37`
+		if [ $REASONNUM -eq $RES ]; then
+		    OK=1
+		else
+		    echo "test$NUM failed - expected validation result $RES; result was $REASONNUM"
+		    OK=0
+		fi
+	    else
+		echo "test$NUM failed - expected validation failure; other type of error detected"
+		OK=0
+	    fi
+	fi
+    fi
+    if [ $OK -eq 1 ]; then
+	rm $TMPOUT.$NUM
+	SUCCESS="$SUCCESS $NUM"
+    else
+	FAILURE="$FAILURE $NUM"
+    fi
+}
+
+P=$TESTS/test
+
+run_test 1 0 "${P}1/${END}CP.01.01.crt" "${P}1/${ROOT}CP.01.01.crt"
+run_test 2 1 "${P}2/${END}CP.01.02.crt" "${P}2/${ICA}CP.01.02.crt" "${P}2/${ROOT}CP.01.01.crt"
+run_test 3 1 "${P}3/${END}CP.01.03.crt" "${P}3/${ICA}CP.01.03.crt" "${P}3/${ROOT}CP.01.01.crt"
+run_test 4 0 "${P}4/${END}CP.02.01.crt" "${P}4/${ICA}2 CP.02.01.crt" "${P}4/${ICA}1 CP.02.01.crt" "${P}4/${ROOT}CP.01.01.crt"
+run_test 5 4 "${P}5/${END}CP.02.02.crt" "${P}5/${ICA}CP.02.02.crt" "${P}5/${ROOT}CP.01.01.crt"
+run_test 6 4 "${P}6/${END}CP.02.03.crt" "${P}6/${ICA}CP.02.03.crt" "${P}6/${ROOT}CP.01.01.crt"
+run_test 7 0 "${P}7/${END}CP.02.04.crt" "${P}7/${ICA}CP.02.04.crt" "${P}7/${ROOT}CP.01.01.crt"
+run_test 8 4 "${P}8/${END}CP.02.05.crt" "${P}8/${ICA}CP.02.05.crt" "${P}8/${ROOT}CP.01.01.crt"
+run_test 9 4 "${P}9/${END}CP.03.01.crt" "${P}9/${ICA}CP.03.01.crt" "${P}9/${ROOT}CP.01.01.crt"
+run_test 10 4 "${P}10/${END}CP.03.02.crt" "${P}10/${ICA}CP.03.02.crt" "${P}10/${ROOT}CP.01.01.crt"
+run_test 11 4 "${P}11/${END}CP.03.03.crt" "${P}11/${ICA}CP.03.03.crt" "${P}11/${ROOT}CP.01.01.crt"
+run_test 12 0 "${P}12/${END}CP.03.04.crt" "${P}12/${ICA}CP.03.04.crt" "${P}12/${ROOT}CP.01.01.crt"
+run_test 13 5 "${P}13/${END}CP.04.01.crt" "${P}13/${ICA}CP.04.01.crt" "${P}13/${ROOT}CP.01.01.crt"
+run_test 14 5 "${P}14/${END}CP.04.02.crt" "${P}14/${ICA}CP.04.02.crt" "${P}14/${ROOT}CP.01.01.crt"
+run_test 15 0 "${P}15/${END}CP.04.03.crt" "${P}15/${ICA}CP.04.03.crt" "${P}15/${ROOT}CP.01.01.crt"
+run_test 16 0 "${P}16/${END}CP.04.04.crt" "${P}16/${ICA}CP.04.04.crt" "${P}16/${ROOT}CP.01.01.crt"
+run_test 17 0 "${P}17/${END}CP.04.05.crt" "${P}17/${ICA}CP.04.05.crt" "${P}17/${ROOT}CP.01.01.crt"
+run_test 18 0 "${P}18/${END}CP.04.06.crt" "${P}18/${ICA}CP.04.06.crt" "${P}18/${ROOT}CP.01.01.crt"
+run_test 19 1 "${P}19/${END}CP.05.01.crt" "${P}19/${ICA}CP.05.01.crt" "${P}19/${ROOT}CP.01.01.crt"
+run_test 20 3 "${P}20/${END}CP.06.01.crt" "${P}20/${ICA}CP.06.01.crt" "${P}20/${ROOT}CP.01.01.crt"
+run_test 21 3 "${P}21/${END}CP.06.02.crt" "${P}21/${ICA}CP.06.02.crt" "${P}21/${ROOT}CP.01.01.crt"
+run_test 22 1 "${P}22/${END}IC.01.01.crt" "${P}22/${ICA}IC.01.01.crt" "${P}22/${ROOT}CP.01.01.crt"
+run_test 23 1 "${P}23/${END}IC.02.01.crt" "${P}23/${ICA}IC.02.01.crt" "${P}23/${ROOT}CP.01.01.crt"
+run_test 24 0 "${P}24/${END}IC.02.02.crt" "${P}24/${ICA}IC.02.02.crt" "${P}24/${ROOT}CP.01.01.crt"
+run_test 25 1 "${P}25/${END}IC.02.03.crt" "${P}25/${ICA}IC.02.03.crt" "${P}25/${ROOT}CP.01.01.crt"
+run_test 26 0 "${P}26/${END}IC.02.04.crt" "${P}26/${ICA}IC.02.04.crt" "${P}26/${ROOT}CP.01.01.crt"
+run_test 27 0 "${P}27/${END}IC.04.01.crt" "${P}27/${ICA}IC.04.01.crt" "${P}27/${ROOT}CP.01.01.crt"
+run_test 28 1 "${P}28/${END}IC.05.01.crt" "${P}28/${ICA}IC.05.01.crt" "${P}28/${ROOT}CP.01.01.crt"
+run_test 29 1 "${P}29/${END}IC.05.02.crt" "${P}29/${ICA}IC.05.02.crt" "${P}29/${ROOT}CP.01.01.crt"
+run_test 30 0 "${P}30/${END}IC.05.03.crt" "${P}30/${ICA}IC.05.03.crt" "${P}30/${ROOT}CP.01.01.crt"
+run_test 31 1 "${P}31/${END}IC.06.01.crt" "${P}31/${ICA}IC.06.01.crt" "${P}31/${ROOT}CP.01.01.crt"
+run_test 32 1 "${P}32/${END}IC.06.02.crt" "${P}32/${ICA}IC.06.02.crt" "${P}32/${ROOT}CP.01.01.crt"
+run_test 33 0 "${P}33/${END}IC.06.03.crt" "${P}33/${ICA}IC.06.03.crt" "${P}33/${ROOT}CP.01.01.crt"
+run_test 34 0 "${P}34/${END}PP.01.01.crt" "${P}34/${ICA}PP.01.01.crt" "${P}34/${ROOT}CP.01.01.crt"
+run_test 35 0 "${P}35/${END}PP.01.02.crt" "${P}35/${ICA}PP.01.02.crt" "${P}35/${ROOT}CP.01.01.crt"
+run_test 36 0 "${P}36/${END}PP.01.03.crt" "${P}36/${ICA}2 PP.01.03.crt" "${P}36/${ICA}1 PP.01.03.crt" "${P}36/${ROOT}CP.01.01.crt"
+run_test 37 0 "${P}37/${END}PP.01.04.crt" "${P}37/${ICA}2 PP.01.04.crt" "${P}37/${ICA}1 PP.01.04.crt" "${P}37/${ROOT}CP.01.01.crt"
+run_test 38 0 "${P}38/${END}PP.01.05.crt" "${P}38/${ICA}2 PP.01.05.crt" "${P}38/${ICA}1 PP.01.05.crt" "${P}38/${ROOT}CP.01.01.crt"
+run_test 39 0 "${P}39/${END}PP.01.06.crt" "${P}39/${ICA}3 PP.01.06.crt" "${P}39/${ICA}2 PP.01.06.crt" "${P}39/${ICA}1 PP.01.06.crt" "${P}39/${ROOT}CP.01.01.crt"
+run_test 40 0 "${P}40/${END}PP.01.07.crt" "${P}40/${ICA}3 PP.01.07.crt" "${P}40/${ICA}2 PP.01.07.crt" "${P}40/${ICA}1 PP.01.07.crt" "${P}40/${ROOT}CP.01.01.crt"
+run_test 41 0 "${P}41/${END}PP.01.08.crt" "${P}41/${ICA}3 PP.01.08.crt" "${P}41/${ICA}2 PP.01.08.crt" "${P}41/${ICA}1 PP.01.08.crt" "${P}41/${ROOT}CP.01.01.crt"
+run_test 42 0 "${P}42/${END}PP.01.09.crt" "${P}42/${ICA}4 PP.01.09.crt" "${P}42/${ICA}3 PP.01.09.crt" "${P}42/${ICA}2 PP.01.09.crt" "${P}42/${ICA}1 PP.01.09.crt" "${P}42/${ROOT}CP.01.01.crt"
+run_test 43 0 "${P}43/${END}PP.06.01.crt" "${P}43/${ICA}4 PP.06.01.crt" "${P}43/${ICA}3 PP.06.01.crt" "${P}43/${ICA}2 PP.06.01.crt" "${P}43/${ICA}1 PP.06.01.crt" "${P}43/${ROOT}CP.01.01.crt"
+run_test 44 0 "${P}44/${END}PP.06.02.crt" "${P}44/${ICA}4 PP.06.02.crt" "${P}44/${ICA}3 PP.06.02.crt" "${P}44/${ICA}2 PP.06.02.crt" "${P}44/${ICA}1 PP.06.02.crt" "${P}44/${ROOT}CP.01.01.crt"
+run_test 45 0 "${P}45/${END}PP.06.03.crt" "${P}45/${ICA}4 PP.06.03.crt" "${P}45/${ICA}3 PP.06.03.crt" "${P}45/${ICA}2 PP.06.03.crt" "${P}45/${ICA}1 PP.06.03.crt" "${P}45/${ROOT}CP.01.01.crt"
+run_test 46 0 "${P}46/${END}PP.06.04.crt" "${P}46/${ICA}4 PP.06.04.crt" "${P}46/${ICA}3 PP.06.04.crt" "${P}46/${ICA}2 PP.06.04.crt" "${P}46/${ICA}1 PP.06.04.crt" "${P}46/${ROOT}CP.01.01.crt"
+run_test 47 0 "${P}47/${END}PP.06.05.crt" "${P}47/${ICA}4 PP.06.05.crt" "${P}47/${ICA}3 PP.06.05.crt" "${P}47/${ICA}2 PP.06.05.crt" "${P}47/${ICA}1 PP.06.05.crt" "${P}47/${ROOT}CP.01.01.crt"
+run_test 48 0 "${P}48/${END}PP.08.01.crt" "${P}48/${ICA}PP.08.01.crt" "${P}48/${ROOT}CP.01.01.crt"
+run_test 49 0 "${P}49/${END}PP.08.02.crt" "${P}49/${ICA}PP.08.02.crt" "${P}49/${ROOT}CP.01.01.crt"
+run_test 50 0 "${P}50/${END}PP.08.03.crt" "${P}50/${ICA}PP.08.03.crt" "${P}50/${ROOT}CP.01.01.crt"
+run_test 51 0 "${P}51/${END}PP.08.04.crt" "${P}51/${ICA}PP.08.04.crt" "${P}51/${ROOT}CP.01.01.crt"
+run_test 52 0 "${P}52/${END}PP.08.05.crt" "${P}52/${ICA}PP.08.05.crt" "${P}52/${ROOT}CP.01.01.crt"
+run_test 53 0 "${P}53/${END}PP.08.06.crt" "${P}53/${ICA}PP.08.06.crt" "${P}53/${ROOT}CP.01.01.crt"
+run_test 54 1 "${P}54/${END}PL.01.01.crt" "${P}54/${ICA}2 PL.01.01.crt" "${P}54/${ICA}1 PL.01.01.crt" "${P}54/${ROOT}CP.01.01.crt"
+run_test 55 1 "${P}55/${END}PL.01.02.crt" "${P}55/${ICA}2 PL.01.02.crt" "${P}55/${ICA}1 PL.01.02.crt" "${P}55/${ROOT}CP.01.01.crt"
+run_test 56 0 "${P}56/${END}PL.01.03.crt" "${P}56/${ICA}PL.01.03.crt" "${P}56/${ROOT}CP.01.01.crt"
+run_test 57 0 "${P}57/${END}PL.01.04.crt" "${P}57/${ICA}PL.01.04.crt" "${P}57/${ROOT}CP.01.01.crt"
+run_test 58 1 "${P}58/${END}PL.01.05.crt" "${P}58/${ICA}3 PL.01.05.crt" "${P}58/${ICA}2 PL.01.05.crt" "${P}58/${ICA}1 PL.01.05.crt" "${P}58/${ROOT}CP.01.01.crt"
+run_test 59 1 "${P}59/${END}PL.01.06.crt" "${P}59/${ICA}3 PL.01.06.crt" "${P}59/${ICA}2 PL.01.06.crt" "${P}59/${ICA}1 PL.01.06.crt" "${P}59/${ROOT}CP.01.01.crt"
+run_test 60 1 "${P}60/${END}PL.01.07.crt" "${P}60/${ICA}4 PL.01.07.crt" "${P}60/${ICA}3 PL.01.07.crt" "${P}60/${ICA}2 PL.01.07.crt" "${P}60/${ICA}1 PL.01.07.crt" "${P}60/${ROOT}CP.01.01.crt"
+run_test 61 1 "${P}61/${END}PL.01.08.crt" "${P}61/${ICA}4 PL.01.08.crt" "${P}61/${ICA}3 PL.01.08.crt" "${P}61/${ICA}2 PL.01.08.crt" "${P}61/${ICA}1 PL.01.08.crt" "${P}61/${ROOT}CP.01.01.crt"
+run_test 62 0 "${P}62/${END}PL.01.09.crt" "${P}62/${ICA}4 PL.01.09.crt" "${P}62/${ICA}3 PL.01.09.crt" "${P}62/${ICA}2 PL.01.09.crt" "${P}62/${ICA}1 PL.01.09.crt" "${P}62/${ROOT}CP.01.01.crt"
+run_test 63 0 "${P}63/${END}PL.01.10.crt" "${P}63/${ICA}4 PL.01.10.crt" "${P}63/${ICA}3 PL.01.10.crt" "${P}63/${ICA}2 PL.01.10.crt" "${P}63/${ICA}1 PL.01.10.crt" "${P}63/${ROOT}CP.01.01.crt"
+
+
+echo "Successful tests:$SUCCESS"
+echo "Failed tests:$FAILURE"

Propchange: wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist.sh
------------------------------------------------------------------------------
    svn:executable = *

Added: wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist2.sh
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist2.sh?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist2.sh (added)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist2.sh Sat Nov  3 08:40:37 2007
@@ -1,0 +1,165 @@
+#!/bin/sh
+
+# Public Key Interoperability Test Suite (PKITS)
+# http://csrc.nist.gov/pki/testing/x509paths.html
+# http://csrc.nist.gov/pki/testing/PKITS_data.zip
+
+if [ -z "$1" ]; then
+    echo "usage: $0 <path to root test directory>"
+    exit 1
+fi
+
+TESTS=$1
+
+if [ ! -d $TESTS ]; then
+    echo "Not a directory: $TESTS"
+    exit 1
+fi
+
+X509TEST="$PWD/test_x509v3 -v"
+TMPOUT="$PWD/test_x509v3_nist2.out"
+
+# TODO: add support for validating CRLs
+
+SUCCESS=""
+FAILURE=""
+
+function run_test
+{
+    NUM=$1
+    RES=$2
+    shift 2
+    $X509TEST "$@" TrustAnchorRootCertificate.crt > $TMPOUT.$NUM
+    VALRES=$?
+    OK=0
+    if [ $RES -eq 0 ]; then
+	# expecting success
+	if [ $VALRES -eq 0 ]; then
+	    OK=1
+	else
+	    echo "$NUM failed - expected validation success"
+	    OK=0
+	fi
+    else
+	# expecting failure
+	if [ $VALRES -eq 0 ]; then
+	    echo "$NUM failed - expected validation failure"
+	    OK=0
+	else
+	    REASON=`grep "Certificate chain validation failed: " $TMPOUT.$NUM`
+	    if [ $? -eq 0 ]; then
+		REASONNUM=`echo "$REASON" | colrm 1 37`
+		if [ $REASONNUM -eq $RES ]; then
+		    OK=1
+		else
+		    echo "$NUM failed - expected validation result $RES; result was $REASONNUM"
+		    OK=0
+		fi
+	    else
+		echo "$NUM failed - expected validation failure; other type of error detected"
+		OK=0
+	    fi
+	fi
+    fi
+    if [ $OK -eq 1 ]; then
+	rm $TMPOUT.$NUM
+	SUCCESS="$SUCCESS $NUM"
+    else
+	FAILURE="$FAILURE $NUM"
+    fi
+}
+
+pushd $TESTS/certs
+
+run_test 4.1.1 0 ValidCertificatePathTest1EE.crt GoodCACert.crt
+run_test 4.1.2 1 InvalidCASignatureTest2EE.crt BadSignedCACert.crt
+run_test 4.1.3 1 InvalidEESignatureTest3EE.crt GoodCACert.crt
+
+run_test 4.2.1 4 InvalidCAnotBeforeDateTest1EE.crt BadnotBeforeDateCACert.crt
+run_test 4.2.2 4 InvalidEEnotBeforeDateTest2EE.crt GoodCACert.crt
+run_test 4.2.3 0 Validpre2000UTCnotBeforeDateTest3EE.crt GoodCACert.crt
+run_test 4.2.4 0 ValidGeneralizedTimenotBeforeDateTest4EE.crt GoodCACert.crt
+run_test 4.2.5 4 InvalidCAnotAfterDateTest5EE.crt BadnotAfterDateCACert.crt
+run_test 4.2.6 4 InvalidEEnotAfterDateTest6EE.crt GoodCACert.crt
+run_test 4.2.7 4 Invalidpre2000UTCEEnotAfterDateTest7EE.crt GoodCACert.crt
+run_test 4.2.8 0 ValidGeneralizedTimenotAfterDateTest8EE.crt GoodCACert.crt
+
+run_test 4.3.1 5 InvalidNameChainingTest1EE.crt GoodCACert.crt
+run_test 4.3.2 5 InvalidNameChainingOrderTest2EE.crt NameOrderingCACert.crt
+run_test 4.3.3 0 ValidNameChainingWhitespaceTest3EE.crt GoodCACert.crt
+run_test 4.3.4 0 ValidNameChainingWhitespaceTest4EE.crt GoodCACert.crt
+run_test 4.3.5 0 ValidNameChainingCapitalizationTest5EE.crt GoodCACert.crt
+run_test 4.3.6 0 ValidNameUIDsTest6EE.crt UIDCACert.crt
+run_test 4.3.7 0 ValidRFC3280MandatoryAttributeTypesTest7EE.crt RFC3280MandatoryAttributeTypesCACert.crt
+run_test 4.3.8 0 ValidRFC3280OptionalAttributeTypesTest8EE.crt RFC3280OptionalAttributeTypesCACert.crt
+run_test 4.3.9 0 ValidUTF8StringEncodedNamesTest9EE.crt UTF8StringEncodedNamesCACert.crt
+run_test 4.3.10 0 ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt RolloverfromPrintableStringtoUTF8StringCACert.crt
+run_test 4.3.11 0 ValidUTF8StringCaseInsensitiveMatchTest11EE.crt UTF8StringCaseInsensitiveMatchCACert.crt
+
+run_test 4.4.1 1 InvalidMissingCRLTest1EE.crt NoCRLCACert.crt
+# skip rest of 4.4.x tests since CRLs are not yet supported
+
+run_test 4.5.1 0 ValidBasicSelfIssuedOldWithNewTest1EE.crt BasicSelfIssuedNewKeyOldWithNewCACert.crt BasicSelfIssuedNewKeyCACert.crt
+run_test 4.5.2 3 InvalidBasicSelfIssuedOldWithNewTest2EE.crt BasicSelfIssuedNewKeyOldWithNewCACert.crt BasicSelfIssuedNewKeyCACert.crt
+run_test 4.5.3 0 ValidBasicSelfIssuedNewWithOldTest3EE.crt BasicSelfIssuedOldKeyNewWithOldCACert.crt BasicSelfIssuedOldKeyCACert.crt
+run_test 4.5.4 0 ValidBasicSelfIssuedNewWithOldTest4EE.crt BasicSelfIssuedOldKeyNewWithOldCACert.crt BasicSelfIssuedOldKeyCACert.crt
+run_test 4.5.5 3 InvalidBasicSelfIssuedNewWithOldTest5EE.crt BasicSelfIssuedOldKeyNewWithOldCACert.crt BasicSelfIssuedOldKeyCACert.crt
+run_test 4.5.6 0 ValidBasicSelfIssuedCRLSigningKeyTest6EE.crt BasicSelfIssuedCRLSigningKeyCRLCert.crt BasicSelfIssuedCRLSigningKeyCACert.crt
+run_test 4.5.7 3 InvalidBasicSelfIssuedCRLSigningKeyTest7EE.crt BasicSelfIssuedCRLSigningKeyCRLCert.crt BasicSelfIssuedCRLSigningKeyCACert.crt
+run_test 4.5.8 1 InvalidBasicSelfIssuedCRLSigningKeyTest8EE.crt BasicSelfIssuedCRLSigningKeyCRLCert.crt BasicSelfIssuedCRLSigningKeyCACert.crt
+
+run_test 4.6.1 1 InvalidMissingbasicConstraintsTest1EE.crt MissingbasicConstraintsCACert.crt
+run_test 4.6.2 1 InvalidcAFalseTest2EE.crt basicConstraintsCriticalcAFalseCACert.crt
+run_test 4.6.3 1 InvalidcAFalseTest3EE.crt basicConstraintsNotCriticalcAFalseCACert.crt
+run_test 4.6.4 0 ValidbasicConstraintsNotCriticalTest4EE.crt basicConstraintsNotCriticalCACert.crt
+run_test 4.6.5 1 InvalidpathLenConstraintTest5EE.crt pathLenConstraint0subCACert.crt pathLenConstraint0CACert.crt
+run_test 4.6.6 1 InvalidpathLenConstraintTest6EE.crt pathLenConstraint0subCACert.crt pathLenConstraint0CACert.crt
+run_test 4.6.7 0 ValidpathLenConstraintTest7EE.crt pathLenConstraint0CACert.crt
+run_test 4.6.8 0 ValidpathLenConstraintTest8EE.crt pathLenConstraint0CACert.crt
+run_test 4.6.9 1 InvalidpathLenConstraintTest9EE.crt pathLenConstraint6subsubCA00Cert.crt pathLenConstraint6subCA0Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.10 1 InvalidpathLenConstraintTest10EE.crt pathLenConstraint6subsubCA00Cert.crt pathLenConstraint6subCA0Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.11 1 InvalidpathLenConstraintTest11EE.crt pathLenConstraint6subsubsubCA11XCert.crt pathLenConstraint6subsubCA11Cert.crt pathLenConstraint6subCA1Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.12 1 InvalidpathLenConstraintTest12EE.crt pathLenConstraint6subsubsubCA11XCert.crt pathLenConstraint6subsubCA11Cert.crt pathLenConstraint6subCA1Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.13 0 ValidpathLenConstraintTest13EE.crt pathLenConstraint6subsubsubCA41XCert.crt pathLenConstraint6subsubCA41Cert.crt pathLenConstraint6subCA4Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.14 0 ValidpathLenConstraintTest14EE.crt pathLenConstraint6subsubsubCA41XCert.crt pathLenConstraint6subsubCA41Cert.crt pathLenConstraint6subCA4Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.15 0 ValidSelfIssuedpathLenConstraintTest15EE.crt pathLenConstraint0SelfIssuedCACert.crt pathLenConstraint0CACert.crt
+run_test 4.6.16 1 InvalidSelfIssuedpathLenConstraintTest16EE.crt pathLenConstraint0subCA2Cert.crt pathLenConstraint0SelfIssuedCACert.crt pathLenConstraint0CACert.crt
+run_test 4.6.17 0 ValidSelfIssuedpathLenConstraintTest17EE.crt pathLenConstraint1SelfIssuedsubCACert.crt pathLenConstraint1subCACert.crt pathLenConstraint1SelfIssuedCACert.crt pathLenConstraint1CACert.crt
+
+run_test 4.7.1 1 InvalidkeyUsageCriticalkeyCertSignFalseTest1EE.crt keyUsageCriticalkeyCertSignFalseCACert.crt
+run_test 4.7.2 1 InvalidkeyUsageNotCriticalkeyCertSignFalseTest2EE.crt keyUsageNotCriticalkeyCertSignFalseCACert.crt
+run_test 4.7.3 0 ValidkeyUsageNotCriticalTest3EE.crt keyUsageNotCriticalCACert.crt
+run_test 4.7.4 1 InvalidkeyUsageCriticalcRLSignFalseTest4EE.crt keyUsageCriticalcRLSignFalseCACert.crt
+run_test 4.7.5 1 InvalidkeyUsageNotCriticalcRLSignFalseTest5EE.crt keyUsageNotCriticalcRLSignFalseCACert.crt
+
+run_test 4.8.1 0 ValidCertificatePathTest1EE.crt GoodCACert.crt
+run_test 4.8.2 0 AllCertificatesNoPoliciesTest2EE.crt NoPoliciesCACert.crt
+run_test 4.8.3 0 DifferentPoliciesTest3EE.crt PoliciesP2subCACert.crt GoodCACert.crt
+run_test 4.8.4 0 DifferentPoliciesTest4EE.crt GoodsubCACert.crt GoodCACert.crt
+run_test 4.8.5 0 DifferentPoliciesTest5EE.crt PoliciesP2subCA2Cert.crt GoodCACert.crt
+run_test 4.8.6 0 OverlappingPoliciesTest6EE.crt PoliciesP1234subsubCAP123P12Cert.crt PoliciesP1234subCAP123Cert.crt PoliciesP1234CACert.crt
+run_test 4.8.7 0 DifferentPoliciesTest7EE.crt PoliciesP123subsubCAP12P1Cert.crt PoliciesP123subCAP12Cert.crt PoliciesP123CACert.crt
+run_test 4.8.8 0 DifferentPoliciesTest8EE.crt PoliciesP12subsubCAP1P2Cert.crt PoliciesP12subCAP1Cert.crt PoliciesP12CACert.crt
+run_test 4.8.9 0 DifferentPoliciesTest9EE.crt PoliciesP123subsubsubCAP12P2P1Cert.crt PoliciesP123subsubCAP12P2Cert.crt PoliciesP123subCAP12Cert.crt PoliciesP123CACert.crt
+run_test 4.8.10 0 AllCertificatesSamePoliciesTest10EE.crt PoliciesP12CACert.crt
+run_test 4.8.11 0 AllCertificatesanyPolicyTest11EE.crt anyPolicyCACert.crt
+run_test 4.8.12 0 DifferentPoliciesTest12EE.crt PoliciesP3CACert.crt
+run_test 4.8.13 0 AllCertificatesSamePoliciesTest13EE.crt PoliciesP123CACert.crt
+run_test 4.8.14 0 AnyPolicyTest14EE.crt anyPolicyCACert.crt
+run_test 4.8.15 0 UserNoticeQualifierTest15EE.crt
+run_test 4.8.16 0 UserNoticeQualifierTest16EE.crt GoodCACert.crt
+run_test 4.8.17 0 UserNoticeQualifierTest17EE.crt GoodCACert.crt
+run_test 4.8.18 0 UserNoticeQualifierTest18EE.crt PoliciesP12CACert.crt
+run_test 4.8.19 0 UserNoticeQualifierTest19EE.crt TrustAnchorRootCertificate.crt
+run_test 4.8.20 0 CPSPointerQualifierTest20EE.crt GoodCACert.crt
+
+if false; then
+# DSA tests
+run_test 4.1.4 0 ValidDSASignaturesTest4EE.crt DSACACert.crt
+fi
+
+popd
+
+
+echo "Successful tests:$SUCCESS"
+echo "Failed tests:$FAILURE"

Propchange: wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist2.sh
------------------------------------------------------------------------------
    svn:executable = *

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt Sat Nov  3 08:40:37 2007
@@ -50,8 +50,6 @@
 - possibility to link in WPA Authenticator state machine to wpa_supplicant
   (new STAKey handshake, WPA2 IBSS)
 - consider merging hostapd and wpa_supplicant PMKSA cache implementations
-- add support for configuring password for MSCHAPv2 as NtPasswordHash in
-  the same way as was added to hostapd (hash:<hex value>)
 - consider adding generic buffer functionality that could be used in number
   of places
   * allocate buffer (with default max size), allow reserving head room to
@@ -110,15 +108,16 @@
 - change TLS/crypto library interface to use a structure of function
   pointers and helper inline functions (like driver_ops) instead of
   requiring every TLS wrapper to implement all functions
-- move from CVS to git (0.3.x, 0.4.x, 0.5.x releases will continue
-  to be updated only on CVS)
-- move files into subdirectories and combine wpa_supplicant and hostapd
-  into a repository that matches in directory structure with the release
-  tarballs
-  (subdirs: eap_common, eap_peer, eap_server, driver, driver_ap, ...)
 - make it clearer that EAP server/peer can be used as a separate library
   for other programs
 - add support for encrypted configuration fields (e.g., password, psk,
   passphrase, pin)
 - wpa_gui: add support for setting and showing priority, id_str, auth_alg
   (open/shared for static WEP)
+
+- cleanup TLS/PEAP/TTLS/FAST fragmentation: both the handshake and Appl. Data
+  phases should be able to use the same functions for this;
+  the last step in processing sent should be this code and rest of the code
+  should not need to care about fragmentation at all
+- test EAP-FAST peer with OpenSSL and verify that fallback to full handshake
+  (ServerHello followed by something else than ChangeCipherSpec)

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c Sat Nov  3 08:40:37 2007
@@ -120,8 +120,10 @@
 "    list of variables when run without arguments)\n"
 "  get_network <network id> <variable> = get network variables\n"
 "  save_config = save the current configuration\n"
-"  disconnect = disconnect and wait for reassociate command before "
-"connecting\n"
+"  disconnect = disconnect and wait for reassociate/reconnect command before\n "
+"    connecting\n"
+"  reconnect = like reassociate, but only takes effect if already "
+"disconnected\n"
 "  scan = request new BSS scan\n"
 "  scan_results = get latest scan results\n"
 "  get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = "
@@ -323,13 +325,13 @@
 	if (argc != 2) {
 		printf("Invalid SET command: needs two arguments (variable "
 		       "name and value)\n");
-		return 0;
+		return -1;
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
 		printf("Too long SET command.\n");
-		return 0;
+		return -1;
 	}
 	return wpa_ctrl_command(ctrl, cmd);
 }
@@ -363,13 +365,13 @@
 	if (argc != 1) {
 		printf("Invalid PREAUTH command: needs one argument "
 		       "(BSSID)\n");
-		return 0;
+		return -1;
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]);
 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
 		printf("Too long PREAUTH command.\n");
-		return 0;
+		return -1;
 	}
 	return wpa_ctrl_command(ctrl, cmd);
 }
@@ -383,12 +385,12 @@
 	if (argc != 1) {
 		printf("Invalid AP_SCAN command: needs one argument (ap_scan "
 		       "value)\n");
-		return 0;
+		return -1;
 	}
 	res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]);
 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
 		printf("Too long AP_SCAN command.\n");
-		return 0;
+		return -1;
 	}
 	return wpa_ctrl_command(ctrl, cmd);
 }
@@ -403,13 +405,13 @@
 	if (argc != 1) {
 		printf("Invalid STKSTART command: needs one argument "
 		       "(Peer STA MAC address)\n");
-		return 0;
+		return -1;
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]);
 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
 		printf("Too long STKSTART command.\n");
-		return 0;
+		return -1;
 	}
 	return wpa_ctrl_command(ctrl, cmd);
 }
@@ -423,13 +425,13 @@
 	if (argc != 1) {
 		printf("Invalid FT_DS command: needs one argument "
 		       "(Target AP MAC address)\n");
-		return 0;
+		return -1;
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]);
 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
 		printf("Too long FT_DS command.\n");
-		return 0;
+		return -1;
 	}
 	return wpa_ctrl_command(ctrl, cmd);
 }
@@ -443,12 +445,12 @@
 	if (argc != 1) {
 		printf("Invalid LEVEL command: needs one argument (debug "
 		       "level)\n");
-		return 0;
+		return -1;
 	}
 	res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
 		printf("Too long LEVEL command.\n");
-		return 0;
+		return -1;
 	}
 	return wpa_ctrl_command(ctrl, cmd);
 }
@@ -462,7 +464,7 @@
 	if (argc < 2) {
 		printf("Invalid IDENTITY command: needs two arguments "
 		       "(network id and identity)\n");
-		return 0;
+		return -1;
 	}
 
 	end = cmd + sizeof(cmd);
@@ -471,14 +473,14 @@
 			  argv[0], argv[1]);
 	if (ret < 0 || ret >= end - pos) {
 		printf("Too long IDENTITY command.\n");
-		return 0;
+		return -1;
 	}
 	pos += ret;
 	for (i = 2; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
 		if (ret < 0 || ret >= end - pos) {
 			printf("Too long IDENTITY command.\n");
-			return 0;
+			return -1;
 		}
 		pos += ret;
 	}
@@ -495,7 +497,7 @@
 	if (argc < 2) {
 		printf("Invalid PASSWORD command: needs two arguments "
 		       "(network id and password)\n");
-		return 0;
+		return -1;
 	}
 
 	end = cmd + sizeof(cmd);
@@ -504,14 +506,14 @@
 			  argv[0], argv[1]);
 	if (ret < 0 || ret >= end - pos) {
 		printf("Too long PASSWORD command.\n");
-		return 0;
+		return -1;
 	}
 	pos += ret;
 	for (i = 2; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
 		if (ret < 0 || ret >= end - pos) {
 			printf("Too long PASSWORD command.\n");
-			return 0;
+			return -1;
 		}
 		pos += ret;
 	}
@@ -529,7 +531,7 @@
 	if (argc < 2) {
 		printf("Invalid NEW_PASSWORD command: needs two arguments "
 		       "(network id and password)\n");
-		return 0;
+		return -1;
 	}
 
 	end = cmd + sizeof(cmd);
@@ -538,14 +540,14 @@
 			  argv[0], argv[1]);
 	if (ret < 0 || ret >= end - pos) {
 		printf("Too long NEW_PASSWORD command.\n");
-		return 0;
+		return -1;
 	}
 	pos += ret;
 	for (i = 2; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
 		if (ret < 0 || ret >= end - pos) {
 			printf("Too long NEW_PASSWORD command.\n");
-			return 0;
+			return -1;
 		}
 		pos += ret;
 	}
@@ -562,7 +564,7 @@
 	if (argc < 2) {
 		printf("Invalid PIN command: needs two arguments "
 		       "(network id and pin)\n");
-		return 0;
+		return -1;
 	}
 
 	end = cmd + sizeof(cmd);
@@ -571,14 +573,14 @@
 			  argv[0], argv[1]);
 	if (ret < 0 || ret >= end - pos) {
 		printf("Too long PIN command.\n");
-		return 0;
+		return -1;
 	}
 	pos += ret;
 	for (i = 2; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
 		if (ret < 0 || ret >= end - pos) {
 			printf("Too long PIN command.\n");
-			return 0;
+			return -1;
 		}
 		pos += ret;
 	}
@@ -594,7 +596,7 @@
 	if (argc < 2) {
 		printf("Invalid OTP command: needs two arguments (network "
 		       "id and password)\n");
-		return 0;
+		return -1;
 	}
 
 	end = cmd + sizeof(cmd);
@@ -603,14 +605,14 @@
 			  argv[0], argv[1]);
 	if (ret < 0 || ret >= end - pos) {
 		printf("Too long OTP command.\n");
-		return 0;
+		return -1;
 	}
 	pos += ret;
 	for (i = 2; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
 		if (ret < 0 || ret >= end - pos) {
 			printf("Too long OTP command.\n");
-			return 0;
+			return -1;
 		}
 		pos += ret;
 	}
@@ -628,7 +630,7 @@
 	if (argc < 2) {
 		printf("Invalid PASSPHRASE command: needs two arguments "
 		       "(network id and passphrase)\n");
-		return 0;
+		return -1;
 	}
 
 	end = cmd + sizeof(cmd);
@@ -637,14 +639,14 @@
 			  argv[0], argv[1]);
 	if (ret < 0 || ret >= end - pos) {
 		printf("Too long PASSPHRASE command.\n");
-		return 0;
+		return -1;
 	}
 	pos += ret;
 	for (i = 2; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
 		if (ret < 0 || ret >= end - pos) {
 			printf("Too long PASSPHRASE command.\n");
-			return 0;
+			return -1;
 		}
 		pos += ret;
 	}
@@ -661,7 +663,7 @@
 	if (argc < 2) {
 		printf("Invalid BSSID command: needs two arguments (network "
 		       "id and BSSID)\n");
-		return 0;
+		return -1;
 	}
 
 	end = cmd + sizeof(cmd);
@@ -669,14 +671,14 @@
 	ret = os_snprintf(pos, end - pos, "BSSID");
 	if (ret < 0 || ret >= end - pos) {
 		printf("Too long BSSID command.\n");
-		return 0;
+		return -1;
 	}
 	pos += ret;
 	for (i = 0; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
 		if (ret < 0 || ret >= end - pos) {
 			printf("Too long BSSID command.\n");
-			return 0;
+			return -1;
 		}
 		pos += ret;
 	}
@@ -701,7 +703,7 @@
 	if (argc < 1) {
 		printf("Invalid SELECT_NETWORK command: needs one argument "
 		       "(network id)\n");
-		return 0;
+		return -1;
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
@@ -722,7 +724,7 @@
 	if (argc < 1) {
 		printf("Invalid ENABLE_NETWORK command: needs one argument "
 		       "(network id)\n");
-		return 0;
+		return -1;
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
@@ -743,7 +745,7 @@
 	if (argc < 1) {
 		printf("Invalid DISABLE_NETWORK command: needs one argument "
 		       "(network id)\n");
-		return 0;
+		return -1;
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
@@ -771,7 +773,7 @@
 	if (argc < 1) {
 		printf("Invalid REMOVE_NETWORK command: needs one argument "
 		       "(network id)\n");
-		return 0;
+		return -1;
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
@@ -818,14 +820,14 @@
 	if (argc != 3) {
 		printf("Invalid SET_NETWORK command: needs three arguments\n"
 		       "(network id, variable name, and value)\n");
-		return 0;
+		return -1;
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
 			  argv[0], argv[1], argv[2]);
 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
 		printf("Too long SET_NETWORK command.\n");
-		return 0;
+		return -1;
 	}
 	return wpa_ctrl_command(ctrl, cmd);
 }
@@ -845,14 +847,14 @@
 	if (argc != 2) {
 		printf("Invalid GET_NETWORK command: needs two arguments\n"
 		       "(network id and variable name)\n");
-		return 0;
+		return -1;
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
 			  argv[0], argv[1]);
 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
 		printf("Too long GET_NETWORK command.\n");
-		return 0;
+		return -1;
 	}
 	return wpa_ctrl_command(ctrl, cmd);
 }
@@ -862,6 +864,13 @@
 				  char *argv[])
 {
 	return wpa_ctrl_command(ctrl, "DISCONNECT");
+}
+
+
+static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "RECONNECT");
 }
 
 
@@ -894,13 +903,13 @@
 	if (argc < 1 || argc > 2) {
 		printf("Invalid GET_CAPABILITY command: need either one or "
 		       "two arguments\n");
-		return 0;
+		return -1;
 	}
 
 	if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
 		printf("Invalid GET_CAPABILITY command: second argument, "
 		       "if any, must be 'strict'\n");
-		return 0;
+		return -1;
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0],
@@ -972,7 +981,7 @@
 		       "argument (interface name)\n"
 		       "All arguments: ifname confname driver ctrl_interface "
 		       "driver_param bridge_name\n");
-		return 0;
+		return -1;
 	}
 
 	/*
@@ -1001,7 +1010,7 @@
 	if (argc != 1) {
 		printf("Invalid INTERFACE_REMOVE command: needs one argument "
 		       "(interface name)\n");
-		return 0;
+		return -1;
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
@@ -1049,6 +1058,7 @@
 	{ "get_network", wpa_cli_cmd_get_network },
 	{ "save_config", wpa_cli_cmd_save_config },
 	{ "disconnect", wpa_cli_cmd_disconnect },
+	{ "reconnect", wpa_cli_cmd_reconnect },
 	{ "scan", wpa_cli_cmd_scan },
 	{ "scan_results", wpa_cli_cmd_scan_results },
 	{ "get_capability", wpa_cli_cmd_get_capability },
@@ -1063,10 +1073,11 @@
 };
 
 
-static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	struct wpa_cli_cmd *cmd, *match = NULL;
 	int count;
+	int ret = 0;
 
 	count = 0;
 	cmd = wpa_cli_commands;
@@ -1095,11 +1106,15 @@
 			cmd++;
 		}
 		printf("\n");
+		ret = 1;
 	} else if (count == 0) {
 		printf("Unknown command '%s'\n", argv[0]);
+		ret = 1;
 	} else {
-		match->handler(ctrl, argc - 1, &argv[1]);
-	}
+		ret = match->handler(ctrl, argc - 1, &argv[1]);
+	}
+
+	return ret;
 }
 
 
@@ -1554,6 +1569,7 @@
 	int warning_displayed = 0;
 	int c;
 	int daemonize = 0;
+	int ret = 0;
 	const char *global = NULL;
 
 	if (os_program_init())
@@ -1665,12 +1681,12 @@
 	else if (action_file)
 		wpa_cli_action(ctrl_conn);
 	else
-		wpa_request(ctrl_conn, argc - optind, &argv[optind]);
+		ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]);
 
 	os_free(ctrl_ifname);
 	wpa_cli_cleanup();
 
-	return 0;
+	return ret;
 }
 
 #else /* CONFIG_CTRL_IFACE */

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c Sat Nov  3 08:40:37 2007
@@ -1512,6 +1512,11 @@
 	}
 	params.wep_tx_keyidx = ssid->wep_tx_keyidx;
 
+	if (wpa_s->driver_4way_handshake &&
+	    (params.key_mgmt_suite == KEY_MGMT_PSK ||
+	     params.key_mgmt_suite == KEY_MGMT_FT_PSK))
+		params.passphrase = ssid->passphrase;
+
 #ifdef CONFIG_IEEE80211W
 	switch (ssid->ieee80211w) {
 	case NO_IEEE80211W:
@@ -1987,7 +1992,11 @@
 		return;
 	}
 
-	if (wpa_s->eapol_received == 0) {
+	if (wpa_s->eapol_received == 0 &&
+	    (!wpa_s->driver_4way_handshake ||
+	     (wpa_s->key_mgmt != WPA_KEY_MGMT_PSK &&
+	      wpa_s->key_mgmt != WPA_KEY_MGMT_FT_PSK) ||
+	     wpa_s->wpa_state != WPA_COMPLETED)) {
 		/* Timeout for completing IEEE 802.1X and WPA authentication */
 		wpa_supplicant_req_auth_timeout(
 			wpa_s,
@@ -2016,7 +2025,18 @@
 	    eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
 		return;
 	wpa_drv_poll(wpa_s);
-	wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
+	if (!wpa_s->driver_4way_handshake)
+		wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
+	else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
+		 wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+		/*
+		 * Set portValid = TRUE here since we are going to skip 4-way
+		 * handshake processing which would normally set portValid. We
+		 * need this to allow the EAPOL state machines to be completed
+		 * without going through EAPOL-Key handshake.
+		 */
+		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+	}
 }
 
 
@@ -2220,6 +2240,57 @@
 }
 
 
+#ifdef IEEE8021X_EAPOL
+static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
+				    void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	int res, pmk_len;
+	u8 pmk[PMK_LEN];
+
+	wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
+		   success ? "" : "un");
+
+	if (!success || !wpa_s->driver_4way_handshake)
+		return;
+
+	if (wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
+	    wpa_s->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way "
+		   "handshake");
+
+	pmk_len = PMK_LEN;
+	res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
+	if (res) {
+		/*
+		 * EAP-LEAP is an exception from other EAP methods: it
+		 * uses only 16-byte PMK.
+		 */
+		res = eapol_sm_get_key(eapol, pmk, 16);
+		pmk_len = 16;
+	}
+
+	if (res) {
+		wpa_printf(MSG_DEBUG, "Failed to get PMK from EAPOL state "
+			   "machines");
+		return;
+	}
+
+	if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
+			    pmk_len)) {
+		wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
+	}
+
+	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
+	wpa_supplicant_cancel_auth_timeout(wpa_s);
+	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+
+}
+#endif /* IEEE8021X_EAPOL */
+
+
 static int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
 {
 #ifdef IEEE8021X_EAPOL
@@ -2243,6 +2314,8 @@
 	ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
 	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
 	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+	ctx->cb = wpa_supplicant_eapol_cb;
+	ctx->cb_ctx = wpa_s;
 	wpa_s->eapol = eapol_sm_init(ctx);
 	if (wpa_s->eapol == NULL) {
 		os_free(ctx);
@@ -2392,11 +2465,14 @@
 		return -1;
 	}
 
-	if (wpa_drv_get_capa(wpa_s, &capa) == 0 &&
-	    capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-		wpa_s->use_client_mlme = 1;
-		if (ieee80211_sta_init(wpa_s))
-			return -1;
+	if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+		if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
+			wpa_s->use_client_mlme = 1;
+			if (ieee80211_sta_init(wpa_s))
+				return -1;
+		}
+		if (capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)
+			wpa_s->driver_4way_handshake = 1;
 	}
 
 	return 0;

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf Sat Nov  3 08:40:37 2007
@@ -295,7 +295,11 @@
 # anonymous_identity: Anonymous identity string for EAP (to be used as the
 #	unencrypted identity with EAP types that support different tunnelled
 #	identity, e.g., EAP-TTLS)
-# password: Password string for EAP
+# password: Password string for EAP. This field can include either the
+#	plaintext password (using ASCII or hex string) or a NtPasswordHash
+#	(16-byte MD4 hash of password) in hash:<32 hex digits> format.
+#	NtPasswordHash can only be used when the password is for MSCHAPv2 or
+#	MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP)
 # ca_cert: File path to CA certificate file (PEM/DER). This file can have one
 #	or more trusted CA certificates. If ca_cert and ca_path are not
 #	included, server certificate will not be verified. This is insecure and

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h Sat Nov  3 08:40:37 2007
@@ -349,6 +349,7 @@
 
 	struct wpa_client_mlme mlme;
 	int use_client_mlme;
+	int driver_4way_handshake;
 };
 
 




More information about the Pkg-wpa-devel mailing list