[pkg-wpa-devel] r1186 - in /wpasupplicant/branches/upstream/current: patches/ src/common/ src/crypto/ src/drivers/ src/eap_common/ src/eap_peer/ src/eap_server/ src/radius/ src/rsn_supp/ src/tls/ src/utils/ wpa_supplicant/ wpa_supplicant/doc/docbook/ wpa_supplicant/examples/ wpa_supplicant/wpa_gui/
kelmo-guest at users.alioth.debian.org
kelmo-guest at users.alioth.debian.org
Sat Jun 14 00:26:58 UTC 2008
Author: kelmo-guest
Date: Sat Jun 14 00:26:56 2008
New Revision: 1186
URL: http://svn.debian.org/wsvn/?sc=1&rev=1186
Log:
[svn-upgrade] Integrating new upstream version, wpasupplicant (0.6.4~git20080614.f598194)
Added:
wpasupplicant/branches/upstream/current/patches/openssl-0.9.8h-tls-extensions.patch
wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c
wpasupplicant/branches/upstream/current/src/drivers/driver_ps3.c
wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.c
wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.c
wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.h
wpasupplicant/branches/upstream/current/src/eap_server/eap_tnc.c
wpasupplicant/branches/upstream/current/src/eap_server/tncs.c
wpasupplicant/branches/upstream/current/src/eap_server/tncs.h
wpasupplicant/branches/upstream/current/wpa_supplicant/examples/openCryptoki.conf
Removed:
wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.c
wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.h
wpasupplicant/branches/upstream/current/src/eap_server/eap_tlv.c
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_gui.8
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_passphrase.8
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.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/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/common/ieee802_11_defs.h
wpasupplicant/branches/upstream/current/src/common/wpa_common.h
wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c
wpasupplicant/branches/upstream/current/src/crypto/sha1.c
wpasupplicant/branches/upstream/current/src/crypto/tls.h
wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c
wpasupplicant/branches/upstream/current/src/drivers/driver_hostap.h
wpasupplicant/branches/upstream/current/src/drivers/driver_ndis.c
wpasupplicant/branches/upstream/current/src/drivers/driver_ralink.c
wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c
wpasupplicant/branches/upstream/current/src/drivers/driver_wext.h
wpasupplicant/branches/upstream/current/src/drivers/drivers.c
wpasupplicant/branches/upstream/current/src/eap_common/eap_defs.h
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_peer/eap_config.h
wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c
wpasupplicant/branches/upstream/current/src/eap_peer/eap_peap.c
wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c
wpasupplicant/branches/upstream/current/src/eap_peer/eap_tnc.c
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_peer/tncc.h
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_fast.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_ikev2.c
wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c
wpasupplicant/branches/upstream/current/src/eap_server/eap_peap.c
wpasupplicant/branches/upstream/current/src/eap_server/eap_tls.c
wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.c
wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.h
wpasupplicant/branches/upstream/current/src/eap_server/eap_ttls.c
wpasupplicant/branches/upstream/current/src/radius/radius.c
wpasupplicant/branches/upstream/current/src/radius/radius.h
wpasupplicant/branches/upstream/current/src/radius/radius_client.c
wpasupplicant/branches/upstream/current/src/radius/radius_client.h
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/peerkey.c
wpasupplicant/branches/upstream/current/src/rsn_supp/preauth.c
wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.c
wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.h
wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c
wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_i.h
wpasupplicant/branches/upstream/current/src/tls/libtommath.c
wpasupplicant/branches/upstream/current/src/utils/base64.c
wpasupplicant/branches/upstream/current/src/utils/common.h
wpasupplicant/branches/upstream/current/src/utils/eloop.c
wpasupplicant/branches/upstream/current/src/utils/eloop.h
wpasupplicant/branches/upstream/current/src/utils/eloop_none.c
wpasupplicant/branches/upstream/current/src/utils/eloop_win.c
wpasupplicant/branches/upstream/current/src/utils/wpabuf.c
wpasupplicant/branches/upstream/current/src/utils/wpabuf.h
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_file.c
wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c
wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c
wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c
wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.c
wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.h
wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_unix.c
wpasupplicant/branches/upstream/current/wpa_supplicant/dbus_dict_helpers.c
wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.sgml
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.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/main.c
wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c
wpasupplicant/branches/upstream/current/wpa_supplicant/preauth_test.c
wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c
wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/networkconfig.ui.h
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/userdatarequest.ui.h
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpagui.ui.h
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpamsg.h
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf
wpasupplicant/branches/upstream/current/wpa_supplicant/wpas_glue.c
Modified: 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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch (original)
+++ wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch Sat Jun 14 00:26:56 2008
@@ -1,4 +1,4 @@
-This patch adds support for TLS SessionTicket extension (RFC 4507) for
+This patch adds support for TLS SessionTicket extension (RFC 5077) for
the parts used by EAP-FAST (RFC 4851).
This is based on the patch from Alexey Kobozev <akobozev at cisco.com>
@@ -10,25 +10,14 @@
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)
+--- openssl-0.9.8g.orig/ssl/s3_clnt.c 2007-08-31 03:28:51.000000000 +0300
++++ openssl-0.9.8g/ssl/s3_clnt.c 2008-04-15 17:11:46.000000000 +0300
+@@ -727,6 +727,20 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
-- if (j != 0 && j == s->session->session_id_length
++#ifndef OPENSSL_NO_TLSEXT
+ /* 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;
@@ -36,22 +25,17 @@
+ 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
+ if (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
+--- openssl-0.9.8g.orig/ssl/s3_srvr.c 2007-09-30 21:55:59.000000000 +0300
++++ openssl-0.9.8g/ssl/s3_srvr.c 2008-04-15 17:10:37.000000000 +0300
@@ -928,6 +928,59 @@ int ssl3_get_client_hello(SSL *s)
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
goto err;
@@ -137,8 +121,8 @@
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
+--- openssl-0.9.8g.orig/ssl/ssl.h 2007-10-19 10:42:38.000000000 +0300
++++ openssl-0.9.8g/ssl/ssl.h 2008-04-15 17:10:37.000000000 +0300
@@ -342,6 +342,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
@@ -193,8 +177,8 @@
/* 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
+--- openssl-0.9.8g.orig/ssl/ssl_err.c 2007-10-11 17:36:59.000000000 +0300
++++ openssl-0.9.8g/ssl/ssl_err.c 2008-04-15 17:10:37.000000000 +0300
@@ -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"},
@@ -204,8 +188,8 @@
};
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
+--- openssl-0.9.8g.orig/ssl/ssl_sess.c 2007-10-19 10:36:34.000000000 +0300
++++ openssl-0.9.8g/ssl/ssl_sess.c 2008-04-15 17:10:37.000000000 +0300
@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return(s->session_timeout);
}
@@ -260,8 +244,8 @@
{
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
+--- openssl-0.9.8g.orig/ssl/t1_lib.c 2007-10-19 10:44:10.000000000 +0300
++++ openssl-0.9.8g/ssl/t1_lib.c 2008-04-15 17:10:37.000000000 +0300
@@ -105,6 +105,12 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
@@ -318,8 +302,8 @@
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
+--- openssl-0.9.8g.orig/ssl/tls1.h 2007-08-28 04:12:44.000000000 +0300
++++ openssl-0.9.8g/ssl/tls1.h 2008-04-15 17:10:37.000000000 +0300
@@ -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
@@ -336,8 +320,8 @@
}
#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
+--- openssl-0.9.8g.orig/util/ssleay.num 2007-08-13 01:31:16.000000000 +0300
++++ openssl-0.9.8g/util/ssleay.num 2008-04-15 17:10:37.000000000 +0300
@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb
SSL_set_SSL_CTX 290 EXIST::FUNCTION:
SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
Added: wpasupplicant/branches/upstream/current/patches/openssl-0.9.8h-tls-extensions.patch
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/patches/openssl-0.9.8h-tls-extensions.patch?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/patches/openssl-0.9.8h-tls-extensions.patch (added)
+++ wpasupplicant/branches/upstream/current/patches/openssl-0.9.8h-tls-extensions.patch Sat Jun 14 00:26:56 2008
@@ -1,0 +1,344 @@
+This patch adds support for TLS SessionTicket extension (RFC 5077) 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.8h 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.8h.orig/ssl/s3_clnt.c openssl-0.9.8h/ssl/s3_clnt.c
+--- openssl-0.9.8h.orig/ssl/s3_clnt.c 2008-05-28 10:29:27.000000000 +0300
++++ openssl-0.9.8h/ssl/s3_clnt.c 2008-05-29 10:44:25.000000000 +0300
+@@ -752,6 +752,20 @@ int ssl3_get_server_hello(SSL *s)
+ goto f_err;
+ }
+
++#ifndef OPENSSL_NO_TLSEXT
++ /* check if we want to resume the session based on external pre-shared secret */
++ 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->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
++ }
++ }
++#endif /* OPENSSL_NO_TLSEXT */
++
+ if (j != 0 && j == s->session->session_id_length
+ && memcmp(p,s->session->session_id,j) == 0)
+ {
+@@ -2693,11 +2707,8 @@ static int ssl3_check_finished(SSL *s)
+ {
+ int ok;
+ long n;
+- /* If we have no ticket or session ID is non-zero length (a match of
+- * a non-zero session length would never reach here) it cannot be a
+- * resumed session.
+- */
+- if (!s->session->tlsext_tick || s->session->session_id_length)
++ /* If we have no ticket it cannot be a resumed session. */
++ if (!s->session->tlsext_tick)
+ return 1;
+ /* this function is called when we really expect a Certificate
+ * message, so permit appropriate message length */
+diff -upr openssl-0.9.8h.orig/ssl/s3_srvr.c openssl-0.9.8h/ssl/s3_srvr.c
+--- openssl-0.9.8h.orig/ssl/s3_srvr.c 2008-04-30 19:11:32.000000000 +0300
++++ openssl-0.9.8h/ssl/s3_srvr.c 2008-05-28 18:49:34.000000000 +0300
+@@ -959,6 +959,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
+@@ -1097,16 +1150,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.8h.orig/ssl/ssl.h openssl-0.9.8h/ssl/ssl.h
+--- openssl-0.9.8h.orig/ssl/ssl.h 2008-04-30 19:11:32.000000000 +0300
++++ openssl-0.9.8h/ssl/ssl.h 2008-05-28 18:49:34.000000000 +0300
+@@ -343,6 +343,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
+@@ -364,6 +365,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
+ {
+@@ -1027,6 +1030,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
+@@ -1625,6 +1636,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.
+@@ -1815,6 +1832,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.8h.orig/ssl/ssl_err.c openssl-0.9.8h/ssl/ssl_err.c
+--- openssl-0.9.8h.orig/ssl/ssl_err.c 2007-10-12 03:00:30.000000000 +0300
++++ openssl-0.9.8h/ssl/ssl_err.c 2008-05-28 18:49:34.000000000 +0300
+@@ -251,6 +251,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.8h.orig/ssl/ssl_sess.c openssl-0.9.8h/ssl/ssl_sess.c
+--- openssl-0.9.8h.orig/ssl/ssl_sess.c 2007-10-17 20:30:15.000000000 +0300
++++ openssl-0.9.8h/ssl/ssl_sess.c 2008-05-28 18:49:34.000000000 +0300
+@@ -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.8h.orig/ssl/t1_lib.c openssl-0.9.8h/ssl/t1_lib.c
+--- openssl-0.9.8h.orig/ssl/t1_lib.c 2008-05-28 10:26:33.000000000 +0300
++++ openssl-0.9.8h/ssl/t1_lib.c 2008-05-28 18:49:34.000000000 +0300
+@@ -106,6 +106,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);
+ }
+
+@@ -175,8 +181,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
+ */
+@@ -190,6 +212,7 @@ unsigned char *ssl_add_clienthello_tlsex
+ ret += ticklen;
+ }
+ }
++ skip_ext:
+
+ if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+ {
+@@ -774,6 +797,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.8h.orig/ssl/tls1.h openssl-0.9.8h/ssl/tls1.h
+--- openssl-0.9.8h.orig/ssl/tls1.h 2008-04-30 19:11:33.000000000 +0300
++++ openssl-0.9.8h/ssl/tls1.h 2008-05-28 18:49:34.000000000 +0300
+@@ -398,6 +398,14 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
+ #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.8h.orig/util/ssleay.num openssl-0.9.8h/util/ssleay.num
+--- openssl-0.9.8h.orig/util/ssleay.num 2007-08-13 01:31:16.000000000 +0300
++++ openssl-0.9.8h/util/ssleay.num 2008-05-28 18:49:34.000000000 +0300
+@@ -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
Modified: 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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch (original)
+++ wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch Sat Jun 14 00:26:56 2008
@@ -1,4 +1,4 @@
-This patch adds support for TLS SessionTicket extension (RFC 4507) for
+This patch adds support for TLS SessionTicket extension (RFC 5077) for
the parts used by EAP-FAST (RFC 4851).
This is based on the patch from Alexey Kobozev <akobozev at cisco.com>
@@ -6,26 +6,15 @@
-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)
+diff -upr openssl-SNAP-20080528.orig/ssl/s3_clnt.c openssl-SNAP-20080528/ssl/s3_clnt.c
+--- openssl-SNAP-20080528.orig/ssl/s3_clnt.c 2008-04-29 21:00:17.000000000 +0300
++++ openssl-SNAP-20080528/ssl/s3_clnt.c 2008-05-29 10:55:43.000000000 +0300
+@@ -785,6 +785,20 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
-- if (j != 0 && j == s->session->session_id_length
++#ifndef OPENSSL_NO_TLSEXT
+ /* 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;
@@ -33,23 +22,32 @@
+ 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
+ if (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)
+@@ -2918,11 +2932,8 @@ static int ssl3_check_finished(SSL *s)
+ {
+ int ok;
+ long n;
+- /* If we have no ticket or session ID is non-zero length (a match of
+- * a non-zero session length would never reach here) it cannot be a
+- * resumed session.
+- */
+- if (!s->session->tlsext_tick || s->session->session_id_length)
++ /* If we have no ticket it cannot be a resumed session. */
++ if (!s->session->tlsext_tick)
+ return 1;
+ /* this function is called when we really expect a Certificate
+ * message, so permit appropriate message length */
+diff -upr openssl-SNAP-20080528.orig/ssl/s3_srvr.c openssl-SNAP-20080528/ssl/s3_srvr.c
+--- openssl-SNAP-20080528.orig/ssl/s3_srvr.c 2008-04-30 20:00:38.000000000 +0300
++++ openssl-SNAP-20080528/ssl/s3_srvr.c 2008-05-29 10:49:25.000000000 +0300
+@@ -1004,6 +1004,59 @@ int ssl3_get_client_hello(SSL *s)
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
goto err;
}
@@ -109,7 +107,7 @@
#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)
+@@ -1130,16 +1183,22 @@ int ssl3_send_server_hello(SSL *s)
unsigned char *buf;
unsigned char *p,*d;
int i,sl;
@@ -133,10 +131,10 @@
/* 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" {
+diff -upr openssl-SNAP-20080528.orig/ssl/ssl.h openssl-SNAP-20080528/ssl/ssl.h
+--- openssl-SNAP-20080528.orig/ssl/ssl.h 2008-05-26 15:00:37.000000000 +0300
++++ openssl-SNAP-20080528/ssl/ssl.h 2008-05-29 10:49:25.000000000 +0300
+@@ -354,6 +354,7 @@ extern "C" {
* 'struct ssl_st *' function parameters used to prototype callbacks
* in SSL_CTX. */
typedef struct ssl_st *ssl_crock_st;
@@ -144,7 +142,7 @@
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st
-@@ -379,6 +380,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+@@ -380,6 +381,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
typedef struct ssl_st SSL;
typedef struct ssl_ctx_st SSL_CTX;
@@ -153,7 +151,7 @@
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st
{
-@@ -1121,6 +1124,13 @@ struct ssl_st
+@@ -1128,6 +1131,13 @@ struct ssl_st
void *tlsext_opaque_prf_input;
size_t tlsext_opaque_prf_input_len;
@@ -167,7 +165,7 @@
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
+@@ -1729,6 +1739,12 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id,void *cm);
#endif
@@ -180,7 +178,7 @@
/* 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);
+@@ -1928,6 +1944,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
@@ -188,9 +186,9 @@
/* 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
+diff -upr openssl-SNAP-20080528.orig/ssl/ssl_err.c openssl-SNAP-20080528/ssl/ssl_err.c
+--- openssl-SNAP-20080528.orig/ssl/ssl_err.c 2007-10-27 03:01:29.000000000 +0300
++++ openssl-SNAP-20080528/ssl/ssl_err.c 2008-05-29 10:49:25.000000000 +0300
@@ -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"},
@@ -199,9 +197,9 @@
{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
+diff -upr openssl-SNAP-20080528.orig/ssl/ssl_sess.c openssl-SNAP-20080528/ssl/ssl_sess.c
+--- openssl-SNAP-20080528.orig/ssl/ssl_sess.c 2008-05-26 15:00:37.000000000 +0300
++++ openssl-SNAP-20080528/ssl/ssl_sess.c 2008-05-29 10:49:25.000000000 +0300
@@ -831,6 +831,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return(s->session_timeout);
}
@@ -255,9 +253,9 @@
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
+diff -upr openssl-SNAP-20080528.orig/ssl/t1_lib.c openssl-SNAP-20080528/ssl/t1_lib.c
+--- openssl-SNAP-20080528.orig/ssl/t1_lib.c 2008-04-30 20:00:39.000000000 +0300
++++ openssl-SNAP-20080528/ssl/t1_lib.c 2008-05-29 10:49:25.000000000 +0300
@@ -154,6 +154,12 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
@@ -271,7 +269,7 @@
ssl3_free(s);
}
-@@ -355,8 +361,24 @@ unsigned char *ssl_add_clienthello_tlsex
+@@ -357,8 +363,24 @@ unsigned char *ssl_add_clienthello_tlsex
int ticklen;
if (s->session && s->session->tlsext_tick)
ticklen = s->session->tlsext_ticklen;
@@ -296,7 +294,7 @@
/* Check for enough room 2 for extension type, 2 for len
* rest for ticket
*/
-@@ -369,6 +391,7 @@ unsigned char *ssl_add_clienthello_tlsex
+@@ -371,6 +393,7 @@ unsigned char *ssl_add_clienthello_tlsex
ret += ticklen;
}
}
@@ -304,7 +302,7 @@
#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
+@@ -1427,6 +1450,8 @@ int tls1_process_ticket(SSL *s, unsigned
s->tlsext_ticket_expected = 1;
return 0; /* Cache miss */
}
@@ -313,10 +311,10 @@
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
+diff -upr openssl-SNAP-20080528.orig/ssl/tls1.h openssl-SNAP-20080528/ssl/tls1.h
+--- openssl-SNAP-20080528.orig/ssl/tls1.h 2008-04-30 20:00:39.000000000 +0300
++++ openssl-SNAP-20080528/ssl/tls1.h 2008-05-29 10:49:25.000000000 +0300
+@@ -512,6 +512,14 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
#endif
@@ -331,9 +329,9 @@
#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
+diff -upr openssl-SNAP-20080528.orig/util/ssleay.num openssl-SNAP-20080528/util/ssleay.num
+--- openssl-SNAP-20080528.orig/util/ssleay.num 2007-08-31 16:03:14.000000000 +0300
++++ openssl-SNAP-20080528/util/ssleay.num 2008-05-29 10:49:25.000000000 +0300
@@ -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:
Modified: wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h Sat Jun 14 00:26:56 2008
@@ -112,9 +112,9 @@
#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
/* 802.11g */
-#define WLAN_STATUS_ASSOC_DENOED_NO_SHORT_SLOT_TIME 25
-#define WLAN_STATUS_ASSOC_DENOED_NO_ER_PBCC 26
-#define WLAN_STATUS_ASSOC_DENOED_NO_DSSS_OFDM 27
+#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
+#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26
+#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27
/* IEEE 802.11i */
#define WLAN_STATUS_INVALID_IE 40
#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
@@ -123,6 +123,11 @@
#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44
#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45
#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46
+#define WLAN_STATUS_TS_NOT_CREATED 47
+#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48
+#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
+#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
+#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
/* IEEE 802.11r */
#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
#define WLAN_STATUS_EXPECTED_RESOURCE_REQ_FT 53
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/wpa_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/wpa_common.h Sat Jun 14 00:26:56 2008
@@ -87,8 +87,8 @@
#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
-#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((a), (val))
-#define RSN_SELECTOR_GET(a) WPA_GET_BE32((a))
+#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val))
+#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a))
#define RSN_NUM_REPLAY_COUNTERS_1 0
#define RSN_NUM_REPLAY_COUNTERS_2 1
@@ -188,8 +188,7 @@
struct wpa_ie_hdr {
u8 elem_id;
u8 len;
- u8 oui[3];
- u8 oui_type;
+ u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */
u8 version[2]; /* little endian */
} STRUCT_PACKED;
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c Sat Jun 14 00:26:56 2008
@@ -22,6 +22,7 @@
#include "aes.h"
#include "tls/rsa.h"
#include "tls/bignum.h"
+#include "tls/asn1.h"
#ifdef EAP_TLS_FUNCS
@@ -434,9 +435,122 @@
}
+static struct crypto_private_key *
+crypto_pkcs8_key_import(const u8 *buf, size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+ struct bignum *zero;
+ struct asn1_oid oid;
+ char obuf[80];
+
+ /* PKCS #8, Chapter 6 */
+
+ /* PrivateKeyInfo ::= SEQUENCE */
+ if (asn1_get_next(buf, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
+ "header (SEQUENCE); assume PKCS #8 not used");
+ return NULL;
+ }
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ /* version Version (Version ::= INTEGER) */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found "
+ "class %d tag 0x%x; assume PKCS #8 not used",
+ hdr.class, hdr.tag);
+ return NULL;
+ }
+
+ zero = bignum_init();
+ if (zero == NULL)
+ return NULL;
+
+ if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) {
+ wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER");
+ bignum_deinit(zero);
+ return NULL;
+ }
+ pos = hdr.payload + hdr.length;
+
+ if (bignum_cmp_d(zero, 0) != 0) {
+ wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the "
+ "beginning of private key; not found; assume "
+ "PKCS #8 not used");
+ bignum_deinit(zero);
+ return NULL;
+ }
+ bignum_deinit(zero);
+
+ /* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
+ * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
+ if (asn1_get_next(pos, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
+ "(AlgorithmIdentifier) - found class %d tag 0x%x; "
+ "assume PKCS #8 not used",
+ hdr.class, hdr.tag);
+ return NULL;
+ }
+
+ if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID "
+ "(algorithm); assume PKCS #8 not used");
+ return NULL;
+ }
+
+ asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+ wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf);
+
+ if (oid.len != 7 ||
+ oid.oid[0] != 1 /* iso */ ||
+ oid.oid[1] != 2 /* member-body */ ||
+ oid.oid[2] != 840 /* us */ ||
+ oid.oid[3] != 113549 /* rsadsi */ ||
+ oid.oid[4] != 1 /* pkcs */ ||
+ oid.oid[5] != 1 /* pkcs-1 */ ||
+ oid.oid[6] != 1 /* rsaEncryption */) {
+ wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key "
+ "algorithm %s", obuf);
+ return NULL;
+ }
+
+ pos = hdr.payload + hdr.length;
+
+ /* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
+ "(privateKey) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
+
+ return (struct crypto_private_key *)
+ crypto_rsa_import_private_key(hdr.payload, hdr.length);
+}
+
+
struct crypto_private_key * crypto_private_key_import(const u8 *key,
size_t len)
{
+ struct crypto_private_key *res;
+
+ /* First, check for possible PKCS #8 encoding */
+ res = crypto_pkcs8_key_import(key, len);
+ if (res)
+ return res;
+
+ /* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */
+ wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private "
+ "key");
return (struct crypto_private_key *)
crypto_rsa_import_private_key(key, len);
}
Modified: wpasupplicant/branches/upstream/current/src/crypto/sha1.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/sha1.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/sha1.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/sha1.c Sat Jun 14 00:26:56 2008
@@ -265,6 +265,10 @@
L_S1 = L_S2 = (secret_len + 1) / 2;
S1 = secret;
S2 = secret + L_S1;
+ if (secret_len & 1) {
+ /* The last byte of S1 will be shared with S2 */
+ S2--;
+ }
hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
Modified: wpasupplicant/branches/upstream/current/src/crypto/tls.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls.h (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls.h Sat Jun 14 00:26:56 2008
@@ -63,7 +63,10 @@
* @engine_id: engine id string (this is OpenSSL specific for now)
* @ppin: pointer to the pin variable in the configuration
* (this is OpenSSL specific for now)
- * @key_id: the private key's key id (this is OpenSSL specific for now)
+ * @key_id: the private key's id when using engine (this is OpenSSL
+ * specific for now)
+ * @cert_id: the certificate's id when using engine
+ * @ca_cert_id: the CA certificate's id when using engine
* @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
*
* TLS connection parameters to be configured with tls_connection_set_params()
@@ -98,6 +101,8 @@
const char *engine_id;
const char *pin;
const char *key_id;
+ const char *cert_id;
+ const char *ca_cert_id;
};
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c Sat Jun 14 00:26:56 2008
@@ -777,7 +777,8 @@
static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
- const char *pin, const char *key_id)
+ const char *pin, const char *key_id,
+ const char *cert_id, const char *ca_cert_id)
{
#ifndef OPENSSL_NO_ENGINE
int ret = -1;
@@ -814,6 +815,7 @@
ERR_error_string(ERR_get_error(), NULL));
goto err;
}
+ /* load private key first in-case PIN is required for cert */
conn->private_key = ENGINE_load_private_key(conn->engine,
key_id, NULL, NULL);
if (!conn->private_key) {
@@ -823,6 +825,21 @@
ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
goto err;
}
+
+ /* handle a certificate and/or CA certificate */
+ if (cert_id || ca_cert_id) {
+ const char *cmd_name = "LOAD_CERT_CTRL";
+
+ /* test if the engine supports a LOAD_CERT_CTRL */
+ if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
+ 0, (void *)cmd_name, NULL)) {
+ wpa_printf(MSG_ERROR, "ENGINE: engine does not support"
+ " loading certificates");
+ ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ goto err;
+ }
+ }
+
return 0;
err:
@@ -877,6 +894,7 @@
{
SSL_CTX *ssl = ssl_ctx;
struct tls_connection *conn;
+ long options;
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
@@ -890,9 +908,12 @@
}
SSL_set_app_data(conn->ssl, conn);
- SSL_set_options(conn->ssl,
- SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
- SSL_OP_SINGLE_DH_USE);
+ options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
+ SSL_OP_SINGLE_DH_USE;
+#ifdef SSL_OP_NO_COMPRESSION
+ options |= SSL_OP_NO_COMPRESSION;
+#endif /* SSL_OP_NO_COMPRESSION */
+ SSL_set_options(conn->ssl, options);
conn->ssl_in = BIO_new(BIO_s_mem());
if (!conn->ssl_in) {
@@ -1261,6 +1282,8 @@
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
int verify_peer)
{
+ static int counter = 0;
+
if (conn == NULL)
return -1;
@@ -1273,6 +1296,19 @@
}
SSL_set_accept_state(conn->ssl);
+
+ /*
+ * Set session id context in order to avoid fatal errors when client
+ * tries to resume a session. However, set the context to a unique
+ * value in order to effectively disable session resumption for now
+ * since not all areas of the server code are ready for it (e.g.,
+ * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS
+ * handshake).
+ */
+ counter++;
+ SSL_set_session_id_context(conn->ssl,
+ (const unsigned char *) &counter,
+ sizeof(counter));
return 0;
}
@@ -1488,6 +1524,110 @@
"p12/pfx blobs");
return -1;
#endif /* PKCS12_FUNCS */
+}
+
+
+#ifndef OPENSSL_NO_ENGINE
+static int tls_engine_get_cert(struct tls_connection *conn,
+ const char *cert_id,
+ X509 **cert)
+{
+ /* this runs after the private key is loaded so no PIN is required */
+ struct {
+ const char *cert_id;
+ X509 *cert;
+ } params;
+ params.cert_id = cert_id;
+ params.cert = NULL;
+
+ if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
+ 0, ¶ms, NULL, 1)) {
+ wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
+ " '%s' [%s]", cert_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ }
+ if (!params.cert) {
+ wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id"
+ " '%s'", cert_id);
+ return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ }
+ *cert = params.cert;
+ return 0;
+}
+#endif /* OPENSSL_NO_ENGINE */
+
+
+static int tls_connection_engine_client_cert(struct tls_connection *conn,
+ const char *cert_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+ X509 *cert;
+
+ if (tls_engine_get_cert(conn, cert_id, &cert))
+ return -1;
+
+ if (!SSL_use_certificate(conn->ssl, cert)) {
+ tls_show_errors(MSG_ERROR, __func__,
+ "SSL_use_certificate failed");
+ X509_free(cert);
+ return -1;
+ }
+ X509_free(cert);
+ wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
+ "OK");
+ return 0;
+
+#else /* OPENSSL_NO_ENGINE */
+ return -1;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static int tls_connection_engine_ca_cert(void *_ssl_ctx,
+ struct tls_connection *conn,
+ const char *ca_cert_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+ X509 *cert;
+ SSL_CTX *ssl_ctx = _ssl_ctx;
+
+ if (tls_engine_get_cert(conn, ca_cert_id, &cert))
+ return -1;
+
+ /* start off the same as tls_connection_ca_cert */
+ X509_STORE_free(ssl_ctx->cert_store);
+ ssl_ctx->cert_store = X509_STORE_new();
+ if (ssl_ctx->cert_store == NULL) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
+ "certificate store", __func__);
+ X509_free(cert);
+ return -1;
+ }
+ if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+ unsigned long err = ERR_peek_error();
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to add CA certificate from engine "
+ "to certificate store");
+ if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
+ ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert"
+ " already in hash table error",
+ __func__);
+ } else {
+ X509_free(cert);
+ return -1;
+ }
+ }
+ X509_free(cert);
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
+ "to certificate store", __func__);
+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ return 0;
+
+#else /* OPENSSL_NO_ENGINE */
+ return -1;
+#endif /* OPENSSL_NO_ENGINE */
}
@@ -1976,8 +2116,11 @@
{
int res;
u8 *out_data;
- char buf[10];
-
+
+ /*
+ * Give TLS handshake data from the client (if available) to OpenSSL
+ * for processing.
+ */
if (in_data &&
BIO_write(conn->ssl_in, in_data, in_len) < 0) {
tls_show_errors(MSG_INFO, __func__,
@@ -1985,12 +2128,23 @@
return NULL;
}
- res = SSL_read(conn->ssl, buf, sizeof(buf));
- if (res >= 0) {
- wpa_printf(MSG_DEBUG, "SSL: Unexpected data from SSL_read "
- "(res=%d)", res);
- }
-
+ /* Initiate TLS handshake or continue the existing handshake */
+ res = SSL_accept(conn->ssl);
+ if (res != 1) {
+ int err = SSL_get_error(conn->ssl, res);
+ if (err == SSL_ERROR_WANT_READ)
+ wpa_printf(MSG_DEBUG, "SSL: SSL_accept - want "
+ "more data");
+ else if (err == SSL_ERROR_WANT_WRITE)
+ wpa_printf(MSG_DEBUG, "SSL: SSL_accept - want to "
+ "write");
+ else {
+ tls_show_errors(MSG_INFO, __func__, "SSL_accept");
+ return NULL;
+ }
+ }
+
+ /* Get the TLS handshake data to be sent to the client */
res = BIO_ctrl_pending(conn->ssl_out);
wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
out_data = os_malloc(res == 0 ? 1 : res);
@@ -2229,26 +2383,39 @@
__func__, ERR_error_string(err, NULL));
}
+ if (params->engine) {
+ wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
+ ret = tls_engine_init(conn, params->engine_id, params->pin,
+ params->key_id, params->cert_id,
+ params->ca_cert_id);
+ if (ret)
+ return ret;
+ }
if (tls_connection_set_subject_match(conn,
params->subject_match,
params->altsubject_match))
return -1;
- if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
- params->ca_cert_blob,
- params->ca_cert_blob_len,
- params->ca_path))
- return -1;
- if (tls_connection_client_cert(conn, params->client_cert,
- params->client_cert_blob,
- params->client_cert_blob_len))
- return -1;
-
- if (params->engine) {
- wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
- ret = tls_engine_init(conn, params->engine_id, params->pin,
- params->key_id);
- if (ret)
- return ret;
+
+ if (params->engine && params->ca_cert_id) {
+ if (tls_connection_engine_ca_cert(tls_ctx, conn,
+ params->ca_cert_id))
+ return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+ } else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+ params->ca_cert_blob,
+ params->ca_cert_blob_len,
+ params->ca_path))
+ return -1;
+
+ if (params->engine && params->cert_id) {
+ if (tls_connection_engine_client_cert(conn, params->cert_id))
+ return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+ } else if (tls_connection_client_cert(conn, params->client_cert,
+ params->client_cert_blob,
+ params->client_cert_blob_len))
+ return -1;
+
+ if (params->engine && params->key_id) {
+ wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
if (tls_connection_engine_private_key(conn))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_private_key(tls_ctx, conn,
Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_hostap.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_hostap.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_hostap.h (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_hostap.h Sat Jun 14 00:26:56 2008
@@ -84,9 +84,9 @@
#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
#define PRISM2_HOSTAPD_RID_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
*/
Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_ndis.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_ndis.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_ndis.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_ndis.c Sat Jun 14 00:26:56 2008
@@ -1317,8 +1317,7 @@
if (wpa_driver_ndis_get_bssid(drv, bssid)) {
/* Disconnected */
- if (os_memcmp(drv->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN)
- != 0) {
+ if (!is_zero_ether_addr(drv->bssid)) {
os_memset(drv->bssid, 0, ETH_ALEN);
wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
}
Added: wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c Sat Jun 14 00:26:56 2008
@@ -1,0 +1,2098 @@
+/*
+ * WPA Supplicant - driver interaction with Linux nl80211/cfg80211
+ * Copyright (c) 2003-2008, 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 <sys/ioctl.h>
+#include <net/if_arp.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/nl80211.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT 0x20000 /* driver signals dormant */
+#endif
+
+#ifndef IF_OPER_DORMANT
+#define IF_OPER_DORMANT 5
+#endif
+#ifndef IF_OPER_UP
+#define IF_OPER_UP 6
+#endif
+
+
+struct wpa_driver_nl80211_data {
+ void *ctx;
+ int event_sock;
+ int ioctl_sock;
+ char ifname[IFNAMSIZ + 1];
+ int ifindex;
+ u8 *assoc_req_ies;
+ size_t assoc_req_ies_len;
+ u8 *assoc_resp_ies;
+ size_t assoc_resp_ies_len;
+ struct wpa_driver_capa capa;
+ int has_capability;
+ int we_version_compiled;
+
+ /* for set_auth_alg fallback */
+ int use_crypt;
+ int auth_alg_fallback;
+
+ int operstate;
+
+ char mlmedev[IFNAMSIZ + 1];
+
+ int scan_complete_events;
+
+ struct nl_handle *nl_handle;
+ struct nl_cache *nl_cache;
+ struct nl_cb *nl_cb;
+ struct genl_family *nl80211;
+};
+
+
+static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+static int wpa_driver_nl80211_set_mode(void *priv, int mode);
+static int wpa_driver_nl80211_flush_pmkid(void *priv);
+static int wpa_driver_nl80211_get_range(void *priv);
+
+static int wpa_driver_nl80211_send_oper_ifla(
+ struct wpa_driver_nl80211_data *drv,
+ int linkmode, int operstate)
+{
+ struct {
+ struct nlmsghdr hdr;
+ struct ifinfomsg ifinfo;
+ char opts[16];
+ } req;
+ struct rtattr *rta;
+ static int nl_seq;
+ ssize_t ret;
+
+ os_memset(&req, 0, sizeof(req));
+
+ req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.hdr.nlmsg_type = RTM_SETLINK;
+ req.hdr.nlmsg_flags = NLM_F_REQUEST;
+ req.hdr.nlmsg_seq = ++nl_seq;
+ req.hdr.nlmsg_pid = 0;
+
+ req.ifinfo.ifi_family = AF_UNSPEC;
+ req.ifinfo.ifi_type = 0;
+ req.ifinfo.ifi_index = drv->ifindex;
+ req.ifinfo.ifi_flags = 0;
+ req.ifinfo.ifi_change = 0;
+
+ if (linkmode != -1) {
+ rta = (struct rtattr *)
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
+ rta->rta_type = IFLA_LINKMODE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = linkmode;
+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+ RTA_LENGTH(sizeof(char));
+ }
+ if (operstate != -1) {
+ rta = (struct rtattr *)
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
+ rta->rta_type = IFLA_OPERSTATE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = operstate;
+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+ RTA_LENGTH(sizeof(char));
+ }
+
+ wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d",
+ linkmode, operstate);
+
+ ret = send(drv->event_sock, &req, req.hdr.nlmsg_len, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: "
+ "%s (assume operstate is not supported)",
+ strerror(errno));
+ }
+
+ return ret < 0 ? -1 : 0;
+}
+
+
+static int wpa_driver_nl80211_set_auth_param(
+ struct wpa_driver_nl80211_data *drv, int idx, u32 value)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.param.flags = idx & IW_AUTH_INDEX;
+ iwr.u.param.value = value;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
+ if (errno != EOPNOTSUPP) {
+ wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
+ "value 0x%x) failed: %s)",
+ idx, value, strerror(errno));
+ }
+ ret = errno == EOPNOTSUPP ? -2 : -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
+ perror("ioctl[SIOCGIWAP]");
+ ret = -1;
+ }
+ os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_bssid(void *priv, const u8 *bssid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
+ if (bssid)
+ os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
+ else
+ os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
+ perror("ioctl[SIOCSIWAP]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) ssid;
+ iwr.u.essid.length = 32;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCGIWESSID]");
+ ret = -1;
+ } else {
+ ret = iwr.u.essid.length;
+ if (ret > 32)
+ ret = 32;
+ /* Some drivers include nul termination in the SSID, so let's
+ * remove it here before further processing. WE-21 changes this
+ * to explicitly require the length _not_ to include nul
+ * termination. */
+ if (ret > 0 && ssid[ret - 1] == '\0' &&
+ drv->we_version_compiled < 21)
+ ret--;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_ssid(void *priv, const u8 *ssid,
+ size_t ssid_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+ char buf[33];
+
+ if (ssid_len > 32)
+ return -1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* flags: 1 = ESSID is active, 0 = not (promiscuous) */
+ iwr.u.essid.flags = (ssid_len != 0);
+ os_memset(buf, 0, sizeof(buf));
+ os_memcpy(buf, ssid, ssid_len);
+ iwr.u.essid.pointer = (caddr_t) buf;
+ if (drv->we_version_compiled < 21) {
+ /* For historic reasons, set SSID length to include one extra
+ * character, C string nul termination, even though SSID is
+ * really an octet string that should not be presented as a C
+ * string. Some Linux drivers decrement the length by one and
+ * can thus end up missing the last octet of the SSID if the
+ * length is not incremented here. WE-21 changes this to
+ * explicitly require the length _not_ to include nul
+ * termination. */
+ if (ssid_len)
+ ssid_len++;
+ }
+ iwr.u.essid.length = ssid_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_freq(void *priv, int freq)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.freq.m = freq * 100000;
+ iwr.u.freq.e = 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+ perror("ioctl[SIOCSIWFREQ]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static void
+wpa_driver_nl80211_event_wireless_custom(void *ctx, char *custom)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
+ custom);
+
+ os_memset(&data, 0, sizeof(data));
+ /* Host AP driver */
+ if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ data.michael_mic_failure.unicast =
+ os_strstr(custom, " unicast ") != NULL;
+ /* TODO: parse parameters(?) */
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
+ char *spos;
+ int bytes;
+
+ spos = custom + 17;
+
+ bytes = strspn(spos, "0123456789abcdefABCDEF");
+ if (!bytes || (bytes & 1))
+ return;
+ bytes /= 2;
+
+ data.assoc_info.req_ies = os_malloc(bytes);
+ if (data.assoc_info.req_ies == NULL)
+ return;
+
+ data.assoc_info.req_ies_len = bytes;
+ hexstr2bin(spos, data.assoc_info.req_ies, bytes);
+
+ spos += bytes * 2;
+
+ data.assoc_info.resp_ies = NULL;
+ data.assoc_info.resp_ies_len = 0;
+
+ if (os_strncmp(spos, " RespIEs=", 9) == 0) {
+ spos += 9;
+
+ bytes = strspn(spos, "0123456789abcdefABCDEF");
+ if (!bytes || (bytes & 1))
+ goto done;
+ bytes /= 2;
+
+ data.assoc_info.resp_ies = os_malloc(bytes);
+ if (data.assoc_info.resp_ies == NULL)
+ goto done;
+
+ data.assoc_info.resp_ies_len = bytes;
+ hexstr2bin(spos, data.assoc_info.resp_ies, bytes);
+ }
+
+ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
+
+ done:
+ os_free(data.assoc_info.resp_ies);
+ os_free(data.assoc_info.req_ies);
+#ifdef CONFIG_PEERKEY
+ } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
+ if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
+ wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
+ "STKSTART.request '%s'", custom + 17);
+ return;
+ }
+ wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
+#endif /* CONFIG_PEERKEY */
+ }
+}
+
+
+static int wpa_driver_nl80211_event_wireless_michaelmicfailure(
+ void *ctx, const char *ev, size_t len)
+{
+ const struct iw_michaelmicfailure *mic;
+ union wpa_event_data data;
+
+ if (len < sizeof(*mic))
+ return -1;
+
+ mic = (const struct iw_michaelmicfailure *) ev;
+
+ wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
+ "flags=0x%x src_addr=" MACSTR, mic->flags,
+ MAC2STR(mic->src_addr.sa_data));
+
+ os_memset(&data, 0, sizeof(data));
+ data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_event_wireless_pmkidcand(
+ struct wpa_driver_nl80211_data *drv, const char *ev, size_t len)
+{
+ const struct iw_pmkid_cand *cand;
+ union wpa_event_data data;
+ const u8 *addr;
+
+ if (len < sizeof(*cand))
+ return -1;
+
+ cand = (const struct iw_pmkid_cand *) ev;
+ addr = (const u8 *) cand->bssid.sa_data;
+
+ wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
+ "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
+ cand->index, MAC2STR(addr));
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
+ data.pmkid_candidate.index = cand->index;
+ data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_event_wireless_assocreqie(
+ struct wpa_driver_nl80211_data *drv, const char *ev, int len)
+{
+ if (len < 0)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
+ len);
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = os_malloc(len);
+ if (drv->assoc_req_ies == NULL) {
+ drv->assoc_req_ies_len = 0;
+ return -1;
+ }
+ os_memcpy(drv->assoc_req_ies, ev, len);
+ drv->assoc_req_ies_len = len;
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_event_wireless_assocrespie(
+ struct wpa_driver_nl80211_data *drv, const char *ev, int len)
+{
+ if (len < 0)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
+ len);
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = os_malloc(len);
+ if (drv->assoc_resp_ies == NULL) {
+ drv->assoc_resp_ies_len = 0;
+ return -1;
+ }
+ os_memcpy(drv->assoc_resp_ies, ev, len);
+ drv->assoc_resp_ies_len = len;
+
+ return 0;
+}
+
+
+static void wpa_driver_nl80211_event_assoc_ies(struct wpa_driver_nl80211_data *drv)
+{
+ union wpa_event_data data;
+
+ if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ if (drv->assoc_req_ies) {
+ data.assoc_info.req_ies = drv->assoc_req_ies;
+ drv->assoc_req_ies = NULL;
+ data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
+ }
+ if (drv->assoc_resp_ies) {
+ data.assoc_info.resp_ies = drv->assoc_resp_ies;
+ drv->assoc_resp_ies = NULL;
+ data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
+
+ os_free(data.assoc_info.req_ies);
+ os_free(data.assoc_info.resp_ies);
+}
+
+
+static void wpa_driver_nl80211_event_wireless(struct wpa_driver_nl80211_data *drv,
+ void *ctx, char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (drv->we_version_compiled > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ iwe->cmd == IWEVCUSTOM ||
+ iwe->cmd == IWEVASSOCREQIE ||
+ iwe->cmd == IWEVASSOCRESPIE ||
+ iwe->cmd == IWEVPMKIDCAND)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case SIOCGIWAP:
+ wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
+ MACSTR,
+ MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
+ if (is_zero_ether_addr(
+ (const u8 *) iwe->u.ap_addr.sa_data) ||
+ os_memcmp(iwe->u.ap_addr.sa_data,
+ "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
+ 0) {
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
+ wpa_supplicant_event(ctx, EVENT_DISASSOC,
+ NULL);
+
+ } else {
+ wpa_driver_nl80211_event_assoc_ies(drv);
+ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ }
+ break;
+ case IWEVMICHAELMICFAILURE:
+ wpa_driver_nl80211_event_wireless_michaelmicfailure(
+ ctx, custom, iwe->u.data.length);
+ break;
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = os_malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return;
+ os_memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ wpa_driver_nl80211_event_wireless_custom(ctx, buf);
+ os_free(buf);
+ break;
+ case SIOCGIWSCAN:
+ drv->scan_complete_events = 1;
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
+ drv, ctx);
+ wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
+ break;
+ case IWEVASSOCREQIE:
+ wpa_driver_nl80211_event_wireless_assocreqie(
+ drv, custom, iwe->u.data.length);
+ break;
+ case IWEVASSOCRESPIE:
+ wpa_driver_nl80211_event_wireless_assocrespie(
+ drv, custom, iwe->u.data.length);
+ break;
+ case IWEVPMKIDCAND:
+ wpa_driver_nl80211_event_wireless_pmkidcand(
+ drv, custom, iwe->u.data.length);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void wpa_driver_nl80211_event_link(void *ctx, char *buf, size_t len,
+ int del)
+{
+ union wpa_event_data event;
+
+ os_memset(&event, 0, sizeof(event));
+ if (len > sizeof(event.interface_status.ifname))
+ len = sizeof(event.interface_status.ifname) - 1;
+ os_memcpy(event.interface_status.ifname, buf, len);
+ event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
+ EVENT_INTERFACE_ADDED;
+
+ wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
+ del ? "DEL" : "NEW",
+ event.interface_status.ifname,
+ del ? "removed" : "added");
+
+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
+static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data *drv,
+ void *ctx, struct nlmsghdr *h,
+ size_t len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, _nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ if (drv->ifindex != ifi->ifi_index) {
+ wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
+ ifi->ifi_index);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
+ "(%s%s%s%s)",
+ drv->operstate, ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+ /*
+ * Some drivers send the association event before the operup event--in
+ * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
+ * fails. This will hit us when wpa_supplicant does not need to do
+ * IEEE 802.1X authentication
+ */
+ if (drv->operstate == 1 &&
+ (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
+ !(ifi->ifi_flags & IFF_RUNNING))
+ wpa_driver_nl80211_send_oper_ifla(drv, -1, IF_OPER_UP);
+
+ _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - _nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ wpa_driver_nl80211_event_wireless(
+ drv, ctx, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ } else if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_nl80211_event_link(ctx,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 0);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void wpa_driver_nl80211_event_rtm_dellink(struct wpa_driver_nl80211_data *drv,
+ void *ctx, struct nlmsghdr *h,
+ size_t len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, _nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - _nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_nl80211_event_link(ctx,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 1);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ char buf[8192];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ int max_events = 10;
+
+try_again:
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (left >= (int) sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ wpa_printf(MSG_DEBUG, "Malformed netlink message: "
+ "len=%d left=%d plen=%d",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ wpa_driver_nl80211_event_rtm_newlink(eloop_ctx, sock_ctx,
+ h, plen);
+ break;
+ case RTM_DELLINK:
+ wpa_driver_nl80211_event_rtm_dellink(eloop_ctx, sock_ctx,
+ h, plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
+ "message", left);
+ }
+
+ if (--max_events > 0) {
+ /*
+ * Try to receive all events in one eloop call in order to
+ * limit race condition on cases where AssocInfo event, Assoc
+ * event, and EAPOL frames are received more or less at the
+ * same time. We want to process the event messages first
+ * before starting EAPOL processing.
+ */
+ goto try_again;
+ }
+}
+
+
+static int wpa_driver_nl80211_get_ifflags_ifname(struct wpa_driver_nl80211_data *drv,
+ const char *ifname, int *flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+ *flags = ifr.ifr_flags & 0xffff;
+ return 0;
+}
+
+
+/**
+ * wpa_driver_nl80211_get_ifflags - Get interface flags (SIOCGIFFLAGS)
+ * @drv: driver_nl80211 private data
+ * @flags: Pointer to returned flags value
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_get_ifflags(struct wpa_driver_nl80211_data *drv,
+ int *flags)
+{
+ return wpa_driver_nl80211_get_ifflags_ifname(drv, drv->ifname, flags);
+}
+
+
+static int wpa_driver_nl80211_set_ifflags_ifname(
+ struct wpa_driver_nl80211_data *drv,
+ const char *ifname, int flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("SIOCSIFFLAGS");
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * wpa_driver_nl80211_set_ifflags - Set interface flags (SIOCSIFFLAGS)
+ * @drv: driver_nl80211 private data
+ * @flags: New value for flags
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_set_ifflags(struct wpa_driver_nl80211_data *drv,
+ int flags)
+{
+ return wpa_driver_nl80211_set_ifflags_ifname(drv, drv->ifname, flags);
+}
+
+
+/**
+ * wpa_driver_nl80211_init - Initialize WE driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * Returns: Pointer to private data, %NULL on failure
+ */
+void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
+{
+ int s, flags;
+ struct sockaddr_nl local;
+ struct wpa_driver_nl80211_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+ drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (drv->nl_cb == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+ "callbacks");
+ goto err1;
+ }
+
+ drv->nl_handle = nl_handle_alloc_cb(drv->nl_cb);
+ if (drv->nl_handle == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+ "callbacks");
+ goto err2;
+ }
+
+ if (genl_connect(drv->nl_handle)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
+ "netlink");
+ goto err3;
+ }
+
+ drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
+ if (drv->nl_cache == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+ "netlink cache");
+ goto err3;
+ }
+
+ drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
+ if (drv->nl80211 == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
+ "found");
+ goto err4;
+ }
+
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket(PF_INET,SOCK_DGRAM)");
+ goto err5;
+ }
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ goto err6;
+ }
+
+ os_memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ goto err6;
+ }
+
+ eloop_register_read_sock(s, wpa_driver_nl80211_event_receive, drv,
+ ctx);
+ drv->event_sock = s;
+
+ if (wpa_driver_nl80211_get_ifflags(drv, &flags) != 0)
+ printf("Could not get interface '%s' flags\n", drv->ifname);
+ else if (!(flags & IFF_UP)) {
+ if (wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP) != 0) {
+ printf("Could not set interface '%s' UP\n",
+ drv->ifname);
+ } else {
+ /*
+ * Wait some time to allow driver to initialize before
+ * starting configuring the driver. This seems to be
+ * needed at least some drivers that load firmware etc.
+ * when the interface is set up.
+ */
+ wpa_printf(MSG_DEBUG, "Interface %s set UP - waiting "
+ "a second for the driver to complete "
+ "initialization", drv->ifname);
+ sleep(1);
+ }
+ }
+
+ /*
+ * Make sure that the driver does not have any obsolete PMKID entries.
+ */
+ wpa_driver_nl80211_flush_pmkid(drv);
+
+ if (wpa_driver_nl80211_set_mode(drv, 0) < 0) {
+ printf("Could not configure driver to use managed mode\n");
+ }
+
+ wpa_driver_nl80211_get_range(drv);
+
+ drv->ifindex = if_nametoindex(drv->ifname);
+
+ wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
+
+ return drv;
+
+err6:
+ close(drv->ioctl_sock);
+err5:
+ genl_family_put(drv->nl80211);
+err4:
+ nl_cache_free(drv->nl_cache);
+err3:
+ nl_handle_destroy(drv->nl_handle);
+err2:
+ nl_cb_put(drv->nl_cb);
+err1:
+ os_free(drv);
+ return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_deinit - Deinitialize WE driver interface
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ *
+ * Shut down driver interface and processing of driver events. Free
+ * private data buffer if one was allocated in wpa_driver_nl80211_init().
+ */
+void wpa_driver_nl80211_deinit(void *priv)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int flags;
+
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+
+ /*
+ * Clear possibly configured driver parameters in order to make it
+ * easier to use the driver after wpa_supplicant has been terminated.
+ */
+ (void) wpa_driver_nl80211_set_bssid(drv,
+ (u8 *) "\x00\x00\x00\x00\x00\x00");
+
+ wpa_driver_nl80211_send_oper_ifla(priv, 0, IF_OPER_UP);
+
+ eloop_unregister_read_sock(drv->event_sock);
+
+ if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0)
+ (void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
+
+ close(drv->event_sock);
+ close(drv->ioctl_sock);
+ os_free(drv->assoc_req_ies);
+ os_free(drv->assoc_resp_ies);
+
+ genl_family_put(drv->nl80211);
+ nl_cache_free(drv->nl_cache);
+ nl_handle_destroy(drv->nl_handle);
+ nl_cb_put(drv->nl_cb);
+
+ os_free(drv);
+}
+
+
+/**
+ * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
+ * @eloop_ctx: Unused
+ * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
+ *
+ * This function can be used as registered timeout when starting a scan to
+ * generate a scan completed event if the driver does not report this.
+ */
+static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+/**
+ * wpa_driver_nl80211_scan - Request the driver to initiate scan
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * @ssid: Specific SSID to scan for (ProbeReq) or %NULL to scan for
+ * all SSIDs (either active scan with broadcast SSID or passive
+ * scan
+ * @ssid_len: Length of the SSID
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0, timeout;
+ struct iw_scan_req req;
+
+ if (ssid_len > IW_ESSID_MAX_SIZE) {
+ wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
+ __FUNCTION__, (unsigned long) ssid_len);
+ return -1;
+ }
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ssid && ssid_len) {
+ os_memset(&req, 0, sizeof(req));
+ req.essid_len = ssid_len;
+ req.bssid.sa_family = ARPHRD_ETHER;
+ os_memset(req.bssid.sa_data, 0xff, ETH_ALEN);
+ os_memcpy(req.essid, ssid, ssid_len);
+ iwr.u.data.pointer = (caddr_t) &req;
+ iwr.u.data.length = sizeof(req);
+ iwr.u.data.flags = IW_SCAN_THIS_ESSID;
+ }
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
+ perror("ioctl[SIOCSIWSCAN]");
+ ret = -1;
+ }
+
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ timeout = 5;
+ if (drv->scan_complete_events) {
+ /*
+ * The driver seems to deliver SIOCGIWSCAN events to notify
+ * when scan is complete, so use longer timeout to avoid race
+ * conditions with scanning and following association request.
+ */
+ timeout = 30;
+ }
+ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
+ "seconds", ret, timeout);
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+
+ return ret;
+}
+
+
+static u8 * wpa_driver_nl80211_giwscan(struct wpa_driver_nl80211_data *drv,
+ size_t *len)
+{
+ struct iwreq iwr;
+ u8 *res_buf;
+ size_t res_buf_len;
+
+ res_buf_len = IW_SCAN_MAX_DATA;
+ for (;;) {
+ res_buf = os_malloc(res_buf_len);
+ if (res_buf == NULL)
+ return NULL;
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = res_buf;
+ iwr.u.data.length = res_buf_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
+ break;
+
+ if (errno == E2BIG && res_buf_len < 100000) {
+ os_free(res_buf);
+ res_buf = NULL;
+ res_buf_len *= 2;
+ wpa_printf(MSG_DEBUG, "Scan results did not fit - "
+ "trying larger buffer (%lu bytes)",
+ (unsigned long) res_buf_len);
+ } else {
+ perror("ioctl[SIOCGIWSCAN]");
+ os_free(res_buf);
+ return NULL;
+ }
+ }
+
+ if (iwr.u.data.length > res_buf_len) {
+ os_free(res_buf);
+ return NULL;
+ }
+ *len = iwr.u.data.length;
+
+ return res_buf;
+}
+
+
+/*
+ * Data structure for collecting WEXT scan results. This is needed to allow
+ * the various methods of reporting IEs to be combined into a single IE buffer.
+ */
+struct wext_scan_data {
+ struct wpa_scan_res res;
+ u8 *ie;
+ size_t ie_len;
+ u8 ssid[32];
+ size_t ssid_len;
+ int maxrate;
+};
+
+
+static void wext_get_scan_mode(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ if (iwe->u.mode == IW_MODE_ADHOC)
+ res->res.caps |= IEEE80211_CAP_IBSS;
+ else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA)
+ res->res.caps |= IEEE80211_CAP_ESS;
+}
+
+
+static void wext_get_scan_ssid(struct iw_event *iwe,
+ struct wext_scan_data *res, char *custom,
+ char *end)
+{
+ int ssid_len = iwe->u.essid.length;
+ if (custom + ssid_len > end)
+ return;
+ if (iwe->u.essid.flags &&
+ ssid_len > 0 &&
+ ssid_len <= IW_ESSID_MAX_SIZE) {
+ os_memcpy(res->ssid, custom, ssid_len);
+ res->ssid_len = ssid_len;
+ }
+}
+
+
+static void wext_get_scan_freq(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ int divi = 1000000, i;
+
+ if (iwe->u.freq.e == 0) {
+ /*
+ * Some drivers do not report frequency, but a channel.
+ * Try to map this to frequency by assuming they are using
+ * IEEE 802.11b/g. But don't overwrite a previously parsed
+ * frequency if the driver sends both frequency and channel,
+ * since the driver may be sending an A-band channel that we
+ * don't handle here.
+ */
+
+ if (res->res.freq)
+ return;
+
+ if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
+ res->res.freq = 2407 + 5 * iwe->u.freq.m;
+ return;
+ } else if (iwe->u.freq.m == 14) {
+ res->res.freq = 2484;
+ return;
+ }
+ }
+
+ if (iwe->u.freq.e > 6) {
+ wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID="
+ MACSTR " m=%d e=%d)",
+ MAC2STR(res->res.bssid), iwe->u.freq.m,
+ iwe->u.freq.e);
+ return;
+ }
+
+ for (i = 0; i < iwe->u.freq.e; i++)
+ divi /= 10;
+ res->res.freq = iwe->u.freq.m / divi;
+}
+
+
+static void wext_get_scan_qual(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ res->res.qual = iwe->u.qual.qual;
+ res->res.noise = iwe->u.qual.noise;
+ res->res.level = iwe->u.qual.level;
+}
+
+
+static void wext_get_scan_encode(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ if (!(iwe->u.data.flags & IW_ENCODE_DISABLED))
+ res->res.caps |= IEEE80211_CAP_PRIVACY;
+}
+
+
+static void wext_get_scan_rate(struct iw_event *iwe,
+ struct wext_scan_data *res, char *pos,
+ char *end)
+{
+ int maxrate;
+ char *custom = pos + IW_EV_LCP_LEN;
+ struct iw_param p;
+ size_t clen;
+
+ clen = iwe->len;
+ if (custom + clen > end)
+ return;
+ maxrate = 0;
+ while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) {
+ /* Note: may be misaligned, make a local, aligned copy */
+ os_memcpy(&p, custom, sizeof(struct iw_param));
+ if (p.value > maxrate)
+ maxrate = p.value;
+ clen -= sizeof(struct iw_param);
+ custom += sizeof(struct iw_param);
+ }
+ res->maxrate = maxrate;
+}
+
+
+static void wext_get_scan_iwevgenie(struct iw_event *iwe,
+ struct wext_scan_data *res, char *custom,
+ char *end)
+{
+ char *genie, *gpos, *gend;
+ u8 *tmp;
+
+ gpos = genie = custom;
+ gend = genie + iwe->u.data.length;
+ if (gend > end) {
+ wpa_printf(MSG_INFO, "IWEVGENIE overflow");
+ return;
+ }
+
+ tmp = os_realloc(res->ie, res->ie_len + gend - gpos);
+ if (tmp == NULL)
+ return;
+ os_memcpy(tmp + res->ie_len, gpos, gend - gpos);
+ res->ie = tmp;
+ res->ie_len += gend - gpos;
+}
+
+
+static void wext_get_scan_custom(struct iw_event *iwe,
+ struct wext_scan_data *res, char *custom,
+ char *end)
+{
+ size_t clen;
+ u8 *tmp;
+
+ clen = iwe->u.data.length;
+ if (custom + clen > end)
+ return;
+
+ if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) {
+ char *spos;
+ int bytes;
+ spos = custom + 7;
+ bytes = custom + clen - spos;
+ if (bytes & 1)
+ return;
+ bytes /= 2;
+ tmp = os_realloc(res->ie, res->ie_len + bytes);
+ if (tmp == NULL)
+ return;
+ hexstr2bin(spos, tmp + res->ie_len, bytes);
+ res->ie = tmp;
+ res->ie_len += bytes;
+ } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) {
+ char *spos;
+ int bytes;
+ spos = custom + 7;
+ bytes = custom + clen - spos;
+ if (bytes & 1)
+ return;
+ bytes /= 2;
+ tmp = os_realloc(res->ie, res->ie_len + bytes);
+ if (tmp == NULL)
+ return;
+ hexstr2bin(spos, tmp + res->ie_len, bytes);
+ res->ie = tmp;
+ res->ie_len += bytes;
+ } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) {
+ char *spos;
+ int bytes;
+ u8 bin[8];
+ spos = custom + 4;
+ bytes = custom + clen - spos;
+ if (bytes != 16) {
+ wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes);
+ return;
+ }
+ bytes /= 2;
+ hexstr2bin(spos, bin, bytes);
+ res->res.tsf += WPA_GET_BE64(bin);
+ }
+}
+
+
+static int wext_19_iw_point(struct wpa_driver_nl80211_data *drv, u16 cmd)
+{
+ return drv->we_version_compiled > 18 &&
+ (cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE ||
+ cmd == IWEVGENIE || cmd == IWEVCUSTOM);
+}
+
+
+static void wpa_driver_nl80211_add_scan_entry(struct wpa_scan_results *res,
+ struct wext_scan_data *data)
+{
+ struct wpa_scan_res **tmp;
+ struct wpa_scan_res *r;
+ size_t extra_len;
+ u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL;
+
+ /* Figure out whether we need to fake any IEs */
+ pos = data->ie;
+ end = pos + data->ie_len;
+ while (pos && pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_SSID)
+ ssid_ie = pos;
+ else if (pos[0] == WLAN_EID_SUPP_RATES)
+ rate_ie = pos;
+ else if (pos[0] == WLAN_EID_EXT_SUPP_RATES)
+ rate_ie = pos;
+ pos += 2 + pos[1];
+ }
+
+ extra_len = 0;
+ if (ssid_ie == NULL)
+ extra_len += 2 + data->ssid_len;
+ if (rate_ie == NULL && data->maxrate)
+ extra_len += 3;
+
+ r = os_zalloc(sizeof(*r) + extra_len + data->ie_len);
+ if (r == NULL)
+ return;
+ os_memcpy(r, &data->res, sizeof(*r));
+ r->ie_len = extra_len + data->ie_len;
+ pos = (u8 *) (r + 1);
+ if (ssid_ie == NULL) {
+ /*
+ * Generate a fake SSID IE since the driver did not report
+ * a full IE list.
+ */
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = data->ssid_len;
+ os_memcpy(pos, data->ssid, data->ssid_len);
+ pos += data->ssid_len;
+ }
+ if (rate_ie == NULL && data->maxrate) {
+ /*
+ * Generate a fake Supported Rates IE since the driver did not
+ * report a full IE list.
+ */
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = 1;
+ *pos++ = data->maxrate;
+ }
+ if (data->ie)
+ os_memcpy(pos, data->ie, data->ie_len);
+
+ tmp = os_realloc(res->res,
+ (res->num + 1) * sizeof(struct wpa_scan_res *));
+ if (tmp == NULL) {
+ os_free(r);
+ return;
+ }
+ tmp[res->num++] = r;
+ res->res = tmp;
+}
+
+
+/**
+ * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * Returns: Scan results on success, -1 on failure
+ */
+struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ size_t ap_num = 0, len;
+ int first;
+ u8 *res_buf;
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom;
+ struct wpa_scan_results *res;
+ struct wext_scan_data data;
+
+ res_buf = wpa_driver_nl80211_giwscan(drv, &len);
+ if (res_buf == NULL)
+ return NULL;
+
+ ap_num = 0;
+ first = 1;
+
+ res = os_zalloc(sizeof(*res));
+ if (res == NULL) {
+ os_free(res_buf);
+ return NULL;
+ }
+
+ pos = (char *) res_buf;
+ end = (char *) res_buf + len;
+ os_memset(&data, 0, sizeof(data));
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ break;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (wext_19_iw_point(drv, iwe->cmd)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case SIOCGIWAP:
+ if (!first)
+ wpa_driver_nl80211_add_scan_entry(res, &data);
+ first = 0;
+ os_free(data.ie);
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.res.bssid,
+ iwe->u.ap_addr.sa_data, ETH_ALEN);
+ break;
+ case SIOCGIWMODE:
+ wext_get_scan_mode(iwe, &data);
+ break;
+ case SIOCGIWESSID:
+ wext_get_scan_ssid(iwe, &data, custom, end);
+ break;
+ case SIOCGIWFREQ:
+ wext_get_scan_freq(iwe, &data);
+ break;
+ case IWEVQUAL:
+ wext_get_scan_qual(iwe, &data);
+ break;
+ case SIOCGIWENCODE:
+ wext_get_scan_encode(iwe, &data);
+ break;
+ case SIOCGIWRATE:
+ wext_get_scan_rate(iwe, &data, pos, end);
+ break;
+ case IWEVGENIE:
+ wext_get_scan_iwevgenie(iwe, &data, custom, end);
+ break;
+ case IWEVCUSTOM:
+ wext_get_scan_custom(iwe, &data, custom, end);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+ os_free(res_buf);
+ res_buf = NULL;
+ if (!first)
+ wpa_driver_nl80211_add_scan_entry(res, &data);
+ os_free(data.ie);
+
+ wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)",
+ (unsigned long) len, (unsigned long) res->num);
+
+ return res;
+}
+
+
+static int wpa_driver_nl80211_get_range(void *priv)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ os_free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->has_capability = 1;
+ drv->we_version_compiled = range->we_version_compiled;
+ if (range->enc_capa & IW_ENC_CAPA_WPA) {
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
+ }
+ if (range->enc_capa & IW_ENC_CAPA_WPA2) {
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ }
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
+ WPA_DRIVER_CAPA_ENC_WEP104;
+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+ wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x",
+ drv->capa.key_mgmt, drv->capa.enc);
+ } else {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
+ "assuming WPA is not supported");
+ }
+
+ os_free(range);
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_WPA_ENABLED,
+ enabled);
+}
+
+
+static int wpa_driver_nl80211_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_nl80211_data *drv = priv;
+ int ret = -1, err;
+ struct nl_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
+ "seq_len=%lu key_len=%lu",
+ __func__, alg, addr, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ msg = nlmsg_alloc();
+ if (msg == NULL)
+ return -1;
+
+ if (alg == WPA_ALG_NONE) {
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_DEL_KEY, 0);
+ } else {
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_NEW_KEY, 0);
+ NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
+ switch (alg) {
+ case WPA_ALG_WEP:
+ if (key_len == 5)
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ 0x000FAC01);
+ else
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ 0x000FAC05);
+ break;
+ case WPA_ALG_TKIP:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02);
+ break;
+ case WPA_ALG_CCMP:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);
+ break;
+ default:
+ nlmsg_free(msg);
+ return -1;
+ }
+ }
+
+ if (addr && os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
+ {
+ wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ }
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ err = 0;
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ (err = nl_wait_for_ack(drv->nl_handle)) < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d", err);
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ if (set_tx && alg != WPA_ALG_NONE) {
+ nlmsg_free(msg);
+ msg = nlmsg_alloc();
+ if (msg == NULL)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_KEY, 0);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+
+ err = 0;
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ (err = nl_wait_for_ack(drv->nl_handle)) < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: set default key "
+ "failed; err=%d", err);
+ nlmsg_free(msg);
+ return -1;
+ }
+ }
+
+ ret = 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_countermeasures(void *priv,
+ int enabled)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_TKIP_COUNTERMEASURES,
+ enabled);
+}
+
+
+static int wpa_driver_nl80211_set_drop_unencrypted(void *priv,
+ int enabled)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ drv->use_crypt = enabled;
+ return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
+ enabled);
+}
+
+
+static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr, int cmd, int reason_code)
+{
+ struct iwreq iwr;
+ struct iw_mlme mlme;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.cmd = cmd;
+ mlme.reason_code = reason_code;
+ mlme.addr.sa_family = ARPHRD_ETHER;
+ os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
+ iwr.u.data.pointer = (caddr_t) &mlme;
+ iwr.u.data.length = sizeof(mlme);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
+ perror("ioctl[SIOCSIWMLME]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_nl80211_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+}
+
+
+static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_nl80211_mlme(drv, addr, IW_MLME_DISASSOC,
+ reason_code);
+}
+
+
+static int wpa_driver_nl80211_set_gen_ie(void *priv, const u8 *ie,
+ size_t ie_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) ie;
+ iwr.u.data.length = ie_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWGENIE]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_cipher2wext(int cipher)
+{
+ switch (cipher) {
+ case CIPHER_NONE:
+ return IW_AUTH_CIPHER_NONE;
+ case CIPHER_WEP40:
+ return IW_AUTH_CIPHER_WEP40;
+ case CIPHER_TKIP:
+ return IW_AUTH_CIPHER_TKIP;
+ case CIPHER_CCMP:
+ return IW_AUTH_CIPHER_CCMP;
+ case CIPHER_WEP104:
+ return IW_AUTH_CIPHER_WEP104;
+ default:
+ return 0;
+ }
+}
+
+
+static int wpa_driver_nl80211_keymgmt2wext(int keymgmt)
+{
+ switch (keymgmt) {
+ case KEY_MGMT_802_1X:
+ case KEY_MGMT_802_1X_NO_WPA:
+ return IW_AUTH_KEY_MGMT_802_1X;
+ case KEY_MGMT_PSK:
+ return IW_AUTH_KEY_MGMT_PSK;
+ default:
+ return 0;
+ }
+}
+
+
+static int
+wpa_driver_nl80211_auth_alg_fallback(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
+ "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* Just changing mode, not actual keys */
+ iwr.u.encoding.flags = 0;
+ iwr.u.encoding.pointer = (caddr_t) NULL;
+ iwr.u.encoding.length = 0;
+
+ /*
+ * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
+ * different things. Here they are used to indicate Open System vs.
+ * Shared Key authentication algorithm. However, some drivers may use
+ * them to select between open/restricted WEP encrypted (open = allow
+ * both unencrypted and encrypted frames; restricted = only allow
+ * encrypted frames).
+ */
+
+ if (!drv->use_crypt) {
+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+ } else {
+ if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ iwr.u.encoding.flags |= IW_ENCODE_OPEN;
+ if (params->auth_alg & AUTH_ALG_SHARED_KEY)
+ iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
+ }
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWENCODE]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_associate(
+ void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int ret = 0;
+ int allow_unencrypted_eapol;
+ int value;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ /*
+ * If the driver did not support SIOCSIWAUTH, fallback to
+ * SIOCSIWENCODE here.
+ */
+ if (drv->auth_alg_fallback &&
+ wpa_driver_nl80211_auth_alg_fallback(drv, params) < 0)
+ ret = -1;
+
+ if (!params->bssid &&
+ wpa_driver_nl80211_set_bssid(drv, NULL) < 0)
+ ret = -1;
+
+ if (wpa_driver_nl80211_set_mode(drv, params->mode) < 0)
+ ret = -1;
+ /* TODO: should consider getting wpa version and cipher/key_mgmt suites
+ * from configuration, not from here, where only the selected suite is
+ * available */
+ if (wpa_driver_nl80211_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
+ < 0)
+ ret = -1;
+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
+ value = IW_AUTH_WPA_VERSION_DISABLED;
+ else if (params->wpa_ie[0] == WLAN_EID_RSN)
+ value = IW_AUTH_WPA_VERSION_WPA2;
+ else
+ value = IW_AUTH_WPA_VERSION_WPA;
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_WPA_VERSION, value) < 0)
+ ret = -1;
+ value = wpa_driver_nl80211_cipher2wext(params->pairwise_suite);
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_CIPHER_PAIRWISE, value) < 0)
+ ret = -1;
+ value = wpa_driver_nl80211_cipher2wext(params->group_suite);
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_CIPHER_GROUP, value) < 0)
+ ret = -1;
+ value = wpa_driver_nl80211_keymgmt2wext(params->key_mgmt_suite);
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_KEY_MGMT, value) < 0)
+ ret = -1;
+ value = params->key_mgmt_suite != KEY_MGMT_NONE ||
+ params->pairwise_suite != CIPHER_NONE ||
+ params->group_suite != CIPHER_NONE ||
+ params->wpa_ie_len;
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_PRIVACY_INVOKED, value) < 0)
+ ret = -1;
+
+ /* Allow unencrypted EAPOL messages even if pairwise keys are set when
+ * not using WPA. IEEE 802.1X specifies that these frames are not
+ * encrypted, but WPA encrypts them when pairwise keys are in use. */
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_PSK)
+ allow_unencrypted_eapol = 0;
+ else
+ allow_unencrypted_eapol = 1;
+
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_RX_UNENCRYPTED_EAPOL,
+ allow_unencrypted_eapol) < 0)
+ ret = -1;
+ if (params->freq && wpa_driver_nl80211_set_freq(drv, params->freq) < 0)
+ ret = -1;
+ if (wpa_driver_nl80211_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+ ret = -1;
+ if (params->bssid &&
+ wpa_driver_nl80211_set_bssid(drv, params->bssid) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int algs = 0, res;
+
+ if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ algs |= IW_AUTH_ALG_OPEN_SYSTEM;
+ if (auth_alg & AUTH_ALG_SHARED_KEY)
+ algs |= IW_AUTH_ALG_SHARED_KEY;
+ if (auth_alg & AUTH_ALG_LEAP)
+ algs |= IW_AUTH_ALG_LEAP;
+ if (algs == 0) {
+ /* at least one algorithm should be set */
+ algs = IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+
+ res = wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
+ algs);
+ drv->auth_alg_fallback = res == -2;
+ return res;
+}
+
+
+/**
+ * wpa_driver_nl80211_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_set_mode(void *priv, int mode)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int ret = -1, flags;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP);
+
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0)
+ goto try_again;
+
+ nlmsg_free(msg);
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -1;
+
+try_again:
+ /* mac80211 doesn't allow mode changes while the device is up, so
+ * take the device down, try to set the mode again, and bring the
+ * device back up.
+ */
+ if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0) {
+ (void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
+
+ /* Try to set the mode again while the interface is down */
+ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+ nl_wait_for_ack(drv->nl_handle) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to set interface %s "
+ "mode", drv->ifname);
+ } else
+ ret = 0;
+
+ /* Ignore return value of get_ifflags to ensure that the device
+ * is always up like it was before this function was called.
+ */
+ (void) wpa_driver_nl80211_get_ifflags(drv, &flags);
+ (void) wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP);
+ }
+
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_pmksa(struct wpa_driver_nl80211_data *drv,
+ u32 cmd, const u8 *bssid, const u8 *pmkid)
+{
+ struct iwreq iwr;
+ struct iw_pmksa pmksa;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_memset(&pmksa, 0, sizeof(pmksa));
+ pmksa.cmd = cmd;
+ pmksa.bssid.sa_family = ARPHRD_ETHER;
+ if (bssid)
+ os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
+ if (pmkid)
+ os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
+ iwr.u.data.pointer = (caddr_t) &pmksa;
+ iwr.u.data.length = sizeof(pmksa);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
+ if (errno != EOPNOTSUPP)
+ perror("ioctl[SIOCSIWPMKSA]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_add_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
+}
+
+
+static int wpa_driver_nl80211_remove_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
+}
+
+
+static int wpa_driver_nl80211_flush_pmkid(void *priv)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
+}
+
+
+static int wpa_driver_nl80211_get_capa(void *priv,
+ struct wpa_driver_capa *capa)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ if (!drv->has_capability)
+ return -1;
+ os_memcpy(capa, &drv->capa, sizeof(*capa));
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
+ __func__, drv->operstate, state, state ? "UP" : "DORMANT");
+ drv->operstate = state;
+ return wpa_driver_nl80211_send_oper_ifla(
+ drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
+}
+
+
+const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+ .name = "nl80211",
+ .desc = "Linux nl80211/cfg80211",
+ .get_bssid = wpa_driver_nl80211_get_bssid,
+ .get_ssid = wpa_driver_nl80211_get_ssid,
+ .set_wpa = wpa_driver_nl80211_set_wpa,
+ .set_key = wpa_driver_nl80211_set_key,
+ .set_countermeasures = wpa_driver_nl80211_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_nl80211_set_drop_unencrypted,
+ .scan = wpa_driver_nl80211_scan,
+ .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
+ .deauthenticate = wpa_driver_nl80211_deauthenticate,
+ .disassociate = wpa_driver_nl80211_disassociate,
+ .associate = wpa_driver_nl80211_associate,
+ .set_auth_alg = wpa_driver_nl80211_set_auth_alg,
+ .init = wpa_driver_nl80211_init,
+ .deinit = wpa_driver_nl80211_deinit,
+ .add_pmkid = wpa_driver_nl80211_add_pmkid,
+ .remove_pmkid = wpa_driver_nl80211_remove_pmkid,
+ .flush_pmkid = wpa_driver_nl80211_flush_pmkid,
+ .get_capa = wpa_driver_nl80211_get_capa,
+ .set_operstate = wpa_driver_nl80211_set_operstate,
+};
Added: wpasupplicant/branches/upstream/current/src/drivers/driver_ps3.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_ps3.c?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_ps3.c (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_ps3.c Sat Jun 14 00:26:56 2008
@@ -1,0 +1,186 @@
+/*
+ * WPA Supplicant - PS3 Linux wireless extension driver interface
+ * Copyright 2007, 2008 Sony Corporation
+ *
+ * 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 <sys/ioctl.h>
+#include "wireless_copy.h"
+#include "common.h"
+#include "wpa_common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "driver_wext.h"
+#include "ieee802_11_defs.h"
+
+static int wpa_driver_ps3_set_wpa_key(struct wpa_driver_wext_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ int ret, i;
+ struct iwreq iwr;
+ char *buf, *str;
+
+ if (!params->psk && !params->passphrase) {
+ wpa_printf(MSG_INFO, "%s:no PSK error", __func__);
+ return -EINVAL;
+ }
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ if (params->psk) {
+ /* includes null */
+ iwr.u.data.length = PMK_LEN * 2 + 1;
+ buf = os_malloc(iwr.u.data.length);
+ if (!buf)
+ return -ENOMEM;
+ str = buf;
+ for (i = 0; i < PMK_LEN; i++) {
+ str += snprintf(str, iwr.u.data.length - (str - buf),
+ "%02x", params->psk[i]);
+ }
+ } else if (params->passphrase) {
+ /* including quotations and null */
+ iwr.u.data.length = strlen(params->passphrase) + 3;
+ buf = os_malloc(iwr.u.data.length);
+ if (!buf)
+ return -ENOMEM;
+ buf[0] = '"';
+ os_memcpy(buf + 1, params->passphrase, iwr.u.data.length - 3);
+ buf[iwr.u.data.length - 2] = '"';
+ buf[iwr.u.data.length - 1] = '\0';
+ } else
+ return -EINVAL;
+ iwr.u.data.pointer = (caddr_t) buf;
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ ret = ioctl(drv->ioctl_sock, SIOCIWFIRSTPRIV, &iwr);
+ os_free(buf);
+
+ return ret;
+}
+
+static int wpa_driver_ps3_set_wep_keys(struct wpa_driver_wext_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ int ret, i;
+ struct iwreq iwr;
+
+ for (i = 0; i < 4; i++) {
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.encoding.flags = i + 1;
+ if (params->wep_key_len[i]) {
+ iwr.u.encoding.pointer = (caddr_t) params->wep_key[i];
+ iwr.u.encoding.length = params->wep_key_len[i];
+ } else
+ iwr.u.encoding.flags = IW_ENCODE_NOKEY |
+ IW_ENCODE_DISABLED;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWENCODE]");
+ ret = -1;
+ }
+ }
+ return ret;
+}
+
+static int wpa_driver_ps3_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int ret, value;
+
+ wpa_printf(MSG_DEBUG, "%s: <-", __func__);
+
+ /* clear BSSID */
+ if (!params->bssid &&
+ wpa_driver_wext_set_bssid(drv, NULL) < 0)
+ ret = -1;
+
+ if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
+ ret = -1;
+
+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
+ value = IW_AUTH_WPA_VERSION_DISABLED;
+ else if (params->wpa_ie[0] == WLAN_EID_RSN)
+ value = IW_AUTH_WPA_VERSION_WPA2;
+ else
+ value = IW_AUTH_WPA_VERSION_WPA;
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_WPA_VERSION, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_CIPHER_PAIRWISE, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_cipher2wext(params->group_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_CIPHER_GROUP, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
+ if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_KEY_MGMT, value) < 0)
+ ret = -1;
+
+ /* set selected BSSID */
+ if (params->bssid &&
+ wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
+ ret = -1;
+
+ switch (params->group_suite) {
+ case CIPHER_NONE:
+ ret = 0;
+ break;
+ case CIPHER_WEP40:
+ case CIPHER_WEP104:
+ ret = wpa_driver_ps3_set_wep_keys(drv, params);
+ break;
+ case CIPHER_TKIP:
+ case CIPHER_CCMP:
+ ret = wpa_driver_ps3_set_wpa_key(drv, params);
+ break;
+ }
+
+ /* start to associate */
+ ret = wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len);
+
+ wpa_printf(MSG_DEBUG, "%s: ->", __func__);
+
+ return ret;
+}
+
+static int wpa_driver_ps3_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ int ret;
+ wpa_printf(MSG_DEBUG, "%s:<-", __func__);
+
+ ret = wpa_driver_wext_get_capa(priv, capa);
+ if (ret) {
+ wpa_printf(MSG_INFO, "%s: base wext returns error %d",
+ __func__, ret);
+ return ret;
+ }
+ /* PS3 hypervisor does association and 4way handshake by itself */
+ capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ wpa_printf(MSG_DEBUG, "%s:->", __func__);
+ return 0;
+}
+
+const struct wpa_driver_ops wpa_driver_ps3_ops = {
+ .name = "ps3",
+ .desc = "PLAYSTATION3 Linux wireless extension driver",
+ .get_bssid = wpa_driver_wext_get_bssid,
+ .get_ssid = wpa_driver_wext_get_ssid,
+ .scan = wpa_driver_wext_scan,
+ .get_scan_results2 = wpa_driver_wext_get_scan_results,
+ .associate = wpa_driver_ps3_associate, /* PS3 */
+ .init = wpa_driver_wext_init,
+ .deinit = wpa_driver_wext_deinit,
+ .get_capa = wpa_driver_ps3_get_capa, /* PS3 */
+};
Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_ralink.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_ralink.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_ralink.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_ralink.c Sat Jun 14 00:26:56 2008
@@ -57,7 +57,7 @@
if (buf == NULL)
return -1;
os_memset(&iwr, 0, sizeof(iwr));
- os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.data.flags = oid;
iwr.u.data.flags |= OID_GET_SET_TOGGLE;
@@ -84,7 +84,7 @@
UCHAR enabled = 0;
os_memset(&iwr, 0, sizeof(iwr));
- os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.data.pointer = (UCHAR*) &enabled;
iwr.u.data.flags = RT_OID_NEW_DRIVER;
@@ -108,7 +108,7 @@
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
os_memset(&iwr, 0, sizeof(iwr));
- os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
perror("ioctl[SIOCGIWAP]");
@@ -145,7 +145,7 @@
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
os_memset(&iwr, 0, sizeof(iwr));
- os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.essid.pointer = (caddr_t) ssid;
iwr.u.essid.length = 32;
@@ -236,7 +236,7 @@
buf->SsidLength = ssid_len;
os_memcpy(buf->Ssid, ssid, ssid_len);
os_memset(&iwr, 0, sizeof(iwr));
- os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.data.flags = OID_802_11_SSID;
iwr.u.data.flags |= OID_GET_SET_TOGGLE;
@@ -611,8 +611,10 @@
"receive ReqIEs !!!");
drv->assoc_req_ies =
os_malloc(iwe->u.data.length);
- if (drv->assoc_req_ies == NULL)
+ if (drv->assoc_req_ies == NULL) {
+ os_free(buf);
return;
+ }
drv->assoc_req_ies_len = iwe->u.data.length;
os_memcpy(drv->assoc_req_ies, custom,
@@ -625,6 +627,7 @@
if (drv->assoc_resp_ies == NULL) {
os_free(drv->assoc_req_ies);
drv->assoc_req_ies = NULL;
+ os_free(buf);
return;
}
@@ -637,7 +640,7 @@
"receive ASSOCINFO_EVENT !!!");
assoc_info_buf =
- os_malloc(drv->assoc_req_ies_len +
+ os_zalloc(drv->assoc_req_ies_len +
drv->assoc_resp_ies_len + 1);
if (assoc_info_buf == NULL) {
@@ -649,18 +652,26 @@
return;
}
- os_memcpy(assoc_info_buf, drv->assoc_req_ies,
- drv->assoc_req_ies_len);
+ if (drv->assoc_req_ies) {
+ os_memcpy(assoc_info_buf,
+ drv->assoc_req_ies,
+ drv->assoc_req_ies_len);
+ }
info_pos = assoc_info_buf +
drv->assoc_req_ies_len;
- os_memcpy(info_pos, drv->assoc_resp_ies,
- drv->assoc_resp_ies_len);
+ if (drv->assoc_resp_ies) {
+ os_memcpy(info_pos,
+ drv->assoc_resp_ies,
+ drv->assoc_resp_ies_len);
+ }
assoc_info_buf[drv->assoc_req_ies_len +
drv->assoc_resp_ies_len] = '\0';
wpa_driver_ralink_event_wireless_custom(
drv, ctx, assoc_info_buf);
os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
os_free(assoc_info_buf);
} else if (iwe->u.data.flags == RT_DISASSOC_EVENT_FLAG)
{
@@ -836,7 +847,7 @@
UINT we_version_compiled = 0;
os_memset(&iwr, 0, sizeof(iwr));
- os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.data.pointer = (caddr_t) &we_version_compiled;
iwr.u.data.flags = RT_OID_WE_VERSION_COMPILED;
@@ -898,7 +909,7 @@
return NULL;
}
/* do it */
- os_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
perror(ifr.ifr_name);
@@ -912,7 +923,7 @@
drv->scanning_done = 1;
drv->ap_scan = 1; /* for now - let's assume ap_scan=1 is used */
drv->ctx = ctx;
- os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
drv->ioctl_sock = s;
drv->g_driver_down = 0;
@@ -1034,7 +1045,7 @@
/* wpa_driver_ralink_set_ssid(drv, ssid, ssid_len); */
os_memset(&iwr, 0, sizeof(iwr));
- os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
perror("ioctl[SIOCSIWSCAN]");
@@ -1083,7 +1094,7 @@
wsr = (NDIS_802_11_BSSID_LIST_EX *) buf;
wsr->NumberOfItems = 0;
- os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.data.pointer = (void *) buf;
iwr.u.data.flags = OID_802_11_BSSID_LIST;
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c Sat Jun 14 00:26:56 2008
@@ -149,32 +149,6 @@
#endif /* CONFIG_CLIENT_MLME */
-struct wpa_driver_wext_data {
- void *ctx;
- int event_sock;
- int ioctl_sock;
- int mlme_sock;
- char ifname[IFNAMSIZ + 1];
- int ifindex;
- int ifindex2;
- u8 *assoc_req_ies;
- size_t assoc_req_ies_len;
- u8 *assoc_resp_ies;
- size_t assoc_resp_ies_len;
- struct wpa_driver_capa capa;
- int has_capability;
- int we_version_compiled;
-
- /* for set_auth_alg fallback */
- int use_crypt;
- int auth_alg_fallback;
-
- int operstate;
-
- char mlmedev[IFNAMSIZ + 1];
-
- int scan_complete_events;
-};
static int wpa_driver_wext_flush_pmkid(void *priv);
@@ -239,8 +213,8 @@
}
-static int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
- int idx, u32 value)
+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
+ int idx, u32 value)
{
struct iwreq iwr;
int ret = 0;
@@ -251,9 +225,11 @@
iwr.u.param.value = value;
if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
- perror("ioctl[SIOCSIWAUTH]");
- fprintf(stderr, "WEXT auth param %d value 0x%x - ",
- idx, value);
+ if (errno != EOPNOTSUPP) {
+ wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
+ "value 0x%x) failed: %s)",
+ idx, value, strerror(errno));
+ }
ret = errno == EOPNOTSUPP ? -2 : -1;
}
@@ -655,9 +631,8 @@
wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
MACSTR,
MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
- if (os_memcmp(iwe->u.ap_addr.sa_data,
- "\x00\x00\x00\x00\x00\x00", ETH_ALEN) ==
- 0 ||
+ if (is_zero_ether_addr(
+ (const u8 *) iwe->u.ap_addr.sa_data) ||
os_memcmp(iwe->u.ap_addr.sa_data,
"\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
0) {
@@ -760,7 +735,7 @@
(ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
(ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
(ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
- (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT" : "");
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
/*
* Some drivers send the association event before the operup event--in
* this case, lifting operstate in wpa_driver_wext_set_operstate()
@@ -1318,8 +1293,15 @@
/*
* Some drivers do not report frequency, but a channel.
* Try to map this to frequency by assuming they are using
- * IEEE 802.11b/g.
+ * IEEE 802.11b/g. But don't overwrite a previously parsed
+ * frequency if the driver sends both frequency and channel,
+ * since the driver may be sending an A-band channel that we
+ * don't handle here.
*/
+
+ if (res->res.freq)
+ return;
+
if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
res->res.freq = 2407 + 5 * iwe->u.freq.m;
return;
@@ -1975,7 +1957,7 @@
}
-static int wpa_driver_wext_cipher2wext(int cipher)
+int wpa_driver_wext_cipher2wext(int cipher)
{
switch (cipher) {
case CIPHER_NONE:
@@ -1994,7 +1976,7 @@
}
-static int wpa_driver_wext_keymgmt2wext(int keymgmt)
+int wpa_driver_wext_keymgmt2wext(int keymgmt)
{
switch (keymgmt) {
case KEY_MGMT_802_1X:
@@ -2052,9 +2034,8 @@
}
-static int
-wpa_driver_wext_associate(void *priv,
- struct wpa_driver_associate_params *params)
+int wpa_driver_wext_associate(void *priv,
+ struct wpa_driver_associate_params *params)
{
struct wpa_driver_wext_data *drv = priv;
int ret = 0;
@@ -2170,17 +2151,54 @@
{
struct wpa_driver_wext_data *drv = priv;
struct iwreq iwr;
- int ret = 0;
+ int ret = -1, flags;
+ unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
- iwr.u.mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
-
- if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
+ iwr.u.mode = new_mode;
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) {
+ ret = 0;
+ goto done;
+ }
+
+ if (errno != EBUSY) {
perror("ioctl[SIOCSIWMODE]");
- ret = -1;
- }
-
+ goto done;
+ }
+
+ /* mac80211 doesn't allow mode changes while the device is up, so if
+ * the device isn't in the mode we're about to change to, take device
+ * down, try to set the mode again, and bring it back up.
+ */
+ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWMODE]");
+ goto done;
+ }
+
+ if (iwr.u.mode == new_mode) {
+ ret = 0;
+ goto done;
+ }
+
+ if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) {
+ (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
+
+ /* Try to set the mode again while the interface is down */
+ iwr.u.mode = new_mode;
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
+ perror("ioctl[SIOCSIWMODE]");
+ else
+ ret = 0;
+
+ /* Ignore return value of get_ifflags to ensure that the device
+ * is always up like it was before this function was called.
+ */
+ (void) wpa_driver_wext_get_ifflags(drv, &flags);
+ (void) wpa_driver_wext_set_ifflags(drv, flags | IFF_UP);
+ }
+
+done:
return ret;
}
@@ -2237,7 +2255,7 @@
}
-static int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
{
struct wpa_driver_wext_data *drv = priv;
if (!drv->has_capability)
Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_wext.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_wext.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_wext.h (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_wext.h Sat Jun 14 00:26:56 2008
@@ -15,7 +15,34 @@
#ifndef DRIVER_WEXT_H
#define DRIVER_WEXT_H
-struct wpa_driver_wext_data;
+#include <net/if.h>
+
+struct wpa_driver_wext_data {
+ void *ctx;
+ int event_sock;
+ int ioctl_sock;
+ int mlme_sock;
+ char ifname[IFNAMSIZ + 1];
+ int ifindex;
+ int ifindex2;
+ u8 *assoc_req_ies;
+ size_t assoc_req_ies_len;
+ u8 *assoc_resp_ies;
+ size_t assoc_resp_ies_len;
+ struct wpa_driver_capa capa;
+ int has_capability;
+ int we_version_compiled;
+
+ /* for set_auth_alg fallback */
+ int use_crypt;
+ int auth_alg_fallback;
+
+ int operstate;
+
+ char mlmedev[IFNAMSIZ + 1];
+
+ int scan_complete_events;
+};
int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags);
int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags);
@@ -43,4 +70,12 @@
int wpa_driver_wext_set_operstate(void *priv, int state);
int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv);
+int wpa_driver_wext_associate(void *priv,
+ struct wpa_driver_associate_params *params);
+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa);
+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
+ int idx, u32 value);
+int wpa_driver_wext_cipher2wext(int cipher);
+int wpa_driver_wext_keymgmt2wext(int keymgmt);
+
#endif /* DRIVER_WEXT_H */
Modified: wpasupplicant/branches/upstream/current/src/drivers/drivers.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/drivers.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/drivers.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/drivers.c Sat Jun 14 00:26:56 2008
@@ -18,6 +18,9 @@
#ifdef CONFIG_DRIVER_WEXT
extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
#endif /* CONFIG_DRIVER_WEXT */
+#ifdef CONFIG_DRIVER_NL80211
+extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
+#endif /* CONFIG_DRIVER_NL80211 */
#ifdef CONFIG_DRIVER_HOSTAP
extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
#endif /* CONFIG_DRIVER_HOSTAP */
@@ -61,6 +64,9 @@
#ifdef CONFIG_DRIVER_OSX
extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */
#endif /* CONFIG_DRIVER_OSX */
+#ifdef CONFIG_DRIVER_PS3
+extern struct wpa_driver_ops wpa_driver_ps3_ops; /* driver_ps3.c */
+#endif /* CONFIG_DRIVER_PS3 */
#ifdef CONFIG_DRIVER_IPHONE
extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */
#endif /* CONFIG_DRIVER_IPHONE */
@@ -71,6 +77,9 @@
#ifdef CONFIG_DRIVER_WEXT
&wpa_driver_wext_ops,
#endif /* CONFIG_DRIVER_WEXT */
+#ifdef CONFIG_DRIVER_NL80211
+ &wpa_driver_nl80211_ops,
+#endif /* CONFIG_DRIVER_NL80211 */
#ifdef CONFIG_DRIVER_HOSTAP
&wpa_driver_hostap_ops,
#endif /* CONFIG_DRIVER_HOSTAP */
@@ -113,6 +122,9 @@
#ifdef CONFIG_DRIVER_OSX
&wpa_driver_osx_ops,
#endif /* CONFIG_DRIVER_OSX */
+#ifdef CONFIG_DRIVER_PS3
+ &wpa_driver_ps3_ops,
+#endif /* CONFIG_DRIVER_PS3 */
#ifdef CONFIG_DRIVER_IPHONE
&wpa_driver_iphone_ops,
#endif /* CONFIG_DRIVER_IPHONE */
Modified: wpasupplicant/branches/upstream/current/src/eap_common/eap_defs.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_defs.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_defs.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_defs.h Sat Jun 14 00:26:56 2008
@@ -75,6 +75,7 @@
/* SMI Network Management Private Enterprise Code for vendor specific types */
enum {
EAP_VENDOR_IETF = 0,
+ EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */,
EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */
};
Added: wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.c?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.c (added)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.c Sat Jun 14 00:26:56 2008
@@ -1,0 +1,304 @@
+/*
+ * EAP-FAST common helper functions (RFC 4851)
+ * Copyright (c) 2008, 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 "eap_defs.h"
+#include "eap_tlv_common.h"
+#include "eap_fast_common.h"
+
+
+void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
+{
+ struct pac_tlv_hdr hdr;
+ hdr.type = host_to_be16(type);
+ hdr.len = host_to_be16(len);
+ wpabuf_put_data(buf, &hdr, sizeof(hdr));
+}
+
+
+void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
+ u16 len)
+{
+ eap_fast_put_tlv_hdr(buf, type, len);
+ wpabuf_put_data(buf, data, len);
+}
+
+
+void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
+ const struct wpabuf *data)
+{
+ eap_fast_put_tlv_hdr(buf, type, wpabuf_len(data));
+ wpabuf_put_buf(buf, data);
+}
+
+
+struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf)
+{
+ struct wpabuf *e;
+
+ if (buf == NULL)
+ return NULL;
+
+ /* Encapsulate EAP packet in EAP-Payload TLV */
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV");
+ e = wpabuf_alloc(sizeof(struct pac_tlv_hdr) + wpabuf_len(buf));
+ if (e == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
+ "for TLV encapsulation");
+ wpabuf_free(buf);
+ return NULL;
+ }
+ eap_fast_put_tlv_buf(e,
+ EAP_TLV_TYPE_MANDATORY | EAP_TLV_EAP_PAYLOAD_TLV,
+ buf);
+ wpabuf_free(buf);
+ return e;
+}
+
+
+void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
+ const u8 *client_random, u8 *master_secret)
+{
+#define TLS_RANDOM_LEN 32
+#define TLS_MASTER_SECRET_LEN 48
+ u8 seed[2 * TLS_RANDOM_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);
+
+ /*
+ * 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);
+}
+
+
+u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
+ const char *label, size_t len)
+{
+ struct tls_keys keys;
+ u8 *rnd = NULL, *out;
+ int block_size;
+
+ block_size = tls_connection_get_keyblock_size(ssl_ctx, conn);
+ if (block_size < 0)
+ return NULL;
+
+ out = os_malloc(block_size + len);
+ if (out == NULL)
+ return NULL;
+
+ if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len)
+ == 0) {
+ os_memmove(out, out + block_size, len);
+ return out;
+ }
+
+ if (tls_connection_get_keys(ssl_ctx, 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;
+}
+
+
+void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk)
+{
+ /*
+ * RFC 4851, Section 5.4: EAP Master Session Key Generation
+ * MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64)
+ */
+
+ sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
+ "Session Key Generating Function", (u8 *) "", 0,
+ msk, EAP_FAST_KEY_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
+ msk, EAP_FAST_KEY_LEN);
+}
+
+
+void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
+{
+ /*
+ * RFC 4851, Section 5.4: EAP Master Session Key Genreration
+ * EMSK = T-PRF(S-IMCK[j],
+ * "Extended Session Key Generating Function", 64)
+ */
+
+ sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
+ "Extended Session Key Generating Function", (u8 *) "", 0,
+ emsk, EAP_EMSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
+ emsk, EAP_EMSK_LEN);
+}
+
+
+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;
+}
Modified: 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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h Sat Jun 14 00:26:56 2008
@@ -1,6 +1,6 @@
/*
* EAP-FAST definitions (RFC 4851)
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2008, 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
@@ -19,6 +19,7 @@
#define EAP_FAST_KEY_LEN 64
#define EAP_FAST_SIMCK_LEN 40
#define EAP_FAST_SKS_LEN 40
+#define EAP_FAST_CMK_LEN 20
#define TLS_EXT_PAC_OPAQUE 35
@@ -82,4 +83,35 @@
u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */
};
+
+struct wpabuf;
+struct tls_connection;
+
+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;
+};
+
+void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len);
+void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
+ u16 len);
+void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
+ const struct wpabuf *data);
+struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf);
+void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
+ const u8 *client_random, u8 *master_secret);
+u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
+ const char *label, size_t len);
+void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
+void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
+int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
+ int tlv_type, u8 *pos, int len);
+
#endif /* EAP_FAST_H */
Added: wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.c?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.c (added)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.c Sat Jun 14 00:26:56 2008
@@ -1,0 +1,87 @@
+/*
+ * EAP-PEAP common routines
+ * Copyright (c) 2008, 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"
+
+void peap_prfplus(int version, const u8 *key, size_t key_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *buf, size_t buf_len)
+{
+ unsigned char counter = 0;
+ size_t pos, plen;
+ u8 hash[SHA1_MAC_LEN];
+ size_t label_len = os_strlen(label);
+ u8 extra[2];
+ const unsigned char *addr[5];
+ size_t len[5];
+
+ addr[0] = hash;
+ len[0] = 0;
+ addr[1] = (unsigned char *) label;
+ len[1] = label_len;
+ addr[2] = seed;
+ len[2] = seed_len;
+
+ if (version == 0) {
+ /*
+ * PRF+(K, S, LEN) = T1 | T2 | ... | Tn
+ * T1 = HMAC-SHA1(K, S | 0x01 | 0x00 | 0x00)
+ * T2 = HMAC-SHA1(K, T1 | S | 0x02 | 0x00 | 0x00)
+ * ...
+ * Tn = HMAC-SHA1(K, Tn-1 | S | n | 0x00 | 0x00)
+ */
+
+ extra[0] = 0;
+ extra[1] = 0;
+
+ addr[3] = &counter;
+ len[3] = 1;
+ addr[4] = extra;
+ len[4] = 2;
+ } else {
+ /*
+ * PRF (K,S,LEN) = T1 | T2 | T3 | T4 | ... where:
+ * T1 = HMAC-SHA1(K, S | LEN | 0x01)
+ * T2 = HMAC-SHA1 (K, T1 | S | LEN | 0x02)
+ * T3 = HMAC-SHA1 (K, T2 | S | LEN | 0x03)
+ * T4 = HMAC-SHA1 (K, T3 | S | LEN | 0x04)
+ * ...
+ */
+
+ extra[0] = buf_len & 0xff;
+
+ addr[3] = extra;
+ len[3] = 1;
+ addr[4] = &counter;
+ len[4] = 1;
+ }
+
+ pos = 0;
+ while (pos < buf_len) {
+ counter++;
+ plen = buf_len - pos;
+ hmac_sha1_vector(key, key_len, 5, addr, len, hash);
+ if (plen >= SHA1_MAC_LEN) {
+ os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
+ pos += SHA1_MAC_LEN;
+ } else {
+ os_memcpy(&buf[pos], hash, plen);
+ break;
+ }
+ len[0] = SHA1_MAC_LEN;
+ }
+}
Added: wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.h?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.h (added)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.h Sat Jun 14 00:26:56 2008
@@ -1,0 +1,22 @@
+/*
+ * EAP-PEAP common routines
+ * Copyright (c) 2008, 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_PEAP_COMMON_H
+#define EAP_PEAP_COMMON_H
+
+void peap_prfplus(int version, const u8 *key, size_t key_len,
+ const char *label, const u8 *seed, size_t seed_len,
+ u8 *buf, size_t buf_len);
+
+#endif /* EAP_PEAP_COMMON_H */
Modified: 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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h Sat Jun 14 00:26:56 2008
@@ -73,7 +73,7 @@
} STRUCT_PACKED;
/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */
-struct eap_tlv_crypto_binding__tlv {
+struct eap_tlv_crypto_binding_tlv {
be16 tlv_type;
be16 length;
u8 reserved;
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_config.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_config.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_config.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_config.h Sat Jun 14 00:26:56 2008
@@ -350,6 +350,12 @@
* fast_pac_format=binary option can be used to select binary format
* for storing PAC entires in order to save some space (the default
* text format uses about 2.5 times the size of minimal binary format).
+ *
+ * crypto_binding option can be used to control PEAPv0 cryptobinding
+ * behavior:
+ * 0 = do not use cryptobinding
+ * 1 = use cryptobinding if server supports it (default)
+ * 2 = require cryptobinding
*/
char *phase1;
@@ -409,6 +415,44 @@
* using a smartcard.
*/
char *key_id;
+
+ /**
+ * cert_id - Cert ID for OpenSSL engine
+ *
+ * This is used if the certificate operations for EAP-TLS are performed
+ * using a smartcard.
+ */
+ char *cert_id;
+
+ /**
+ * ca_cert_id - CA Cert ID for OpenSSL engine
+ *
+ * This is used if the CA certificate for EAP-TLS is on a smartcard.
+ */
+ char *ca_cert_id;
+
+ /**
+ * key2_id - Key ID for OpenSSL engine (phase2)
+ *
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
+ */
+ char *key2_id;
+
+ /**
+ * cert2_id - Cert ID for OpenSSL engine (phase2)
+ *
+ * This is used if the certificate operations for EAP-TLS are performed
+ * using a smartcard.
+ */
+ char *cert2_id;
+
+ /**
+ * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2)
+ *
+ * This is used if the CA certificate for EAP-TLS is on a smartcard.
+ */
+ char *ca_cert2_id;
/**
* otp - One-time-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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c Sat Jun 14 00:26:56 2008
@@ -19,7 +19,7 @@
#include "eap_tls_common.h"
#include "eap_config.h"
#include "tls.h"
-#include "eap_tlv.h"
+#include "eap_common/eap_tlv_common.h"
#include "sha1.h"
#include "eap_fast_pac.h"
@@ -80,9 +80,6 @@
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");
@@ -101,10 +98,6 @@
}
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 "
@@ -113,19 +106,9 @@
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);
+ eap_fast_derive_master_secret(data->current_pac->pac_key,
+ server_random, client_random,
+ master_secret);
data->session_ticket_used = 1;
@@ -268,71 +251,10 @@
static int eap_fast_derive_msk(struct eap_fast_data *data)
{
- /* Derive EAP Master Session Keys (section 5.4) */
- sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
- "Session Key Generating Function", (u8 *) "", 0,
- data->key_data, EAP_FAST_KEY_LEN);
- wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
- data->key_data, EAP_FAST_KEY_LEN);
-
- sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
- "Extended Session Key Generating Function",
- (u8 *) "", 0, data->emsk, EAP_EMSK_LEN);
- wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
- data->emsk, EAP_EMSK_LEN);
-
+ eap_fast_derive_eap_msk(data->simck, data->key_data);
+ eap_fast_derive_eap_emsk(data->simck, data->emsk);
data->success = 1;
-
return 0;
-}
-
-
-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;
}
@@ -345,7 +267,7 @@
* Extra key material after TLS key_block: session_key_seed[40]
*/
- sks = eap_fast_derive_key(sm, &data->ssl, "key expansion",
+ sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
EAP_FAST_SKS_LEN);
if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -371,7 +293,8 @@
{
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",
+ eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
+ "key expansion",
sizeof(*data->key_block_p));
if (data->key_block_p == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -435,12 +358,27 @@
{
size_t i;
+ /* TODO: TNC with anonymous provisioning; need to require both
+ * completed MSCHAPv2 and TNC */
+
if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) {
wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed "
"during unauthenticated provisioning; reject phase2"
" type %d", type);
return -1;
}
+
+#ifdef EAP_TNC
+ if (type == EAP_TYPE_TNC) {
+ data->phase2_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_type.method = EAP_TYPE_TNC;
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
+ "vendor %d method %d for TNC",
+ data->phase2_type.vendor,
+ data->phase2_type.method);
+ return 0;
+ }
+#endif /* EAP_TNC */
for (i = 0; i < data->num_phase2_types; i++) {
if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
@@ -485,6 +423,17 @@
if (*pos == EAP_TYPE_IDENTITY) {
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
return 0;
+ }
+
+ if (data->phase2_priv && data->phase2_method &&
+ *pos != data->phase2_type.method) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - "
+ "deinitialize previous method");
+ data->phase2_method->deinit(sm, data->phase2_priv);
+ data->phase2_method = NULL;
+ data->phase2_priv = NULL;
+ data->phase2_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_type.method = EAP_TYPE_NONE;
}
if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
@@ -596,32 +545,6 @@
}
-static struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf)
-{
- struct wpabuf *msg;
- struct eap_tlv_hdr *tlv;
-
- if (buf == NULL)
- return NULL;
-
- /* Encapsulate EAP packet in EAP Payload TLV */
- msg = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
- if (msg == NULL) {
- wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
- "for TLV encapsulation");
- wpabuf_free(buf);
- return NULL;
- }
- tlv = wpabuf_put(msg, sizeof(*tlv));
- tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
- EAP_TLV_EAP_PAYLOAD_TLV);
- tlv->length = host_to_be16(wpabuf_len(buf));
- wpabuf_put_buf(msg, buf);
- wpabuf_free(buf);
- return msg;
-}
-
-
static struct wpabuf * eap_fast_process_eap_payload_tlv(
struct eap_sm *sm, struct eap_fast_data *data,
struct eap_method_ret *ret, const struct eap_hdr *req,
@@ -661,7 +584,7 @@
static int eap_fast_validate_crypto_binding(
- struct eap_tlv_crypto_binding__tlv *_bind)
+ struct eap_tlv_crypto_binding_tlv *_bind)
{
wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV: Version %d "
"Received Version %d SubType %d",
@@ -687,8 +610,8 @@
static void eap_fast_write_crypto_binding(
- struct eap_tlv_crypto_binding__tlv *rbind,
- struct eap_tlv_crypto_binding__tlv *_bind, const u8 *cmk)
+ struct eap_tlv_crypto_binding_tlv *rbind,
+ struct eap_tlv_crypto_binding_tlv *_bind, const u8 *cmk)
{
rbind->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
EAP_TLV_CRYPTO_BINDING_TLV);
@@ -699,7 +622,8 @@
rbind->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE;
os_memcpy(rbind->nonce, _bind->nonce, sizeof(_bind->nonce));
inc_byte_array(rbind->nonce, sizeof(rbind->nonce));
- hmac_sha1(cmk, 20, (u8 *) rbind, sizeof(*rbind), rbind->compound_mac);
+ hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) rbind, sizeof(*rbind),
+ rbind->compound_mac);
wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: Version %d "
"Received Version %d SubType %d",
@@ -773,8 +697,9 @@
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(cmk, imck + EAP_FAST_SIMCK_LEN, 20);
- wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", cmk, 20);
+ os_memcpy(cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]",
+ cmk, EAP_FAST_CMK_LEN);
return 0;
}
@@ -807,17 +732,16 @@
static struct wpabuf * eap_fast_process_crypto_binding(
struct eap_sm *sm, struct eap_fast_data *data,
struct eap_method_ret *ret,
- struct eap_tlv_crypto_binding__tlv *_bind, size_t bind_len, int final)
+ struct eap_tlv_crypto_binding_tlv *_bind, size_t bind_len)
{
struct wpabuf *resp;
u8 *pos;
- struct eap_tlv_intermediate_result_tlv *rresult;
- u8 cmk[20], cmac[20];
- int res, req_tunnel_pac = 0;
+ u8 cmk[EAP_FAST_CMK_LEN], cmac[SHA1_MAC_LEN];
+ int res;
size_t len;
if (eap_fast_validate_crypto_binding(_bind) < 0)
- return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1);
+ return NULL;
if (eap_fast_get_cmk(sm, data, cmk) < 0)
return NULL;
@@ -827,7 +751,8 @@
os_memset(_bind->compound_mac, 0, sizeof(cmac));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for Compound "
"MAC calculation", (u8 *) _bind, bind_len);
- hmac_sha1(cmk, 20, (u8 *) _bind, bind_len, _bind->compound_mac);
+ hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) _bind, bind_len,
+ _bind->compound_mac);
res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC",
cmac, sizeof(cmac));
@@ -835,9 +760,8 @@
_bind->compound_mac, sizeof(cmac));
if (res != 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match");
- resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1);
os_memcpy(_bind->compound_mac, cmac, sizeof(cmac));
- return resp;
+ return NULL;
}
/*
@@ -845,72 +769,24 @@
* crypto binding to allow server to complete authentication.
*/
- if (data->current_pac == NULL && data->provisioning &&
- !data->anon_provisioning) {
- /*
- * Need to request Tunnel PAC when using authenticated
- * provisioning.
- */
- wpa_printf(MSG_DEBUG, "EAP-FAST: Request Tunnel PAC");
- req_tunnel_pac = 1;
- }
-
- len = sizeof(*rresult) + sizeof(struct eap_tlv_crypto_binding__tlv);
- if (req_tunnel_pac)
- len += sizeof(struct eap_tlv_hdr) +
- sizeof(struct eap_tlv_request_action_tlv) +
- sizeof(struct eap_tlv_pac_type_tlv);
+ len = sizeof(struct eap_tlv_crypto_binding_tlv);
resp = wpabuf_alloc(len);
if (resp == NULL)
return NULL;
-
- /*
- * Both intermediate and final Result TLVs are identical, so ok to use
- * the same structure definition for them.
- */
- rresult = wpabuf_put(resp, sizeof(*rresult));
- rresult->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
- (final ? EAP_TLV_RESULT_TLV :
- EAP_TLV_INTERMEDIATE_RESULT_TLV));
- rresult->length = host_to_be16(2);
- rresult->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
if (!data->anon_provisioning && data->phase2_success &&
eap_fast_derive_msk(data) < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
- rresult->status = host_to_be16(EAP_TLV_RESULT_FAILURE);
data->phase2_success = 0;
- }
-
- pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding__tlv));
- eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding__tlv *)
+ wpabuf_free(resp);
+ return NULL;
+ }
+
+ pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv));
+ eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *)
pos, _bind, cmk);
-
- if (req_tunnel_pac) {
- u8 *pos2;
- pos = wpabuf_put(resp, 0);
- pos2 = eap_fast_write_pac_request(pos, PAC_TYPE_TUNNEL_PAC);
- wpabuf_put(resp, pos2 - pos);
- }
-
- if (final && data->phase2_success) {
- if (data->anon_provisioning) {
- wpa_printf(MSG_DEBUG, "EAP-FAST: Unauthenticated "
- "provisioning completed successfully.");
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_FAIL;
- } else {
- wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
- "completed successfully.");
- if (data->provisioning)
- ret->methodState = METHOD_MAY_CONT;
- else
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_UNCOND_SUCC;
- }
- }
return resp;
}
@@ -1128,7 +1004,7 @@
os_memset(&entry, 0, sizeof(entry));
if (eap_fast_process_pac_tlv(&entry, pac, pac_len) ||
eap_fast_process_pac_info(&entry))
- return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0);
+ return NULL;
eap_fast_add_pac(&data->pac, &data->current_pac, &entry);
eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len);
@@ -1169,94 +1045,6 @@
}
-struct eap_fast_tlv_parse {
- u8 *eap_payload_tlv;
- size_t eap_payload_tlv_len;
- u8 *pac;
- size_t pac_len;
- struct eap_tlv_crypto_binding__tlv *crypto_binding;
- size_t crypto_binding_len;
- int iresult;
- int result;
-};
-
-
-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);
- 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 (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;
- }
- 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);
- 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_PAC_TLV:
- wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len);
- tlv->pac = pos;
- tlv->pac_len = len;
- break;
- default:
- /* Unknown TLV */
- return -1;
- }
-
- return 0;
-}
-
-
static int eap_fast_parse_decrypted(struct wpabuf *decrypted,
struct eap_fast_tlv_parse *tlv,
struct wpabuf **resp)
@@ -1328,6 +1116,24 @@
}
+static struct wpabuf * eap_fast_pac_request(void)
+{
+ struct wpabuf *tmp;
+ u8 *pos, *pos2;
+
+ tmp = wpabuf_alloc(sizeof(struct eap_tlv_hdr) +
+ sizeof(struct eap_tlv_request_action_tlv) +
+ sizeof(struct eap_tlv_pac_type_tlv));
+ if (tmp == NULL)
+ return NULL;
+
+ pos = wpabuf_put(tmp, 0);
+ pos2 = eap_fast_write_pac_request(pos, PAC_TYPE_TUNNEL_PAC);
+ wpabuf_put(tmp, pos2 - pos);
+ return tmp;
+}
+
+
static int eap_fast_process_decrypted(struct eap_sm *sm,
struct eap_fast_data *data,
struct eap_method_ret *ret,
@@ -1335,8 +1141,9 @@
struct wpabuf *decrypted,
struct wpabuf **out_data)
{
- struct wpabuf *resp = NULL;
+ struct wpabuf *resp = NULL, *tmp;
struct eap_fast_tlv_parse tlv;
+ int failed = 0;
if (eap_fast_parse_decrypted(decrypted, &tlv, &resp) < 0)
return 0;
@@ -1356,43 +1163,84 @@
req->identifier, out_data);
}
+ if (tlv.crypto_binding) {
+ tmp = eap_fast_process_crypto_binding(sm, data, ret,
+ tlv.crypto_binding,
+ tlv.crypto_binding_len);
+ if (tmp == NULL)
+ failed = 1;
+ else
+ resp = wpabuf_concat(resp, tmp);
+ }
+
+ if (tlv.iresult == EAP_TLV_RESULT_SUCCESS) {
+ tmp = eap_fast_tlv_result(failed ? EAP_TLV_RESULT_FAILURE :
+ EAP_TLV_RESULT_SUCCESS, 1);
+ resp = wpabuf_concat(resp, tmp);
+ }
+
if (tlv.eap_payload_tlv) {
- resp = eap_fast_process_eap_payload_tlv(
+ tmp = eap_fast_process_eap_payload_tlv(
sm, data, ret, req, tlv.eap_payload_tlv,
tlv.eap_payload_tlv_len);
- return eap_fast_encrypt_response(sm, data, resp,
- req->identifier, out_data);
- }
-
- if (tlv.crypto_binding) {
- int final = tlv.result == EAP_TLV_RESULT_SUCCESS;
- resp = eap_fast_process_crypto_binding(sm, data, ret,
- tlv.crypto_binding,
- tlv.crypto_binding_len,
- final);
- return eap_fast_encrypt_response(sm, data, resp,
- req->identifier, out_data);
+ resp = wpabuf_concat(resp, tmp);
}
if (tlv.pac && tlv.result != EAP_TLV_RESULT_SUCCESS) {
wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV "
"acknowledging success");
- resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0);
- return eap_fast_encrypt_response(sm, data, resp,
- req->identifier, out_data);
- }
-
- if (tlv.pac && tlv.result == EAP_TLV_RESULT_SUCCESS) {
- resp = eap_fast_process_pac(sm, data, ret, tlv.pac,
- tlv.pac_len);
- return eap_fast_encrypt_response(sm, data, resp,
- req->identifier, out_data);
- }
-
- wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
- "empty response packet");
- return eap_fast_encrypt_response(sm, data, wpabuf_alloc(1),
- req->identifier, out_data);
+ failed = 1;
+ } else if (tlv.pac && tlv.result == EAP_TLV_RESULT_SUCCESS) {
+ tmp = eap_fast_process_pac(sm, data, ret, tlv.pac,
+ tlv.pac_len);
+ resp = wpabuf_concat(resp, tmp);
+ }
+
+ if (data->current_pac == NULL && data->provisioning &&
+ !data->anon_provisioning) {
+ /*
+ * Need to request Tunnel PAC when using authenticated
+ * provisioning.
+ */
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Request Tunnel PAC");
+ tmp = eap_fast_pac_request();
+ resp = wpabuf_concat(resp, tmp);
+ }
+
+ if (tlv.result == EAP_TLV_RESULT_SUCCESS && !failed) {
+ tmp = eap_fast_tlv_result(EAP_TLV_RESULT_SUCCESS, 0);
+ resp = wpabuf_concat(resp, tmp);
+ } else if (failed) {
+ tmp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0);
+ resp = wpabuf_concat(resp, tmp);
+ }
+
+ if (resp && tlv.result == EAP_TLV_RESULT_SUCCESS && !failed &&
+ tlv.crypto_binding && data->phase2_success) {
+ if (data->anon_provisioning) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unauthenticated "
+ "provisioning completed successfully.");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
+ "completed successfully.");
+ if (data->provisioning)
+ ret->methodState = METHOD_MAY_CONT;
+ else
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ }
+ }
+
+ if (resp == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
+ "empty response packet");
+ resp = wpabuf_alloc(1);
+ }
+
+ return eap_fast_encrypt_response(sm, data, resp, req->identifier,
+ out_data);
}
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_peap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_peap.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_peap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_peap.c Sat Jun 14 00:26:56 2008
@@ -15,11 +15,14 @@
#include "includes.h"
#include "common.h"
+#include "crypto/sha1.h"
#include "eap_i.h"
#include "eap_tls_common.h"
#include "eap_config.h"
#include "tls.h"
-#include "eap_tlv.h"
+#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_peap_common.h"
+#include "tncc.h"
/* Maximum supported PEAP version
@@ -60,6 +63,12 @@
u8 *key_data;
struct wpabuf *pending_phase2_req;
+ enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
+ int crypto_binding_used;
+ u8 ipmk[40];
+ u8 cmk[20];
+ int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)
+ * is enabled. */
};
@@ -96,6 +105,24 @@
"receiving tunneled EAP-Success");
}
+ if (os_strstr(phase1, "crypto_binding=0")) {
+ data->crypto_binding = NO_BINDING;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding");
+ } else if (os_strstr(phase1, "crypto_binding=1")) {
+ data->crypto_binding = OPTIONAL_BINDING;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding");
+ } else if (os_strstr(phase1, "crypto_binding=2")) {
+ data->crypto_binding = REQUIRE_BINDING;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding");
+ }
+
+#ifdef EAP_TNC
+ if (os_strstr(phase1, "tnc=soh")) {
+ data->soh = 1;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH enabled");
+ }
+#endif /* EAP_TNC */
+
return 0;
}
@@ -112,6 +139,7 @@
data->peap_version = EAP_PEAP_VERSION;
data->force_peap_version = -1;
data->peap_outer_success = 2;
+ data->crypto_binding = OPTIONAL_BINDING;
if (config && config->phase1 &&
eap_peap_parse_phase1(data, config->phase1) < 0) {
@@ -154,6 +182,396 @@
}
+/**
+ * eap_tlv_build_nak - Build EAP-TLV NAK message
+ * @id: EAP identifier for the header
+ * @nak_type: TLV type (EAP_TLV_*)
+ * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
+ *
+ * This funtion builds an EAP-TLV NAK message. The caller is responsible for
+ * freeing the returned buffer.
+ */
+static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
+{
+ struct wpabuf *msg;
+
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10,
+ EAP_CODE_RESPONSE, id);
+ if (msg == NULL)
+ return NULL;
+
+ wpabuf_put_u8(msg, 0x80); /* Mandatory */
+ wpabuf_put_u8(msg, EAP_TLV_NAK_TLV);
+ wpabuf_put_be16(msg, 6); /* Length */
+ wpabuf_put_be32(msg, 0); /* Vendor-Id */
+ wpabuf_put_be16(msg, nak_type); /* NAK-Type */
+
+ return msg;
+}
+
+
+static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_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 ||
+ data->phase2_method->isKeyAvailable == NULL ||
+ data->phase2_method->getKey == NULL)
+ return 0;
+
+ if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) ||
+ (key = data->phase2_method->getKey(sm, data->phase2_priv,
+ &key_len)) == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material "
+ "from Phase 2");
+ return -1;
+ }
+
+ if (key_len == 32 &&
+ data->phase2_method->vendor == EAP_VENDOR_IETF &&
+ data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
+ /*
+ * Microsoft uses reverse order for MS-MPPE keys in
+ * EAP-PEAP when compared to EAP-FAST derivation of
+ * ISK. Swap the keys here to get the correct ISK for
+ * EAP-PEAPv0 cryptobinding.
+ */
+ u8 tmp[16];
+ os_memcpy(tmp, key, 16);
+ os_memcpy(key, key + 16, 16);
+ os_memcpy(key + 16, tmp, 16);
+ }
+
+ if (key_len > isk_len)
+ key_len = isk_len;
+ os_memcpy(isk, key, key_len);
+ os_free(key);
+
+ return 0;
+}
+
+
+static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
+{
+ u8 *tk;
+ u8 isk[32], imck[60];
+
+ /*
+ * Tunnel key (TK) is the first 60 octets of the key generated by
+ * phase 1 of PEAP (based on TLS).
+ */
+ tk = data->key_data;
+ if (tk == NULL)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
+
+ if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
+
+ /*
+ * IPMK Seed = "Inner Methods Compound Keys" | ISK
+ * TempKey = First 40 octets of TK
+ * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
+ * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
+ * in the end of the label just before ISK; is that just a typo?)
+ */
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
+ peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck));
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
+ imck, sizeof(imck));
+
+ /* TODO: fast-connect: IPMK|CMK = TK */
+ os_memcpy(data->ipmk, imck, 40);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
+ os_memcpy(data->cmk, imck + 40, 20);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
+
+ return 0;
+}
+
+
+static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ struct wpabuf *buf)
+{
+ u8 *mac;
+ u8 eap_type = EAP_TYPE_PEAP;
+ const u8 *addr[2];
+ size_t len[2];
+ u16 tlv_type;
+ u8 binding_nonce[32];
+
+ /* FIX: should binding_nonce be copied from request? */
+ if (os_get_random(binding_nonce, 32))
+ return -1;
+
+ /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+ addr[0] = wpabuf_put(buf, 0);
+ len[0] = 60;
+ addr[1] = &eap_type;
+ len[1] = 1;
+
+ tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
+ if (data->peap_version >= 2)
+ tlv_type |= EAP_TLV_TYPE_MANDATORY;
+ wpabuf_put_be16(buf, tlv_type);
+ wpabuf_put_be16(buf, 56);
+
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ wpabuf_put_u8(buf, data->peap_version); /* Version */
+ wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */
+ wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */
+ wpabuf_put_data(buf, binding_nonce, 32); /* Nonce */
+ mac = wpabuf_put(buf, 20); /* Compound_MAC */
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
+ addr[0], len[0]);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
+ addr[1], len[1]);
+ hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
+ data->crypto_binding_used = 1;
+
+ return 0;
+}
+
+
+/**
+ * eap_tlv_build_result - Build EAP-TLV Result message
+ * @id: EAP identifier for the header
+ * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
+ * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
+ *
+ * This funtion builds an EAP-TLV Result message. The caller is responsible for
+ * freeing the returned buffer.
+ */
+static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ int crypto_tlv_used,
+ int id, u16 status)
+{
+ struct wpabuf *msg;
+ size_t len;
+
+ if (data->crypto_binding == NO_BINDING)
+ crypto_tlv_used = 0;
+
+ len = 6;
+ if (crypto_tlv_used)
+ len += 60; /* Cryptobinding TLV */
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
+ EAP_CODE_RESPONSE, id);
+ if (msg == NULL)
+ return NULL;
+
+ wpabuf_put_u8(msg, 0x80); /* Mandatory */
+ wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV);
+ wpabuf_put_be16(msg, 2); /* Length */
+ wpabuf_put_be16(msg, status); /* Status */
+
+ if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
+ wpabuf_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+
+static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ const u8 *crypto_tlv,
+ size_t crypto_tlv_len)
+{
+ u8 buf[61], mac[SHA1_MAC_LEN];
+ const u8 *pos;
+
+ if (eap_peap_derive_cmk(sm, data) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK");
+ return -1;
+ }
+
+ if (crypto_tlv_len != 4 + 56) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
+ "length %d", (int) crypto_tlv_len);
+ return -1;
+ }
+
+ pos = crypto_tlv;
+ pos += 4; /* TLV header */
+ if (pos[1] != data->peap_version) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
+ "mismatch (was %d; expected %d)",
+ pos[1], data->peap_version);
+ return -1;
+ }
+
+ if (pos[3] != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
+ "SubType %d", pos[3]);
+ return -1;
+ }
+ pos += 4;
+ pos += 32; /* Nonce */
+
+ /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+ os_memcpy(buf, crypto_tlv, 60);
+ os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
+ buf[60] = EAP_TYPE_PEAP;
+ hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
+
+ if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
+ "cryptobinding TLV");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
+
+ return 0;
+}
+
+
+/**
+ * eap_tlv_process - Process a received EAP-TLV message and generate a response
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @ret: Return values from EAP request validation and processing
+ * @req: EAP-TLV request to be processed. The caller must have validated that
+ * the buffer is large enough to contain full request (hdr->length bytes) and
+ * that the EAP type is EAP_TYPE_TLV.
+ * @resp: Buffer to return a pointer to the allocated response message. This
+ * field should be initialized to %NULL before the call. The value will be
+ * updated if a response message is generated. The caller is responsible for
+ * freeing the allocated message.
+ * @force_failure: Force negotiation to fail
+ * Returns: 0 on success, -1 on failure
+ */
+static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
+ struct eap_method_ret *ret,
+ const struct wpabuf *req, struct wpabuf **resp,
+ int force_failure)
+{
+ size_t left, tlv_len;
+ const u8 *pos;
+ const u8 *result_tlv = NULL, *crypto_tlv = NULL;
+ size_t result_tlv_len = 0, crypto_tlv_len = 0;
+ int tlv_type, mandatory;
+
+ /* Parse TLVs */
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left);
+ if (pos == NULL)
+ return -1;
+ wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
+ while (left >= 4) {
+ mandatory = !!(pos[0] & 0x80);
+ tlv_type = WPA_GET_BE16(pos) & 0x3fff;
+ pos += 2;
+ tlv_len = WPA_GET_BE16(pos);
+ pos += 2;
+ left -= 4;
+ if (tlv_len > left) {
+ wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
+ "(tlv_len=%lu left=%lu)",
+ (unsigned long) tlv_len,
+ (unsigned long) left);
+ return -1;
+ }
+ switch (tlv_type) {
+ case EAP_TLV_RESULT_TLV:
+ result_tlv = pos;
+ result_tlv_len = tlv_len;
+ break;
+ case EAP_TLV_CRYPTO_BINDING_TLV:
+ crypto_tlv = pos;
+ crypto_tlv_len = tlv_len;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
+ "%d%s", tlv_type,
+ mandatory ? " (mandatory)" : "");
+ if (mandatory) {
+ /* NAK TLV and ignore all TLVs in this packet.
+ */
+ *resp = eap_tlv_build_nak(eap_get_id(req),
+ tlv_type);
+ return *resp == NULL ? -1 : 0;
+ }
+ /* Ignore this TLV, but process other TLVs */
+ break;
+ }
+
+ pos += tlv_len;
+ left -= tlv_len;
+ }
+ if (left) {
+ wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
+ "Request (left=%lu)", (unsigned long) left);
+ return -1;
+ }
+
+ /* Process supported TLVs */
+ if (crypto_tlv && data->crypto_binding != NO_BINDING) {
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
+ crypto_tlv, crypto_tlv_len);
+ if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
+ crypto_tlv_len + 4) < 0) {
+ if (result_tlv == NULL)
+ return -1;
+ force_failure = 1;
+ }
+ } else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
+ return -1;
+ }
+
+ if (result_tlv) {
+ int status, resp_status;
+ wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
+ result_tlv, result_tlv_len);
+ if (result_tlv_len < 2) {
+ wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
+ "(len=%lu)",
+ (unsigned long) result_tlv_len);
+ return -1;
+ }
+ status = WPA_GET_BE16(result_tlv);
+ if (status == EAP_TLV_RESULT_SUCCESS) {
+ wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
+ "- EAP-TLV/Phase2 Completed");
+ if (force_failure) {
+ wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure"
+ " - force failed Phase 2");
+ resp_status = EAP_TLV_RESULT_FAILURE;
+ ret->decision = DECISION_FAIL;
+ } else {
+ resp_status = EAP_TLV_RESULT_SUCCESS;
+ ret->decision = DECISION_UNCOND_SUCC;
+ }
+ } else if (status == EAP_TLV_RESULT_FAILURE) {
+ wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
+ resp_status = EAP_TLV_RESULT_FAILURE;
+ ret->decision = DECISION_FAIL;
+ } else {
+ wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
+ "Status %d", status);
+ resp_status = EAP_TLV_RESULT_FAILURE;
+ ret->decision = DECISION_FAIL;
+ }
+ ret->methodState = METHOD_DONE;
+
+ *resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL,
+ eap_get_id(req), resp_status);
+ }
+
+ return 0;
+}
+
+
static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
{
struct wpabuf *e;
@@ -206,7 +624,7 @@
break;
case EAP_TYPE_TLV:
os_memset(&iret, 0, sizeof(iret));
- if (eap_tlv_process(sm, &iret, req, resp,
+ if (eap_tlv_process(sm, data, &iret, req, resp,
data->phase2_eap_started &&
!data->phase2_eap_success)) {
ret->methodState = METHOD_DONE;
@@ -220,6 +638,38 @@
data->phase2_success = 1;
}
break;
+ case EAP_TYPE_EXPANDED:
+#ifdef EAP_TNC
+ if (data->soh) {
+ const u8 *epos;
+ size_t eleft;
+
+ epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21,
+ req, &eleft);
+ if (epos) {
+ struct wpabuf *buf;
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: SoH EAP Extensions");
+ buf = tncc_process_soh_request(epos, eleft);
+ if (buf) {
+ *resp = eap_msg_alloc(
+ EAP_VENDOR_MICROSOFT, 0x21,
+ wpabuf_len(buf),
+ EAP_CODE_RESPONSE,
+ hdr->identifier);
+ if (*resp == NULL) {
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return -1;
+ }
+ wpabuf_put_buf(*resp, buf);
+ wpabuf_free(buf);
+ break;
+ }
+ }
+ }
+#endif /* EAP_TNC */
+ /* fall through */
default:
if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
data->phase2_type.method == EAP_TYPE_NONE) {
@@ -256,9 +706,11 @@
data->phase2_type.method);
if (data->phase2_method) {
sm->init_phase2 = 1;
+ sm->mschapv2_full_key = 1;
data->phase2_priv =
data->phase2_method->init(sm);
sm->init_phase2 = 0;
+ sm->mschapv2_full_key = 0;
}
}
if (data->phase2_priv == NULL || data->phase2_method == NULL) {
@@ -713,6 +1165,7 @@
struct eap_peap_data *data = priv;
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
+ data->crypto_binding_used = 0;
}
@@ -777,7 +1230,23 @@
return NULL;
*len = EAP_TLS_KEY_LEN;
- os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
+
+ if (data->crypto_binding_used) {
+ u8 csk[128];
+ /*
+ * Note: It looks like Microsoft implementation requires null
+ * termination for this label while the one used for deriving
+ * IPMK|CMK did not use null termination.
+ */
+ peap_prfplus(data->peap_version, data->ipmk, 40,
+ "Session Key Generating Function",
+ (u8 *) "\00", 1, csk, sizeof(csk));
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
+ os_memcpy(key, csk, EAP_TLS_KEY_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
+ key, EAP_TLS_KEY_LEN);
+ } else
+ os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
return key;
}
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c Sat Jun 14 00:26:56 2008
@@ -59,6 +59,8 @@
params->engine_id = config->engine_id;
params->pin = config->pin;
params->key_id = config->key_id;
+ params->cert_id = config->cert_id;
+ params->ca_cert_id = config->ca_cert_id;
}
@@ -73,6 +75,11 @@
params->dh_file = (char *) config->dh_file2;
params->subject_match = (char *) config->subject_match2;
params->altsubject_match = (char *) config->altsubject_match2;
+ params->engine_id = config->engine_id;
+ params->pin = config->pin;
+ params->key_id = config->key2_id;
+ params->cert_id = config->cert2_id;
+ params->ca_cert_id = config->ca_cert2_id;
}
@@ -820,6 +827,14 @@
buf_len = wpabuf_len(in_data);
if (data->tls_in_total > buf_len)
buf_len = data->tls_in_total;
+ /*
+ * Even though we try to disable TLS compression, it is possible that
+ * this cannot be done with all TLS libraries. Add extra buffer space
+ * to handle the possibility of the decrypted data being longer than
+ * input data.
+ */
+ buf_len += 500;
+ buf_len *= 3;
*in_decrypted = wpabuf_alloc(buf_len ? buf_len : 1);
if (*in_decrypted == NULL) {
eap_peer_tls_reset_input(data);
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_tnc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_tnc.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_tnc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_tnc.c Sat Jun 14 00:26:56 2008
@@ -21,8 +21,12 @@
struct eap_tnc_data {
- EapMethodState state;
+ enum { WAIT_START, MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
struct tncc_data *tncc;
+ struct wpabuf *in_buf;
+ struct wpabuf *out_buf;
+ size_t out_used;
+ size_t fragment_size;
};
@@ -42,7 +46,8 @@
data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- data->state = METHOD_INIT;
+ data->state = WAIT_START;
+ data->fragment_size = 1300;
data->tncc = tncc_init();
if (data->tncc == NULL) {
os_free(data);
@@ -57,8 +62,140 @@
{
struct eap_tnc_data *data = priv;
+ wpabuf_free(data->in_buf);
+ wpabuf_free(data->out_buf);
tncc_deinit(data->tncc);
os_free(data);
+}
+
+
+static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
+{
+ struct wpabuf *msg;
+
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 0, code, id);
+ if (msg == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
+ "for fragment ack");
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
+
+ return msg;
+}
+
+
+static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data,
+ struct eap_method_ret *ret, u8 id)
+{
+ struct wpabuf *resp;
+ u8 flags;
+ size_t send_len, plen;
+
+ ret->ignore = FALSE;
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response");
+ ret->allowNotifications = TRUE;
+
+ flags = EAP_TNC_VERSION;
+ send_len = wpabuf_len(data->out_buf) - data->out_used;
+ if (1 + send_len > data->fragment_size) {
+ send_len = data->fragment_size - 1;
+ flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
+ if (data->out_used == 0) {
+ flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
+ send_len -= 4;
+ }
+ }
+
+ plen = 1 + send_len;
+ if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
+ plen += 4;
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
+ EAP_CODE_RESPONSE, id);
+ if (resp == NULL)
+ return NULL;
+
+ wpabuf_put_u8(resp, flags); /* Flags */
+ if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
+ wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
+
+ wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
+ send_len);
+ data->out_used += send_len;
+
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_FAIL;
+
+ if (data->out_used == wpabuf_len(data->out_buf)) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
+ "(message sent completely)",
+ (unsigned long) send_len);
+ wpabuf_free(data->out_buf);
+ data->out_buf = NULL;
+ data->out_used = 0;
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
+ "(%lu more to send)", (unsigned long) send_len,
+ (unsigned long) wpabuf_len(data->out_buf) -
+ data->out_used);
+ data->state = WAIT_FRAG_ACK;
+ }
+
+ return resp;
+}
+
+
+static int eap_tnc_process_cont(struct eap_tnc_data *data,
+ const u8 *buf, size_t len)
+{
+ /* Process continuation of a pending message */
+ if (len > wpabuf_tailroom(data->in_buf)) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
+ data->state = FAIL;
+ return -1;
+ }
+
+ wpabuf_put_data(data->in_buf, buf, len);
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for "
+ "%lu bytes more", (unsigned long) len,
+ (unsigned long) wpabuf_tailroom(data->in_buf));
+
+ return 0;
+}
+
+
+static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data,
+ struct eap_method_ret *ret,
+ u8 id, u8 flags,
+ u32 message_length,
+ const u8 *buf, size_t len)
+{
+ /* Process a fragment that is not the last one of the message */
+ if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
+ "fragmented packet");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (data->in_buf == NULL) {
+ /* First fragment of the message */
+ data->in_buf = wpabuf_alloc(message_length);
+ if (data->in_buf == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
+ "message");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ wpabuf_put_data(data->in_buf, buf, len);
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
+ "fragment, waiting for %lu bytes more",
+ (unsigned long) len,
+ (unsigned long) wpabuf_tailroom(data->in_buf));
+ }
+
+ return eap_tnc_build_frag_ack(id, EAP_CODE_RESPONSE);
}
@@ -68,33 +205,93 @@
{
struct eap_tnc_data *data = priv;
struct wpabuf *resp;
- const u8 *pos;
+ const u8 *pos, *end;
u8 *rpos, *rpos1, *start;
size_t len, rlen;
size_t imc_len;
char *start_buf, *end_buf;
size_t start_len, end_len;
int tncs_done = 0;
+ u8 flags, id;
+ u32 message_length = 0;
+ struct wpabuf tmpbuf;
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len);
- if (pos == NULL || len == 0) {
+ if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)",
pos, (unsigned long) len);
ret->ignore = TRUE;
return NULL;
}
- wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload", pos, len);
-
- if ((*pos & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
+ id = eap_get_id(reqData);
+
+ end = pos + len;
+
+ if (len == 0)
+ flags = 0; /* fragment ack */
+ else
+ flags = *pos++;
+
+ if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
- *pos & EAP_TNC_VERSION_MASK);
+ flags & EAP_TNC_VERSION_MASK);
ret->ignore = TRUE;
return NULL;
}
- if (data->state == METHOD_INIT) {
- if (!(*pos & EAP_TNC_FLAGS_START)) {
+ if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
+ if (end - pos < 4) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ message_length = WPA_GET_BE32(pos);
+ pos += 4;
+
+ if (message_length < (u32) (end - pos)) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
+ "Length (%d; %ld remaining in this msg)",
+ message_length, (long) (end - pos));
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
+ "Message Length %u", flags, message_length);
+
+ if (data->state == WAIT_FRAG_ACK) {
+ if (len != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in "
+ "WAIT_FRAG_ACK state");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
+ data->state = MSG;
+ return eap_tnc_build_msg(data, ret, id);
+ }
+
+ if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
+ return eap_tnc_process_fragment(data, ret, id, flags,
+ message_length, pos,
+ end - pos);
+ }
+
+ if (data->in_buf == NULL) {
+ /* Wrap unfragmented messages as wpabuf without extra copy */
+ wpabuf_set(&tmpbuf, pos, end - pos);
+ data->in_buf = &tmpbuf;
+ }
+
+ if (data->state == WAIT_START) {
+ if (!(flags & EAP_TNC_FLAGS_START)) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
"start flag in the first message");
ret->ignore = TRUE;
@@ -103,18 +300,20 @@
tncc_init_connection(data->tncc);
- data->state = METHOD_MAY_CONT;
+ data->state = MSG;
} else {
enum tncc_process_res res;
- if (*pos & EAP_TNC_FLAGS_START) {
+ if (flags & EAP_TNC_FLAGS_START) {
wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
"flag again");
ret->ignore = TRUE;
return NULL;
}
- res = tncc_process_if_tnccs(data->tncc, pos + 1, len - 1);
+ res = tncc_process_if_tnccs(data->tncc,
+ wpabuf_head(data->in_buf),
+ wpabuf_len(data->in_buf));
switch (res) {
case TNCCS_PROCESS_ERROR:
ret->ignore = TRUE;
@@ -142,10 +341,19 @@
}
}
+ if (data->in_buf != &tmpbuf)
+ wpabuf_free(data->in_buf);
+ data->in_buf = NULL;
+
ret->ignore = FALSE;
- ret->methodState = data->state;
+ ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_UNCOND_SUCC;
ret->allowNotifications = TRUE;
+
+ if (data->out_buf) {
+ data->state = MSG;
+ return eap_tnc_build_msg(data, ret, id);
+ }
if (tncs_done) {
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
@@ -195,7 +403,9 @@
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response", start, rlen);
- return resp;
+ data->out_buf = resp;
+ data->state = MSG;
+ return eap_tnc_build_msg(data, ret, id);
}
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c Sat Jun 14 00:26:56 2008
@@ -669,7 +669,7 @@
/* MS-CHAP-Challenge */
challenge = eap_ttls_implicit_challenge(
- sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN * 2 + 1);
+ sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
if (challenge == NULL) {
wpabuf_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
@@ -753,7 +753,8 @@
identity, identity_len);
/* MS-CHAP-Challenge */
- challenge = eap_ttls_implicit_challenge(sm, data, EAP_TLS_KEY_LEN);
+ challenge = eap_ttls_implicit_challenge(
+ sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
if (challenge == NULL) {
wpabuf_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive "
@@ -901,7 +902,8 @@
identity, identity_len);
/* CHAP-Challenge */
- challenge = eap_ttls_implicit_challenge(sm, data, EAP_TLS_KEY_LEN);
+ challenge = eap_ttls_implicit_challenge(
+ sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
if (challenge == NULL) {
wpabuf_free(msg);
wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive "
@@ -991,7 +993,7 @@
}
}
- switch (data->phase2_type) {
+ switch (phase2_type) {
case EAP_TTLS_PHASE2_EAP:
res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp);
break;
@@ -1334,6 +1336,15 @@
}
if (parse->mschapv2 == NULL) {
+#ifdef EAP_TNC
+ if (data->phase2_success && parse->eapdata) {
+ /*
+ * Allow EAP-TNC to be started after successfully
+ * completed MSCHAPV2.
+ */
+ return 1;
+ }
+#endif /* EAP_TNC */
wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP "
"received for Phase2 MSCHAPV2");
return -1;
@@ -1435,9 +1446,7 @@
case EAP_TTLS_PHASE2_MSCHAPV2:
res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse);
#ifdef EAP_TNC
- if (res == 1 && parse->eapdata &&
- ret->methodState == METHOD_DONE &&
- ret->decision == DECISION_UNCOND_SUCC) {
+ if (res == 1 && parse->eapdata && data->phase2_success) {
/*
* TNC may be required as the next
* authentication method within the tunnel.
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c Sat Jun 14 00:26:56 2008
@@ -20,6 +20,8 @@
#include "common.h"
#include "base64.h"
#include "tncc.h"
+#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_defs.h"
#ifdef UNICODE
@@ -37,7 +39,7 @@
"xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
"xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
-"IF_TNCCS#https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
+"IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
#define IF_TNCCS_END "\n</TNCCS-Batch>"
/* TNC IF-IMC */
@@ -1202,3 +1204,116 @@
os_free(tncc);
}
+
+
+static struct wpabuf * tncc_build_soh(void)
+{
+ struct wpabuf *buf;
+ u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end;
+ u8 correlation_id[24];
+ int ver = 2;
+
+ if (os_get_random(correlation_id, sizeof(correlation_id)))
+ return NULL;
+ wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID",
+ correlation_id, sizeof(correlation_id));
+
+ buf = wpabuf_alloc(200);
+ if (buf == NULL)
+ return NULL;
+
+ /* Vendor-Specific TLV (Microsoft) - SoH */
+ wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
+ tlv_len = wpabuf_put(buf, 2); /* Length */
+ wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
+ wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */
+ tlv_len2 = wpabuf_put(buf, 2); /* Length */
+
+ /* SoH Header */
+ wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */
+ outer_len = wpabuf_put(buf, 2);
+ wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
+ wpabuf_put_be16(buf, ver); /* Inner Type */
+ inner_len = wpabuf_put(buf, 2);
+
+ if (ver == 2) {
+ /* SoH Mode Sub-Header */
+ /* Outer Type */
+ wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
+ wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */
+ wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
+ /* Value: */
+ wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
+ wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */
+ wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */
+ }
+
+ /* SSoH TLV */
+ /* System-Health-Id */
+ wpabuf_put_be16(buf, 0x0002); /* Type */
+ wpabuf_put_be16(buf, 4); /* Length */
+ wpabuf_put_be32(buf, 79616);
+ /* Vendor-Specific Attribute */
+ wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
+ ssoh_len = wpabuf_put(buf, 2);
+ wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
+ /* TODO: MS-Machine-Inventory */
+ /* TODO: MS-Quarantine-State */
+ /* MS-Packet-Info */
+ wpabuf_put_u8(buf, 0x03);
+ wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */
+ /* TODO: MS-MachineName */
+ /* MS-CorrelationId */
+ wpabuf_put_u8(buf, 0x06);
+ wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
+ end = wpabuf_put(buf, 0);
+ WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2);
+
+ /* TODO: SoHReportEntry TLV (zero or more) */
+
+ /* Update length fields */
+ end = wpabuf_put(buf, 0);
+ WPA_PUT_BE16(tlv_len, end - tlv_len - 2);
+ WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2);
+ WPA_PUT_BE16(outer_len, end - outer_len - 2);
+ WPA_PUT_BE16(inner_len, end - inner_len - 2);
+
+ return buf;
+}
+
+
+struct wpabuf * tncc_process_soh_request(const u8 *data, size_t len)
+{
+ const u8 *pos;
+
+ wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len);
+
+ if (len < 12)
+ return NULL;
+
+ /* SoH Request */
+ pos = data;
+
+ /* TLV Type */
+ if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV)
+ return NULL;
+ pos += 2;
+
+ /* Length */
+ if (WPA_GET_BE16(pos) < 8)
+ return NULL;
+ pos += 2;
+
+ /* Vendor_Id */
+ if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT)
+ return NULL;
+ pos += 4;
+
+ /* TLV Type */
+ if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received");
+
+ return tncc_build_soh();
+}
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/tncc.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/tncc.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/tncc.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/tncc.h Sat Jun 14 00:26:56 2008
@@ -37,4 +37,6 @@
enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
const u8 *msg, size_t len);
+struct wpabuf * tncc_process_soh_request(const u8 *data, size_t len);
+
#endif /* TNCC_H */
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap.c Sat Jun 14 00:26:56 2008
@@ -1154,6 +1154,7 @@
if (conf->eap_fast_a_id)
sm->eap_fast_a_id = os_strdup(conf->eap_fast_a_id);
sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
+ sm->tnc = conf->tnc;
wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap.h Sat Jun 14 00:26:56 2008
@@ -97,6 +97,7 @@
u8 *pac_opaque_encr_key;
char *eap_fast_a_id;
int eap_sim_aka_result_ind;
+ int tnc;
};
Modified: 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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c Sat Jun 14 00:26:56 2008
@@ -31,6 +31,7 @@
#define PAC_OPAQUE_TYPE_PAD 0
#define PAC_OPAQUE_TYPE_KEY 1
#define PAC_OPAQUE_TYPE_LIFETIME 2
+#define PAC_OPAQUE_TYPE_IDENTITY 3
/* PAC-Key lifetime in seconds (hard limit) */
#define PAC_KEY_LIFETIME (7 * 24 * 60 * 60)
@@ -62,7 +63,7 @@
struct eap_fast_key_block_provisioning *key_block_p;
u8 simck[EAP_FAST_SIMCK_LEN];
- u8 cmk[20];
+ u8 cmk[EAP_FAST_CMK_LEN];
int simck_idx;
u8 pac_opaque_encr[16];
@@ -71,6 +72,10 @@
int anon_provisioning;
int send_new_pac; /* server triggered re-keying of Tunnel PAC */
struct wpabuf *pending_phase2_resp;
+ u8 *identity; /* from PAC-Opaque */
+ size_t identity_len;
+ int eap_seq;
+ int tnc_started;
};
@@ -125,22 +130,17 @@
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;
+ u8 *identity = NULL;
+ size_t identity_len = 0;
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 "
@@ -217,6 +217,10 @@
}
lifetime = WPA_GET_BE32(pos + 2);
break;
+ case PAC_OPAQUE_TYPE_IDENTITY:
+ identity = pos + 2;
+ identity_len = pos[1];
+ break;
}
pos += 2 + pos[1];
@@ -229,6 +233,17 @@
return -1;
}
+ if (identity) {
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Identity from "
+ "PAC-Opaque", identity, identity_len);
+ os_free(data->identity);
+ data->identity = os_malloc(identity_len);
+ if (data->identity) {
+ os_memcpy(data->identity, identity, identity_len);
+ data->identity_len = identity_len;
+ }
+ }
+
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);
@@ -239,72 +254,12 @@
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);
+ eap_fast_derive_master_secret(pac_key, server_random, client_random,
+ master_secret);
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;
}
@@ -317,7 +272,7 @@
* Extra key material after TLS key_block: session_key_seed[40]
*/
- sks = eap_fast_derive_key(sm, &data->ssl, "key expansion",
+ sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
EAP_FAST_SKS_LEN);
if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -343,7 +298,8 @@
{
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",
+ eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
+ "key expansion",
sizeof(*data->key_block_p));
if (data->key_block_p == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -428,8 +384,9 @@
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);
+ os_memcpy(data->cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]",
+ data->cmk, EAP_FAST_CMK_LEN);
return 0;
}
@@ -517,6 +474,7 @@
os_free(data->srv_id);
os_free(data->key_block_p);
wpabuf_free(data->pending_phase2_resp);
+ os_free(data->identity);
os_free(data);
}
@@ -525,11 +483,10 @@
struct eap_fast_data *data, u8 id)
{
struct wpabuf *req;
- struct pac_tlv_hdr *a_id;
size_t srv_id_len = os_strlen(data->srv_id);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_FAST,
- 1 + sizeof(*a_id) + srv_id_len,
+ 1 + sizeof(struct pac_tlv_hdr) + srv_id_len,
EAP_CODE_REQUEST, id);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-FAST: Failed to allocate memory for"
@@ -539,10 +496,9 @@
}
wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->fast_version);
- a_id = wpabuf_put(req, sizeof(*a_id));
- a_id->type = host_to_be16(PAC_TYPE_A_ID);
- a_id->len = host_to_be16(srv_id_len);
- wpabuf_put_data(req, data->srv_id, srv_id_len);
+
+ /* RFC 4851, 4.1.1. Authority ID Data */
+ eap_fast_put_tlv(req, PAC_TYPE_A_ID, data->srv_id, srv_id_len);
eap_fast_state(data, PHASE1);
@@ -577,90 +533,6 @@
}
-static struct wpabuf * eap_fast_build_req(struct eap_sm *sm,
- struct eap_fast_data *data, u8 id)
-{
- int res;
- struct wpabuf *req;
-
- res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_FAST,
- data->fast_version, id, &req);
-
- 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(id, EAP_TYPE_FAST,
- data->fast_version);
- return req;
-}
-
-
-static struct wpabuf * eap_fast_encrypt(struct eap_sm *sm,
- struct eap_fast_data *data,
- u8 id, u8 *plain, size_t plain_len)
-{
- int res;
- struct wpabuf *buf;
-
- /* TODO: add support for fragmentation, if needed. This will need to
- * add TLS Message Length field, if the frame is fragmented. */
- buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_FAST,
- 1 + data->ssl.tls_out_limit,
- EAP_CODE_REQUEST, id);
- if (buf == NULL)
- return NULL;
-
- wpabuf_put_u8(buf, data->fast_version);
-
- res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
- plain, plain_len, wpabuf_put(buf, 0),
- data->ssl.tls_out_limit);
- if (res < 0) {
- wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt Phase 2 "
- "data");
- wpabuf_free(buf);
- return NULL;
- }
-
- wpabuf_put(buf, res);
- eap_update_len(buf);
-
- return buf;
-}
-
-
-static struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf)
-{
- struct wpabuf *e;
- 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");
- e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
- if (e == NULL) {
- wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
- "for TLV encapsulation");
- wpabuf_free(buf);
- return NULL;
- }
- tlv = wpabuf_put(e, sizeof(*tlv));
- tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
- EAP_TLV_EAP_PAYLOAD_TLV);
- tlv->length = host_to_be16(wpabuf_len(buf));
- wpabuf_put_buf(e, buf);
- wpabuf_free(buf);
- return e;
-}
-
-
static struct wpabuf * eap_fast_build_phase2_req(struct eap_sm *sm,
struct eap_fast_data *data,
u8 id)
@@ -686,27 +558,40 @@
{
struct wpabuf *buf;
struct eap_tlv_result_tlv *result;
- struct eap_tlv_crypto_binding__tlv *binding;
- int type;
-
- buf = wpabuf_alloc(sizeof(*result) + sizeof(*binding));
+ struct eap_tlv_crypto_binding_tlv *binding;
+
+ buf = wpabuf_alloc(2 * sizeof(*result) + sizeof(*binding));
if (buf == NULL)
return NULL;
- if (data->send_new_pac || data->anon_provisioning) {
- type = EAP_TLV_INTERMEDIATE_RESULT_TLV;
+ if (data->send_new_pac || data->anon_provisioning ||
+ data->phase2_method)
data->final_result = 0;
- } else {
- type = EAP_TLV_RESULT_TLV;
+ else
data->final_result = 1;
- }
-
- /* Result TLV */
- wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)");
- result = wpabuf_put(buf, sizeof(*result));
- 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);
+
+ if (!data->final_result || data->eap_seq > 1) {
+ /* Intermediate-Result */
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add Intermediate-Result TLV "
+ "(status=SUCCESS)");
+ result = wpabuf_put(buf, sizeof(*result));
+ result->tlv_type = host_to_be16(
+ EAP_TLV_TYPE_MANDATORY |
+ EAP_TLV_INTERMEDIATE_RESULT_TLV);
+ result->length = host_to_be16(2);
+ result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
+ }
+
+ if (data->final_result) {
+ /* Result TLV */
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV "
+ "(status=SUCCESS)");
+ result = wpabuf_put(buf, sizeof(*result));
+ result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+ EAP_TLV_RESULT_TLV);
+ result->length = host_to_be16(2);
+ result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
+ }
/* Crypto-Binding TLV */
binding = wpabuf_put(buf, sizeof(*binding));
@@ -737,7 +622,8 @@
* Compound-MAC = HMAC-SHA1( CMK, Crypto-Binding TLV )
*/
- hmac_sha1(data->cmk, 20, (u8 *) binding, sizeof(*binding),
+ hmac_sha1(data->cmk, EAP_FAST_CMK_LEN,
+ (u8 *) binding, sizeof(*binding),
binding->compound_mac);
wpa_printf(MSG_DEBUG, "EAP-FAST: Add Crypto-Binding TLV: Version %d "
@@ -756,45 +642,80 @@
static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
struct eap_fast_data *data)
{
- u8 pac_key[2 + EAP_FAST_PAC_KEY_LEN + 6];
- u8 pac_opaque[8 + EAP_FAST_PAC_KEY_LEN + 8];
+ u8 pac_key[EAP_FAST_PAC_KEY_LEN];
+ u8 *pac_buf, *pac_opaque;
struct wpabuf *buf;
u8 *pos;
- size_t buf_len, srv_id_len;
+ size_t buf_len, srv_id_len, pac_len;
struct eap_tlv_hdr *pac_tlv;
- struct pac_tlv_hdr *hdr, *pac_info;
+ struct pac_tlv_hdr *pac_info;
struct eap_tlv_result_tlv *result;
struct os_time now;
+ if (os_get_random(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 ||
+ os_get_time(&now) < 0)
+ return NULL;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key",
+ pac_key, EAP_FAST_PAC_KEY_LEN);
+
+ pac_len = (2 + EAP_FAST_PAC_KEY_LEN) + (2 + 4) +
+ (2 + sm->identity_len) + 8;
+ pac_buf = os_malloc(pac_len);
+ if (pac_buf == NULL)
+ return NULL;
+
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_buf;
+ *pos++ = PAC_OPAQUE_TYPE_KEY;
+ *pos++ = EAP_FAST_PAC_KEY_LEN;
+ os_memcpy(pos, pac_key, EAP_FAST_PAC_KEY_LEN);
+ pos += 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;
-
+ pos += 4;
+
+ if (sm->identity) {
+ *pos++ = PAC_OPAQUE_TYPE_IDENTITY;
+ *pos++ = sm->identity_len;
+ os_memcpy(pos, sm->identity, sm->identity_len);
+ pos += sm->identity_len;
+ }
+
+ pac_len = pos - pac_buf;
+ if (pac_len % 8) {
+ *pos++ = PAC_OPAQUE_TYPE_PAD;
+ pac_len++;
+ }
+
+ pac_opaque = os_malloc(pac_len + 8);
+ if (pac_opaque == NULL) {
+ os_free(pac_buf);
+ return NULL;
+ }
+ if (aes_wrap(data->pac_opaque_encr, pac_len / 8, pac_buf,
+ pac_opaque) < 0) {
+ os_free(pac_buf);
+ os_free(pac_opaque);
+ return NULL;
+ }
+ os_free(pac_buf);
+
+ pac_len += 8;
wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
- pac_opaque, sizeof(pac_opaque));
+ pac_opaque, pac_len);
buf_len = sizeof(*pac_tlv) +
- sizeof(*hdr) + EAP_FAST_PAC_KEY_LEN +
- sizeof(*hdr) + sizeof(pac_opaque) +
+ sizeof(struct pac_tlv_hdr) + EAP_FAST_PAC_KEY_LEN +
+ sizeof(struct pac_tlv_hdr) + pac_len +
2 * srv_id_len + 100 + sizeof(*result);
buf = wpabuf_alloc(buf_len);
- if (buf == NULL)
- return NULL;
+ if (buf == NULL) {
+ os_free(pac_opaque);
+ return NULL;
+ }
/* PAC TLV */
wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV");
@@ -803,45 +724,30 @@
EAP_TLV_PAC_TLV);
/* PAC-Key */
- hdr = wpabuf_put(buf, sizeof(*hdr));
- hdr->type = host_to_be16(PAC_TYPE_PAC_KEY);
- hdr->len = host_to_be16(EAP_FAST_PAC_KEY_LEN);
- wpabuf_put_data(buf, pac_key + 2, EAP_FAST_PAC_KEY_LEN);
+ eap_fast_put_tlv(buf, PAC_TYPE_PAC_KEY, pac_key, EAP_FAST_PAC_KEY_LEN);
/* PAC-Opaque */
- hdr = wpabuf_put(buf, sizeof(*hdr));
- hdr->type = host_to_be16(PAC_TYPE_PAC_OPAQUE);
- hdr->len = host_to_be16(sizeof(pac_opaque));
- wpabuf_put_data(buf, pac_opaque, sizeof(pac_opaque));
+ eap_fast_put_tlv(buf, PAC_TYPE_PAC_OPAQUE, pac_opaque, pac_len);
+ os_free(pac_opaque);
/* PAC-Info */
pac_info = wpabuf_put(buf, sizeof(*pac_info));
pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO);
/* PAC-Lifetime (inside PAC-Info) */
- hdr = wpabuf_put(buf, sizeof(*hdr));
- hdr->type = host_to_be16(PAC_TYPE_CRED_LIFETIME);
- hdr->len = host_to_be16(4);
+ eap_fast_put_tlv_hdr(buf, PAC_TYPE_CRED_LIFETIME, 4);
wpabuf_put_be32(buf, now.sec + PAC_KEY_LIFETIME);
/* A-ID (inside PAC-Info) */
- hdr = wpabuf_put(buf, sizeof(*hdr));
- hdr->type = host_to_be16(PAC_TYPE_A_ID);
- hdr->len = host_to_be16(srv_id_len);
- wpabuf_put_data(buf, data->srv_id, srv_id_len);
+ eap_fast_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, srv_id_len);
/* Note: headers may be misaligned after A-ID */
/* A-ID-Info (inside PAC-Info) */
- hdr = wpabuf_put(buf, sizeof(*hdr));
- WPA_PUT_BE16((u8 *) &hdr->type, PAC_TYPE_A_ID_INFO);
- WPA_PUT_BE16((u8 *) &hdr->len, srv_id_len);
- wpabuf_put_data(buf, data->srv_id, srv_id_len);
+ eap_fast_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id, srv_id_len);
/* PAC-Type (inside PAC-Info) */
- hdr = wpabuf_put(buf, sizeof(*hdr));
- WPA_PUT_BE16((u8 *) &hdr->type, PAC_TYPE_PAC_TYPE);
- WPA_PUT_BE16((u8 *) &hdr->len, 2);
+ eap_fast_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2);
wpabuf_put_be16(buf, PAC_TYPE_TUNNEL_PAC);
/* Update PAC-Info and PAC TLV Length fields */
@@ -864,22 +770,45 @@
static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id)
{
struct eap_fast_data *data = priv;
- struct wpabuf *req;
+ struct wpabuf *req = NULL;
struct wpabuf *encr;
- if (data->state == START)
+ if (data->ssl.state == FRAG_ACK) {
+ return eap_server_tls_build_ack(id, EAP_TYPE_FAST,
+ data->fast_version);
+ }
+
+ if (data->ssl.state == WAIT_FRAG_ACK) {
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST,
+ data->fast_version, id);
+ }
+
+ switch (data->state) {
+ case START:
return eap_fast_build_start(sm, data, id);
-
- if (data->state == PHASE1)
- return eap_fast_build_req(sm, data, id);
-
- switch (data->state) {
+ case PHASE1:
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (eap_fast_phase1_done(sm, data) < 0)
+ return NULL;
+ }
+ break;
case PHASE2_ID:
case PHASE2_METHOD:
req = eap_fast_build_phase2_req(sm, data, id);
break;
case CRYPTO_BINDING:
req = eap_fast_build_crypto_binding(sm, data);
+ if (data->phase2_method) {
+ /*
+ * Include the start of the next EAP method in the
+ * sequence in the same message with Crypto-Binding to
+ * save a round-trip.
+ */
+ struct wpabuf *eap;
+ eap = eap_fast_build_phase2_req(sm, data, id);
+ req = wpabuf_concat(req, eap);
+ eap_fast_state(data, PHASE2_METHOD);
+ }
break;
case REQUEST_PAC:
req = eap_fast_build_pac(sm, data);
@@ -890,16 +819,21 @@
return NULL;
}
- if (req == NULL)
- return NULL;
-
- wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs",
- req);
- encr = eap_fast_encrypt(sm, data, id, wpabuf_mhead(req),
- wpabuf_len(req));
- wpabuf_free(req);
-
- return encr;
+ if (req) {
+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 "
+ "TLVs", req);
+ encr = eap_server_tls_encrypt(sm, &data->ssl,
+ wpabuf_mhead(req),
+ wpabuf_len(req));
+ wpabuf_free(req);
+
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = encr;
+ }
+
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST,
+ data->fast_version, id);
}
@@ -971,6 +905,16 @@
left = in_len - sizeof(*hdr);
wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; "
"allowed types", pos + 1, left - 1);
+#ifdef EAP_TNC
+ if (m && m->vendor == EAP_VENDOR_IETF &&
+ m->method == EAP_TYPE_TNC) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required "
+ "TNC negotiation");
+ next_type = eap_fast_req_failure(sm, data);
+ eap_fast_phase2_init(sm, data, next_type);
+ return;
+ }
+#endif /* EAP_TNC */
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 !=
@@ -1033,9 +977,18 @@
wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type);
break;
case PHASE2_METHOD:
+ case CRYPTO_BINDING:
eap_fast_update_icmk(sm, data);
eap_fast_state(data, CRYPTO_BINDING);
+ data->eap_seq++;
next_type = EAP_TYPE_NONE;
+#ifdef EAP_TNC
+ if (sm->tnc && !data->tnc_started) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC");
+ next_type = EAP_TYPE_TNC;
+ data->tnc_started = 1;
+ }
+#endif /* EAP_TNC */
break;
case FAILURE:
break;
@@ -1082,144 +1035,6 @@
"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;
}
@@ -1271,10 +1086,10 @@
static int eap_fast_validate_crypto_binding(
- struct eap_fast_data *data, struct eap_tlv_crypto_binding__tlv *b,
+ struct eap_fast_data *data, struct eap_tlv_crypto_binding_tlv *b,
size_t bind_len)
{
- u8 cmac[20];
+ u8 cmac[SHA1_MAC_LEN];
wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: "
"Version %d Received Version %d SubType %d",
@@ -1311,7 +1126,8 @@
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);
+ hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (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",
@@ -1388,11 +1204,6 @@
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 "
@@ -1424,7 +1235,11 @@
}
wpa_printf(MSG_DEBUG, "EAP-FAST: Valid Crypto-Binding TLV "
- "received - authentication completed successfully");
+ "received");
+ if (data->final_result) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
+ "completed successfully");
+ }
if (data->anon_provisioning ||
(tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
@@ -1437,19 +1252,29 @@
wpa_printf(MSG_DEBUG, "EAP-FAST: Server triggered "
"re-keying of Tunnel PAC");
eap_fast_state(data, REQUEST_PAC);
- } else
+ } else if (data->final_result)
eap_fast_state(data, SUCCESS);
+ }
+
+ if (tlv.eap_payload_tlv) {
+ eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv,
+ tlv.eap_payload_tlv_len);
}
}
static void eap_fast_process_phase2(struct eap_sm *sm,
struct eap_fast_data *data,
- const u8 *in_data, size_t in_len)
+ struct wpabuf *in_buf)
{
u8 *in_decrypted;
- int len_decrypted, res;
+ int len_decrypted;
size_t buf_len;
+ u8 *in_data;
+ size_t in_len;
+
+ in_data = wpabuf_mhead(in_buf);
+ in_len = wpabuf_len(in_buf);
wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
@@ -1465,20 +1290,17 @@
return;
}
- /* FIX: get rid of const -> non-const typecast */
- res = eap_server_tls_data_reassemble(sm, &data->ssl, (u8 **) &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;
+ /*
+ * Even though we try to disable TLS compression, it is possible that
+ * this cannot be done with all TLS libraries. Add extra buffer space
+ * to handle the possibility of the decrypted data being longer than
+ * input data.
+ */
+ buf_len += 500;
+ buf_len *= 3;
in_decrypted = os_malloc(buf_len);
if (in_decrypted == NULL) {
- os_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;
@@ -1487,9 +1309,6 @@
len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
in_data, in_len,
in_decrypted, buf_len);
- os_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");
@@ -1515,105 +1334,125 @@
}
-static void eap_fast_process(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static int eap_fast_process_version(struct eap_sm *sm, void *priv,
+ int peer_version)
{
struct eap_fast_data *data = priv;
- const u8 *pos;
- u8 flags;
- size_t left;
- unsigned int tls_msg_len;
- int peer_version;
-
- pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData,
- &left);
- if (pos == NULL || left < 1)
- return;
- flags = *pos++;
- left--;
- wpa_printf(MSG_DEBUG, "EAP-FAST: Received packet(len=%lu) - "
- "Flags 0x%02x", (unsigned long) wpabuf_len(respData),
- flags);
- data->peer_version = peer_version = flags & EAP_PEAP_VERSION_MASK;
+
+ data->peer_version = peer_version;
+
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;
- }
+ return -1;
+ }
+
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;
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
- }
- pos += 4;
- left -= 4;
- }
+
+ return 0;
+}
+
+
+static int eap_fast_process_phase1(struct eap_sm *sm,
+ struct eap_fast_data *data)
+{
+ if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: TLS processing failed");
+ eap_fast_state(data, FAILURE);
+ return -1;
+ }
+
+ if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+ wpabuf_len(data->ssl.out_buf) > 0)
+ return 1;
+
+ /*
+ * 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.
+ */
+
+ return eap_fast_phase1_done(sm, data);
+}
+
+
+static void eap_fast_process_phase2_start(struct eap_sm *sm,
+ struct eap_fast_data *data)
+{
+ u8 next_type;
+
+ if (data->identity) {
+ os_free(sm->identity);
+ sm->identity = data->identity;
+ data->identity = NULL;
+ sm->identity_len = data->identity_len;
+ data->identity_len = 0;
+ sm->require_identity_match = 1;
+ 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);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Identity already "
+ "known - skip Phase 2 Identity Request");
+ next_type = sm->user->methods[0].method;
+ sm->user_eap_method_index = 1;
+ }
+
+ eap_fast_state(data, PHASE2_METHOD);
+ } else {
+ eap_fast_state(data, PHASE2_ID);
+ next_type = EAP_TYPE_IDENTITY;
+ }
+
+ eap_fast_phase2_init(sm, data, next_type);
+}
+
+
+static void eap_fast_process_msg(struct eap_sm *sm, void *priv,
+ const struct wpabuf *respData)
+{
+ struct eap_fast_data *data = priv;
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)
+ if (eap_fast_process_phase1(sm, data))
break;
/* fall through to PHASE2_START */
case PHASE2_START:
- eap_fast_state(data, PHASE2_ID);
- eap_fast_phase2_init(sm, data, EAP_TYPE_IDENTITY);
+ eap_fast_process_phase2_start(sm, data);
break;
case PHASE2_ID:
case PHASE2_METHOD:
case CRYPTO_BINDING:
case REQUEST_PAC:
- eap_fast_process_phase2(sm, data, pos, left);
+ eap_fast_process_phase2(sm, data, data->ssl.in_buf);
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");
+}
+
+
+static void eap_fast_process(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
+{
+ struct eap_fast_data *data = priv;
+ if (eap_server_tls_process(sm, &data->ssl, respData, data,
+ EAP_TYPE_FAST, eap_fast_process_version,
+ eap_fast_process_msg) < 0)
eap_fast_state(data, FAILURE);
- }
}
@@ -1632,20 +1471,11 @@
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);
+ eap_fast_derive_eap_msk(data->simck, eapKeyData);
*len = EAP_FAST_KEY_LEN;
return eapKeyData;
@@ -1660,22 +1490,11 @@
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);
-
+ eap_fast_derive_eap_emsk(data->simck, eapKeyData);
*len = EAP_EMSK_LEN;
return eapKeyData;
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c Sat Jun 14 00:26:56 2008
@@ -134,14 +134,26 @@
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 (sm->identity && sm->require_identity_match &&
+ (pos2 - pos != (int) sm->identity_len ||
+ os_memcmp(pos, sm->identity, sm->identity_len))) {
+ wpa_printf(MSG_DEBUG, "EAP-GTC: Phase 2 Identity did "
+ "not match with required Identity");
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Expected "
+ "identity",
+ sm->identity, sm->identity_len);
+ data->state = FAILURE;
+ return;
+ } else {
+ 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 "
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h Sat Jun 14 00:26:56 2008
@@ -150,12 +150,13 @@
void *eap_method_priv;
u8 *identity;
size_t identity_len;
+ /* Whether Phase 2 method should validate identity match */
+ int require_identity_match;
int lastId; /* Identifier used in the last EAP-Packet */
struct eap_user *user;
int user_eap_method_index;
int init_phase2;
void *ssl_ctx;
- enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
void *eap_sim_db_priv;
Boolean backend_auth;
Boolean update_user;
@@ -172,6 +173,7 @@
u8 *pac_opaque_encr_key;
char *eap_fast_a_id;
int eap_sim_aka_result_ind;
+ int tnc;
};
int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_ikev2.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_ikev2.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_ikev2.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_ikev2.c Sat Jun 14 00:26:56 2008
@@ -416,6 +416,9 @@
else
eap_ikev2_state(data, FRAG_ACK);
return;
+ } else if (data->state == FRAG_ACK) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received");
+ data->state = MSG;
}
if (data->in_buf == NULL) {
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c Sat Jun 14 00:26:56 2008
@@ -261,6 +261,13 @@
}
#endif /* EAP_IKEV2 */
+#ifdef EAP_TNC
+ if (ret == 0) {
+ int eap_server_tnc_register(void);
+ ret = eap_server_tnc_register();
+ }
+#endif /* EAP_TNC */
+
return ret;
}
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_peap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_peap.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_peap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_peap.c Sat Jun 14 00:26:56 2008
@@ -15,10 +15,13 @@
#include "includes.h"
#include "common.h"
+#include "sha1.h"
#include "eap_i.h"
#include "eap_tls_common.h"
#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_peap_common.h"
#include "tls.h"
+#include "tncs.h"
/* Maximum supported PEAP version
@@ -36,15 +39,26 @@
struct eap_ssl_data ssl;
enum {
START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID,
- PHASE2_METHOD,
+ PHASE2_METHOD, PHASE2_SOH,
PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE
} state;
int peap_version;
+ int recv_version;
const struct eap_method *phase2_method;
void *phase2_priv;
int force_version;
struct wpabuf *pending_phase2_resp;
+ enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
+ int crypto_binding_sent;
+ int crypto_binding_used;
+ enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
+ u8 binding_nonce[32];
+ u8 ipmk[40];
+ u8 cmk[20];
+ u8 *phase2_key;
+ size_t phase2_key_len;
+ struct wpabuf *soh_response;
};
@@ -63,6 +77,8 @@
return "PHASE2_ID";
case PHASE2_METHOD:
return "PHASE2_METHOD";
+ case PHASE2_SOH:
+ return "PHASE2_SOH";
case PHASE2_TLV:
return "PHASE2_TLV";
case SUCCESS_REQ:
@@ -115,43 +131,37 @@
}
-static EapType eap_peap_req_success(struct eap_sm *sm,
- struct eap_peap_data *data)
+static void eap_peap_req_success(struct eap_sm *sm,
+ struct eap_peap_data *data)
{
if (data->state == FAILURE || data->state == FAILURE_REQ) {
eap_peap_state(data, FAILURE);
- return EAP_TYPE_NONE;
+ return;
}
if (data->peap_version == 0) {
- sm->tlv_request = TLV_REQ_SUCCESS;
+ data->tlv_request = TLV_REQ_SUCCESS;
eap_peap_state(data, PHASE2_TLV);
- return EAP_TYPE_TLV;
} else {
eap_peap_state(data, SUCCESS_REQ);
- return EAP_TYPE_NONE;
- }
-}
-
-
-static EapType eap_peap_req_failure(struct eap_sm *sm,
- struct eap_peap_data *data)
+ }
+}
+
+
+static void eap_peap_req_failure(struct eap_sm *sm,
+ struct eap_peap_data *data)
{
if (data->state == FAILURE || data->state == FAILURE_REQ ||
- data->state == SUCCESS_REQ ||
- (data->phase2_method &&
- data->phase2_method->method == EAP_TYPE_TLV)) {
+ data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) {
eap_peap_state(data, FAILURE);
- return EAP_TYPE_NONE;
+ return;
}
if (data->peap_version == 0) {
- sm->tlv_request = TLV_REQ_FAILURE;
+ data->tlv_request = TLV_REQ_FAILURE;
eap_peap_state(data, PHASE2_TLV);
- return EAP_TYPE_TLV;
} else {
eap_peap_state(data, FAILURE_REQ);
- return EAP_TYPE_NONE;
}
}
@@ -172,6 +182,7 @@
data->peap_version = data->force_version;
}
data->state = START;
+ data->crypto_binding = OPTIONAL_BINDING;
if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
@@ -192,6 +203,8 @@
data->phase2_method->reset(sm, data->phase2_priv);
eap_server_tls_ssl_deinit(sm, &data->ssl);
wpabuf_free(data->pending_phase2_resp);
+ os_free(data->phase2_key);
+ wpabuf_free(data->soh_response);
os_free(data);
}
@@ -218,64 +231,6 @@
}
-static struct wpabuf * eap_peap_build_req(struct eap_sm *sm,
- struct eap_peap_data *data, u8 id)
-{
- int res;
- struct wpabuf *req;
-
- res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_PEAP,
- data->peap_version, id, &req);
-
- if (data->peap_version < 2 &&
- tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, starting "
- "Phase2");
- eap_peap_state(data, PHASE2_START);
- }
-
- if (res == 1)
- return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
- data->peap_version);
- return req;
-}
-
-
-static struct wpabuf * eap_peap_encrypt(struct eap_sm *sm,
- struct eap_peap_data *data,
- u8 id, const u8 *plain,
- size_t plain_len)
-{
- int res;
- struct wpabuf *buf;
-
- /* TODO: add support for fragmentation, if needed. This will need to
- * add TLS Message Length field, if the frame is fragmented. */
- buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP,
- 1 + data->ssl.tls_out_limit,
- EAP_CODE_REQUEST, id);
- if (buf == NULL)
- return NULL;
-
- wpabuf_put_u8(buf, data->peap_version);
-
- res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
- plain, plain_len, wpabuf_put(buf, 0),
- data->ssl.tls_out_limit);
- if (res < 0) {
- wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt Phase 2 "
- "data");
- wpabuf_free(buf);
- return NULL;
- }
-
- wpabuf_put(buf, res);
- eap_update_len(buf);
-
- return buf;
-}
-
-
static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
struct eap_peap_data *data,
u8 id)
@@ -284,6 +239,10 @@
const u8 *req;
size_t req_len;
+ if (data->phase2_method == NULL || data->phase2_priv == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready");
+ return NULL;
+ }
buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
if (data->peap_version >= 2 && buf)
buf = eap_peapv2_tlv_eap_payload(buf);
@@ -301,7 +260,198 @@
req_len -= sizeof(struct eap_hdr);
}
- encr_req = eap_peap_encrypt(sm, data, id, req, req_len);
+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
+ wpabuf_free(buf);
+
+ return encr_req;
+}
+
+
+#ifdef EAP_TNC
+static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ u8 id)
+{
+ struct wpabuf *buf1, *buf, *encr_req;
+ const u8 *req;
+ size_t req_len;
+
+ buf1 = tncs_build_soh_request();
+ if (buf1 == NULL)
+ return NULL;
+
+ buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1),
+ EAP_CODE_REQUEST, id);
+ if (buf == NULL) {
+ wpabuf_free(buf1);
+ return NULL;
+ }
+ wpabuf_put_buf(buf, buf1);
+ wpabuf_free(buf1);
+
+ req = wpabuf_head(buf);
+ req_len = wpabuf_len(buf);
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data",
+ req, req_len);
+
+ req += sizeof(struct eap_hdr);
+ req_len -= sizeof(struct eap_hdr);
+
+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
+ wpabuf_free(buf);
+
+ return encr_req;
+}
+#endif /* EAP_TNC */
+
+
+static void eap_peap_get_isk(struct eap_peap_data *data,
+ u8 *isk, size_t isk_len)
+{
+ size_t key_len;
+
+ os_memset(isk, 0, isk_len);
+ if (data->phase2_key == NULL)
+ return;
+
+ key_len = data->phase2_key_len;
+ if (key_len > isk_len)
+ key_len = isk_len;
+ os_memcpy(isk, data->phase2_key, key_len);
+}
+
+
+static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
+{
+ u8 *tk;
+ u8 isk[32], imck[60];
+
+ /*
+ * Tunnel key (TK) is the first 60 octets of the key generated by
+ * phase 1 of PEAP (based on TLS).
+ */
+ tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
+ EAP_TLS_KEY_LEN);
+ if (tk == NULL)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
+
+ eap_peap_get_isk(data, isk, sizeof(isk));
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
+
+ /*
+ * IPMK Seed = "Inner Methods Compound Keys" | ISK
+ * TempKey = First 40 octets of TK
+ * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
+ * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
+ * in the end of the label just before ISK; is that just a typo?)
+ */
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
+ peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck));
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
+ imck, sizeof(imck));
+
+ os_free(tk);
+
+ /* TODO: fast-connect: IPMK|CMK = TK */
+ os_memcpy(data->ipmk, imck, 40);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
+ os_memcpy(data->cmk, imck + 40, 20);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
+
+ return 0;
+}
+
+
+static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ u8 id)
+{
+ struct wpabuf *buf, *encr_req;
+ size_t len;
+
+ len = 6; /* Result TLV */
+ if (data->crypto_binding != NO_BINDING)
+ len += 60; /* Cryptobinding TLV */
+#ifdef EAP_TNC
+ if (data->soh_response)
+ len += wpabuf_len(data->soh_response);
+#endif /* EAP_TNC */
+
+ buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
+ EAP_CODE_REQUEST, id);
+ if (buf == NULL)
+ return NULL;
+
+ wpabuf_put_u8(buf, 0x80); /* Mandatory */
+ wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV);
+ /* Length */
+ wpabuf_put_be16(buf, 2);
+ /* Status */
+ wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?
+ EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);
+
+ if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
+ data->crypto_binding != NO_BINDING) {
+ u8 *mac;
+ u8 eap_type = EAP_TYPE_PEAP;
+ const u8 *addr[2];
+ size_t len[2];
+ u16 tlv_type;
+
+#ifdef EAP_TNC
+ if (data->soh_response) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH "
+ "Response TLV");
+ wpabuf_put_buf(buf, data->soh_response);
+ wpabuf_free(data->soh_response);
+ data->soh_response = NULL;
+ }
+#endif /* EAP_TNC */
+
+ if (eap_peap_derive_cmk(sm, data) < 0 ||
+ os_get_random(data->binding_nonce, 32)) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+ addr[0] = wpabuf_put(buf, 0);
+ len[0] = 60;
+ addr[1] = &eap_type;
+ len[1] = 1;
+
+ tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
+ if (data->peap_version >= 2)
+ tlv_type |= EAP_TLV_TYPE_MANDATORY;
+ wpabuf_put_be16(buf, tlv_type);
+ wpabuf_put_be16(buf, 56);
+
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ wpabuf_put_u8(buf, data->peap_version); /* Version */
+ wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */
+ wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */
+ wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
+ mac = wpabuf_put(buf, 20); /* Compound_MAC */
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK",
+ data->cmk, 20);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
+ addr[0], len[0]);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
+ addr[1], len[1]);
+ hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",
+ mac, SHA1_MAC_LEN);
+ data->crypto_binding_sent = 1;
+ }
+
+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
+ buf);
+
+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, wpabuf_head(buf),
+ wpabuf_len(buf));
wpabuf_free(buf);
return encr_req;
@@ -328,7 +478,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
(u8 *) hdr, req_len);
- encr_req = eap_peap_encrypt(sm, data, id, (u8 *) hdr, req_len);
+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, (u8 *) hdr, req_len);
os_free(hdr);
return encr_req;
@@ -338,26 +488,67 @@
static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
{
struct eap_peap_data *data = priv;
+
+ if (data->ssl.state == FRAG_ACK) {
+ return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
+ data->peap_version);
+ }
+
+ if (data->ssl.state == WAIT_FRAG_ACK) {
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
+ data->peap_version, id);
+ }
switch (data->state) {
case START:
return eap_peap_build_start(sm, data, id);
case PHASE1:
case PHASE1_ID2:
- return eap_peap_build_req(sm, data, id);
+ if (data->peap_version < 2 &&
+ tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
+ "starting Phase2");
+ eap_peap_state(data, PHASE2_START);
+ }
+ break;
case PHASE2_ID:
case PHASE2_METHOD:
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_peap_build_phase2_req(sm, data, id);
+ break;
+#ifdef EAP_TNC
+ case PHASE2_SOH:
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_peap_build_phase2_soh(sm, data, id);
+ break;
+#endif /* EAP_TNC */
case PHASE2_TLV:
- return eap_peap_build_phase2_req(sm, data, id);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_peap_build_phase2_tlv(sm, data, id);
+ break;
case SUCCESS_REQ:
- return eap_peap_build_phase2_term(sm, data, id, 1);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_peap_build_phase2_term(sm, data, id,
+ 1);
+ break;
case FAILURE_REQ:
- return eap_peap_build_phase2_term(sm, data, id, 0);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_peap_build_phase2_term(sm, data, id,
+ 0);
+ break;
default:
wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
__func__, data->state);
return NULL;
}
+
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
+ data->peap_version, id);
}
@@ -397,6 +588,306 @@
}
+static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ const u8 *crypto_tlv,
+ size_t crypto_tlv_len)
+{
+ u8 buf[61], mac[SHA1_MAC_LEN];
+ const u8 *pos;
+
+ if (crypto_tlv_len != 4 + 56) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
+ "length %d", (int) crypto_tlv_len);
+ return -1;
+ }
+
+ pos = crypto_tlv;
+ pos += 4; /* TLV header */
+ if (pos[1] != data->peap_version) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
+ "mismatch (was %d; expected %d)",
+ pos[1], data->peap_version);
+ return -1;
+ }
+
+ if (pos[3] != 1) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
+ "SubType %d", pos[3]);
+ return -1;
+ }
+ pos += 4;
+ pos += 32; /* Nonce */
+
+ /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+ os_memcpy(buf, crypto_tlv, 60);
+ os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
+ buf[60] = EAP_TYPE_PEAP;
+ hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
+
+ if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
+ "cryptobinding TLV");
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data",
+ buf, 61);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
+
+ return 0;
+}
+
+
+static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ struct wpabuf *in_data)
+{
+ const u8 *pos;
+ size_t left;
+ const u8 *result_tlv = NULL, *crypto_tlv = NULL;
+ size_t result_tlv_len = 0, crypto_tlv_len = 0;
+ int tlv_type, mandatory, tlv_len;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left);
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header");
+ return;
+ }
+
+ /* Parse TLVs */
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left);
+ while (left >= 4) {
+ mandatory = !!(pos[0] & 0x80);
+ tlv_type = pos[0] & 0x3f;
+ tlv_type = (tlv_type << 8) | pos[1];
+ tlv_len = ((int) pos[2] << 8) | pos[3];
+ pos += 4;
+ left -= 4;
+ if ((size_t) tlv_len > left) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
+ "(tlv_len=%d left=%lu)", tlv_len,
+ (unsigned long) left);
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+ switch (tlv_type) {
+ case EAP_TLV_RESULT_TLV:
+ result_tlv = pos;
+ result_tlv_len = tlv_len;
+ break;
+ case EAP_TLV_CRYPTO_BINDING_TLV:
+ crypto_tlv = pos;
+ crypto_tlv_len = tlv_len;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
+ "%d%s", tlv_type,
+ mandatory ? " (mandatory)" : "");
+ if (mandatory) {
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+ /* Ignore this TLV, but process other TLVs */
+ break;
+ }
+
+ pos += tlv_len;
+ left -= tlv_len;
+ }
+ if (left) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
+ "Request (left=%lu)", (unsigned long) left);
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+
+ /* Process supported TLVs */
+ if (crypto_tlv && data->crypto_binding_sent) {
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
+ crypto_tlv, crypto_tlv_len);
+ if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
+ crypto_tlv_len + 4) < 0) {
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+ data->crypto_binding_used = 1;
+ } else if (!crypto_tlv && data->crypto_binding_sent &&
+ data->crypto_binding == REQUIRE_BINDING) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+
+ if (result_tlv) {
+ int status;
+ const char *requested;
+
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV",
+ result_tlv, result_tlv_len);
+ if (result_tlv_len < 2) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV "
+ "(len=%lu)",
+ (unsigned long) result_tlv_len);
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+ requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" :
+ "Failure";
+ status = WPA_GET_BE16(result_tlv);
+ if (status == EAP_TLV_RESULT_SUCCESS) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
+ "- requested %s", requested);
+ if (data->tlv_request == TLV_REQ_SUCCESS)
+ eap_peap_state(data, SUCCESS);
+ else
+ eap_peap_state(data, FAILURE);
+
+ } else if (status == EAP_TLV_RESULT_FAILURE) {
+ wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
+ "- requested %s", requested);
+ eap_peap_state(data, FAILURE);
+ } else {
+ wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result "
+ "Status %d", status);
+ eap_peap_state(data, FAILURE);
+ }
+ }
+}
+
+
+#ifdef EAP_TNC
+static void eap_peap_process_phase2_soh(struct eap_sm *sm,
+ struct eap_peap_data *data,
+ struct wpabuf *in_data)
+{
+ const u8 *pos, *vpos;
+ size_t left;
+ const u8 *soh_tlv = NULL;
+ size_t soh_tlv_len = 0;
+ int tlv_type, mandatory, tlv_len, vtlv_len;
+ u8 next_type;
+ u32 vendor_id;
+
+ pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP "
+ "Extensions Method header - skip TNC");
+ goto auth_method;
+ }
+
+ /* Parse TLVs */
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left);
+ while (left >= 4) {
+ mandatory = !!(pos[0] & 0x80);
+ tlv_type = pos[0] & 0x3f;
+ tlv_type = (tlv_type << 8) | pos[1];
+ tlv_len = ((int) pos[2] << 8) | pos[3];
+ pos += 4;
+ left -= 4;
+ if ((size_t) tlv_len > left) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
+ "(tlv_len=%d left=%lu)", tlv_len,
+ (unsigned long) left);
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+ switch (tlv_type) {
+ case EAP_TLV_VENDOR_SPECIFIC_TLV:
+ if (tlv_len < 4) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short "
+ "vendor specific TLV (len=%d)",
+ (int) tlv_len);
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+
+ vendor_id = WPA_GET_BE32(pos);
+ if (vendor_id != EAP_VENDOR_MICROSOFT) {
+ if (mandatory) {
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+ break;
+ }
+
+ vpos = pos + 4;
+ mandatory = !!(vpos[0] & 0x80);
+ tlv_type = vpos[0] & 0x3f;
+ tlv_type = (tlv_type << 8) | vpos[1];
+ vtlv_len = ((int) vpos[2] << 8) | vpos[3];
+ vpos += 4;
+ if (vpos + vtlv_len > pos + left) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV "
+ "underrun");
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+
+ if (tlv_type == 1) {
+ soh_tlv = vpos;
+ soh_tlv_len = vtlv_len;
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV "
+ "Type %d%s", tlv_type,
+ mandatory ? " (mandatory)" : "");
+ if (mandatory) {
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+ /* Ignore this TLV, but process other TLVs */
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
+ "%d%s", tlv_type,
+ mandatory ? " (mandatory)" : "");
+ if (mandatory) {
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+ /* Ignore this TLV, but process other TLVs */
+ break;
+ }
+
+ pos += tlv_len;
+ left -= tlv_len;
+ }
+ if (left) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
+ "Request (left=%lu)", (unsigned long) left);
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+
+ /* Process supported TLVs */
+ if (soh_tlv) {
+ int failure = 0;
+ wpabuf_free(data->soh_response);
+ data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len,
+ &failure);
+ if (failure) {
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received");
+ eap_peap_state(data, FAILURE);
+ return;
+ }
+
+auth_method:
+ eap_peap_state(data, PHASE2_METHOD);
+ next_type = sm->user->methods[0].method;
+ sm->user_eap_method_index = 1;
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
+ eap_peap_phase2_init(sm, data, next_type);
+}
+#endif /* EAP_TNC */
+
+
static void eap_peap_process_phase2_response(struct eap_sm *sm,
struct eap_peap_data *data,
struct wpabuf *in_data)
@@ -405,6 +896,18 @@
const struct eap_hdr *hdr;
const u8 *pos;
size_t left;
+
+ if (data->state == PHASE2_TLV) {
+ eap_peap_process_phase2_tlv(sm, data, in_data);
+ return;
+ }
+
+#ifdef EAP_TNC
+ if (data->state == PHASE2_SOH) {
+ eap_peap_process_phase2_soh(sm, data, in_data);
+ return;
+ }
+#endif /* EAP_TNC */
if (data->phase2_priv == NULL) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not "
@@ -428,7 +931,8 @@
wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
next_type);
} else {
- next_type = eap_peap_req_failure(sm, data);
+ eap_peap_req_failure(sm, data);
+ next_type = EAP_TYPE_NONE;
}
eap_peap_phase2_init(sm, data, next_type);
return;
@@ -454,22 +958,64 @@
if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
- next_type = eap_peap_req_failure(sm, data);
+ eap_peap_req_failure(sm, data);
+ next_type = EAP_TYPE_NONE;
eap_peap_phase2_init(sm, data, next_type);
return;
+ }
+
+ os_free(data->phase2_key);
+ if (data->phase2_method->getKey) {
+ data->phase2_key = data->phase2_method->getKey(
+ sm, data->phase2_priv, &data->phase2_key_len);
+ if (data->phase2_key == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
+ "failed");
+ eap_peap_req_failure(sm, data);
+ eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
+ return;
+ }
+
+ if (data->phase2_key_len == 32 &&
+ data->phase2_method->vendor == EAP_VENDOR_IETF &&
+ data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
+ /*
+ * Microsoft uses reverse order for MS-MPPE keys in
+ * EAP-PEAP when compared to EAP-FAST derivation of
+ * ISK. Swap the keys here to get the correct ISK for
+ * EAP-PEAPv0 cryptobinding.
+ */
+ u8 tmp[16];
+ os_memcpy(tmp, data->phase2_key, 16);
+ os_memcpy(data->phase2_key, data->phase2_key + 16, 16);
+ os_memcpy(data->phase2_key + 16, tmp, 16);
+ }
}
switch (data->state) {
case PHASE1_ID2:
case PHASE2_ID:
+ case PHASE2_SOH:
if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 "
"Identity not found in the user "
"database",
sm->identity, sm->identity_len);
- next_type = eap_peap_req_failure(sm, data);
+ eap_peap_req_failure(sm, data);
+ next_type = EAP_TYPE_NONE;
break;
}
+
+#ifdef EAP_TNC
+ if (data->state != PHASE2_SOH && sm->tnc &&
+ data->peap_version == 0) {
+ eap_peap_state(data, PHASE2_SOH);
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
+ "TNC (NAP SOH)");
+ next_type = EAP_TYPE_NONE;
+ break;
+ }
+#endif /* EAP_TNC */
eap_peap_state(data, PHASE2_METHOD);
next_type = sm->user->methods[0].method;
@@ -477,15 +1023,8 @@
wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
break;
case PHASE2_METHOD:
- next_type = eap_peap_req_success(sm, data);
- break;
- case PHASE2_TLV:
- if (sm->tlv_request == TLV_REQ_SUCCESS ||
- data->state == SUCCESS_REQ) {
- eap_peap_state(data, SUCCESS);
- } else {
- eap_peap_state(data, FAILURE);
- }
+ eap_peap_req_success(sm, data);
+ next_type = EAP_TYPE_NONE;
break;
case FAILURE:
break;
@@ -502,12 +1041,17 @@
static void eap_peap_process_phase2(struct eap_sm *sm,
struct eap_peap_data *data,
const struct wpabuf *respData,
- const u8 *in_data, size_t in_len)
+ struct wpabuf *in_buf)
{
struct wpabuf *in_decrypted;
- int len_decrypted, res;
+ int len_decrypted;
const struct eap_hdr *hdr;
size_t buf_len, len;
+ u8 *in_data;
+ size_t in_len;
+
+ in_data = wpabuf_mhead(in_buf);
+ in_len = wpabuf_len(in_buf);
wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
@@ -522,20 +1066,17 @@
return;
}
- /* FIX: get rid of const -> non-const typecast */
- res = eap_server_tls_data_reassemble(sm, &data->ssl, (u8 **) &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;
+ /*
+ * Even though we try to disable TLS compression, it is possible that
+ * this cannot be done with all TLS libraries. Add extra buffer space
+ * to handle the possibility of the decrypted data being longer than
+ * input data.
+ */
+ buf_len += 500;
+ buf_len *= 3;
in_decrypted = wpabuf_alloc(buf_len);
if (in_decrypted == NULL) {
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory "
"for decryption");
return;
@@ -545,9 +1086,6 @@
in_data, in_len,
wpabuf_mhead(in_decrypted),
buf_len);
- os_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-PEAP: Failed to decrypt Phase 2 "
"data");
@@ -677,7 +1215,6 @@
{
struct wpabuf *buf, *buf2;
int res;
- u8 *tls_out;
wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 "
"payload in the same message");
@@ -720,50 +1257,28 @@
buf);
/* Append TLS data into the pending buffer after the Server Finished */
- tls_out = os_realloc(data->ssl.tls_out,
- data->ssl.tls_out_len + wpabuf_len(buf));
- if (tls_out == NULL) {
+ if (wpabuf_resize(&data->ssl.out_buf, wpabuf_len(buf)) < 0) {
wpabuf_free(buf);
return -1;
}
-
- os_memcpy(tls_out + data->ssl.tls_out_len, wpabuf_head(buf),
- wpabuf_len(buf));
- data->ssl.tls_out = tls_out;
- data->ssl.tls_out_len += wpabuf_len(buf);
-
+ wpabuf_put_buf(data->ssl.out_buf, buf);
wpabuf_free(buf);
return 0;
}
-static void eap_peap_process(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static int eap_peap_process_version(struct eap_sm *sm, void *priv,
+ int peer_version)
{
struct eap_peap_data *data = priv;
- const u8 *pos;
- u8 flags;
- size_t left;
- unsigned int tls_msg_len;
- int peer_version;
-
- pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData,
- &left);
- if (pos == NULL || left < 1)
- return;
- flags = *pos++;
- left--;
- wpa_printf(MSG_DEBUG, "EAP-PEAP: Received packet(len=%lu) - "
- "Flags 0x%02x", (unsigned long) wpabuf_len(respData),
- flags);
- peer_version = flags & EAP_PEAP_VERSION_MASK;
+
+ data->recv_version = peer_version;
if (data->force_version >= 0 && peer_version != data->force_version) {
wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
" version (forced=%d peer=%d) - reject",
data->force_version, peer_version);
- eap_peap_state(data, FAILURE);
- return;
+ return -1;
}
if (peer_version < data->peap_version) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; "
@@ -771,33 +1286,19 @@
peer_version, data->peap_version, peer_version);
data->peap_version = peer_version;
}
- if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
- if (left < 4) {
- wpa_printf(MSG_INFO, "EAP-PEAP: Short frame with TLS "
- "length");
- eap_peap_state(data, FAILURE);
- return;
- }
- tls_msg_len = WPA_GET_BE32(pos);
- wpa_printf(MSG_DEBUG, "EAP-PEAP: 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;
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
- }
- pos += 4;
- left -= 4;
- }
+
+ return 0;
+}
+
+
+static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
+ const struct wpabuf *respData)
+{
+ struct eap_peap_data *data = priv;
switch (data->state) {
case PHASE1:
- if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) <
- 0) {
- wpa_printf(MSG_INFO, "EAP-PEAP: TLS processing "
- "failed");
+ if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
eap_peap_state(data, FAILURE);
break;
}
@@ -817,8 +1318,9 @@
case PHASE1_ID2:
case PHASE2_ID:
case PHASE2_METHOD:
+ case PHASE2_SOH:
case PHASE2_TLV:
- eap_peap_process_phase2(sm, data, respData, pos, left);
+ eap_peap_process_phase2(sm, data, respData, data->ssl.in_buf);
break;
case SUCCESS_REQ:
eap_peap_state(data, SUCCESS);
@@ -831,12 +1333,17 @@
data->state, __func__);
break;
}
-
- if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
- wpa_printf(MSG_INFO, "EAP-PEAP: Locally detected fatal error "
- "in TLS processing");
+}
+
+
+static void eap_peap_process(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
+{
+ struct eap_peap_data *data = priv;
+ if (eap_server_tls_process(sm, &data->ssl, respData, data,
+ EAP_TYPE_PEAP, eap_peap_process_version,
+ eap_peap_process_msg) < 0)
eap_peap_state(data, FAILURE);
- }
}
@@ -854,6 +1361,31 @@
if (data->state != SUCCESS)
return NULL;
+
+ if (data->crypto_binding_used) {
+ u8 csk[128];
+ /*
+ * Note: It looks like Microsoft implementation requires null
+ * termination for this label while the one used for deriving
+ * IPMK|CMK did not use null termination.
+ */
+ peap_prfplus(data->peap_version, data->ipmk, 40,
+ "Session Key Generating Function",
+ (u8 *) "\00", 1, csk, sizeof(csk));
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
+ eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
+ if (eapKeyData) {
+ os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN);
+ *len = EAP_TLS_KEY_LEN;
+ wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
+ eapKeyData, EAP_TLS_KEY_LEN);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive "
+ "key");
+ }
+
+ return eapKeyData;
+ }
/* TODO: PEAPv1 - different label in some cases */
eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_tls.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_tls.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_tls.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_tls.c Sat Jun 14 00:26:56 2008
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2008, 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,6 +29,32 @@
};
+static const char * eap_tls_state_txt(int state)
+{
+ switch (state) {
+ case START:
+ return "START";
+ case CONTINUE:
+ return "CONTINUE";
+ case SUCCESS:
+ return "SUCCESS";
+ case FAILURE:
+ return "FAILURE";
+ default:
+ return "Unknown?!";
+ }
+}
+
+
+static void eap_tls_state(struct eap_tls_data *data, int state)
+{
+ wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
+ eap_tls_state_txt(data->state),
+ eap_tls_state_txt(state));
+ data->state = state;
+}
+
+
static void * eap_tls_init(struct eap_sm *sm)
{
struct eap_tls_data *data;
@@ -68,52 +94,48 @@
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
"request");
- data->state = FAILURE;
+ eap_tls_state(data, FAILURE);
return NULL;
}
wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
- data->state = CONTINUE;
+ eap_tls_state(data, CONTINUE);
return req;
}
-static struct wpabuf * eap_tls_build_req(struct eap_sm *sm,
- struct eap_tls_data *data, u8 id)
-{
- int res;
- struct wpabuf *req;
-
- res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_TLS, 0,
- id, &req);
-
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
- data->state = SUCCESS;
- }
-
- if (res == 1)
+static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+ struct eap_tls_data *data = priv;
+
+
+ if (data->ssl.state == FRAG_ACK) {
return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
- return req;
-}
-
-
-static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
- struct eap_tls_data *data = priv;
+ }
+
+ if (data->ssl.state == WAIT_FRAG_ACK) {
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0,
+ id);
+ }
switch (data->state) {
case START:
return eap_tls_build_start(sm, data, id);
case CONTINUE:
- return eap_tls_build_req(sm, data, id);
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
+ eap_tls_state(data, SUCCESS);
+ }
+ break;
default:
wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
__func__, data->state);
return NULL;
}
+
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
}
@@ -133,57 +155,28 @@
}
+static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
+ const struct wpabuf *respData)
+{
+ struct eap_tls_data *data = priv;
+ if (data->state == SUCCESS && wpabuf_len(data->ssl.in_buf) == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
+ "handshake message");
+ return;
+ }
+ if (eap_server_tls_phase1(sm, &data->ssl) < 0)
+ eap_tls_state(data, FAILURE);
+}
+
+
static void eap_tls_process(struct eap_sm *sm, void *priv,
struct wpabuf *respData)
{
struct eap_tls_data *data = priv;
- const u8 *pos;
- u8 flags;
- size_t left;
- unsigned int tls_msg_len;
-
- pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &left);
- if (pos == NULL || left < 1)
- return; /* Should not happen - frame already validated */
-
- flags = *pos++;
- left--;
- wpa_printf(MSG_DEBUG, "EAP-TLS: Received packet(len=%lu) - "
- "Flags 0x%02x", (unsigned long) wpabuf_len(respData),
- flags);
- if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
- if (left < 4) {
- wpa_printf(MSG_INFO, "EAP-TLS: Short frame with TLS "
- "length");
- data->state = FAILURE;
- return;
- }
- tls_msg_len = WPA_GET_BE32(pos);
- wpa_printf(MSG_DEBUG, "EAP-TLS: 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;
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
- }
- pos += 4;
- left -= 4;
- }
-
- if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) < 0) {
- wpa_printf(MSG_INFO, "EAP-TLS: TLS processing failed");
- data->state = FAILURE;
- return;
- }
-
- if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
- wpa_printf(MSG_INFO, "EAP-TLS: Locally detected fatal error "
- "in TLS processing");
- data->state = FAILURE;
- return;
- }
+ if (eap_server_tls_process(sm, &data->ssl, respData, data,
+ EAP_TYPE_TLS, NULL, eap_tls_process_msg) <
+ 0)
+ eap_tls_state(data, FAILURE);
}
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.c Sat Jun 14 00:26:56 2008
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2008, 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
@@ -58,8 +58,8 @@
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
{
tls_connection_deinit(sm->ssl_ctx, data->conn);
- os_free(data->tls_in);
- os_free(data->tls_out);
+ os_free(data->in_buf);
+ os_free(data->out_buf);
}
@@ -106,188 +106,305 @@
}
-int eap_server_tls_data_reassemble(struct eap_sm *sm,
- struct eap_ssl_data *data,
- u8 **in_data, size_t *in_len)
-{
- u8 *buf;
-
- if (data->tls_in_left > *in_len || data->tls_in) {
- if (*in_len == 0) {
- wpa_printf(MSG_INFO, "SSL: Empty fragment when trying "
- "to reassemble");
- return -1;
+struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
+ int eap_type, int version, u8 id)
+{
+ struct wpabuf *req;
+ u8 flags;
+ size_t send_len, plen;
+
+ wpa_printf(MSG_DEBUG, "SSL: Generating Request");
+ if (data->out_buf == NULL) {
+ wpa_printf(MSG_ERROR, "SSL: out_buf NULL in %s", __func__);
+ return NULL;
+ }
+
+ flags = version;
+ send_len = wpabuf_len(data->out_buf) - data->out_used;
+ if (1 + send_len > data->tls_out_limit) {
+ send_len = data->tls_out_limit - 1;
+ flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
+ if (data->out_used == 0) {
+ flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
+ send_len -= 4;
}
- if (data->tls_in_len + *in_len > 65536) {
- /* Limit length to avoid rogue peers from causing large
- * memory allocations. */
- os_free(data->tls_in);
- data->tls_in = NULL;
- data->tls_in_len = 0;
+ }
+
+ plen = 1 + send_len;
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
+ plen += 4;
+
+ req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, plen,
+ EAP_CODE_REQUEST, id);
+ if (req == NULL)
+ return NULL;
+
+ wpabuf_put_u8(req, flags); /* Flags */
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
+ wpabuf_put_be32(req, wpabuf_len(data->out_buf));
+
+ wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
+ send_len);
+ data->out_used += send_len;
+
+ if (data->out_used == wpabuf_len(data->out_buf)) {
+ wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
+ "(message sent completely)",
+ (unsigned long) send_len);
+ wpabuf_free(data->out_buf);
+ data->out_buf = NULL;
+ data->out_used = 0;
+ data->state = MSG;
+ } else {
+ wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
+ "(%lu more to send)", (unsigned long) send_len,
+ (unsigned long) wpabuf_len(data->out_buf) -
+ data->out_used);
+ data->state = WAIT_FRAG_ACK;
+ }
+
+ return req;
+}
+
+
+struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version)
+{
+ struct wpabuf *req;
+
+ req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST,
+ id);
+ if (req == NULL)
+ return NULL;
+ wpa_printf(MSG_DEBUG, "SSL: Building ACK");
+ wpabuf_put_u8(req, version); /* Flags */
+ return req;
+}
+
+
+static int eap_server_tls_process_cont(struct eap_ssl_data *data,
+ const u8 *buf, size_t len)
+{
+ /* Process continuation of a pending message */
+ if (len > wpabuf_tailroom(data->in_buf)) {
+ wpa_printf(MSG_DEBUG, "SSL: Fragment overflow");
+ return -1;
+ }
+
+ wpabuf_put_data(data->in_buf, buf, len);
+ wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu "
+ "bytes more", (unsigned long) len,
+ (unsigned long) wpabuf_tailroom(data->in_buf));
+
+ return 0;
+}
+
+
+static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
+ u8 flags, u32 message_length,
+ const u8 *buf, size_t len)
+{
+ /* Process a fragment that is not the last one of the message */
+ if (data->in_buf == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) {
+ wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a "
+ "fragmented packet");
+ return -1;
+ }
+
+ if (data->in_buf == NULL) {
+ /* First fragment of the message */
+
+ /* Limit length to avoid rogue peers from causing large
+ * memory allocations. */
+ if (message_length > 65536) {
wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
" over 64 kB)");
return -1;
}
- buf = os_realloc(data->tls_in, data->tls_in_len + *in_len);
- if (buf == NULL) {
- os_free(data->tls_in);
- data->tls_in = NULL;
- data->tls_in_len = 0;
- wpa_printf(MSG_INFO, "SSL: Could not allocate memory "
- "for TLS data");
+
+ data->in_buf = wpabuf_alloc(message_length);
+ if (data->in_buf == NULL) {
+ wpa_printf(MSG_DEBUG, "SSL: No memory for message");
return -1;
}
- os_memcpy(buf + data->tls_in_len, *in_data, *in_len);
- data->tls_in = buf;
- data->tls_in_len += *in_len;
- if (*in_len > data->tls_in_left) {
- wpa_printf(MSG_INFO, "SSL: more data than TLS message "
- "length indicated");
- data->tls_in_left = 0;
+ wpabuf_put_data(data->in_buf, buf, len);
+ wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first "
+ "fragment, waiting for %lu bytes more",
+ (unsigned long) len,
+ (unsigned long) wpabuf_tailroom(data->in_buf));
+ }
+
+ return 0;
+}
+
+
+int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
+{
+ u8 *next;
+ size_t next_len;
+
+ next = tls_connection_server_handshake(
+ sm->ssl_ctx, data->conn,
+ wpabuf_mhead(data->in_buf),
+ wpabuf_len(data->in_buf),
+ &next_len);
+ if (next == NULL) {
+ wpa_printf(MSG_INFO, "SSL: TLS processing failed");
+ return -1;
+ }
+ if (data->out_buf) {
+ /* This should not happen.. */
+ wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
+ "processing new message");
+ os_free(data->out_buf);
+ WPA_ASSERT(data->out_buf == NULL);
+ }
+ data->out_buf = wpabuf_alloc_ext_data(next, next_len);
+ if (data->out_buf == NULL) {
+ os_free(next);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
+ const u8 **pos, size_t *left)
+{
+ unsigned int tls_msg_len = 0;
+ const u8 *end = *pos + *left;
+
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+ if (*left < 4) {
+ wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
+ "length");
return -1;
}
- data->tls_in_left -= *in_len;
- if (data->tls_in_left > 0) {
- wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
- "data", (unsigned long) data->tls_in_left);
- return 1;
- }
-
- *in_data = data->tls_in;
- *in_len = data->tls_in_len;
- } else
- data->tls_in_left = 0;
-
- return 0;
-}
-
-
-int eap_server_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- const u8 *in_data, size_t in_len)
-{
- WPA_ASSERT(data->tls_out_len == 0 || in_len == 0);
-
- if (data->tls_out_len == 0) {
- u8 *_in_data = (u8 *) in_data; /* FIX: get rid of the typecast
- */
- /* No more data to send out - expect to receive more data from
- * the peer. */
- int res = eap_server_tls_data_reassemble(sm, data, &_in_data,
- &in_len);
- if (res < 0 || res == 1) {
- wpa_printf(MSG_DEBUG, "SSL: data reassembly failed");
- return res;
- }
- /* Full TLS message reassembled - continue handshake processing
- */
- if (data->tls_out) {
- /* This should not happen.. */
- wpa_printf(MSG_INFO, "SSL: eap_tls_process_helper - "
- "pending tls_out data even though "
- "tls_out_len = 0");
- os_free(data->tls_out);
- WPA_ASSERT(data->tls_out == NULL);
- }
- data->tls_out = tls_connection_server_handshake(
- sm->ssl_ctx, data->conn, _in_data, in_len,
- &data->tls_out_len);
-
- /* Clear reassembled input data (if the buffer was needed). */
- data->tls_in_left = data->tls_in_total = data->tls_in_len = 0;
- os_free(data->tls_in);
- data->tls_in = NULL;
- }
-
- if (data->tls_out == NULL) {
- wpa_printf(MSG_DEBUG, "SSL: failed to generate output data");
- data->tls_out_len = 0;
- return -1;
- }
- if (data->tls_out_len == 0) {
- /* TLS negotiation should now be complete since all other cases
- * needing more that should have been catched above based on
- * the TLS Message Length field. */
- wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
- os_free(data->tls_out);
- data->tls_out = NULL;
-
- if (tls_connection_get_read_alerts(sm->ssl_ctx, data->conn)) {
- wpa_printf(MSG_DEBUG, "SSL: Remote end sent a fatal "
- "alert - abort handshake");
+ tls_msg_len = WPA_GET_BE32(*pos);
+ wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
+ tls_msg_len);
+ *pos += 4;
+ *left -= 4;
+ }
+
+ wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
+ "Message Length %u", flags, tls_msg_len);
+
+ if (data->state == WAIT_FRAG_ACK) {
+ if (*left != 0) {
+ wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in "
+ "WAIT_FRAG_ACK state");
return -1;
}
-
+ wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged");
return 1;
}
- wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
- "%lu bytes)",
- (unsigned long) data->tls_out_len - data->tls_out_pos,
- (unsigned long) data->tls_out_len);
+ if (data->in_buf &&
+ eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
+ return -1;
+
+ if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
+ if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
+ *pos, end - *pos) < 0)
+ return -1;
+
+ data->state = FRAG_ACK;
+ return 1;
+ }
+
+ if (data->state == FRAG_ACK) {
+ wpa_printf(MSG_DEBUG, "SSL: All fragments received");
+ data->state = MSG;
+ }
+
+ if (data->in_buf == NULL) {
+ /* Wrap unfragmented messages as wpabuf without extra copy */
+ wpabuf_set(&data->tmpbuf, *pos, end - *pos);
+ data->in_buf = &data->tmpbuf;
+ }
return 0;
}
-int eap_server_tls_buildReq_helper(struct eap_sm *sm,
- struct eap_ssl_data *data,
- int eap_type, int peap_version, u8 id,
- struct wpabuf **out_data)
-{
- size_t len;
- u8 *flags;
- struct wpabuf *req;
- int incl_len;
-
- incl_len = data->tls_out_pos == 0 &&
- data->tls_out_len > data->tls_out_limit;
- req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type,
- 1 + (incl_len ? 4 : 0) + data->tls_out_limit,
- EAP_CODE_REQUEST, id);
- if (req == NULL) {
- *out_data = NULL;
- return -1;
- }
- flags = wpabuf_put(req, 1);
- *flags = peap_version;
- if (incl_len) {
- *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
- wpabuf_put_be32(req, data->tls_out_len);
- }
-
- len = data->tls_out_len - data->tls_out_pos;
- if (len > data->tls_out_limit) {
- *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
- len = data->tls_out_limit;
- wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
- "will follow", (unsigned long) len);
- }
- wpabuf_put_data(req, &data->tls_out[data->tls_out_pos], len);
- data->tls_out_pos += len;
-
- eap_update_len(req);
- *out_data = req;
-
- if (!(*flags & EAP_TLS_FLAGS_MORE_FRAGMENTS)) {
- data->tls_out_len = 0;
- data->tls_out_pos = 0;
- os_free(data->tls_out);
- data->tls_out = NULL;
- }
-
- return 0;
-}
-
-
-struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int peap_version)
-{
- struct wpabuf *req;
-
- req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST,
- id);
- if (req == NULL)
- return NULL;
- wpa_printf(MSG_DEBUG, "SSL: Building ACK");
- wpabuf_put_u8(req, peap_version); /* Flags */
- return req;
-}
+static void eap_server_tls_free_in_buf(struct eap_ssl_data *data)
+{
+ if (data->in_buf != &data->tmpbuf)
+ wpabuf_free(data->in_buf);
+ data->in_buf = NULL;
+}
+
+
+struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
+ struct eap_ssl_data *data,
+ const u8 *plain, size_t plain_len)
+{
+ int res;
+ struct wpabuf *buf;
+ size_t buf_len;
+
+ /* reserve some extra room for encryption overhead */
+ buf_len = plain_len + 200;
+ buf = wpabuf_alloc(buf_len);
+ if (buf == NULL)
+ return NULL;
+ res = tls_connection_encrypt(sm->ssl_ctx, data->conn,
+ plain, plain_len, wpabuf_put(buf, 0),
+ buf_len);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ wpabuf_put(buf, res);
+
+ return buf;
+}
+
+
+int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
+ struct wpabuf *respData, void *priv, int eap_type,
+ int (*proc_version)(struct eap_sm *sm, void *priv,
+ int peer_version),
+ void (*proc_msg)(struct eap_sm *sm, void *priv,
+ const struct wpabuf *respData))
+{
+ const u8 *pos;
+ u8 flags;
+ size_t left;
+ int ret, res = 0;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, &left);
+ if (pos == NULL || left < 1)
+ return 0; /* Should not happen - frame already validated */
+ flags = *pos++;
+ left--;
+ wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x",
+ (unsigned long) wpabuf_len(respData), flags);
+
+ if (proc_version &&
+ proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0)
+ return -1;
+
+ ret = eap_server_tls_reassemble(data, flags, &pos, &left);
+ if (ret < 0) {
+ res = -1;
+ goto done;
+ } else if (ret == 1)
+ return 0;
+
+ if (proc_msg)
+ proc_msg(sm, priv, respData);
+
+ if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) {
+ wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in "
+ "TLS processing");
+ res = -1;
+ }
+
+done:
+ eap_server_tls_free_in_buf(data);
+
+ return res;
+}
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.h Sat Jun 14 00:26:56 2008
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2008, 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
@@ -18,18 +18,17 @@
struct eap_ssl_data {
struct tls_connection *conn;
- u8 *tls_out;
- size_t tls_out_len;
- size_t tls_out_pos;
size_t tls_out_limit;
- u8 *tls_in;
- size_t tls_in_len;
- size_t tls_in_left;
- size_t tls_in_total;
int phase2;
struct eap_sm *eap;
+
+ enum { MSG, FRAG_ACK, WAIT_FRAG_ACK } state;
+ struct wpabuf *in_buf;
+ struct wpabuf *out_buf;
+ size_t out_used;
+ struct wpabuf tmpbuf;
};
@@ -37,7 +36,7 @@
#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80
#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40
#define EAP_TLS_FLAGS_START 0x20
-#define EAP_PEAP_VERSION_MASK 0x07
+#define EAP_TLS_VERSION_MASK 0x07
/* could be up to 128 bytes, but only the first 64 bytes are used */
#define EAP_TLS_KEY_LEN 64
@@ -48,16 +47,18 @@
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len);
-int eap_server_tls_data_reassemble(struct eap_sm *sm,
- struct eap_ssl_data *data,
- u8 **in_data, size_t *in_len);
-int eap_server_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- const u8 *in_data, size_t in_len);
-int eap_server_tls_buildReq_helper(struct eap_sm *sm,
- struct eap_ssl_data *data,
- int eap_type, int peap_version, u8 id,
- struct wpabuf **out_data);
-struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type,
- int peap_version);
+struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
+ int eap_type, int version, u8 id);
+struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version);
+int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data);
+struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
+ struct eap_ssl_data *data,
+ const u8 *plain, size_t plain_len);
+int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
+ struct wpabuf *respData, void *priv, int eap_type,
+ int (*proc_version)(struct eap_sm *sm, void *priv,
+ int peer_version),
+ void (*proc_msg)(struct eap_sm *sm, void *priv,
+ const struct wpabuf *respData));
#endif /* EAP_TLS_COMMON_H */
Added: wpasupplicant/branches/upstream/current/src/eap_server/eap_tnc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_tnc.c?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_tnc.c (added)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_tnc.c Sat Jun 14 00:26:56 2008
@@ -1,0 +1,540 @@
+/*
+ * EAP server method: EAP-TNC (Trusted Network Connect)
+ * Copyright (c) 2007-2008, 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 "eap_i.h"
+#include "tncs.h"
+
+
+struct eap_tnc_data {
+ enum { START, CONTINUE, RECOMMENDATION, FRAG_ACK, WAIT_FRAG_ACK, DONE,
+ FAIL } state;
+ enum { ALLOW, ISOLATE, NO_ACCESS, NO_RECOMMENDATION } recommendation;
+ struct tncs_data *tncs;
+ struct wpabuf *in_buf;
+ struct wpabuf *out_buf;
+ size_t out_used;
+ size_t fragment_size;
+};
+
+
+/* EAP-TNC Flags */
+#define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
+#define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
+#define EAP_TNC_FLAGS_START 0x20
+#define EAP_TNC_VERSION_MASK 0x07
+
+#define EAP_TNC_VERSION 1
+
+
+static void * eap_tnc_init(struct eap_sm *sm)
+{
+ struct eap_tnc_data *data;
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ data->state = START;
+ data->tncs = tncs_init();
+ if (data->tncs == NULL) {
+ os_free(data);
+ return NULL;
+ }
+
+ data->fragment_size = 1300;
+
+ return data;
+}
+
+
+static void eap_tnc_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_tnc_data *data = priv;
+ wpabuf_free(data->in_buf);
+ wpabuf_free(data->out_buf);
+ tncs_deinit(data->tncs);
+ os_free(data);
+}
+
+
+static struct wpabuf * eap_tnc_build_start(struct eap_sm *sm,
+ struct eap_tnc_data *data, u8 id)
+{
+ struct wpabuf *req;
+
+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, EAP_CODE_REQUEST,
+ id);
+ if (req == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory for "
+ "request");
+ data->state = FAIL;
+ return NULL;
+ }
+
+ wpabuf_put_u8(req, EAP_TNC_FLAGS_START | EAP_TNC_VERSION);
+
+ data->state = CONTINUE;
+
+ return req;
+}
+
+
+static struct wpabuf * eap_tnc_build(struct eap_sm *sm,
+ struct eap_tnc_data *data, u8 id)
+{
+ struct wpabuf *req;
+ u8 *rpos, *rpos1, *start;
+ size_t rlen;
+ char *start_buf, *end_buf;
+ size_t start_len, end_len;
+ size_t imv_len;
+
+ imv_len = tncs_total_send_len(data->tncs);
+
+ start_buf = tncs_if_tnccs_start(data->tncs);
+ if (start_buf == NULL)
+ return NULL;
+ start_len = os_strlen(start_buf);
+ end_buf = tncs_if_tnccs_end();
+ if (end_buf == NULL) {
+ os_free(start_buf);
+ return NULL;
+ }
+ end_len = os_strlen(end_buf);
+
+ rlen = 1 + start_len + imv_len + end_len;
+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, rlen,
+ EAP_CODE_REQUEST, id);
+ if (req == NULL) {
+ os_free(start_buf);
+ os_free(end_buf);
+ return NULL;
+ }
+
+ start = wpabuf_put(req, 0);
+ wpabuf_put_u8(req, EAP_TNC_VERSION);
+ wpabuf_put_data(req, start_buf, start_len);
+ os_free(start_buf);
+
+ rpos1 = wpabuf_put(req, 0);
+ rpos = tncs_copy_send_buf(data->tncs, rpos1);
+ wpabuf_put(req, rpos - rpos1);
+
+ wpabuf_put_data(req, end_buf, end_len);
+ os_free(end_buf);
+
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Request", start, rlen);
+
+ return req;
+}
+
+
+static struct wpabuf * eap_tnc_build_recommendation(struct eap_sm *sm,
+ struct eap_tnc_data *data,
+ u8 id)
+{
+ switch (data->recommendation) {
+ case ALLOW:
+ data->state = DONE;
+ break;
+ case ISOLATE:
+ data->state = FAIL;
+ /* TODO: support assignment to a different VLAN */
+ break;
+ case NO_ACCESS:
+ data->state = FAIL;
+ break;
+ case NO_RECOMMENDATION:
+ data->state = DONE;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Unknown recommendation");
+ return NULL;
+ }
+
+ return eap_tnc_build(sm, data, id);
+}
+
+
+static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
+{
+ struct wpabuf *msg;
+
+ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 0, code, id);
+ if (msg == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
+ "for fragment ack");
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
+
+ return msg;
+}
+
+
+static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data, u8 id)
+{
+ struct wpabuf *req;
+ u8 flags;
+ size_t send_len, plen;
+
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Request");
+
+ flags = EAP_TNC_VERSION;
+ send_len = wpabuf_len(data->out_buf) - data->out_used;
+ if (1 + send_len > data->fragment_size) {
+ send_len = data->fragment_size - 1;
+ flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
+ if (data->out_used == 0) {
+ flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
+ send_len -= 4;
+ }
+ }
+
+ plen = 1 + send_len;
+ if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
+ plen += 4;
+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
+ EAP_CODE_REQUEST, id);
+ if (req == NULL)
+ return NULL;
+
+ wpabuf_put_u8(req, flags); /* Flags */
+ if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
+ wpabuf_put_be32(req, wpabuf_len(data->out_buf));
+
+ wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
+ send_len);
+ data->out_used += send_len;
+
+ if (data->out_used == wpabuf_len(data->out_buf)) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
+ "(message sent completely)",
+ (unsigned long) send_len);
+ wpabuf_free(data->out_buf);
+ data->out_buf = NULL;
+ data->out_used = 0;
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
+ "(%lu more to send)", (unsigned long) send_len,
+ (unsigned long) wpabuf_len(data->out_buf) -
+ data->out_used);
+ data->state = WAIT_FRAG_ACK;
+ }
+
+ return req;
+}
+
+
+static struct wpabuf * eap_tnc_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+ struct eap_tnc_data *data = priv;
+
+ switch (data->state) {
+ case START:
+ tncs_init_connection(data->tncs);
+ return eap_tnc_build_start(sm, data, id);
+ case CONTINUE:
+ if (data->out_buf == NULL) {
+ data->out_buf = eap_tnc_build(sm, data, id);
+ if (data->out_buf == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to "
+ "generate message");
+ return NULL;
+ }
+ data->out_used = 0;
+ }
+ return eap_tnc_build_msg(data, id);
+ case RECOMMENDATION:
+ if (data->out_buf == NULL) {
+ data->out_buf = eap_tnc_build_recommendation(sm, data,
+ id);
+ if (data->out_buf == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to "
+ "generate recommendation message");
+ return NULL;
+ }
+ data->out_used = 0;
+ }
+ return eap_tnc_build_msg(data, id);
+ case WAIT_FRAG_ACK:
+ return eap_tnc_build_msg(data, id);
+ case FRAG_ACK:
+ return eap_tnc_build_frag_ack(id, EAP_CODE_REQUEST);
+ case DONE:
+ case FAIL:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+
+static Boolean eap_tnc_check(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
+{
+ struct eap_tnc_data *data = priv;
+ const u8 *pos;
+ size_t len;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData,
+ &len);
+ if (pos == NULL) {
+ wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame");
+ return TRUE;
+ }
+
+ if (len == 0 && data->state != WAIT_FRAG_ACK) {
+ wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (empty)");
+ return TRUE;
+ }
+
+ if (len == 0)
+ return FALSE; /* Fragment ACK does not include flags */
+
+ if ((*pos & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
+ *pos & EAP_TNC_VERSION_MASK);
+ return TRUE;
+ }
+
+ if (*pos & EAP_TNC_FLAGS_START) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Peer used Start flag");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static void tncs_process(struct eap_tnc_data *data, struct wpabuf *inbuf)
+{
+ enum tncs_process_res res;
+
+ res = tncs_process_if_tnccs(data->tncs, wpabuf_head(inbuf),
+ wpabuf_len(inbuf));
+ switch (res) {
+ case TNCCS_RECOMMENDATION_ALLOW:
+ wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS allowed access");
+ data->state = RECOMMENDATION;
+ data->recommendation = ALLOW;
+ break;
+ case TNCCS_RECOMMENDATION_NO_RECOMMENDATION:
+ wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS has no recommendation");
+ data->state = RECOMMENDATION;
+ data->recommendation = NO_RECOMMENDATION;
+ break;
+ case TNCCS_RECOMMENDATION_ISOLATE:
+ wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS requested isolation");
+ data->state = RECOMMENDATION;
+ data->recommendation = ISOLATE;
+ break;
+ case TNCCS_RECOMMENDATION_NO_ACCESS:
+ wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS rejected access");
+ data->state = RECOMMENDATION;
+ data->recommendation = NO_ACCESS;
+ break;
+ case TNCCS_PROCESS_ERROR:
+ wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS processing error");
+ data->state = FAIL;
+ break;
+ default:
+ break;
+ }
+}
+
+
+static int eap_tnc_process_cont(struct eap_tnc_data *data,
+ const u8 *buf, size_t len)
+{
+ /* Process continuation of a pending message */
+ if (len > wpabuf_tailroom(data->in_buf)) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
+ data->state = FAIL;
+ return -1;
+ }
+
+ wpabuf_put_data(data->in_buf, buf, len);
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for %lu "
+ "bytes more", (unsigned long) len,
+ (unsigned long) wpabuf_tailroom(data->in_buf));
+
+ return 0;
+}
+
+
+static int eap_tnc_process_fragment(struct eap_tnc_data *data,
+ u8 flags, u32 message_length,
+ const u8 *buf, size_t len)
+{
+ /* Process a fragment that is not the last one of the message */
+ if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
+ "fragmented packet");
+ return -1;
+ }
+
+ if (data->in_buf == NULL) {
+ /* First fragment of the message */
+ data->in_buf = wpabuf_alloc(message_length);
+ if (data->in_buf == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
+ "message");
+ return -1;
+ }
+ wpabuf_put_data(data->in_buf, buf, len);
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
+ "fragment, waiting for %lu bytes more",
+ (unsigned long) len,
+ (unsigned long) wpabuf_tailroom(data->in_buf));
+ }
+
+ return 0;
+}
+
+
+static void eap_tnc_process(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
+{
+ struct eap_tnc_data *data = priv;
+ const u8 *pos, *end;
+ size_t len;
+ u8 flags;
+ u32 message_length = 0;
+ struct wpabuf tmpbuf;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, &len);
+ if (pos == NULL)
+ return; /* Should not happen; message already verified */
+
+ end = pos + len;
+
+ if (len == 1 && (data->state == DONE || data->state == FAIL)) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Peer acknowledged the last "
+ "message");
+ return;
+ }
+
+ if (len == 0) {
+ /* fragment ack */
+ flags = 0;
+ } else
+ flags = *pos++;
+
+ if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
+ if (end - pos < 4) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
+ data->state = FAIL;
+ return;
+ }
+ message_length = WPA_GET_BE32(pos);
+ pos += 4;
+
+ if (message_length < (u32) (end - pos)) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
+ "Length (%d; %ld remaining in this msg)",
+ message_length, (long) (end - pos));
+ data->state = FAIL;
+ return;
+ }
+ }
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
+ "Message Length %u", flags, message_length);
+
+ if (data->state == WAIT_FRAG_ACK) {
+ if (len != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload "
+ "in WAIT_FRAG_ACK state");
+ data->state = FAIL;
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
+ data->state = CONTINUE;
+ return;
+ }
+
+ if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
+ data->state = FAIL;
+ return;
+ }
+
+ if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
+ if (eap_tnc_process_fragment(data, flags, message_length,
+ pos, end - pos) < 0)
+ data->state = FAIL;
+ else
+ data->state = FRAG_ACK;
+ return;
+ } else if (data->state == FRAG_ACK) {
+ wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received");
+ data->state = CONTINUE;
+ }
+
+ if (data->in_buf == NULL) {
+ /* Wrap unfragmented messages as wpabuf without extra copy */
+ wpabuf_set(&tmpbuf, pos, end - pos);
+ data->in_buf = &tmpbuf;
+ }
+
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload",
+ wpabuf_head(data->in_buf), wpabuf_len(data->in_buf));
+ tncs_process(data, data->in_buf);
+
+ if (data->in_buf != &tmpbuf)
+ wpabuf_free(data->in_buf);
+ data->in_buf = NULL;
+}
+
+
+static Boolean eap_tnc_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_tnc_data *data = priv;
+ return data->state == DONE;
+}
+
+
+static Boolean eap_tnc_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_tnc_data *data = priv;
+ return data->state == DONE;
+}
+
+
+int eap_server_tnc_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_tnc_init;
+ eap->reset = eap_tnc_reset;
+ eap->buildReq = eap_tnc_buildReq;
+ eap->check = eap_tnc_check;
+ eap->process = eap_tnc_process;
+ eap->isDone = eap_tnc_isDone;
+ eap->isSuccess = eap_tnc_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_ttls.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_ttls.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_ttls.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_ttls.c Sat Jun 14 00:26:56 2008
@@ -55,6 +55,7 @@
u8 mschapv2_ident;
int tls_ia_configured;
struct wpabuf *pending_phase2_eap_resp;
+ int tnc_started;
};
@@ -444,62 +445,6 @@
}
-static struct wpabuf * eap_ttls_build_req(struct eap_sm *sm,
- struct eap_ttls_data *data, u8 id)
-{
- int res;
- struct wpabuf *req;
-
- res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_TTLS,
- data->ttls_version, id, &req);
-
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, starting "
- "Phase2");
- eap_ttls_state(data, PHASE2_START);
- }
-
- if (res == 1)
- return eap_server_tls_build_ack(id, EAP_TYPE_TTLS,
- data->ttls_version);
- return req;
-}
-
-
-static struct wpabuf * eap_ttls_encrypt(struct eap_sm *sm,
- struct eap_ttls_data *data,
- u8 id, u8 *plain, size_t plain_len)
-{
- int res;
- struct wpabuf *buf;
-
- /* TODO: add support for fragmentation, if needed. This will need to
- * add TLS Message Length field, if the frame is fragmented. */
- buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS,
- 1 + data->ssl.tls_out_limit,
- EAP_CODE_REQUEST, id);
- if (buf == NULL)
- return NULL;
-
- wpabuf_put_u8(buf, data->ttls_version);
-
- res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
- plain, plain_len, wpabuf_put(buf, 0),
- data->ssl.tls_out_limit);
- if (res < 0) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt Phase 2 "
- "data");
- wpabuf_free(buf);
- return NULL;
- }
-
- wpabuf_put(buf, res);
- eap_update_len(buf);
-
- return buf;
-}
-
-
static struct wpabuf * eap_ttls_build_phase2_eap_req(
struct eap_sm *sm, struct eap_ttls_data *data, u8 id)
{
@@ -527,7 +472,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/EAP: Encrypt encapsulated Phase "
"2 data", req, req_len);
- encr_req = eap_ttls_encrypt(sm, data, id, req, req_len);
+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
wpabuf_free(buf);
return encr_req;
@@ -535,7 +480,7 @@
static struct wpabuf * eap_ttls_build_phase2_mschapv2(
- struct eap_sm *sm, struct eap_ttls_data *data, u8 id)
+ struct eap_sm *sm, struct eap_ttls_data *data)
{
struct wpabuf *encr_req;
u8 *req, *pos, *end;
@@ -569,7 +514,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 "
"data", req, req_len);
- encr_req = eap_ttls_encrypt(sm, data, id, req, req_len);
+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
os_free(req);
return encr_req;
@@ -577,19 +522,15 @@
static struct wpabuf * eap_ttls_build_phase_finished(
- struct eap_sm *sm, struct eap_ttls_data *data, u8 id, int final)
+ struct eap_sm *sm, struct eap_ttls_data *data, int final)
{
int len;
struct wpabuf *req;
const int max_len = 300;
- len = 1 + max_len;
- req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, len,
- EAP_CODE_REQUEST, id);
+ req = wpabuf_alloc(max_len);
if (req == NULL)
return NULL;
-
- wpabuf_put_u8(req, data->ttls_version);
len = tls_connection_ia_send_phase_finished(sm->ssl_ctx,
data->ssl.conn, final,
@@ -600,7 +541,6 @@
return NULL;
}
wpabuf_put(req, len);
- eap_update_len(req);
return req;
}
@@ -609,23 +549,51 @@
static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id)
{
struct eap_ttls_data *data = priv;
+
+ if (data->ssl.state == FRAG_ACK) {
+ return eap_server_tls_build_ack(id, EAP_TYPE_TTLS,
+ data->ttls_version);
+ }
+
+ if (data->ssl.state == WAIT_FRAG_ACK) {
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS,
+ data->ttls_version, id);
+ }
switch (data->state) {
case START:
return eap_ttls_build_start(sm, data, id);
case PHASE1:
- return eap_ttls_build_req(sm, data, id);
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, "
+ "starting Phase2");
+ eap_ttls_state(data, PHASE2_START);
+ }
+ break;
case PHASE2_METHOD:
- return eap_ttls_build_phase2_eap_req(sm, data, id);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_ttls_build_phase2_eap_req(sm, data,
+ id);
+ break;
case PHASE2_MSCHAPV2_RESP:
- return eap_ttls_build_phase2_mschapv2(sm, data, id);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_ttls_build_phase2_mschapv2(sm, data);
+ break;
case PHASE_FINISHED:
- return eap_ttls_build_phase_finished(sm, data, id, 1);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_ttls_build_phase_finished(sm, data, 1);
+ break;
default:
wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
__func__, data->state);
return NULL;
}
+
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS,
+ data->ttls_version, id);
}
@@ -1147,12 +1115,17 @@
static void eap_ttls_process_phase2(struct eap_sm *sm,
struct eap_ttls_data *data,
- u8 *in_data, size_t in_len)
+ struct wpabuf *in_buf)
{
u8 *in_decrypted;
- int len_decrypted, res;
+ int len_decrypted;
struct eap_ttls_avp parse;
size_t buf_len;
+ u8 *in_data;
+ size_t in_len;
+
+ in_data = wpabuf_mhead(in_buf);
+ in_len = wpabuf_len(in_buf);
wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
@@ -1168,19 +1141,17 @@
return;
}
- 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;
+ /*
+ * Even though we try to disable TLS compression, it is possible that
+ * this cannot be done with all TLS libraries. Add extra buffer space
+ * to handle the possibility of the decrypted data being longer than
+ * input data.
+ */
+ buf_len += 500;
+ buf_len *= 3;
in_decrypted = os_malloc(buf_len);
if (in_decrypted == NULL) {
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate memory "
"for decryption");
return;
@@ -1189,9 +1160,6 @@
len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
in_data, in_len,
in_decrypted, buf_len);
- os_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-TTLS: Failed to decrypt Phase 2 "
"data");
@@ -1243,6 +1211,15 @@
goto done;
}
}
+
+#ifdef EAP_TNC
+ if (data->tnc_started && parse.eap == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: TNC started but no EAP "
+ "response from peer");
+ eap_ttls_state(data, FAILURE);
+ goto done;
+ }
+#endif /* EAP_TNC */
if (parse.eap) {
eap_ttls_process_phase2_eap(sm, data, parse.eap,
@@ -1276,26 +1253,29 @@
}
-static void eap_ttls_process(struct eap_sm *sm, void *priv,
- struct wpabuf *respData)
+static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data)
+{
+#ifdef EAP_TNC
+ if (!sm->tnc || data->state != SUCCESS || data->tnc_started)
+ return;
+
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Initialize TNC");
+ if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_TNC)) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize TNC");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
+ data->tnc_started = 1;
+ eap_ttls_state(data, PHASE2_METHOD);
+#endif /* EAP_TNC */
+}
+
+
+static int eap_ttls_process_version(struct eap_sm *sm, void *priv,
+ int peer_version)
{
struct eap_ttls_data *data = priv;
- const u8 *pos;
- u8 flags;
- size_t left;
- unsigned int tls_msg_len;
- int peer_version;
-
- pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TTLS, respData,
- &left);
- if (pos == NULL || left < 1)
- return;
- flags = *pos++;
- left--;
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Received packet(len=%lu) - "
- "Flags 0x%02x", (unsigned long) wpabuf_len(respData),
- flags);
- peer_version = flags & EAP_PEAP_VERSION_MASK;
if (peer_version < data->ttls_version) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: peer ver=%d, own ver=%d; "
"use version %d",
@@ -1307,50 +1287,34 @@
if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable "
"TLS/IA");
- eap_ttls_state(data, FAILURE);
- return;
+ return -1;
}
data->tls_ia_configured = 1;
}
- if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
- if (left < 4) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Short frame with TLS "
- "length");
- eap_ttls_state(data, FAILURE);
- return;
- }
- tls_msg_len = WPA_GET_BE32(pos);
- wpa_printf(MSG_DEBUG, "EAP-TTLS: 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;
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
- }
- pos += 4;
- left -= 4;
- }
+ return 0;
+}
+
+
+static void eap_ttls_process_msg(struct eap_sm *sm, void *priv,
+ const struct wpabuf *respData)
+{
+ struct eap_ttls_data *data = priv;
switch (data->state) {
case PHASE1:
- if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) <
- 0) {
- wpa_printf(MSG_INFO, "EAP-TTLS: TLS processing "
- "failed");
+ if (eap_server_tls_phase1(sm, &data->ssl) < 0)
eap_ttls_state(data, FAILURE);
- }
break;
case PHASE2_START:
case PHASE2_METHOD:
case PHASE_FINISHED:
- /* FIX: get rid of const->non-const typecast */
- eap_ttls_process_phase2(sm, data, (u8 *) pos, left);
+ eap_ttls_process_phase2(sm, data, data->ssl.in_buf);
+ eap_ttls_start_tnc(sm, data);
break;
case PHASE2_MSCHAPV2_RESP:
- if (data->mschapv2_resp_ok && left == 0) {
+ if (data->mschapv2_resp_ok && wpabuf_len(data->ssl.in_buf) ==
+ 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
"acknowledged response");
eap_ttls_state(data, data->ttls_version > 0 ?
@@ -1363,21 +1327,28 @@
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Unexpected "
"frame from peer (payload len %lu, "
"expected empty frame)",
- (unsigned long) left);
+ (unsigned long)
+ wpabuf_len(data->ssl.in_buf));
eap_ttls_state(data, FAILURE);
}
+ eap_ttls_start_tnc(sm, data);
break;
default:
wpa_printf(MSG_DEBUG, "EAP-TTLS: 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-TTLS: Locally detected fatal error "
- "in TLS processing");
- eap_ttls_state(data, FAILURE);
- }
+}
+
+
+static void eap_ttls_process(struct eap_sm *sm, void *priv,
+ struct wpabuf *respData)
+{
+ struct eap_ttls_data *data = priv;
+ if (eap_server_tls_process(sm, &data->ssl, respData, data,
+ EAP_TYPE_TTLS, eap_ttls_process_version,
+ eap_ttls_process_msg) < 0)
+ eap_ttls_state(data, FAILURE);
}
Added: wpasupplicant/branches/upstream/current/src/eap_server/tncs.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/tncs.c?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/tncs.c (added)
+++ wpasupplicant/branches/upstream/current/src/eap_server/tncs.c Sat Jun 14 00:26:56 2008
@@ -1,0 +1,1272 @@
+/*
+ * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
+ * Copyright (c) 2007-2008, 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 <dlfcn.h>
+
+#include "common.h"
+#include "base64.h"
+#include "tncs.h"
+#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_defs.h"
+
+
+/* TODO: TNCS must be thread-safe; review the code and add locking etc. if
+ * needed.. */
+
+#define TNC_CONFIG_FILE "/etc/tnc_config"
+#define IF_TNCCS_START \
+"<?xml version=\"1.0\"?>\n" \
+"<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
+"xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
+"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
+"xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
+"IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
+#define IF_TNCCS_END "\n</TNCCS-Batch>"
+
+/* TNC IF-IMV */
+
+typedef unsigned long TNC_UInt32;
+typedef unsigned char *TNC_BufferReference;
+
+typedef TNC_UInt32 TNC_IMVID;
+typedef TNC_UInt32 TNC_ConnectionID;
+typedef TNC_UInt32 TNC_ConnectionState;
+typedef TNC_UInt32 TNC_RetryReason;
+typedef TNC_UInt32 TNC_IMV_Action_Recommendation;
+typedef TNC_UInt32 TNC_IMV_Evaluation_Result;
+typedef TNC_UInt32 TNC_MessageType;
+typedef TNC_MessageType *TNC_MessageTypeList;
+typedef TNC_UInt32 TNC_VendorID;
+typedef TNC_UInt32 TNC_Subtype;
+typedef TNC_UInt32 TNC_Version;
+typedef TNC_UInt32 TNC_Result;
+typedef TNC_UInt32 TNC_AttributeID;
+
+typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)(
+ TNC_IMVID imvID,
+ char *functionName,
+ void **pOutfunctionPointer);
+
+#define TNC_RESULT_SUCCESS 0
+#define TNC_RESULT_NOT_INITIALIZED 1
+#define TNC_RESULT_ALREADY_INITIALIZED 2
+#define TNC_RESULT_NO_COMMON_VERSION 3
+#define TNC_RESULT_CANT_RETRY 4
+#define TNC_RESULT_WONT_RETRY 5
+#define TNC_RESULT_INVALID_PARAMETER 6
+#define TNC_RESULT_CANT_RESPOND 7
+#define TNC_RESULT_ILLEGAL_OPERATION 8
+#define TNC_RESULT_OTHER 9
+#define TNC_RESULT_FATAL 10
+
+#define TNC_CONNECTION_STATE_CREATE 0
+#define TNC_CONNECTION_STATE_HANDSHAKE 1
+#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
+#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
+#define TNC_CONNECTION_STATE_ACCESS_NONE 4
+#define TNC_CONNECTION_STATE_DELETE 5
+
+#define TNC_IFIMV_VERSION_1 1
+
+#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
+#define TNC_SUBTYPE_ANY ((TNC_Subtype) 0xff)
+
+/* TNCC-TNCS Message Types */
+#define TNC_TNCCS_RECOMMENDATION 0x00000001
+#define TNC_TNCCS_ERROR 0x00000002
+#define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003
+#define TNC_TNCCS_REASONSTRINGS 0x00000004
+
+/* Possible TNC_IMV_Action_Recommendation values: */
+enum IMV_Action_Recommendation {
+ TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
+ TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS,
+ TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
+ TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
+};
+
+/* Possible TNC_IMV_Evaluation_Result values: */
+enum IMV_Evaluation_Result {
+ TNC_IMV_EVALUATION_RESULT_COMPLIANT,
+ TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR,
+ TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR,
+ TNC_IMV_EVALUATION_RESULT_ERROR,
+ TNC_IMV_EVALUATION_RESULT_DONT_KNOW
+};
+
+struct tnc_if_imv {
+ struct tnc_if_imv *next;
+ char *name;
+ char *path;
+ void *dlhandle; /* from dlopen() */
+ TNC_IMVID imvID;
+ TNC_MessageTypeList supported_types;
+ size_t num_supported_types;
+
+ /* Functions implemented by IMVs (with TNC_IMV_ prefix) */
+ TNC_Result (*Initialize)(
+ TNC_IMVID imvID,
+ TNC_Version minVersion,
+ TNC_Version maxVersion,
+ TNC_Version *pOutActualVersion);
+ TNC_Result (*NotifyConnectionChange)(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_ConnectionState newState);
+ TNC_Result (*ReceiveMessage)(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_BufferReference message,
+ TNC_UInt32 messageLength,
+ TNC_MessageType messageType);
+ TNC_Result (*SolicitRecommendation)(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID);
+ TNC_Result (*BatchEnding)(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID);
+ TNC_Result (*Terminate)(TNC_IMVID imvID);
+ TNC_Result (*ProvideBindFunction)(
+ TNC_IMVID imvID,
+ TNC_TNCS_BindFunctionPointer bindFunction);
+};
+
+
+#define TNC_MAX_IMV_ID 10
+
+struct tncs_data {
+ struct tncs_data *next;
+ struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */
+ TNC_ConnectionID connectionID;
+ unsigned int last_batchid;
+ enum IMV_Action_Recommendation recommendation;
+ int done;
+
+ struct conn_imv {
+ u8 *imv_send;
+ size_t imv_send_len;
+ enum IMV_Action_Recommendation recommendation;
+ int recommendation_set;
+ } imv_data[TNC_MAX_IMV_ID];
+
+ char *tncs_message;
+};
+
+
+struct tncs_global {
+ struct tnc_if_imv *imv;
+ TNC_ConnectionID next_conn_id;
+ struct tncs_data *connections;
+};
+
+static struct tncs_global *tncs_global_data = NULL;
+
+
+static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID)
+{
+ struct tnc_if_imv *imv;
+
+ if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL)
+ return NULL;
+ imv = tncs_global_data->imv;
+ while (imv) {
+ if (imv->imvID == imvID)
+ return imv;
+ imv = imv->next;
+ }
+ return NULL;
+}
+
+
+static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
+{
+ struct tncs_data *tncs;
+
+ if (tncs_global_data == NULL)
+ return NULL;
+
+ tncs = tncs_global_data->connections;
+ while (tncs) {
+ if (tncs->connectionID == connectionID)
+ return tncs;
+ tncs = tncs->next;
+ }
+
+ wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found",
+ (unsigned long) connectionID);
+
+ return NULL;
+}
+
+
+/* TNCS functions that IMVs can call */
+TNC_Result TNC_TNCS_ReportMessageTypes(
+ TNC_IMVID imvID,
+ TNC_MessageTypeList supportedTypes,
+ TNC_UInt32 typeCount)
+{
+ TNC_UInt32 i;
+ struct tnc_if_imv *imv;
+
+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu "
+ "typeCount=%lu)",
+ (unsigned long) imvID, (unsigned long) typeCount);
+
+ for (i = 0; i < typeCount; i++) {
+ wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
+ i, supportedTypes[i]);
+ }
+
+ imv = tncs_get_imv(imvID);
+ if (imv == NULL)
+ return TNC_RESULT_INVALID_PARAMETER;
+ os_free(imv->supported_types);
+ imv->supported_types =
+ os_malloc(typeCount * sizeof(TNC_MessageTypeList));
+ if (imv->supported_types == NULL)
+ return TNC_RESULT_FATAL;
+ os_memcpy(imv->supported_types, supportedTypes,
+ typeCount * sizeof(TNC_MessageTypeList));
+ imv->num_supported_types = typeCount;
+
+ return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_SendMessage(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_BufferReference message,
+ TNC_UInt32 messageLength,
+ TNC_MessageType messageType)
+{
+ struct tncs_data *tncs;
+ unsigned char *b64;
+ size_t b64len;
+
+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
+ "connectionID=%lu messageType=%lu)",
+ imvID, connectionID, messageType);
+ wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage",
+ message, messageLength);
+
+ if (tncs_get_imv(imvID) == NULL)
+ return TNC_RESULT_INVALID_PARAMETER;
+
+ tncs = tncs_get_conn(connectionID);
+ if (tncs == NULL)
+ return TNC_RESULT_INVALID_PARAMETER;
+
+ b64 = base64_encode(message, messageLength, &b64len);
+ if (b64 == NULL)
+ return TNC_RESULT_FATAL;
+
+ os_free(tncs->imv_data[imvID].imv_send);
+ tncs->imv_data[imvID].imv_send_len = 0;
+ tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100);
+ if (tncs->imv_data[imvID].imv_send == NULL) {
+ os_free(b64);
+ return TNC_RESULT_OTHER;
+ }
+
+ tncs->imv_data[imvID].imv_send_len =
+ os_snprintf((char *) tncs->imv_data[imvID].imv_send,
+ b64len + 100,
+ "<IMC-IMV-Message><Type>%08X</Type>"
+ "<Base64>%s</Base64></IMC-IMV-Message>",
+ (unsigned int) messageType, b64);
+
+ os_free(b64);
+
+ return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_RequestHandshakeRetry(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_RetryReason reason)
+{
+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry");
+ /* TODO */
+ return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_ProvideRecommendation(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_IMV_Action_Recommendation recommendation,
+ TNC_IMV_Evaluation_Result evaluation)
+{
+ struct tncs_data *tncs;
+
+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu "
+ "connectionID=%lu recommendation=%lu evaluation=%lu)",
+ (unsigned long) imvID, (unsigned long) connectionID,
+ (unsigned long) recommendation, (unsigned long) evaluation);
+
+ if (tncs_get_imv(imvID) == NULL)
+ return TNC_RESULT_INVALID_PARAMETER;
+
+ tncs = tncs_get_conn(connectionID);
+ if (tncs == NULL)
+ return TNC_RESULT_INVALID_PARAMETER;
+
+ tncs->imv_data[imvID].recommendation = recommendation;
+ tncs->imv_data[imvID].recommendation_set = 1;
+
+ return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_GetAttribute(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_AttributeID attribureID,
+ TNC_UInt32 bufferLength,
+ TNC_BufferReference buffer,
+ TNC_UInt32 *pOutValueLength)
+{
+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute");
+ /* TODO */
+ return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_SetAttribute(
+ TNC_IMVID imvID,
+ TNC_ConnectionID connectionID,
+ TNC_AttributeID attribureID,
+ TNC_UInt32 bufferLength,
+ TNC_BufferReference buffer)
+{
+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute");
+ /* TODO */
+ return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_BindFunction(
+ TNC_IMVID imvID,
+ char *functionName,
+ void **pOutFunctionPointer)
+{
+ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, "
+ "functionName='%s')", (unsigned long) imvID, functionName);
+
+ if (tncs_get_imv(imvID) == NULL)
+ return TNC_RESULT_INVALID_PARAMETER;
+
+ if (pOutFunctionPointer == NULL)
+ return TNC_RESULT_INVALID_PARAMETER;
+
+ if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0)
+ *pOutFunctionPointer = TNC_TNCS_ReportMessageTypes;
+ else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0)
+ *pOutFunctionPointer = TNC_TNCS_SendMessage;
+ else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") ==
+ 0)
+ *pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry;
+ else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") ==
+ 0)
+ *pOutFunctionPointer = TNC_TNCS_ProvideRecommendation;
+ else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0)
+ *pOutFunctionPointer = TNC_TNCS_GetAttribute;
+ else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0)
+ *pOutFunctionPointer = TNC_TNCS_SetAttribute;
+ else
+ *pOutFunctionPointer = NULL;
+
+ return TNC_RESULT_SUCCESS;
+}
+
+
+static void * tncs_get_sym(void *handle, char *func)
+{
+ void *fptr;
+
+ fptr = dlsym(handle, func);
+
+ return fptr;
+}
+
+
+static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv)
+{
+ void *handle = imv->dlhandle;
+
+ /* Mandatory IMV functions */
+ imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize");
+ if (imv->Initialize == NULL) {
+ wpa_printf(MSG_ERROR, "TNC: IMV does not export "
+ "TNC_IMV_Initialize");
+ return -1;
+ }
+
+ imv->SolicitRecommendation = tncs_get_sym(
+ handle, "TNC_IMV_SolicitRecommendation");
+ if (imv->SolicitRecommendation == NULL) {
+ wpa_printf(MSG_ERROR, "TNC: IMV does not export "
+ "TNC_IMV_SolicitRecommendation");
+ return -1;
+ }
+
+ imv->ProvideBindFunction =
+ tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction");
+ if (imv->ProvideBindFunction == NULL) {
+ wpa_printf(MSG_ERROR, "TNC: IMV does not export "
+ "TNC_IMV_ProvideBindFunction");
+ return -1;
+ }
+
+ /* Optional IMV functions */
+ imv->NotifyConnectionChange =
+ tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange");
+ imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage");
+ imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding");
+ imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate");
+
+ return 0;
+}
+
+
+static int tncs_imv_initialize(struct tnc_if_imv *imv)
+{
+ TNC_Result res;
+ TNC_Version imv_ver;
+
+ wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'",
+ imv->name);
+ res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1,
+ TNC_IFIMV_VERSION_1, &imv_ver);
+ wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu",
+ (unsigned long) res, (unsigned long) imv_ver);
+
+ return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncs_imv_terminate(struct tnc_if_imv *imv)
+{
+ TNC_Result res;
+
+ if (imv->Terminate == NULL)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'",
+ imv->name);
+ res = imv->Terminate(imv->imvID);
+ wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu",
+ (unsigned long) res);
+
+ return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv)
+{
+ TNC_Result res;
+
+ wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for "
+ "IMV '%s'", imv->name);
+ res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction);
+ wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu",
+ (unsigned long) res);
+
+ return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv,
+ TNC_ConnectionID conn,
+ TNC_ConnectionState state)
+{
+ TNC_Result res;
+
+ if (imv->NotifyConnectionChange == NULL)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)"
+ " for IMV '%s'", (int) state, imv->name);
+ res = imv->NotifyConnectionChange(imv->imvID, conn, state);
+ wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
+ (unsigned long) res);
+
+ return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncs_load_imv(struct tnc_if_imv *imv)
+{
+ if (imv->path == NULL) {
+ wpa_printf(MSG_DEBUG, "TNC: No IMV configured");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)",
+ imv->name, imv->path);
+ imv->dlhandle = dlopen(imv->path, RTLD_LAZY);
+ if (imv->dlhandle == NULL) {
+ wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s",
+ imv->name, imv->path, dlerror());
+ return -1;
+ }
+
+ if (tncs_imv_resolve_funcs(imv) < 0) {
+ wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions");
+ return -1;
+ }
+
+ if (tncs_imv_initialize(imv) < 0 ||
+ tncs_imv_provide_bind_function(imv) < 0) {
+ wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void tncs_free_imv(struct tnc_if_imv *imv)
+{
+ os_free(imv->name);
+ os_free(imv->path);
+ os_free(imv->supported_types);
+}
+
+static void tncs_unload_imv(struct tnc_if_imv *imv)
+{
+ tncs_imv_terminate(imv);
+
+ if (imv->dlhandle)
+ dlclose(imv->dlhandle);
+
+ tncs_free_imv(imv);
+}
+
+
+static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type)
+{
+ size_t i;
+ unsigned int vendor, subtype;
+
+ if (imv == NULL || imv->supported_types == NULL)
+ return 0;
+
+ vendor = type >> 8;
+ subtype = type & 0xff;
+
+ for (i = 0; i < imv->num_supported_types; i++) {
+ unsigned int svendor, ssubtype;
+ svendor = imv->supported_types[i] >> 8;
+ ssubtype = imv->supported_types[i] & 0xff;
+ if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
+ (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type,
+ const u8 *msg, size_t len)
+{
+ struct tnc_if_imv *imv;
+ TNC_Result res;
+
+ wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len);
+
+ for (imv = tncs->imv; imv; imv = imv->next) {
+ if (imv->ReceiveMessage == NULL ||
+ !tncs_supported_type(imv, type))
+ continue;
+
+ wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'",
+ imv->name);
+ res = imv->ReceiveMessage(imv->imvID, tncs->connectionID,
+ (TNC_BufferReference) msg, len,
+ type);
+ wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
+ (unsigned long) res);
+ }
+}
+
+
+static void tncs_batch_ending(struct tncs_data *tncs)
+{
+ struct tnc_if_imv *imv;
+ TNC_Result res;
+
+ for (imv = tncs->imv; imv; imv = imv->next) {
+ if (imv->BatchEnding == NULL)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'",
+ imv->name);
+ res = imv->BatchEnding(imv->imvID, tncs->connectionID);
+ wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu",
+ (unsigned long) res);
+ }
+}
+
+
+static void tncs_solicit_recommendation(struct tncs_data *tncs)
+{
+ struct tnc_if_imv *imv;
+ TNC_Result res;
+
+ for (imv = tncs->imv; imv; imv = imv->next) {
+ if (tncs->imv_data[imv->imvID].recommendation_set)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for "
+ "IMV '%s'", imv->name);
+ res = imv->SolicitRecommendation(imv->imvID,
+ tncs->connectionID);
+ wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu",
+ (unsigned long) res);
+ }
+}
+
+
+void tncs_init_connection(struct tncs_data *tncs)
+{
+ struct tnc_if_imv *imv;
+ int i;
+
+ for (imv = tncs->imv; imv; imv = imv->next) {
+ tncs_imv_notify_connection_change(
+ imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE);
+ tncs_imv_notify_connection_change(
+ imv, tncs->connectionID,
+ TNC_CONNECTION_STATE_HANDSHAKE);
+ }
+
+ for (i = 0; i < TNC_MAX_IMV_ID; i++) {
+ os_free(tncs->imv_data[i].imv_send);
+ tncs->imv_data[i].imv_send = NULL;
+ tncs->imv_data[i].imv_send_len = 0;
+ }
+}
+
+
+size_t tncs_total_send_len(struct tncs_data *tncs)
+{
+ int i;
+ size_t len = 0;
+
+ for (i = 0; i < TNC_MAX_IMV_ID; i++)
+ len += tncs->imv_data[i].imv_send_len;
+ if (tncs->tncs_message)
+ len += os_strlen(tncs->tncs_message);
+ return len;
+}
+
+
+u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos)
+{
+ int i;
+
+ for (i = 0; i < TNC_MAX_IMV_ID; i++) {
+ if (tncs->imv_data[i].imv_send == NULL)
+ continue;
+
+ os_memcpy(pos, tncs->imv_data[i].imv_send,
+ tncs->imv_data[i].imv_send_len);
+ pos += tncs->imv_data[i].imv_send_len;
+ os_free(tncs->imv_data[i].imv_send);
+ tncs->imv_data[i].imv_send = NULL;
+ tncs->imv_data[i].imv_send_len = 0;
+ }
+
+ if (tncs->tncs_message) {
+ size_t len = os_strlen(tncs->tncs_message);
+ os_memcpy(pos, tncs->tncs_message, len);
+ pos += len;
+ os_free(tncs->tncs_message);
+ tncs->tncs_message = NULL;
+ }
+
+ return pos;
+}
+
+
+char * tncs_if_tnccs_start(struct tncs_data *tncs)
+{
+ char *buf = os_malloc(1000);
+ if (buf == NULL)
+ return NULL;
+ tncs->last_batchid++;
+ os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid);
+ return buf;
+}
+
+
+char * tncs_if_tnccs_end(void)
+{
+ char *buf = os_malloc(100);
+ if (buf == NULL)
+ return NULL;
+ os_snprintf(buf, 100, IF_TNCCS_END);
+ return buf;
+}
+
+
+static int tncs_get_type(char *start, unsigned int *type)
+{
+ char *pos = os_strstr(start, "<Type>");
+ if (pos == NULL)
+ return -1;
+ pos += 6;
+ *type = strtoul(pos, NULL, 16);
+ return 0;
+}
+
+
+static unsigned char * tncs_get_base64(char *start, size_t *decoded_len)
+{
+ char *pos, *pos2;
+ unsigned char *decoded;
+
+ pos = os_strstr(start, "<Base64>");
+ if (pos == NULL)
+ return NULL;
+
+ pos += 8;
+ pos2 = os_strstr(pos, "</Base64>");
+ if (pos2 == NULL)
+ return NULL;
+ *pos2 = '\0';
+
+ decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
+ decoded_len);
+ *pos2 = '<';
+ if (decoded == NULL) {
+ wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
+ }
+
+ return decoded;
+}
+
+
+static enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs)
+{
+ enum IMV_Action_Recommendation rec;
+ struct tnc_if_imv *imv;
+ TNC_ConnectionState state;
+ char *txt;
+
+ wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs");
+
+ if (tncs->done)
+ return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
+
+ tncs_solicit_recommendation(tncs);
+
+ /* Select the most restrictive recommendation */
+ rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
+ for (imv = tncs->imv; imv; imv = imv->next) {
+ TNC_IMV_Action_Recommendation irec;
+ irec = tncs->imv_data[imv->imvID].recommendation;
+ if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
+ rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
+ if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE &&
+ rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
+ rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
+ if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW &&
+ rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
+ rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
+ }
+
+ wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec);
+ tncs->recommendation = rec;
+ tncs->done = 1;
+
+ txt = NULL;
+ switch (rec) {
+ case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
+ case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
+ txt = "allow";
+ state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
+ txt = "isolate";
+ state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
+ break;
+ case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
+ txt = "none";
+ state = TNC_CONNECTION_STATE_ACCESS_NONE;
+ break;
+ default:
+ state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
+ break;
+ }
+
+ if (txt) {
+ os_free(tncs->tncs_message);
+ tncs->tncs_message = os_zalloc(200);
+ if (tncs->tncs_message) {
+ os_snprintf(tncs->tncs_message, 199,
+ "<TNCC-TNCS-Message><Type>%08X</Type>"
+ "<XML><TNCCS-Recommendation type=\"%s\">"
+ "</TNCCS-Recommendation></XML>"
+ "</TNCC-TNCS-Message>",
+ TNC_TNCCS_RECOMMENDATION, txt);
+ }
+ }
+
+ for (imv = tncs->imv; imv; imv = imv->next) {
+ tncs_imv_notify_connection_change(imv, tncs->connectionID,
+ state);
+ }
+
+ switch (rec) {
+ case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
+ return TNCCS_RECOMMENDATION_ALLOW;
+ case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
+ return TNCCS_RECOMMENDATION_NO_ACCESS;
+ case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
+ return TNCCS_RECOMMENDATION_ISOLATE;
+ case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
+ return TNCCS_RECOMMENDATION_NO_RECOMMENDATION;
+ default:
+ return TNCCS_PROCESS_ERROR;
+ }
+}
+
+
+enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
+ const u8 *msg, size_t len)
+{
+ char *buf, *start, *end, *pos, *pos2, *payload;
+ unsigned int batch_id;
+ unsigned char *decoded;
+ size_t decoded_len;
+
+ buf = os_malloc(len + 1);
+ if (buf == NULL)
+ return TNCCS_PROCESS_ERROR;
+
+ os_memcpy(buf, msg, len);
+ buf[len] = '\0';
+ start = os_strstr(buf, "<TNCCS-Batch ");
+ end = os_strstr(buf, "</TNCCS-Batch>");
+ if (start == NULL || end == NULL || start > end) {
+ os_free(buf);
+ return TNCCS_PROCESS_ERROR;
+ }
+
+ start += 13;
+ while (*start == ' ')
+ start++;
+ *end = '\0';
+
+ pos = os_strstr(start, "BatchId=");
+ if (pos == NULL) {
+ os_free(buf);
+ return TNCCS_PROCESS_ERROR;
+ }
+
+ pos += 8;
+ if (*pos == '"')
+ pos++;
+ batch_id = atoi(pos);
+ wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
+ batch_id);
+ if (batch_id != tncs->last_batchid + 1) {
+ wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
+ "%u (expected %u)",
+ batch_id, tncs->last_batchid + 1);
+ os_free(buf);
+ return TNCCS_PROCESS_ERROR;
+ }
+ tncs->last_batchid = batch_id;
+
+ while (*pos != '\0' && *pos != '>')
+ pos++;
+ if (*pos == '\0') {
+ os_free(buf);
+ return TNCCS_PROCESS_ERROR;
+ }
+ pos++;
+ payload = start;
+
+ /*
+ * <IMC-IMV-Message>
+ * <Type>01234567</Type>
+ * <Base64>foo==</Base64>
+ * </IMC-IMV-Message>
+ */
+
+ while (*start) {
+ char *endpos;
+ unsigned int type;
+
+ pos = os_strstr(start, "<IMC-IMV-Message>");
+ if (pos == NULL)
+ break;
+ start = pos + 17;
+ end = os_strstr(start, "</IMC-IMV-Message>");
+ if (end == NULL)
+ break;
+ *end = '\0';
+ endpos = end;
+ end += 18;
+
+ if (tncs_get_type(start, &type) < 0) {
+ *endpos = '<';
+ start = end;
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
+
+ decoded = tncs_get_base64(start, &decoded_len);
+ if (decoded == NULL) {
+ *endpos = '<';
+ start = end;
+ continue;
+ }
+
+ tncs_send_to_imvs(tncs, type, decoded, decoded_len);
+
+ os_free(decoded);
+
+ start = end;
+ }
+
+ /*
+ * <TNCC-TNCS-Message>
+ * <Type>01234567</Type>
+ * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
+ * <Base64>foo==</Base64>
+ * </TNCC-TNCS-Message>
+ */
+
+ start = payload;
+ while (*start) {
+ unsigned int type;
+ char *xml, *xmlend, *endpos;
+
+ pos = os_strstr(start, "<TNCC-TNCS-Message>");
+ if (pos == NULL)
+ break;
+ start = pos + 19;
+ end = os_strstr(start, "</TNCC-TNCS-Message>");
+ if (end == NULL)
+ break;
+ *end = '\0';
+ endpos = end;
+ end += 20;
+
+ if (tncs_get_type(start, &type) < 0) {
+ *endpos = '<';
+ start = end;
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
+ type);
+
+ /* Base64 OR XML */
+ decoded = NULL;
+ xml = NULL;
+ xmlend = NULL;
+ pos = os_strstr(start, "<XML>");
+ if (pos) {
+ pos += 5;
+ pos2 = os_strstr(pos, "</XML>");
+ if (pos2 == NULL) {
+ *endpos = '<';
+ start = end;
+ continue;
+ }
+ xmlend = pos2;
+ xml = pos;
+ } else {
+ decoded = tncs_get_base64(start, &decoded_len);
+ if (decoded == NULL) {
+ *endpos = '<';
+ start = end;
+ continue;
+ }
+ }
+
+ if (decoded) {
+ wpa_hexdump_ascii(MSG_MSGDUMP,
+ "TNC: TNCC-TNCS-Message Base64",
+ decoded, decoded_len);
+ os_free(decoded);
+ }
+
+ if (xml) {
+ wpa_hexdump_ascii(MSG_MSGDUMP,
+ "TNC: TNCC-TNCS-Message XML",
+ (unsigned char *) xml,
+ xmlend - xml);
+ }
+
+ start = end;
+ }
+
+ os_free(buf);
+
+ tncs_batch_ending(tncs);
+
+ if (tncs_total_send_len(tncs) == 0)
+ return tncs_derive_recommendation(tncs);
+
+ return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
+}
+
+
+static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end,
+ int *error)
+{
+ struct tnc_if_imv *imv;
+ char *pos, *pos2;
+
+ if (id >= TNC_MAX_IMV_ID) {
+ wpa_printf(MSG_DEBUG, "TNC: Too many IMVs");
+ return NULL;
+ }
+
+ imv = os_zalloc(sizeof(*imv));
+ if (imv == NULL) {
+ *error = 1;
+ return NULL;
+ }
+
+ imv->imvID = id;
+
+ pos = start;
+ wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos);
+ if (pos + 1 >= end || *pos != '"') {
+ wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
+ "(no starting quotation mark)", start);
+ os_free(imv);
+ return NULL;
+ }
+
+ pos++;
+ pos2 = pos;
+ while (pos2 < end && *pos2 != '"')
+ pos2++;
+ if (pos2 >= end) {
+ wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
+ "(no ending quotation mark)", start);
+ os_free(imv);
+ return NULL;
+ }
+ *pos2 = '\0';
+ wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
+ imv->name = os_strdup(pos);
+
+ pos = pos2 + 1;
+ if (pos >= end || *pos != ' ') {
+ wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
+ "(no space after name)", start);
+ os_free(imv);
+ return NULL;
+ }
+
+ pos++;
+ wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos);
+ imv->path = os_strdup(pos);
+
+ return imv;
+}
+
+
+static int tncs_read_config(struct tncs_global *global)
+{
+ char *config, *end, *pos, *line_end;
+ size_t config_len;
+ struct tnc_if_imv *imv, *last;
+ int id = 0;
+
+ last = NULL;
+
+ config = os_readfile(TNC_CONFIG_FILE, &config_len);
+ if (config == NULL) {
+ wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
+ "file '%s'", TNC_CONFIG_FILE);
+ return -1;
+ }
+
+ end = config + config_len;
+ for (pos = config; pos < end; pos = line_end + 1) {
+ line_end = pos;
+ while (*line_end != '\n' && *line_end != '\r' &&
+ line_end < end)
+ line_end++;
+ *line_end = '\0';
+
+ if (os_strncmp(pos, "IMV ", 4) == 0) {
+ int error = 0;
+
+ imv = tncs_parse_imv(id++, pos + 4, line_end, &error);
+ if (error)
+ return -1;
+ if (imv) {
+ if (last == NULL)
+ global->imv = imv;
+ else
+ last->next = imv;
+ last = imv;
+ }
+ }
+ }
+
+ os_free(config);
+
+ return 0;
+}
+
+
+struct tncs_data * tncs_init(void)
+{
+ struct tncs_data *tncs;
+
+ if (tncs_global_data == NULL)
+ return NULL;
+
+ tncs = os_zalloc(sizeof(*tncs));
+ if (tncs == NULL)
+ return NULL;
+ tncs->imv = tncs_global_data->imv;
+ tncs->connectionID = tncs_global_data->next_conn_id++;
+ tncs->next = tncs_global_data->connections;
+ tncs_global_data->connections = tncs;
+
+ return tncs;
+}
+
+
+void tncs_deinit(struct tncs_data *tncs)
+{
+ int i;
+ struct tncs_data *prev, *conn;
+
+ if (tncs == NULL)
+ return;
+
+ for (i = 0; i < TNC_MAX_IMV_ID; i++)
+ os_free(tncs->imv_data[i].imv_send);
+
+ prev = NULL;
+ conn = tncs_global_data->connections;
+ while (conn) {
+ if (conn == tncs) {
+ if (prev)
+ prev->next = tncs->next;
+ else
+ tncs_global_data->connections = tncs->next;
+ break;
+ }
+ prev = conn;
+ conn = conn->next;
+ }
+
+ os_free(tncs->tncs_message);
+ os_free(tncs);
+}
+
+
+int tncs_global_init(void)
+{
+ struct tnc_if_imv *imv;
+
+ tncs_global_data = os_zalloc(sizeof(*tncs_global_data));
+ if (tncs_global_data == NULL)
+ return -1;
+
+ if (tncs_read_config(tncs_global_data) < 0) {
+ wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
+ goto failed;
+ }
+
+ for (imv = tncs_global_data->imv; imv; imv = imv->next) {
+ if (tncs_load_imv(imv)) {
+ wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'",
+ imv->name);
+ goto failed;
+ }
+ }
+
+ return 0;
+
+failed:
+ tncs_global_deinit();
+ return -1;
+}
+
+
+void tncs_global_deinit(void)
+{
+ struct tnc_if_imv *imv, *prev;
+
+ if (tncs_global_data == NULL)
+ return;
+
+ imv = tncs_global_data->imv;
+ while (imv) {
+ tncs_unload_imv(imv);
+
+ prev = imv;
+ imv = imv->next;
+ os_free(prev);
+ }
+
+ os_free(tncs_global_data);
+}
+
+
+struct wpabuf * tncs_build_soh_request(void)
+{
+ struct wpabuf *buf;
+
+ /*
+ * Build a SoH Request TLV (to be used inside SoH EAP Extensions
+ * Method)
+ */
+
+ buf = wpabuf_alloc(8 + 4);
+ if (buf == NULL)
+ return NULL;
+
+ /* Vendor-Specific TLV (Microsoft) - SoH Request */
+ wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
+ wpabuf_put_be16(buf, 8); /* Length */
+
+ wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
+
+ wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */
+ wpabuf_put_be16(buf, 0); /* Length */
+
+ return buf;
+}
+
+
+struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
+ int *failure)
+{
+ wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len);
+ *failure = 0;
+
+ /* TODO: return MS-SoH Response TLV */
+
+ return NULL;
+}
Added: wpasupplicant/branches/upstream/current/src/eap_server/tncs.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/tncs.h?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/tncs.h (added)
+++ wpasupplicant/branches/upstream/current/src/eap_server/tncs.h Sat Jun 14 00:26:56 2008
@@ -1,0 +1,49 @@
+/*
+ * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
+ * Copyright (c) 2007-2008, 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 TNCS_H
+#define TNCS_H
+
+struct tncs_data;
+
+struct tncs_data * tncs_init(void);
+void tncs_deinit(struct tncs_data *tncs);
+void tncs_init_connection(struct tncs_data *tncs);
+size_t tncs_total_send_len(struct tncs_data *tncs);
+u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos);
+char * tncs_if_tnccs_start(struct tncs_data *tncs);
+char * tncs_if_tnccs_end(void);
+
+enum tncs_process_res {
+ TNCCS_PROCESS_ERROR = -1,
+ TNCCS_PROCESS_OK_NO_RECOMMENDATION = 0,
+ TNCCS_RECOMMENDATION_ERROR,
+ TNCCS_RECOMMENDATION_ALLOW,
+ TNCCS_RECOMMENDATION_NONE,
+ TNCCS_RECOMMENDATION_ISOLATE,
+ TNCCS_RECOMMENDATION_NO_ACCESS,
+ TNCCS_RECOMMENDATION_NO_RECOMMENDATION
+};
+
+enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
+ const u8 *msg, size_t len);
+
+int tncs_global_init(void);
+void tncs_global_deinit(void);
+
+struct wpabuf * tncs_build_soh_request(void);
+struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
+ int *failure);
+
+#endif /* TNCS_H */
Modified: wpasupplicant/branches/upstream/current/src/radius/radius.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius.c Sat Jun 14 00:26:56 2008
@@ -181,6 +181,8 @@
RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity",
+ RADIUS_ATTR_TEXT },
{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
};
#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
@@ -803,6 +805,7 @@
ppos = plain = os_malloc(plen);
if (plain == NULL)
return NULL;
+ plain[0] = 0;
while (left > 0) {
/* b(1) = MD5(Secret + Request-Authenticator + Salt)
@@ -827,7 +830,7 @@
left -= MD5_MAC_LEN;
}
- if (plain[0] > plen - 1) {
+ if (plain[0] == 0 || plain[0] > plen - 1) {
printf("Failed to decrypt MPPE key\n");
os_free(plain);
return NULL;
Modified: wpasupplicant/branches/upstream/current/src/radius/radius.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius.h (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius.h Sat Jun 14 00:26:56 2008
@@ -87,6 +87,7 @@
RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID = 81,
RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85,
+ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY = 89,
RADIUS_ATTR_NAS_IPV6_ADDRESS = 95
};
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_client.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_client.c Sat Jun 14 00:26:56 2008
@@ -738,15 +738,16 @@
struct hostapd_radius_server *oserv,
int sock, int sock6, int auth)
{
- struct sockaddr_in serv;
+ struct sockaddr_in serv, claddr;
#ifdef CONFIG_IPV6
- struct sockaddr_in6 serv6;
+ struct sockaddr_in6 serv6, claddr6;
#endif /* CONFIG_IPV6 */
- struct sockaddr *addr;
- socklen_t addrlen;
+ struct sockaddr *addr, *cl_addr;
+ socklen_t addrlen, claddrlen;
char abuf[50];
int sel_sock;
struct radius_msg_list *entry;
+ struct hostapd_radius_servers *conf = radius->conf;
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
@@ -816,10 +817,64 @@
return -1;
}
+ if (conf->force_client_addr) {
+ switch (conf->client_addr.af) {
+ case AF_INET:
+ os_memset(&claddr, 0, sizeof(claddr));
+ claddr.sin_family = AF_INET;
+ claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr;
+ claddr.sin_port = htons(0);
+ cl_addr = (struct sockaddr *) &claddr;
+ claddrlen = sizeof(claddr);
+ break;
+#ifdef CONFIG_IPV6
+ case AF_INET6:
+ os_memset(&claddr6, 0, sizeof(claddr6));
+ claddr6.sin6_family = AF_INET6;
+ os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6,
+ sizeof(struct in6_addr));
+ claddr6.sin6_port = htons(0);
+ cl_addr = (struct sockaddr *) &claddr6;
+ claddrlen = sizeof(claddr6);
+ break;
+#endif /* CONFIG_IPV6 */
+ default:
+ return -1;
+ }
+
+ if (bind(sel_sock, cl_addr, claddrlen) < 0) {
+ perror("bind[radius]");
+ return -1;
+ }
+ }
+
if (connect(sel_sock, addr, addrlen) < 0) {
perror("connect[radius]");
return -1;
}
+
+#ifndef CONFIG_NATIVE_WINDOWS
+ switch (nserv->addr.af) {
+ case AF_INET:
+ claddrlen = sizeof(claddr);
+ getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen);
+ wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
+ inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port));
+ break;
+#ifdef CONFIG_IPV6
+ case AF_INET6: {
+ claddrlen = sizeof(claddr6);
+ getsockname(sel_sock, (struct sockaddr *) &claddr6,
+ &claddrlen);
+ wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
+ inet_ntop(AF_INET6, &claddr6.sin6_addr,
+ abuf, sizeof(abuf)),
+ ntohs(claddr6.sin6_port));
+ break;
+ }
+#endif /* CONFIG_IPV6 */
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
if (auth)
radius->auth_sock = sel_sock;
Modified: wpasupplicant/branches/upstream/current/src/radius/radius_client.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius_client.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_client.h (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_client.h Sat Jun 14 00:26:56 2008
@@ -57,6 +57,9 @@
int acct_interim_interval;
int msg_dumps;
+
+ struct hostapd_ip_addr client_addr;
+ int force_client_addr;
};
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_server.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_server.c Sat Jun 14 00:26:56 2008
@@ -87,6 +87,7 @@
u8 *pac_opaque_encr_key;
char *eap_fast_a_id;
int eap_sim_aka_result_ind;
+ int tnc;
int ipv6;
struct os_time start_time;
struct radius_server_counters counters;
@@ -311,6 +312,7 @@
eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
eap_conf.eap_fast_a_id = data->eap_fast_a_id;
eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
+ eap_conf.tnc = data->tnc;
sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
&eap_conf);
if (sess->eap == NULL) {
@@ -1016,6 +1018,7 @@
data->eap_fast_a_id = os_strdup(conf->eap_fast_a_id);
data->get_eap_user = conf->get_eap_user;
data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
+ data->tnc = conf->tnc;
data->clients = radius_server_read_clients(conf->client_file,
conf->ipv6);
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_server.h (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_server.h Sat Jun 14 00:26:56 2008
@@ -27,6 +27,7 @@
u8 *pac_opaque_encr_key;
char *eap_fast_a_id;
int eap_sim_aka_result_ind;
+ int tnc;
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/peerkey.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/peerkey.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/peerkey.c (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/peerkey.c Sat Jun 14 00:26:56 2008
@@ -867,8 +867,8 @@
if (peerkey->cipher == WPA_CIPHER_TKIP) {
/* Swap Tx/Rx keys for Michael MIC */
os_memcpy(key_buf, _key, 16);
- os_memcpy(key_buf + 16, _key + 24, 8);
- os_memcpy(key_buf + 24, _key + 16, 8);
+ os_memcpy(key_buf + 16, peerkey->stk.u.auth.rx_mic_key, 8);
+ os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8);
_key = key_buf;
key_len = 32;
} else
Modified: wpasupplicant/branches/upstream/current/src/rsn_supp/preauth.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/preauth.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/preauth.c (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/preauth.c Sat Jun 14 00:26:56 2008
@@ -68,8 +68,7 @@
wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len);
if (sm->preauth_eapol == NULL ||
- os_memcmp(sm->preauth_bssid, "\x00\x00\x00\x00\x00\x00",
- ETH_ALEN) == 0 ||
+ is_zero_ether_addr(sm->preauth_bssid) ||
os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) {
wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
"unexpected source " MACSTR " - dropped",
Modified: wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.c (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.c Sat Jun 14 00:26:56 2008
@@ -98,8 +98,7 @@
int ver, const u8 *dest, u16 proto,
u8 *msg, size_t msg_len, u8 *key_mic)
{
- if (os_memcmp(dest, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0 &&
- os_memcmp(sm->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0) {
+ if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) {
/*
* Association event was not yet received; try to fetch
* BSSID from the driver.
@@ -451,7 +450,6 @@
MACSTR " [PTK=%s GTK=%s]", MAC2STR(addr),
wpa_cipher_txt(sm->pairwise_cipher),
wpa_cipher_txt(sm->group_cipher));
- wpa_sm_cancel_scan(sm);
wpa_sm_cancel_auth_timeout(sm);
wpa_sm_set_state(sm, WPA_COMPLETED);
@@ -783,7 +781,6 @@
}
wpa_sm_disassociate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
- wpa_sm_req_scan(sm, 0, 0);
}
@@ -1791,7 +1788,6 @@
os_memset(sm->pmk, 0, sizeof(sm->pmk));
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
- wpa_sm_req_scan(sm, 0, 0);
}
}
@@ -1859,6 +1855,8 @@
*/
void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
{
+ int clear_ptk = 1;
+
if (sm == NULL)
return;
@@ -1871,15 +1869,25 @@
rsn_preauth_deinit(sm);
#ifdef CONFIG_IEEE80211R
- if ((sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X ||
- sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) &&
- wpa_ft_is_completed(sm)) {
+ if (wpa_ft_is_completed(sm)) {
wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
/* Prepare for the next transition */
wpa_ft_prepare_auth_request(sm);
+
+ clear_ptk = 0;
}
#endif /* CONFIG_IEEE80211R */
+
+ if (clear_ptk) {
+ /*
+ * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
+ * this is not part of a Fast BSS Transition.
+ */
+ wpa_printf(MSG_DEBUG, "WPA: Clear old PTK");
+ sm->ptk_set = 0;
+ sm->tptk_set = 0;
+ }
}
Modified: wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.h (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.h Sat Jun 14 00:26:56 2008
@@ -36,8 +36,6 @@
void (*set_state)(void *ctx, wpa_states state);
wpa_states (*get_state)(void *ctx);
- void (*req_scan)(void *ctx, int sec, int usec);
- void (*cancel_scan)(void *ctx);
void (*deauthenticate)(void * ctx, int reason_code);
void (*disassociate)(void *ctx, int reason_code);
int (*set_key)(void *ctx, wpa_alg alg,
@@ -280,7 +278,7 @@
int ft_action, const u8 *target_ap);
int wpa_ft_is_completed(struct wpa_sm *sm);
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
- size_t ies_len);
+ size_t ies_len, const u8 *src_addr);
int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap);
#else /* CONFIG_IEEE80211R */
@@ -310,7 +308,8 @@
}
static inline int
-wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
+wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
+ const u8 *src_addr)
{
return -1;
}
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c Sat Jun 14 00:26:56 2008
@@ -121,7 +121,7 @@
const u8 *kck, const u8 *target_ap)
{
size_t buf_len;
- u8 *buf, *pos, *ftie_len;
+ u8 *buf, *pos, *ftie_len, *ftie_pos;
struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
struct rsn_ie_hdr *rsnie;
@@ -226,6 +226,7 @@
mdie->ft_capab = 0; /* FIX: copy from the target AP's MDIE */
/* FTIE[SNonce, R0KH-ID] */
+ ftie_pos = pos;
*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
ftie_len = pos++;
ftie = (struct rsn_ftie *) pos;
@@ -255,7 +256,7 @@
ftie->mic_control[1] = 3; /* Information element count */
if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5,
((u8 *) mdie) - 2, 2 + sizeof(*mdie),
- ((u8 *) ftie) - 2, 2 + *ftie_len,
+ ftie_pos, 2 + *ftie_len,
(u8 *) rsnie, 2 + rsnie->len, NULL, 0,
ftie->mic) < 0) {
wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
@@ -535,7 +536,7 @@
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
- bssid = ft_action ? sm->target_ap : sm->bssid;
+ bssid = target_ap;
wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
bssid, sm->pmk_r1_name,
(u8 *) &sm->ptk, sizeof(sm->ptk), ptk_name);
@@ -581,7 +582,7 @@
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
- size_t ies_len)
+ size_t ies_len, const u8 *src_addr)
{
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
@@ -664,7 +665,7 @@
return -1;
}
- if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, sm->bssid, 6,
+ if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6,
parse.mdie - 2, parse.mdie_len + 2,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2, NULL, 0,
Modified: wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_i.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_i.h (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_i.h Sat Jun 14 00:26:56 2008
@@ -120,18 +120,6 @@
return sm->ctx->get_state(sm->ctx->ctx);
}
-static inline void wpa_sm_req_scan(struct wpa_sm *sm, int sec, int usec)
-{
- WPA_ASSERT(sm->ctx->req_scan);
- sm->ctx->req_scan(sm->ctx->ctx, sec, usec);
-}
-
-static inline void wpa_sm_cancel_scan(struct wpa_sm *sm)
-{
- WPA_ASSERT(sm->ctx->cancel_scan);
- sm->ctx->cancel_scan(sm->ctx->ctx);
-}
-
static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, int reason_code)
{
WPA_ASSERT(sm->ctx->deauthenticate);
Modified: wpasupplicant/branches/upstream/current/src/tls/libtommath.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/libtommath.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/libtommath.c (original)
+++ wpasupplicant/branches/upstream/current/src/tls/libtommath.c Sat Jun 14 00:26:56 2008
@@ -1,17 +1,14 @@
/*
- * Minimal code for RSA support from LibTomMath 0.3.9
- * http://math.libtomcrypt.com/
- * http://math.libtomcrypt.com/files/ltm-0.39.tar.bz2
+ * Minimal code for RSA support from LibTomMath 0.41
+ * http://libtom.org/
+ * http://libtom.org/files/ltm-0.41.tar.bz2
* This library was released in public domain by Tom St Denis.
*
- * The combination in this file is not using many of the optimized algorithms
- * (e.g., Montgomery reduction) and is considerable slower than the LibTomMath
- * with its default of SC_RSA_1 settins. The main purpose of having this
- * version here is to make it easier to build bignum.c wrapper without having
- * to install and build an external library. However, it is likely worth the
- * effort to use the full library with SC_RSA_1 instead of this minimized copy.
- * Including the optimized algorithms may increase the size requirements by
- * 15 kB or so (measured with x86 build).
+ * The combination in this file may not use all of the optimized algorithms
+ * from LibTomMath and may be considerable slower than the LibTomMath with its
+ * default settings. The main purpose of having this version here is to make it
+ * easier to build bignum.c wrapper without having to install and build an
+ * external library.
*
* If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this
* libtommath.c file instead of using the external LibTomMath library.
@@ -30,6 +27,32 @@
#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this
* would require other than mp_reduce */
+#ifdef LTM_FAST
+
+/* Use faster div at the cost of about 1 kB */
+#define BN_MP_MUL_D_C
+
+/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */
+#define BN_MP_EXPTMOD_FAST_C
+#define BN_MP_MONTGOMERY_SETUP_C
+#define BN_FAST_MP_MONTGOMERY_REDUCE_C
+#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+#define BN_MP_MUL_2_C
+
+/* Include faster sqr at the cost of about 0.5 kB in code */
+#define BN_FAST_S_MP_SQR_C
+
+#else /* LTM_FAST */
+
+#define BN_MP_DIV_SMALL
+#define BN_MP_INIT_MULTI_C
+#define BN_MP_CLEAR_MULTI_C
+#define BN_MP_ABS_C
+#endif /* LTM_FAST */
+
+/* Current uses do not require support for negative exponent in exptmod, so we
+ * can save about 1.5 kB in leaving out invmod. */
+#define LTM_NO_NEG_EXP
/* from tommath.h */
@@ -110,8 +133,12 @@
static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+#ifdef BN_MP_INIT_MULTI_C
static int mp_init_multi(mp_int *mp, ...);
+#endif
+#ifdef BN_MP_CLEAR_MULTI_C
static void mp_clear_multi(mp_int *mp, ...);
+#endif
static int mp_lshd(mp_int * a, int b);
static void mp_set(mp_int * a, mp_digit b);
static void mp_clamp(mp_int * a);
@@ -122,16 +149,20 @@
static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d);
static int mp_init_copy(mp_int * a, mp_int * b);
static int mp_mul_2d(mp_int * a, int b, mp_int * c);
+#ifndef LTM_NO_NEG_EXP
static int mp_div_2(mp_int * a, mp_int * b);
+static int mp_invmod(mp_int * a, mp_int * b, mp_int * c);
+static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c);
+#endif /* LTM_NO_NEG_EXP */
static int mp_copy(mp_int * a, mp_int * b);
static int mp_count_bits(mp_int * a);
static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
static int mp_mod(mp_int * a, mp_int * b, mp_int * c);
static int mp_grow(mp_int * a, int size);
static int mp_cmp_mag(mp_int * a, mp_int * b);
-static int mp_invmod(mp_int * a, mp_int * b, mp_int * c);
+#ifdef BN_MP_ABS_C
static int mp_abs(mp_int * a, mp_int * b);
-static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c);
+#endif
static int mp_sqr(mp_int * a, mp_int * b);
static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
@@ -139,6 +170,15 @@
static int mp_reduce_setup(mp_int * a, mp_int * b);
static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu);
static int mp_init_size(mp_int * a, int size);
+#ifdef BN_MP_EXPTMOD_FAST_C
+static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
+#endif /* BN_MP_EXPTMOD_FAST_C */
+#ifdef BN_FAST_S_MP_SQR_C
+static int fast_s_mp_sqr (mp_int * a, mp_int * b);
+#endif /* BN_FAST_S_MP_SQR_C */
+#ifdef BN_MP_MUL_D_C
+static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
+#endif /* BN_MP_MUL_D_C */
@@ -546,6 +586,9 @@
/* if exponent X is negative we have to recurse */
if (X->sign == MP_NEG) {
+#ifdef LTM_NO_NEG_EXP
+ return MP_VAL;
+#else /* LTM_NO_NEG_EXP */
#ifdef BN_MP_INVMOD_C
mp_int tmpG, tmpX;
int err;
@@ -578,6 +621,7 @@
/* no invmod */
return MP_VAL;
#endif
+#endif /* LTM_NO_NEG_EXP */
}
/* modified diminished radix reduction */
@@ -668,6 +712,7 @@
}
+#ifndef LTM_NO_NEG_EXP
/* hac 14.61, pp608 */
static int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
{
@@ -694,6 +739,7 @@
#endif
return MP_VAL;
}
+#endif /* LTM_NO_NEG_EXP */
/* get the size for an unsigned equivalent */
@@ -704,6 +750,7 @@
}
+#ifndef LTM_NO_NEG_EXP
/* hac 14.61, pp608 */
static int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
{
@@ -857,6 +904,7 @@
LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL);
return res;
}
+#endif /* LTM_NO_NEG_EXP */
/* compare maginitude of two ints (unsigned) */
@@ -1233,6 +1281,7 @@
}
+#ifdef BN_MP_ABS_C
/* b = |a|
*
* Simple function copies the input and fixes the sign to positive
@@ -1253,6 +1302,7 @@
return MP_OKAY;
}
+#endif
/* set to a digit */
@@ -1264,6 +1314,7 @@
}
+#ifndef LTM_NO_NEG_EXP
/* b = a/2 */
static int mp_div_2(mp_int * a, mp_int * b)
{
@@ -1310,6 +1361,7 @@
mp_clamp (b);
return MP_OKAY;
}
+#endif /* LTM_NO_NEG_EXP */
/* shift left by a certain bit count */
@@ -1377,6 +1429,7 @@
}
+#ifdef BN_MP_INIT_MULTI_C
static int mp_init_multi(mp_int *mp, ...)
{
mp_err res = MP_OKAY; /* Assume ok until proven otherwise */
@@ -1412,8 +1465,10 @@
va_end(args);
return res; /* Assumed ok, if error flagged above. */
}
-
-
+#endif
+
+
+#ifdef BN_MP_CLEAR_MULTI_C
static void mp_clear_multi(mp_int *mp, ...)
{
mp_int* next_mp = mp;
@@ -1425,6 +1480,7 @@
}
va_end(args);
}
+#endif
/* shift left a certain amount of digits */
@@ -1531,6 +1587,8 @@
return MP_OKAY;
}
+
+#ifdef BN_MP_DIV_SMALL
/* slower bit-bang division... also smaller */
static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
@@ -1599,6 +1657,206 @@
mp_clear_multi(&ta, &tb, &tq, &q, NULL);
return res;
}
+
+#else
+
+/* integer signed division.
+ * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
+ * HAC pp.598 Algorithm 14.20
+ *
+ * Note that the description in HAC is horribly
+ * incomplete. For example, it doesn't consider
+ * the case where digits are removed from 'x' in
+ * the inner loop. It also doesn't consider the
+ * case that y has fewer than three digits, etc..
+ *
+ * The overall algorithm is as described as
+ * 14.20 from HAC but fixed to treat these cases.
+*/
+static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ mp_int q, x, y, t1, t2;
+ int res, n, t, i, norm, neg;
+
+ /* is divisor zero ? */
+ if (mp_iszero (b) == 1) {
+ return MP_VAL;
+ }
+
+ /* if a < b then q=0, r = a */
+ if (mp_cmp_mag (a, b) == MP_LT) {
+ if (d != NULL) {
+ res = mp_copy (a, d);
+ } else {
+ res = MP_OKAY;
+ }
+ if (c != NULL) {
+ mp_zero (c);
+ }
+ return res;
+ }
+
+ if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) {
+ return res;
+ }
+ q.used = a->used + 2;
+
+ if ((res = mp_init (&t1)) != MP_OKAY) {
+ goto LBL_Q;
+ }
+
+ if ((res = mp_init (&t2)) != MP_OKAY) {
+ goto LBL_T1;
+ }
+
+ if ((res = mp_init_copy (&x, a)) != MP_OKAY) {
+ goto LBL_T2;
+ }
+
+ if ((res = mp_init_copy (&y, b)) != MP_OKAY) {
+ goto LBL_X;
+ }
+
+ /* fix the sign */
+ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+ x.sign = y.sign = MP_ZPOS;
+
+ /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
+ norm = mp_count_bits(&y) % DIGIT_BIT;
+ if (norm < (int)(DIGIT_BIT-1)) {
+ norm = (DIGIT_BIT-1) - norm;
+ if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ } else {
+ norm = 0;
+ }
+
+ /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
+ n = x.used - 1;
+ t = y.used - 1;
+
+ /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
+ if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */
+ goto LBL_Y;
+ }
+
+ while (mp_cmp (&x, &y) != MP_LT) {
+ ++(q.dp[n - t]);
+ if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ }
+
+ /* reset y by shifting it back down */
+ mp_rshd (&y, n - t);
+
+ /* step 3. for i from n down to (t + 1) */
+ for (i = n; i >= (t + 1); i--) {
+ if (i > x.used) {
+ continue;
+ }
+
+ /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
+ * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
+ if (x.dp[i] == y.dp[t]) {
+ q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
+ } else {
+ mp_word tmp;
+ tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT);
+ tmp |= ((mp_word) x.dp[i - 1]);
+ tmp /= ((mp_word) y.dp[t]);
+ if (tmp > (mp_word) MP_MASK)
+ tmp = MP_MASK;
+ q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
+ }
+
+ /* while (q{i-t-1} * (yt * b + y{t-1})) >
+ xi * b**2 + xi-1 * b + xi-2
+
+ do q{i-t-1} -= 1;
+ */
+ q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
+ do {
+ q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK;
+
+ /* find left hand */
+ mp_zero (&t1);
+ t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
+ t1.dp[1] = y.dp[t];
+ t1.used = 2;
+ if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ /* find right hand */
+ t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
+ t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
+ t2.dp[2] = x.dp[i];
+ t2.used = 3;
+ } while (mp_cmp_mag(&t1, &t2) == MP_GT);
+
+ /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
+ if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
+ if (x.sign == MP_NEG) {
+ if ((res = mp_copy (&y, &t1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK;
+ }
+ }
+
+ /* now q is the quotient and x is the remainder
+ * [which we have to normalize]
+ */
+
+ /* get sign before writing to c */
+ x.sign = x.used == 0 ? MP_ZPOS : a->sign;
+
+ if (c != NULL) {
+ mp_clamp (&q);
+ mp_exch (&q, c);
+ c->sign = neg;
+ }
+
+ if (d != NULL) {
+ mp_div_2d (&x, norm, &x, NULL);
+ mp_exch (&x, d);
+ }
+
+ res = MP_OKAY;
+
+LBL_Y:mp_clear (&y);
+LBL_X:mp_clear (&x);
+LBL_T2:mp_clear (&t2);
+LBL_T1:mp_clear (&t1);
+LBL_Q:mp_clear (&q);
+ return res;
+}
+
+#endif
#ifdef MP_LOW_MEM
@@ -2368,3 +2626,756 @@
mp_clear (&t);
return MP_OKAY;
}
+
+
+#ifdef BN_MP_MONTGOMERY_SETUP_C
+/* setups the montgomery reduction stuff */
+static int
+mp_montgomery_setup (mp_int * n, mp_digit * rho)
+{
+ mp_digit x, b;
+
+/* fast inversion mod 2**k
+ *
+ * Based on the fact that
+ *
+ * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n)
+ * => 2*X*A - X*X*A*A = 1
+ * => 2*(1) - (1) = 1
+ */
+ b = n->dp[0];
+
+ if ((b & 1) == 0) {
+ return MP_VAL;
+ }
+
+ x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
+ x *= 2 - b * x; /* here x*a==1 mod 2**8 */
+#if !defined(MP_8BIT)
+ x *= 2 - b * x; /* here x*a==1 mod 2**16 */
+#endif
+#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
+ x *= 2 - b * x; /* here x*a==1 mod 2**32 */
+#endif
+#ifdef MP_64BIT
+ x *= 2 - b * x; /* here x*a==1 mod 2**64 */
+#endif
+
+ /* rho = -1/m mod b */
+ *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK;
+
+ return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
+/* computes xR**-1 == x (mod N) via Montgomery Reduction
+ *
+ * This is an optimized implementation of montgomery_reduce
+ * which uses the comba method to quickly calculate the columns of the
+ * reduction.
+ *
+ * Based on Algorithm 14.32 on pp.601 of HAC.
+*/
+int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+{
+ int ix, res, olduse;
+ mp_word W[MP_WARRAY];
+
+ /* get old used count */
+ olduse = x->used;
+
+ /* grow a as required */
+ if (x->alloc < n->used + 1) {
+ if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* first we have to get the digits of the input into
+ * an array of double precision words W[...]
+ */
+ {
+ register mp_word *_W;
+ register mp_digit *tmpx;
+
+ /* alias for the W[] array */
+ _W = W;
+
+ /* alias for the digits of x*/
+ tmpx = x->dp;
+
+ /* copy the digits of a into W[0..a->used-1] */
+ for (ix = 0; ix < x->used; ix++) {
+ *_W++ = *tmpx++;
+ }
+
+ /* zero the high words of W[a->used..m->used*2] */
+ for (; ix < n->used * 2 + 1; ix++) {
+ *_W++ = 0;
+ }
+ }
+
+ /* now we proceed to zero successive digits
+ * from the least significant upwards
+ */
+ for (ix = 0; ix < n->used; ix++) {
+ /* mu = ai * m' mod b
+ *
+ * We avoid a double precision multiplication (which isn't required)
+ * by casting the value down to a mp_digit. Note this requires
+ * that W[ix-1] have the carry cleared (see after the inner loop)
+ */
+ register mp_digit mu;
+ mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
+
+ /* a = a + mu * m * b**i
+ *
+ * This is computed in place and on the fly. The multiplication
+ * by b**i is handled by offseting which columns the results
+ * are added to.
+ *
+ * Note the comba method normally doesn't handle carries in the
+ * inner loop In this case we fix the carry from the previous
+ * column since the Montgomery reduction requires digits of the
+ * result (so far) [see above] to work. This is
+ * handled by fixing up one carry after the inner loop. The
+ * carry fixups are done in order so after these loops the
+ * first m->used words of W[] have the carries fixed
+ */
+ {
+ register int iy;
+ register mp_digit *tmpn;
+ register mp_word *_W;
+
+ /* alias for the digits of the modulus */
+ tmpn = n->dp;
+
+ /* Alias for the columns set by an offset of ix */
+ _W = W + ix;
+
+ /* inner loop */
+ for (iy = 0; iy < n->used; iy++) {
+ *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
+ }
+ }
+
+ /* now fix carry for next digit, W[ix+1] */
+ W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
+ }
+
+ /* now we have to propagate the carries and
+ * shift the words downward [all those least
+ * significant digits we zeroed].
+ */
+ {
+ register mp_digit *tmpx;
+ register mp_word *_W, *_W1;
+
+ /* nox fix rest of carries */
+
+ /* alias for current word */
+ _W1 = W + ix;
+
+ /* alias for next word, where the carry goes */
+ _W = W + ++ix;
+
+ for (; ix <= n->used * 2 + 1; ix++) {
+ *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
+ }
+
+ /* copy out, A = A/b**n
+ *
+ * The result is A/b**n but instead of converting from an
+ * array of mp_word to mp_digit than calling mp_rshd
+ * we just copy them in the right order
+ */
+
+ /* alias for destination word */
+ tmpx = x->dp;
+
+ /* alias for shifted double precision result */
+ _W = W + n->used;
+
+ for (ix = 0; ix < n->used + 1; ix++) {
+ *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
+ }
+
+ /* zero oldused digits, if the input a was larger than
+ * m->used+1 we'll have to clear the digits
+ */
+ for (; ix < olduse; ix++) {
+ *tmpx++ = 0;
+ }
+ }
+
+ /* set the max used and clamp */
+ x->used = n->used + 1;
+ mp_clamp (x);
+
+ /* if A >= m then A = A - m */
+ if (mp_cmp_mag (x, n) != MP_LT) {
+ return s_mp_sub (x, n, x);
+ }
+ return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_MP_MUL_2_C
+/* b = a*2 */
+static int mp_mul_2(mp_int * a, mp_int * b)
+{
+ int x, res, oldused;
+
+ /* grow to accomodate result */
+ if (b->alloc < a->used + 1) {
+ if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ oldused = b->used;
+ b->used = a->used;
+
+ {
+ register mp_digit r, rr, *tmpa, *tmpb;
+
+ /* alias for source */
+ tmpa = a->dp;
+
+ /* alias for dest */
+ tmpb = b->dp;
+
+ /* carry */
+ r = 0;
+ for (x = 0; x < a->used; x++) {
+
+ /* get what will be the *next* carry bit from the
+ * MSB of the current digit
+ */
+ rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
+
+ /* now shift up this digit, add in the carry [from the previous] */
+ *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
+
+ /* copy the carry that would be from the source
+ * digit into the next iteration
+ */
+ r = rr;
+ }
+
+ /* new leading digit? */
+ if (r != 0) {
+ /* add a MSB which is always 1 at this point */
+ *tmpb = 1;
+ ++(b->used);
+ }
+
+ /* now zero any excess digits on the destination
+ * that we didn't write to
+ */
+ tmpb = b->dp + b->used;
+ for (x = b->used; x < oldused; x++) {
+ *tmpb++ = 0;
+ }
+ }
+ b->sign = a->sign;
+ return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+/*
+ * shifts with subtractions when the result is greater than b.
+ *
+ * The method is slightly modified to shift B unconditionally upto just under
+ * the leading bit of b. This saves alot of multiple precision shifting.
+ */
+static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
+{
+ int x, bits, res;
+
+ /* how many bits of last digit does b use */
+ bits = mp_count_bits (b) % DIGIT_BIT;
+
+ if (b->used > 1) {
+ if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
+ return res;
+ }
+ } else {
+ mp_set(a, 1);
+ bits = 1;
+ }
+
+
+ /* now compute C = A * B mod b */
+ for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
+ if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
+ return res;
+ }
+ if (mp_cmp_mag (a, b) != MP_LT) {
+ if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
+ return res;
+ }
+ }
+ }
+
+ return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_MP_EXPTMOD_FAST_C
+/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
+ *
+ * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
+ * The value of k changes based on the size of the exponent.
+ *
+ * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
+ */
+
+static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
+{
+ mp_int M[TAB_SIZE], res;
+ mp_digit buf, mp;
+ int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+
+ /* use a pointer to the reduction algorithm. This allows us to use
+ * one of many reduction algorithms without modding the guts of
+ * the code with if statements everywhere.
+ */
+ int (*redux)(mp_int*,mp_int*,mp_digit);
+
+ /* find window size */
+ x = mp_count_bits (X);
+ if (x <= 7) {
+ winsize = 2;
+ } else if (x <= 36) {
+ winsize = 3;
+ } else if (x <= 140) {
+ winsize = 4;
+ } else if (x <= 450) {
+ winsize = 5;
+ } else if (x <= 1303) {
+ winsize = 6;
+ } else if (x <= 3529) {
+ winsize = 7;
+ } else {
+ winsize = 8;
+ }
+
+#ifdef MP_LOW_MEM
+ if (winsize > 5) {
+ winsize = 5;
+ }
+#endif
+
+ /* init M array */
+ /* init first cell */
+ if ((err = mp_init(&M[1])) != MP_OKAY) {
+ return err;
+ }
+
+ /* now init the second half of the array */
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ if ((err = mp_init(&M[x])) != MP_OKAY) {
+ for (y = 1<<(winsize-1); y < x; y++) {
+ mp_clear (&M[y]);
+ }
+ mp_clear(&M[1]);
+ return err;
+ }
+ }
+
+ /* determine and setup reduction code */
+ if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_SETUP_C
+ /* now setup montgomery */
+ if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
+ goto LBL_M;
+ }
+#else
+ err = MP_VAL;
+ goto LBL_M;
+#endif
+
+ /* automatically pick the comba one if available (saves quite a few calls/ifs) */
+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
+ if (((P->used * 2 + 1) < MP_WARRAY) &&
+ P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ redux = fast_mp_montgomery_reduce;
+ } else
+#endif
+ {
+#ifdef BN_MP_MONTGOMERY_REDUCE_C
+ /* use slower baseline Montgomery method */
+ redux = mp_montgomery_reduce;
+#else
+ err = MP_VAL;
+ goto LBL_M;
+#endif
+ }
+ } else if (redmode == 1) {
+#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
+ /* setup DR reduction for moduli of the form B**k - b */
+ mp_dr_setup(P, &mp);
+ redux = mp_dr_reduce;
+#else
+ err = MP_VAL;
+ goto LBL_M;
+#endif
+ } else {
+#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
+ /* setup DR reduction for moduli of the form 2**k - b */
+ if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
+ goto LBL_M;
+ }
+ redux = mp_reduce_2k;
+#else
+ err = MP_VAL;
+ goto LBL_M;
+#endif
+ }
+
+ /* setup result */
+ if ((err = mp_init (&res)) != MP_OKAY) {
+ goto LBL_M;
+ }
+
+ /* create M table
+ *
+
+ *
+ * The first half of the table is not computed though accept for M[0] and M[1]
+ */
+
+ if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+ /* now we need R mod m */
+ if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+#else
+ err = MP_VAL;
+ goto LBL_RES;
+#endif
+
+ /* now set M[1] to G * R mod m */
+ if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ } else {
+ mp_set(&res, 1);
+ if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
+ if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ for (x = 0; x < (winsize - 1); x++) {
+ if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* create upper table */
+ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+ if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* set initial mode and bit cnt */
+ mode = 0;
+ bitcnt = 1;
+ buf = 0;
+ digidx = X->used - 1;
+ bitcpy = 0;
+ bitbuf = 0;
+
+ for (;;) {
+ /* grab next digit as required */
+ if (--bitcnt == 0) {
+ /* if digidx == -1 we are out of digits so break */
+ if (digidx == -1) {
+ break;
+ }
+ /* read next digit and reset bitcnt */
+ buf = X->dp[digidx--];
+ bitcnt = (int)DIGIT_BIT;
+ }
+
+ /* grab the next msb from the exponent */
+ y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
+ buf <<= (mp_digit)1;
+
+ /* if the bit is zero and mode == 0 then we ignore it
+ * These represent the leading zero bits before the first 1 bit
+ * in the exponent. Technically this opt is not required but it
+ * does lower the # of trivial squaring/reductions used
+ */
+ if (mode == 0 && y == 0) {
+ continue;
+ }
+
+ /* if the bit is zero and mode == 1 then we square */
+ if (mode == 1 && y == 0) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ continue;
+ }
+
+ /* else we add it to the window */
+ bitbuf |= (y << (winsize - ++bitcpy));
+ mode = 2;
+
+ if (bitcpy == winsize) {
+ /* ok window is filled so square as required and multiply */
+ /* square first */
+ for (x = 0; x < winsize; x++) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* then multiply */
+ if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ /* empty window and reset */
+ bitcpy = 0;
+ bitbuf = 0;
+ mode = 1;
+ }
+ }
+
+ /* if bits remain then square/multiply */
+ if (mode == 2 && bitcpy > 0) {
+ /* square then multiply if the bit is set */
+ for (x = 0; x < bitcpy; x++) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ /* get next bit of the window */
+ bitbuf <<= 1;
+ if ((bitbuf & (1 << winsize)) != 0) {
+ /* then multiply */
+ if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+ }
+ }
+
+ if (redmode == 0) {
+ /* fixup result if Montgomery reduction is used
+ * recall that any value in a Montgomery system is
+ * actually multiplied by R mod n. So we have
+ * to reduce one more time to cancel out the factor
+ * of R.
+ */
+ if ((err = redux(&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* swap res with Y */
+ mp_exch (&res, Y);
+ err = MP_OKAY;
+LBL_RES:mp_clear (&res);
+LBL_M:
+ mp_clear(&M[1]);
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ mp_clear (&M[x]);
+ }
+ return err;
+}
+#endif
+
+
+#ifdef BN_FAST_S_MP_SQR_C
+/* the jist of squaring...
+ * you do like mult except the offset of the tmpx [one that
+ * starts closer to zero] can't equal the offset of tmpy.
+ * So basically you set up iy like before then you min it with
+ * (ty-tx) so that it never happens. You double all those
+ * you add in the inner loop
+
+After that loop you do the squares and add them in.
+*/
+
+static int fast_s_mp_sqr (mp_int * a, mp_int * b)
+{
+ int olduse, res, pa, ix, iz;
+ mp_digit W[MP_WARRAY], *tmpx;
+ mp_word W1;
+
+ /* grow the destination as required */
+ pa = a->used + a->used;
+ if (b->alloc < pa) {
+ if ((res = mp_grow (b, pa)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* number of output digits to produce */
+ W1 = 0;
+ for (ix = 0; ix < pa; ix++) {
+ int tx, ty, iy;
+ mp_word _W;
+ mp_digit *tmpy;
+
+ /* clear counter */
+ _W = 0;
+
+ /* get offsets into the two bignums */
+ ty = MIN(a->used-1, ix);
+ tx = ix - ty;
+
+ /* setup temp aliases */
+ tmpx = a->dp + tx;
+ tmpy = a->dp + ty;
+
+ /* this is the number of times the loop will iterrate, essentially
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MIN(a->used-tx, ty+1);
+
+ /* now for squaring tx can never equal ty
+ * we halve the distance since they approach at a rate of 2x
+ * and we have to round because odd cases need to be executed
+ */
+ iy = MIN(iy, (ty-tx+1)>>1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; iz++) {
+ _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+ }
+
+ /* double the inner product and add carry */
+ _W = _W + _W + W1;
+
+ /* even columns have the square term in them */
+ if ((ix&1) == 0) {
+ _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
+ }
+
+ /* store it */
+ W[ix] = (mp_digit)(_W & MP_MASK);
+
+ /* make next carry */
+ W1 = _W >> ((mp_word)DIGIT_BIT);
+ }
+
+ /* setup dest */
+ olduse = b->used;
+ b->used = a->used+a->used;
+
+ {
+ mp_digit *tmpb;
+ tmpb = b->dp;
+ for (ix = 0; ix < pa; ix++) {
+ *tmpb++ = W[ix] & MP_MASK;
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ for (; ix < olduse; ix++) {
+ *tmpb++ = 0;
+ }
+ }
+ mp_clamp (b);
+ return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_MP_MUL_D_C
+/* multiply by a digit */
+static int
+mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
+{
+ mp_digit u, *tmpa, *tmpc;
+ mp_word r;
+ int ix, res, olduse;
+
+ /* make sure c is big enough to hold a*b */
+ if (c->alloc < a->used + 1) {
+ if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* get the original destinations used count */
+ olduse = c->used;
+
+ /* set the sign */
+ c->sign = a->sign;
+
+ /* alias for a->dp [source] */
+ tmpa = a->dp;
+
+ /* alias for c->dp [dest] */
+ tmpc = c->dp;
+
+ /* zero carry */
+ u = 0;
+
+ /* compute columns */
+ for (ix = 0; ix < a->used; ix++) {
+ /* compute product and carry sum for this term */
+ r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
+
+ /* mask off higher bits to get a single digit */
+ *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* send carry into next iteration */
+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+ }
+
+ /* store final carry [if any] and increment ix offset */
+ *tmpc++ = u;
+ ++ix;
+
+ /* now zero digits above the top */
+ while (ix++ < olduse) {
+ *tmpc++ = 0;
+ }
+
+ /* set used count */
+ c->used = a->used + 1;
+ mp_clamp(c);
+
+ return MP_OKAY;
+}
+#endif
Modified: wpasupplicant/branches/upstream/current/src/utils/base64.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/base64.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/base64.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/base64.c Sat Jun 14 00:26:56 2008
@@ -115,7 +115,7 @@
count++;
}
- if (count % 4)
+ if (count == 0 || count % 4)
return NULL;
olen = count / 4 * 3;
Modified: wpasupplicant/branches/upstream/current/src/utils/common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/common.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/common.h (original)
+++ wpasupplicant/branches/upstream/current/src/utils/common.h Sat Jun 14 00:26:56 2008
@@ -428,6 +428,10 @@
const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
+static inline int is_zero_ether_addr(const u8 *a)
+{
+ return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
+}
#include "wpa_debug.h"
Modified: wpasupplicant/branches/upstream/current/src/utils/eloop.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/eloop.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/eloop.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/eloop.c Sat Jun 14 00:26:56 2008
@@ -242,7 +242,10 @@
timeout = os_malloc(sizeof(*timeout));
if (timeout == NULL)
return -1;
- os_get_time(&timeout->time);
+ if (os_get_time(&timeout->time) < 0) {
+ os_free(timeout);
+ return -1;
+ }
timeout->time.sec += secs;
timeout->time.usec += usecs;
while (timeout->time.usec >= 1000000) {
@@ -309,6 +312,25 @@
}
return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *tmp;
+
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (tmp->handler == handler &&
+ tmp->eloop_data == eloop_data &&
+ tmp->user_data == user_data)
+ return 1;
+
+ tmp = tmp->next;
+ }
+
+ return 0;
}
Modified: wpasupplicant/branches/upstream/current/src/utils/eloop.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/eloop.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/eloop.h (original)
+++ wpasupplicant/branches/upstream/current/src/utils/eloop.h Sat Jun 14 00:26:56 2008
@@ -207,6 +207,19 @@
void *eloop_data, void *user_data);
/**
+ * eloop_is_timeout_registered - Check if a timeout is already registered
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * Returns: 1 if the timeout is registered, 0 if the timeout is not registered
+ *
+ * Determine if a matching <handler,eloop_data,user_data> timeout is registered
+ * with eloop_register_timeout().
+ */
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data);
+
+/**
* eloop_register_signal - Register handler for signals
* @sig: Signal number (e.g., SIGHUP)
* @handler: Callback function to be called when the signal is received
Modified: wpasupplicant/branches/upstream/current/src/utils/eloop_none.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/eloop_none.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/eloop_none.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/eloop_none.c Sat Jun 14 00:26:56 2008
@@ -194,6 +194,26 @@
}
return removed;
+}
+
+
+int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx,
+ void *timeout_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *tmp;
+
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (tmp->handler == handler &&
+ tmp->eloop_data == eloop_data &&
+ tmp->user_data == user_data)
+ return 1;
+
+ tmp = tmp->next;
+ }
+
+ return 0;
}
Modified: wpasupplicant/branches/upstream/current/src/utils/eloop_win.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/eloop_win.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/eloop_win.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/eloop_win.c Sat Jun 14 00:26:56 2008
@@ -317,6 +317,25 @@
}
return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *tmp;
+
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (tmp->handler == handler &&
+ tmp->eloop_data == eloop_data &&
+ tmp->user_data == user_data)
+ return 1;
+
+ tmp = tmp->next;
+ }
+
+ return 0;
}
Modified: wpasupplicant/branches/upstream/current/src/utils/wpabuf.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/wpabuf.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/wpabuf.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/wpabuf.c Sat Jun 14 00:26:56 2008
@@ -1,6 +1,6 @@
/*
* Dynamic data buffer
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2007-2008, 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
@@ -123,3 +123,40 @@
}
return tmp;
}
+
+
+/**
+ * wpabuf_concat - Concatenate two buffers into a newly allocated one
+ * @a: First buffer
+ * @b: Second buffer
+ * Returns: wpabuf with concatenated a + b data or %NULL on failure
+ *
+ * Both buffers a and b will be freed regardless of the return value. Input
+ * buffers can be %NULL which is interpreted as an empty buffer.
+ */
+struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b)
+{
+ struct wpabuf *n = NULL;
+ size_t len = 0;
+
+ if (b == NULL)
+ return a;
+
+ if (a)
+ len += wpabuf_len(a);
+ if (b)
+ len += wpabuf_len(b);
+
+ n = wpabuf_alloc(len);
+ if (n) {
+ if (a)
+ wpabuf_put_buf(n, a);
+ if (b)
+ wpabuf_put_buf(n, b);
+ }
+
+ wpabuf_free(a);
+ wpabuf_free(b);
+
+ return n;
+}
Modified: wpasupplicant/branches/upstream/current/src/utils/wpabuf.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/wpabuf.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/wpabuf.h (original)
+++ wpasupplicant/branches/upstream/current/src/utils/wpabuf.h Sat Jun 14 00:26:56 2008
@@ -36,6 +36,7 @@
struct wpabuf * wpabuf_dup(const struct wpabuf *src);
void wpabuf_free(struct wpabuf *buf);
void * wpabuf_put(struct wpabuf *buf, size_t len);
+struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
/**
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog Sat Jun 14 00:26:56 2008
@@ -1,4 +1,21 @@
ChangeLog for wpa_supplicant
+
+????-??-?? - v0.6.4
+ * added support for EAP Sequences in EAP-FAST Phase 2
+ * added support for using TNC with EAP-FAST
+ * added driver_ps3 for the PS3 Linux wireless driver
+ * added support for optional cryptobinding with PEAPv0
+ * fixed the OpenSSL patches (0.9.8g and 0.9.9) for EAP-FAST to
+ allow fallback to full handshake if server rejects PAC-Opaque
+ * added fragmentation support for EAP-TNC
+ * added support for parsing PKCS #8 formatted private keys into the
+ internal TLS implementation (both PKCS #1 RSA key and PKCS #8
+ encapsulated RSA key can now be used)
+ * added option of using faster, but larger, routines in the internal
+ LibTomMath (for internal TLS implementation) to speed up DH and RSA
+ calculations (CONFIG_INTERNAL_LIBTOMMATH_FAST=y)
+ * fixed race condition between disassociation event and group key
+ handshake to avoid getting stuck in incorrect state [Bug 261]
2008-02-22 - v0.6.3
* removed 'nai' and 'eappsk' network configuration variables that were
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile Sat Jun 14 00:26:56 2008
@@ -127,6 +127,12 @@
CONFIG_WIRELESS_EXTENSION=y
endif
+ifdef CONFIG_DRIVER_NL80211
+CFLAGS += -DCONFIG_DRIVER_NL80211
+OBJS_d += ../src/drivers/driver_nl80211.o
+LIBS += -lnl
+endif
+
ifdef CONFIG_DRIVER_PRISM54
CFLAGS += -DCONFIG_DRIVER_PRISM54
OBJS_d += ../src/drivers/driver_prism54.o
@@ -210,6 +216,12 @@
LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211
endif
+ifdef CONFIG_DRIVER_PS3
+CFLAGS += -DCONFIG_DRIVER_PS3 -m64
+OBJS_d += ../src/drivers/driver_ps3.o
+LDFLAGS += -m64
+endif
+
ifdef CONFIG_DRIVER_IPHONE
CFLAGS += -DCONFIG_DRIVER_IPHONE
OBJS_d += ../src/drivers/driver_iphone.o
@@ -264,11 +276,11 @@
else
CFLAGS += -DEAP_PEAP
OBJS += ../src/eap_peer/eap_peap.o
+OBJS += ../src/eap_common/eap_peap_common.o
OBJS_h += ../src/eap_server/eap_peap.o
endif
TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
-CONFIG_EAP_TLV=y
endif
ifdef CONFIG_EAP_TTLS
@@ -411,21 +423,16 @@
NEED_FIPS186_2_PRF=y
endif
-ifdef CONFIG_EAP_TLV
-# EAP-TLV
-CFLAGS += -DEAP_TLV
-OBJS += ../src/eap_peer/eap_tlv.o
-OBJS_h += ../src/eap_server/eap_tlv.o
-endif
-
ifdef CONFIG_EAP_FAST
# EAP-FAST
ifeq ($(CONFIG_EAP_FAST), dyn)
CFLAGS += -DEAP_FAST_DYNAMIC
EAPDYN += ../src/eap_peer/eap_fast.so
+EAPDYN += ../src/eap_common/eap_fast_common.o
else
CFLAGS += -DEAP_FAST
OBJS += ../src/eap_peer/eap_fast.o ../src/eap_peer/eap_fast_pac.o
+OBJS += ../src/eap_common/eap_fast_common.o
OBJS_h += ../src/eap_server/eap_fast.o
endif
TLS_FUNCS=y
@@ -621,6 +628,9 @@
ifeq ($(CONFIG_CRYPTO), internal)
ifdef CONFIG_INTERNAL_LIBTOMMATH
CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+CFLAGS += -DLTM_FAST
+endif
else
LIBS += -ltommath
LIBS_p += -ltommath
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config.c Sat Jun 14 00:26:56 2008
@@ -1296,6 +1296,11 @@
{ STR_KEYe(pin) },
{ STRe(engine_id) },
{ STRe(key_id) },
+ { STRe(cert_id) },
+ { STRe(ca_cert_id) },
+ { STRe(key2_id) },
+ { STRe(cert2_id) },
+ { STRe(ca_cert2_id) },
{ INTe(engine) },
{ INT(eapol_flags) },
#endif /* IEEE8021X_EAPOL */
@@ -1453,6 +1458,11 @@
os_free(eap->pin);
os_free(eap->engine_id);
os_free(eap->key_id);
+ os_free(eap->cert_id);
+ os_free(eap->ca_cert_id);
+ os_free(eap->key2_id);
+ os_free(eap->cert2_id);
+ os_free(eap->ca_cert2_id);
os_free(eap->otp);
os_free(eap->pending_req_otp);
os_free(eap->pac_file);
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c Sat Jun 14 00:26:56 2008
@@ -754,6 +754,11 @@
STR(pin);
STR(engine_id);
STR(key_id);
+ STR(cert_id);
+ STR(ca_cert_id);
+ STR(key2_id);
+ STR(cert2_id);
+ STR(ca_cert2_id);
INTe(engine);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
#endif /* IEEE8021X_EAPOL */
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c Sat Jun 14 00:26:56 2008
@@ -766,6 +766,11 @@
STR(pin);
STR(engine_id);
STR(key_id);
+ STR(cert_id);
+ STR(ca_cert_id);
+ STR(key2_id);
+ STR(cert2_id);
+ STR(ca_cert2_id);
INTe(engine);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
#endif /* IEEE8021X_EAPOL */
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c Sat Jun 14 00:26:56 2008
@@ -76,6 +76,7 @@
}
+#ifdef IEEE8021X_EAPOL
static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
char *addr)
{
@@ -95,6 +96,7 @@
return 0;
}
+#endif /* IEEE8021X_EAPOL */
#ifdef CONFIG_PEERKEY
@@ -328,9 +330,7 @@
}
os_memcpy(ssid->bssid, bssid, ETH_ALEN);
- ssid->bssid_set =
- os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0;
-
+ ssid->bssid_set = !is_zero_ether_addr(bssid);
return 0;
}
@@ -1396,9 +1396,11 @@
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
+#ifdef IEEE8021X_EAPOL
} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
reply_len = -1;
+#endif /* IEEE8021X_EAPOL */
#ifdef CONFIG_PEERKEY
} else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c Sat Jun 14 00:26:56 2008
@@ -21,10 +21,10 @@
#include "ctrl_iface_dbus.h"
#include "ctrl_iface_dbus_handlers.h"
-#define DBUS_VERSION (DBUS_VERSION_MAJOR << 8 | DBUS_VERSION_MINOR)
+#define _DBUS_VERSION (DBUS_VERSION_MAJOR << 8 | DBUS_VERSION_MINOR)
#define DBUS_VER(major, minor) ((major) << 8 | (minor))
-#if DBUS_VERSION < DBUS_VER(1,1)
+#if _DBUS_VERSION < DBUS_VER(1,1)
#define dbus_watch_get_unix_fd dbus_watch_get_fd
#endif
@@ -534,6 +534,9 @@
reply = wpas_dbus_iface_disconnect(message, wpa_s);
else if (!strcmp(method, "setAPScan"))
reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
+ else if (!strcmp(method, "setSmartcardModules"))
+ reply = wpas_dbus_iface_set_smartcard_modules(message,
+ wpa_s);
else if (!strcmp(method, "state"))
reply = wpas_dbus_iface_get_state(message, wpa_s);
else if (!strcmp(method, "setBlobs"))
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.c Sat Jun 14 00:26:56 2008
@@ -22,6 +22,8 @@
#include "eap_peer/eap_methods.h"
#include "dbus_dict_helpers.h"
#include "ieee802_11_defs.h"
+#include "wpas_glue.h"
+#include "eapol_supp/eapol_supp_sm.h"
/**
@@ -1179,6 +1181,76 @@
/**
+ * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ * failure (0)
+ *
+ * Handler function for "setSmartcardModules" method call.
+ */
+DBusMessage * wpas_dbus_iface_set_smartcard_modules(
+ DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+ DBusMessageIter iter, iter_dict;
+ char *opensc_engine_path = NULL;
+ char *pkcs11_engine_path = NULL;
+ char *pkcs11_module_path = NULL;
+ struct wpa_dbus_dict_entry entry;
+
+ if (!dbus_message_iter_init(message, &iter))
+ goto error;
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+ goto error;
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+ if (!strcmp(entry.key, "opensc_engine_path") &&
+ (entry.type == DBUS_TYPE_STRING)) {
+ opensc_engine_path = os_strdup(entry.str_value);
+ if (opensc_engine_path == NULL)
+ goto error;
+ } else if (!strcmp(entry.key, "pkcs11_engine_path") &&
+ (entry.type == DBUS_TYPE_STRING)) {
+ pkcs11_engine_path = os_strdup(entry.str_value);
+ if (pkcs11_engine_path == NULL)
+ goto error;
+ } else if (!strcmp(entry.key, "pkcs11_module_path") &&
+ (entry.type == DBUS_TYPE_STRING)) {
+ pkcs11_module_path = os_strdup(entry.str_value);
+ if (pkcs11_module_path == NULL)
+ goto error;
+ } else {
+ wpa_dbus_dict_entry_clear(&entry);
+ goto error;
+ }
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+
+#ifdef EAP_TLS_OPENSSL
+ os_free(wpa_s->conf->opensc_engine_path);
+ wpa_s->conf->opensc_engine_path = opensc_engine_path;
+ os_free(wpa_s->conf->pkcs11_engine_path);
+ wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
+ os_free(wpa_s->conf->pkcs11_module_path);
+ wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
+#endif /* EAP_TLS_OPENSSL */
+
+ eapol_sm_deinit(wpa_s->eapol);
+ wpa_supplicant_init_eapol(wpa_s);
+
+ return wpas_dbus_new_success_reply(message);
+
+error:
+ os_free(opensc_engine_path);
+ os_free(pkcs11_engine_path);
+ os_free(pkcs11_module_path);
+ return wpas_dbus_new_invalid_opts_error(message, NULL);
+}
+
+/**
* wpas_dbus_iface_get_state - Get interface state
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.h Sat Jun 14 00:26:56 2008
@@ -68,6 +68,9 @@
DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_iface_set_smartcard_modules(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
struct wpa_supplicant *wpa_s);
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_unix.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_unix.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_unix.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_unix.c Sat Jun 14 00:26:56 2008
@@ -311,7 +311,7 @@
/* Group name not found - try to parse this as gid */
gid = strtol(gid_str, &endp, 10);
if (*gid_str == '\0' || *endp != '\0') {
- wpa_printf(MSG_DEBUG, "CTRL: Invalid group "
+ wpa_printf(MSG_ERROR, "CTRL: Invalid group "
"'%s'", gid_str);
goto fail;
}
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/dbus_dict_helpers.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/dbus_dict_helpers.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/dbus_dict_helpers.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/dbus_dict_helpers.c Sat Jun 14 00:26:56 2008
@@ -674,7 +674,7 @@
/* Zero-length arrays are valid. */
if (entry->array_len == 0) {
free(entry->bytearray_value);
- entry->strarray_value = NULL;
+ entry->bytearray_value = NULL;
}
success = TRUE;
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig Sat Jun 14 00:26:56 2008
@@ -307,6 +307,10 @@
#LIBS += -L$(LTM_PATH)
#LIBS_p += -L$(LTM_PATH)
#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
# This is only for Windows builds and requires WMI-related header files and
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=1186&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 Jun 14 00:26:56 2008
@@ -72,17 +72,18 @@
case of OTP request, it includes the challenge from the
authentication server.</para>
- <para>The reply to these requests can be given with 'identity',
- 'password', and 'otp' commands. <id> needs to be copied from the
- the matching request. 'password' and 'otp' commands can be used
- regardless of whether the request was for PASSWORD or OTP. The
- main difference between these two commands is that values given
- with 'password' are remembered as long as wpa_supplicant is
- running whereas values given with 'otp' are used only once and
- then forgotten, i.e., wpa_supplicant will ask frontend for a new
- value for every use. This can be used to implement
- one-time-password lists and generic token card -based
- authentication.</para>
+ <para>The reply to these requests can be given with
+ <emphasis>identity</emphasis>, <emphasis>password</emphasis>, and
+ <emphasis>otp</emphasis> commands. <id> needs to be copied from
+ the matching request. <emphasis>password</emphasis> and
+ <emphasis>otp</emphasis> commands can be used regardless of whether
+ the request was for PASSWORD or OTP. The main difference between these
+ two commands is that values given with <emphasis>password</emphasis> are
+ remembered as long as wpa_supplicant is running whereas values given
+ with <emphasis>otp</emphasis> are used only once and then forgotten,
+ i.e., wpa_supplicant will ask frontend for a new value for every use.
+ This can be used to implement one-time-password lists and generic token
+ card -based authentication.</para>
<para>Example request for password and a matching reply:</para>
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.sgml
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.sgml?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.sgml (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.sgml Sat Jun 14 00:26:56 2008
@@ -49,9 +49,9 @@
<title>Example configuration</title>
<para>The following steps are an example of how to configure
- <command>wpa_priv</command> to allow users in the 'wpapriv' group
- to communicate with <command>wpa_supplicant</command> with privilege
- separation:</para>
+ <command>wpa_priv</command> to allow users in the
+ <emphasis>wpapriv</emphasis> group to communicate with
+ <command>wpa_supplicant</command> with privilege separation:</para>
<para>Create user group (e.g., wpapriv) and assign users that
should be able to use wpa_supplicant into that group.</para>
@@ -111,7 +111,7 @@
supported <command>wpa_supplicant</command> driver backends is to be
used. To get a list of supported driver types see wpa_supplicant help
(e.g, wpa_supplicant -h). The driver backend supported by most good
- drivers is 'wext'.</para>
+ drivers is <emphasis>wext</emphasis>.</para>
<para>The <ifname> string specifies which network
interface is to be managed by <command>wpa_supplicant</command>
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml Sat Jun 14 00:26:56 2008
@@ -26,7 +26,7 @@
<para>Changes to configuration file can be reloaded be sending
SIGHUP signal to <command>wpa_supplicant</command> ('killall -HUP
wpa_supplicant'). Similarly, reloading can be triggered with
- the 'wpa_cli reconfigure' command.</para>
+ the <emphasis>wpa_cli reconfigure</emphasis> command.</para>
<para>Configuration file can include one or more network blocks,
e.g., one for each used SSID. wpa_supplicant will automatically
@@ -174,7 +174,7 @@
<listitem>
<para>Authentication for wired Ethernet. This can be used with
- 'wired' interface (-Dwired on command line).</para>
+ <emphasis>wired</emphasis> interface (-Dwired on command line).</para>
<blockquote><programlisting>
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.sgml?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.sgml (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.sgml Sat Jun 14 00:26:56 2008
@@ -238,7 +238,11 @@
<refsect1>
<title>Available Drivers</title>
- <para>The available drivers to specify with the -D option are:</para>
+ <para>A summary of available driver backends is below. Support for each
+ of the driver backends is chosen at wpa_supplicant compile time. For a
+ list of supported driver backends that may be used with the -D option on
+ your system, refer to the help output of wpa_supplicant
+ (<emphasis>wpa_supplicant -h</emphasis>).</para>
<variablelist>
<varlistentry>
@@ -530,9 +534,9 @@
snapshot/v0.2.x)</term>
<listitem>
<para> (http://hostap.epitest.fi/) Driver needs to be set in
- Managed mode ('iwconfig wlan0 mode managed'). Please note
- that station firmware version needs to be 1.7.0 or newer to
- work in WPA mode.</para>
+ Managed mode (<emphasis>iwconfig wlan0 mode managed</emphasis>).
+ Please note that station firmware version needs to be 1.7.0 or
+ newer to work in WPA mode.</para>
</listitem>
</varlistentry>
@@ -736,8 +740,8 @@
<para>Add MODE="Managed" and WPA="y" to the network scheme in
<filename>/etc/pcmcia/wireless.opts</filename>.</para>
- <para>Add the following block to the end of 'start' action handler
- in <filename>/etc/pcmcia/wireless</filename>:</para>
+ <para>Add the following block to the end of <emphasis>start</emphasis>
+ action handler in <filename>/etc/pcmcia/wireless</filename>:</para>
<blockquote><programlisting>
if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
@@ -746,8 +750,8 @@
</programlisting></blockquote>
- <para>Add the following block to the end of 'stop' action handler
- (may need to be separated from other actions) in
+ <para>Add the following block to the end of <emphasis>stop</emphasis>
+ action handler (may need to be separated from other actions) in
<filename>/etc/pcmcia/wireless</filename>:</para>
<blockquote><programlisting>
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt Sat Jun 14 00:26:56 2008
@@ -91,6 +91,7 @@
EAP-TTLS/EAP-PAX - - - - - - - - - - + -
EAP-TTLS/EAP-SAKE - - - - - - - - - - + -
EAP-TTLS/EAP-GPSK - - - - - - - - - - + -
+EAP-TTLS + TNC - - - - - + - - - - + -
EAP-SIM + - - ? - + - ? - - + -
EAP-AKA - - - - - + - - - - + -
EAP-PSK +7 - - - - + - - - - + -
@@ -110,8 +111,9 @@
EAP-FAST/TLS(auth) - - - - - - - - - - + +
EAP-FAST/SIM(auth) - - - - - - - - - - + -
EAP-FAST/AKA(auth) - - - - - - - - - - + -
+EAP-FAST + TNC - - - - - - - - - - + -
LEAP + - + + + + F +6 - + - +
-EAP-TNC +9 - - - - + - - - - - -
+EAP-TNC +9 - - - - + - - - - + -
EAP-IKEv2 +10 - - - - - - - - - + -
1) PEAPv1 required new label, "client PEAP encryption" instead of "client EAP
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c Sat Jun 14 00:26:56 2008
@@ -66,6 +66,8 @@
char *connect_info;
u8 own_addr[ETH_ALEN];
+ int cui_flag;
+ char *cui_str;
};
static struct eapol_test_data eapol_test;
@@ -162,6 +164,23 @@
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Connect-Info\n");
goto fail;
+ }
+
+ if (e->cui_flag) {
+ int l = 0;
+ if (e->cui_flag == 1) {
+ l = 1;
+ buf[0] = '\0';
+ } else if (e->cui_flag == 2) {
+ os_snprintf(buf, sizeof(buf), "%s", e->cui_str);
+ l = os_strlen(buf);
+ }
+ if (!radius_msg_add_attr(msg,
+ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ (u8 *) buf, l)) {
+ printf("Could not add Chargeable-User-Identity\n");
+ goto fail;
+ }
}
if (eap && !radius_msg_add_eap(msg, eap, len)) {
@@ -616,7 +635,8 @@
static void wpa_init_conf(struct eapol_test_data *e,
struct wpa_supplicant *wpa_s, const char *authsrv,
- int port, const char *secret)
+ int port, const char *secret,
+ const char *cli_addr)
{
struct hostapd_radius_server *as;
int res;
@@ -652,6 +672,16 @@
e->radius_conf->auth_server = as;
e->radius_conf->auth_servers = as;
e->radius_conf->msg_dumps = 1;
+ if (cli_addr) {
+ if (hostapd_parse_ip_addr(cli_addr,
+ &e->radius_conf->client_addr) == 0)
+ e->radius_conf->force_client_addr = 1;
+ else {
+ wpa_printf(MSG_ERROR, "Invalid IP address '%s'",
+ cli_addr);
+ assert(0);
+ }
+ }
e->radius = radius_client_init(wpa_s, e->radius_conf);
assert(e->radius != NULL);
@@ -846,9 +876,10 @@
{
printf("usage:\n"
"eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] "
- "[-s<AS secret>] \\\n"
+ "[-s<AS secret>]\\\n"
" [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
- " [-M<client MAC address>]\n"
+ " [-M<client MAC address>] \\\n"
+ " [-I<CUI>] [-i] [-A<client IP>]\n"
"eapol_test scard\n"
"eapol_test sim <PIN> <num triplets> [debug]\n"
"\n");
@@ -860,6 +891,8 @@
"default 1812\n"
" -s<AS secret> = shared secret with the authentication "
"server, default 'radius'\n"
+ " -A<client IP> = IP address of the client, default: select "
+ "automatically\n"
" -r<count> = number of re-authentications\n"
" -W = wait for a control interface monitor before starting\n"
" -S = save configuration after authentiation\n"
@@ -869,7 +902,10 @@
"CONNECT 11Mbps 802.11b)\n"
" -M<client MAC address> = Set own MAC address "
"(Calling-Station-Id,\n"
- " default: 02:00:00:00:00:01)\n");
+ " default: 02:00:00:00:00:01)\n"
+ " -I<CUI> = send Chargeable-User-Identity containing the "
+ "value of CUI\n"
+ " -i = send NUL value in Chargeable-User-Identity\n");
}
@@ -880,6 +916,7 @@
char *as_addr = "127.0.0.1";
int as_port = 1812;
char *as_secret = "radius";
+ char *cli_addr = NULL;
char *conf = NULL;
int timeout = 30;
@@ -896,18 +933,28 @@
wpa_debug_show_keys = 1;
for (;;) {
- c = getopt(argc, argv, "a:c:C:M:np:r:s:St:W");
+ c = getopt(argc, argv, "a:A:c:C:iI:M:np:r:s:St:W");
if (c < 0)
break;
switch (c) {
case 'a':
as_addr = optarg;
break;
+ case 'A':
+ cli_addr = optarg;
+ break;
case 'c':
conf = optarg;
break;
case 'C':
eapol_test.connect_info = optarg;
+ break;
+ case 'i':
+ eapol_test.cui_flag = 1;
+ break;
+ case 'I':
+ eapol_test.cui_flag = 2;
+ eapol_test.cui_str = optarg;
break;
case 'M':
if (hwaddr_aton(optarg, eapol_test.own_addr)) {
@@ -979,7 +1026,8 @@
return -1;
}
- wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret);
+ wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret,
+ cli_addr);
wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s);
if (wpa_s.ctrl_iface == NULL) {
printf("Failed to initialize control interface '%s'.\n"
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/events.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/events.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/events.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/events.c Sat Jun 14 00:26:56 2008
@@ -805,7 +805,7 @@
if (wpa_s->wpa_state >= WPA_ASSOCIATED)
wpa_supplicant_req_scan(wpa_s, 0, 100000);
bssid = wpa_s->bssid;
- if (os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+ if (is_zero_ether_addr(bssid))
bssid = wpa_s->pending_bssid;
wpa_blacklist_add(wpa_s, bssid);
wpa_sm_notify_disassoc(wpa_s->wpa);
Added: wpasupplicant/branches/upstream/current/wpa_supplicant/examples/openCryptoki.conf
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/examples/openCryptoki.conf?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/examples/openCryptoki.conf (added)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/examples/openCryptoki.conf Sat Jun 14 00:26:56 2008
@@ -1,0 +1,41 @@
+# EAP-TLS using private key and certificates via OpenSSL PKCS#11 engine and
+# openCryptoki (e.g., with TPM token)
+
+# This example uses following PKCS#11 objects:
+# $ pkcs11-tool --module /usr/lib/opencryptoki/libopencryptoki.so -O -l
+# Please enter User PIN:
+# Private Key Object; RSA
+# label: rsakey
+# ID: 04
+# Usage: decrypt, sign, unwrap
+# Certificate Object, type = X.509 cert
+# label: ca
+# ID: 01
+# Certificate Object, type = X.509 cert
+# label: cert
+# ID: 04
+
+# Configure OpenSSL to load the PKCS#11 engine and openCryptoki module
+pkcs11_engine_path=/usr/lib/engines/engine_pkcs11.so
+pkcs11_module_path=/usr/lib/opencryptoki/libopencryptoki.so
+
+network={
+ ssid="test network"
+ key_mgmt=WPA-EAP
+ eap=TLS
+ identity="User"
+
+ # use OpenSSL PKCS#11 engine for this network
+ engine=1
+ engine_id="pkcs11"
+
+ # select the private key and certificates based on ID (see pkcs11-tool
+ # output above)
+ key_id="4"
+ cert_id="4"
+ ca_cert_id="1"
+
+ # set the PIN code; leave this out to configure the PIN to be requested
+ # interactively when needed (e.g., via wpa_gui or wpa_cli)
+ pin="123456"
+}
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/main.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/main.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/main.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/main.c Sat Jun 14 00:26:56 2008
@@ -39,7 +39,7 @@
int i;
printf("%s\n\n%s\n"
"usage:\n"
- " wpa_supplicant [-BddhKLqqtuvwW] [-P<pid file>] "
+ " wpa_supplicant [-BddhKLqqtuvW] [-P<pid file>] "
"[-g<global ctrl>] \\\n"
" -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
"[-p<driver_param>] \\\n"
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c Sat Jun 14 00:26:56 2008
@@ -356,7 +356,7 @@
static void ieee80211_set_associated(struct wpa_supplicant *wpa_s, int assoc)
{
- if (wpa_s->mlme.associated == assoc)
+ if (wpa_s->mlme.associated == assoc && !assoc)
return;
wpa_s->mlme.associated = assoc;
@@ -1051,6 +1051,7 @@
data.ft_ies.ies = mgmt->u.auth.variable;
data.ft_ies.ies_len = len -
(mgmt->u.auth.variable - (u8 *) mgmt);
+ os_memcpy(data.ft_ies.target_ap, wpa_s->bssid, ETH_ALEN);
wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data);
ieee80211_auth_completed(wpa_s);
break;
@@ -1258,7 +1259,8 @@
return;
}
if (wpa_ft_validate_reassoc_resp(
- wpa_s->wpa, pos, len - (pos - (u8 *) mgmt)) < 0) {
+ wpa_s->wpa, pos, len - (pos - (u8 *) mgmt),
+ mgmt->sa) < 0) {
wpa_printf(MSG_DEBUG, "MLME: FT validation of Reassoc"
"Resp failed");
return;
@@ -2453,8 +2455,7 @@
wpa_s->mlme.freq = params->freq;
if (params->bssid) {
os_memcpy(wpa_s->bssid, params->bssid, ETH_ALEN);
- if (os_memcmp(params->bssid, "\x00\x00\x00\x00\x00\x00",
- ETH_ALEN))
+ if (!is_zero_ether_addr(params->bssid))
wpa_s->mlme.bssid_set = 1;
bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
if (bss) {
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/preauth_test.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/preauth_test.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/preauth_test.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/preauth_test.c Sat Jun 14 00:26:56 2008
@@ -43,18 +43,6 @@
};
-static void _wpa_supplicant_req_scan(void *wpa_s, int sec, int usec)
-{
- wpa_supplicant_req_scan(wpa_s, sec, usec);
-}
-
-
-static void _wpa_supplicant_cancel_scan(void *wpa_s)
-{
- wpa_supplicant_cancel_scan(wpa_s);
-}
-
-
static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
{
wpa_supplicant_disassociate(wpa_s, reason_code);
@@ -253,8 +241,6 @@
ctx->ctx = wpa_s;
ctx->set_state = _wpa_supplicant_set_state;
ctx->get_state = _wpa_supplicant_get_state;
- ctx->req_scan = _wpa_supplicant_req_scan;
- ctx->cancel_scan = _wpa_supplicant_cancel_scan;
ctx->deauthenticate = _wpa_supplicant_deauthenticate;
ctx->disassociate = _wpa_supplicant_disassociate;
ctx->set_key = wpa_supplicant_set_key;
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c Sat Jun 14 00:26:56 2008
@@ -172,6 +172,28 @@
*/
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
{
+ /* If there's at least one network that should be specifically scanned
+ * then don't cancel the scan and reschedule. Some drivers do
+ * background scanning which generates frequent scan results, and that
+ * causes the specific SSID scan to get continually pushed back and
+ * never happen, which causes hidden APs to never get probe-scanned.
+ */
+ if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
+ wpa_s->conf->ap_scan == 1) {
+ struct wpa_ssid *ssid = wpa_s->conf->ssid;
+
+ while (ssid) {
+ if (!ssid->disabled && ssid->scan_ssid)
+ break;
+ ssid = ssid->next;
+ }
+ if (ssid) {
+ wpa_msg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
+ "ensure that specific SSID scans occur");
+ return;
+ }
+ }
+
wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
sec, usec);
eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt Sat Jun 14 00:26:56 2008
@@ -59,7 +59,6 @@
could very well be done before EAP has been started
- try to work around race in receiving association event and first EAPOL
message
-- helper function to do memcmp(addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN)
- add wpa_secure_memzero() macro and secure implementation (volatile u8*) to
clear memory; this would be used to clear temporary buffers containing
private data (e.g., keys); the macro can be defined to NOP in order to save
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/networkconfig.ui.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/networkconfig.ui.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/networkconfig.ui.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/networkconfig.ui.h Sat Jun 14 00:26:56 2008
@@ -10,6 +10,7 @@
** destructor.
*****************************************************************************/
+#include <stdlib.h>
enum {
AUTH_NONE = 0,
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/userdatarequest.ui.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/userdatarequest.ui.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/userdatarequest.ui.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/userdatarequest.ui.h Sat Jun 14 00:26:56 2008
@@ -9,6 +9,8 @@
** These will automatically be called by the form's constructor and
** destructor.
*****************************************************************************/
+
+#include <stdlib.h>
int UserDataRequest::setParams(WpaGui *_wpagui, const char *reqMsg)
{
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpagui.ui.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpagui.ui.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpagui.ui.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpagui.ui.h Sat Jun 14 00:26:56 2008
@@ -16,6 +16,7 @@
#include <unistd.h>
#endif
+#include <stdlib.h>
void WpaGui::init()
{
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpamsg.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpamsg.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpamsg.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpamsg.h Sat Jun 14 00:26:56 2008
@@ -14,6 +14,7 @@
class WpaMsg {
public:
+ WpaMsg() {}
WpaMsg(const QString &_msg, int _priority = 2)
: msg(_msg), priority(_priority)
{
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c Sat Jun 14 00:26:56 2008
@@ -187,7 +187,7 @@
{
struct wpa_supplicant *wpa_s = eloop_ctx;
const u8 *bssid = wpa_s->bssid;
- if (os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+ if (is_zero_ether_addr(bssid))
bssid = wpa_s->pending_bssid;
wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
MAC2STR(bssid));
@@ -1090,13 +1090,15 @@
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
} else {
/* Timeout for IEEE 802.11 authentication and association */
- int timeout;
- if (assoc_failed)
- timeout = 5;
- else if (wpa_s->conf->ap_scan == 1)
- timeout = 10;
- else
- timeout = 60;
+ int timeout = 60;
+
+ if (assoc_failed) {
+ /* give IBSS a bit more time */
+ timeout = ssid->mode ? 10 : 5;
+ } else if (wpa_s->conf->ap_scan == 1) {
+ /* give IBSS a bit more time */
+ timeout = ssid->mode ? 20 : 10;
+ }
wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
}
@@ -1131,8 +1133,7 @@
int reason_code)
{
u8 *addr = NULL;
- if (os_memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0)
- {
+ if (!is_zero_ether_addr(wpa_s->bssid)) {
if (wpa_s->use_client_mlme)
ieee80211_sta_disassociate(wpa_s, reason_code);
else
@@ -1160,8 +1161,7 @@
{
u8 *addr = NULL;
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
- if (os_memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0)
- {
+ if (!is_zero_ether_addr(wpa_s->bssid)) {
if (wpa_s->use_client_mlme)
ieee80211_sta_deauthenticate(wpa_s, reason_code);
else
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=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf Sat Jun 14 00:26:56 2008
@@ -304,7 +304,7 @@
# MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
# EAP-PSK (128-bit PSK), EAP-PAX (128-bit PSK), and EAP-SAKE (256-bit
# PSK) is also configured using this field. For EAP-GPSK, this is a
- variable length PSK.
+# variable length PSK.
# 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
@@ -387,6 +387,11 @@
# challenges (by default, it accepts 2 or 3)
# result_ind=1 can be used to enable EAP-SIM and EAP-AKA to use
# protected result indication.
+# 'crypto_binding' option can be used to control PEAPv0 cryptobinding
+# behavior:
+# * 0 = do not use cryptobinding
+# * 1 = use cryptobinding if server supports it (default)
+# * 2 = require cryptobinding
# phase2: Phase2 (inner authentication with TLS tunnel) parameters
# (string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
# "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS)
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpas_glue.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpas_glue.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpas_glue.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpas_glue.c Sat Jun 14 00:26:56 2008
@@ -143,13 +143,11 @@
return -1;
}
- if (os_memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
- {
+ if (is_zero_ether_addr(wpa_s->bssid)) {
wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an "
"EAPOL frame");
if (wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
- os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) !=
- 0) {
+ !is_zero_ether_addr(bssid)) {
dst = bssid;
wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR
" from the driver as the EAPOL destination",
@@ -271,7 +269,6 @@
wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE);
} else {
- wpa_supplicant_cancel_scan(wpa_s);
wpa_supplicant_cancel_auth_timeout(wpa_s);
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
}
@@ -355,18 +352,6 @@
}
-static void _wpa_supplicant_req_scan(void *wpa_s, int sec, int usec)
-{
- wpa_supplicant_req_scan(wpa_s, sec, usec);
-}
-
-
-static void _wpa_supplicant_cancel_scan(void *wpa_s)
-{
- wpa_supplicant_cancel_scan(wpa_s);
-}
-
-
static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s)
{
wpa_supplicant_cancel_auth_timeout(wpa_s);
@@ -399,12 +384,16 @@
static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
{
wpa_supplicant_disassociate(wpa_s, reason_code);
+ /* Schedule a scan to make sure we continue looking for networks */
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
}
static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
{
wpa_supplicant_deauthenticate(wpa_s, reason_code);
+ /* Schedule a scan to make sure we continue looking for networks */
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -576,8 +565,6 @@
ctx->ctx = wpa_s;
ctx->set_state = _wpa_supplicant_set_state;
ctx->get_state = _wpa_supplicant_get_state;
- ctx->req_scan = _wpa_supplicant_req_scan;
- ctx->cancel_scan = _wpa_supplicant_cancel_scan;
ctx->deauthenticate = _wpa_supplicant_deauthenticate;
ctx->disassociate = _wpa_supplicant_disassociate;
ctx->set_key = wpa_supplicant_set_key;
@@ -619,8 +606,10 @@
os_memset(&conf, 0, sizeof(conf));
conf.peerkey_enabled = ssid->peerkey;
conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
+#ifdef IEEE8021X_EAPOL
conf.eap_workaround = ssid->eap_workaround;
conf.eap_conf_ctx = &ssid->eap;
+#endif /* IEEE8021X_EAPOL */
conf.ssid = ssid->ssid;
conf.ssid_len = ssid->ssid_len;
}
More information about the Pkg-wpa-devel
mailing list