[pkg-wpa-devel] r878 - in /wpasupplicant/branches/upstream/current: patches/ src/common/ src/crypto/ src/drivers/ src/eap_common/ src/eap_peer/ src/eap_server/ src/l2_packet/ src/radius/ src/rsn_supp/ src/tls/ src/utils/ wpa_supplicant/ wpa_supplicant/doc/ wpa_supplicant/doc/docbook/ wpa_supplicant/tests/
kelmo-guest at users.alioth.debian.org
kelmo-guest at users.alioth.debian.org
Sat Nov 3 08:40:37 UTC 2007
Author: kelmo-guest
Date: Sat Nov 3 08:40:37 2007
New Revision: 878
URL: http://svn.debian.org/wsvn/?sc=1&rev=878
Log:
[svn-upgrade] Integrating new upstream version, wpasupplicant (0.6.1~git20071103)
Added:
wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch
wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch
wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h
wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.c
wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.h
wpasupplicant/branches/upstream/current/src/drivers/driver_iphone.m
wpasupplicant/branches/upstream/current/src/drivers/driver_osx.m
wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h
wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h
wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c
wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_i.h
wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_read.c
wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_write.c
wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.c
wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.h
wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.c
wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.h
wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.c
wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.h
wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_i.h
wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_read.c
wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_write.c
wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist.sh (with props)
wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist2.sh (with props)
Removed:
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_background.8
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.8
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_passphrase.8
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.8
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
Modified:
wpasupplicant/branches/upstream/current/src/common/defs.h
wpasupplicant/branches/upstream/current/src/common/wpa_common.c
wpasupplicant/branches/upstream/current/src/common/wpa_common.h
wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c
wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.h
wpasupplicant/branches/upstream/current/src/crypto/crypto.h
wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c
wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c
wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.h
wpasupplicant/branches/upstream/current/src/crypto/sha256.c
wpasupplicant/branches/upstream/current/src/crypto/tls.h
wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c
wpasupplicant/branches/upstream/current/src/crypto/tls_internal.c
wpasupplicant/branches/upstream/current/src/crypto/tls_none.c
wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c
wpasupplicant/branches/upstream/current/src/crypto/tls_schannel.c
wpasupplicant/branches/upstream/current/src/drivers/driver.h
wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c
wpasupplicant/branches/upstream/current/src/drivers/drivers.c
wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.c
wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.h
wpasupplicant/branches/upstream/current/src/eap_peer/eap.c
wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c
wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast_pac.h
wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c
wpasupplicant/branches/upstream/current/src/eap_peer/eap_gtc.c
wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h
wpasupplicant/branches/upstream/current/src/eap_peer/eap_leap.c
wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c
wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.h
wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c
wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c
wpasupplicant/branches/upstream/current/src/eap_server/eap.c
wpasupplicant/branches/upstream/current/src/eap_server/eap.h
wpasupplicant/branches/upstream/current/src/eap_server/eap_gpsk.c
wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c
wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h
wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c
wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c
wpasupplicant/branches/upstream/current/src/eap_server/eap_tlv.c
wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_freebsd.c
wpasupplicant/branches/upstream/current/src/radius/radius_client.c
wpasupplicant/branches/upstream/current/src/radius/radius_server.c
wpasupplicant/branches/upstream/current/src/radius/radius_server.h
wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c
wpasupplicant/branches/upstream/current/src/tls/asn1.c
wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c
wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.h
wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.c
wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.h
wpasupplicant/branches/upstream/current/src/tls/x509v3.c
wpasupplicant/branches/upstream/current/src/utils/common.h
wpasupplicant/branches/upstream/current/src/utils/os_unix.c
wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog
wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile
wpasupplicant/branches/upstream/current/wpa_supplicant/config.c
wpasupplicant/branches/upstream/current/wpa_supplicant/config_ssid.h
wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/ctrl_iface.doxygen
wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml
wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt
wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c
wpasupplicant/branches/upstream/current/wpa_supplicant/events.c
wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c
wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_aes.c
wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3.c
wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf
wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h
Added: wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch (added)
+++ wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch Sat Nov 3 08:40:37 2007
@@ -1,0 +1,346 @@
+This patch adds support for TLS SessionTicket extension (RFC 4507) for
+the parts used by EAP-FAST (RFC 4851).
+
+This is based on the patch from Alexey Kobozev <akobozev at cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+OpenSSL 0.9.8g does not enable TLS extension support by default, so it
+will need to be enabled by adding enable-tlsext to config script
+command line.
+
+
+diff -upr openssl-0.9.8g.orig/ssl/s3_clnt.c openssl-0.9.8g/ssl/s3_clnt.c
+--- openssl-0.9.8g.orig/ssl/s3_clnt.c 2007-08-30 17:28:51.000000000 -0700
++++ openssl-0.9.8g/ssl/s3_clnt.c 2007-11-01 20:08:08.000000000 -0700
+@@ -660,7 +660,7 @@ int ssl3_get_server_hello(SSL *s)
+ STACK_OF(SSL_CIPHER) *sk;
+ SSL_CIPHER *c;
+ unsigned char *p,*d;
+- int i,al,ok;
++ int i,al,ok,pre_shared;
+ unsigned int j;
+ long n;
+ #ifndef OPENSSL_NO_COMP
+@@ -727,7 +727,26 @@ int ssl3_get_server_hello(SSL *s)
+ goto f_err;
+ }
+
+- if (j != 0 && j == s->session->session_id_length
++ /* check if we want to resume the session based on external pre-shared secret */
++ pre_shared = 0;
++#ifndef OPENSSL_NO_TLSEXT
++ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++ {
++ SSL_CIPHER *pref_cipher=NULL;
++ s->session->master_key_length=sizeof(s->session->master_key);
++ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++ {
++ s->hit=1;
++ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
++ s->session->session_id_length = j;
++ memcpy(s->session->session_id, p, j);
++ pre_shared = 1;
++ }
++ }
++#endif /* OPENSSL_NO_TLSEXT */
++
++ if ((pre_shared || j != 0) && j == s->session->session_id_length
+ && memcmp(p,s->session->session_id,j) == 0)
+ {
+ if(s->sid_ctx_length != s->session->sid_ctx_length
+diff -upr openssl-0.9.8g.orig/ssl/s3_srvr.c openssl-0.9.8g/ssl/s3_srvr.c
+--- openssl-0.9.8g.orig/ssl/s3_srvr.c 2007-09-30 11:55:59.000000000 -0700
++++ openssl-0.9.8g/ssl/s3_srvr.c 2007-11-02 19:24:20.000000000 -0700
+@@ -928,6 +928,59 @@ int ssl3_get_client_hello(SSL *s)
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ goto err;
+ }
++
++ /* Check if we want to use external pre-shared secret for this
++ * handshake for not reused session only. We need to generate
++ * server_random before calling tls_session_secret_cb in order to allow
++ * SessionTicket processing to use it in key derivation. */
++ {
++ unsigned long Time;
++ unsigned char *pos;
++ Time=(unsigned long)time(NULL); /* Time */
++ pos=s->s3->server_random;
++ l2n(Time,pos);
++ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
++ {
++ al=SSL_AD_INTERNAL_ERROR;
++ goto f_err;
++ }
++ }
++
++ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++ {
++ SSL_CIPHER *pref_cipher=NULL;
++
++ s->session->master_key_length=sizeof(s->session->master_key);
++ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++ {
++ s->hit=1;
++ s->session->ciphers=ciphers;
++ s->session->verify_result=X509_V_OK;
++
++ ciphers=NULL;
++
++ /* check if some cipher was preferred by call back */
++ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++ if (pref_cipher == NULL)
++ {
++ al=SSL_AD_HANDSHAKE_FAILURE;
++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++ goto f_err;
++ }
++
++ s->session->cipher=pref_cipher;
++
++ if (s->cipher_list)
++ sk_SSL_CIPHER_free(s->cipher_list);
++
++ if (s->cipher_list_by_id)
++ sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++ }
++ }
+ #endif
+ /* Worst case, we will use the NULL compression, but if we have other
+ * options, we will now look for them. We have i-1 compression
+@@ -1066,16 +1119,22 @@ int ssl3_send_server_hello(SSL *s)
+ unsigned char *buf;
+ unsigned char *p,*d;
+ int i,sl;
+- unsigned long l,Time;
++ unsigned long l;
++#ifdef OPENSSL_NO_TLSEXT
++ unsigned long Time;
++#endif
+
+ if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ {
+ buf=(unsigned char *)s->init_buf->data;
++#ifdef OPENSSL_NO_TLSEXT
+ p=s->s3->server_random;
++ /* Generate server_random if it was not needed previously */
+ Time=(unsigned long)time(NULL); /* Time */
+ l2n(Time,p);
+ if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+ return -1;
++#endif
+ /* Do the message type and length last */
+ d=p= &(buf[4]);
+
+diff -upr openssl-0.9.8g.orig/ssl/ssl.h openssl-0.9.8g/ssl/ssl.h
+--- openssl-0.9.8g.orig/ssl/ssl.h 2007-10-19 00:42:38.000000000 -0700
++++ openssl-0.9.8g/ssl/ssl.h 2007-11-01 20:08:08.000000000 -0700
+@@ -342,6 +342,7 @@ extern "C" {
+ * 'struct ssl_st *' function parameters used to prototype callbacks
+ * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -363,6 +364,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ {
+@@ -1004,6 +1007,14 @@ struct ssl_st
+ */
+ /* RFC4507 session ticket expected to be received or sent */
+ int tlsext_ticket_expected;
++
++ /* TLS extensions */
++ TLS_EXTENSION *tls_extension;
++
++ /* TLS pre-shared secret session resumption */
++ tls_session_secret_cb_fn tls_session_secret_cb;
++ void *tls_session_secret_cb_arg;
++
+ SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+ #define session_ctx initial_ctx
+ #else
+@@ -1589,6 +1600,12 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+@@ -1778,6 +1795,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
+ #define SSL_F_WRITE_PENDING 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION 213
+
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE 100
+diff -upr openssl-0.9.8g.orig/ssl/ssl_err.c openssl-0.9.8g/ssl/ssl_err.c
+--- openssl-0.9.8g.orig/ssl/ssl_err.c 2007-10-11 07:36:59.000000000 -0700
++++ openssl-0.9.8g/ssl/ssl_err.c 2007-11-01 20:08:08.000000000 -0700
+@@ -250,6 +250,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
+ {0,NULL}
+ };
+
+diff -upr openssl-0.9.8g.orig/ssl/ssl_sess.c openssl-0.9.8g/ssl/ssl_sess.c
+--- openssl-0.9.8g.orig/ssl/ssl_sess.c 2007-10-19 00:36:34.000000000 -0700
++++ openssl-0.9.8g/ssl/ssl_sess.c 2007-11-01 20:08:08.000000000 -0700
+@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ return(s->session_timeout);
+ }
+
++#ifndef OPENSSL_NO_TLSEXT
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
++ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++{
++ if (s == NULL) return(0);
++ s->tls_session_secret_cb = tls_session_secret_cb;
++ s->tls_session_secret_cb_arg = arg;
++ return(1);
++}
++
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
++{
++ if(s->version >= TLS1_VERSION)
++ {
++ if(s->tls_extension)
++ {
++ OPENSSL_free(s->tls_extension);
++ s->tls_extension = NULL;
++ }
++
++ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
++ if(!s->tls_extension)
++ {
++ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
++ return 0;
++ }
++
++ s->tls_extension->type = ext_type;
++
++ if(ext_data)
++ {
++ s->tls_extension->length = ext_len;
++ s->tls_extension->data = s->tls_extension + 1;
++ memcpy(s->tls_extension->data, ext_data, ext_len);
++ } else {
++ s->tls_extension->length = 0;
++ s->tls_extension->data = NULL;
++ }
++
++ return 1;
++ }
++
++ return 0;
++}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ typedef struct timeout_param_st
+ {
+ SSL_CTX *ctx;
+diff -upr openssl-0.9.8g.orig/ssl/t1_lib.c openssl-0.9.8g/ssl/t1_lib.c
+--- openssl-0.9.8g.orig/ssl/t1_lib.c 2007-10-19 00:44:10.000000000 -0700
++++ openssl-0.9.8g/ssl/t1_lib.c 2007-11-01 20:08:08.000000000 -0700
+@@ -105,6 +105,12 @@ int tls1_new(SSL *s)
+
+ void tls1_free(SSL *s)
+ {
++#ifndef OPENSSL_NO_TLSEXT
++ if(s->tls_extension)
++ {
++ OPENSSL_free(s->tls_extension);
++ }
++#endif
+ ssl3_free(s);
+ }
+
+@@ -174,8 +180,24 @@ unsigned char *ssl_add_clienthello_tlsex
+ int ticklen;
+ if (s->session && s->session->tlsext_tick)
+ ticklen = s->session->tlsext_ticklen;
++ else if (s->session && s->tls_extension &&
++ s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++ s->tls_extension->data)
++ {
++ ticklen = s->tls_extension->length;
++ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
++ if (!s->session->tlsext_tick)
++ return NULL;
++ memcpy(s->session->tlsext_tick, s->tls_extension->data,
++ ticklen);
++ s->session->tlsext_ticklen = ticklen;
++ }
+ else
+ ticklen = 0;
++ if (ticklen == 0 && s->tls_extension &&
++ s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++ s->tls_extension->data == NULL)
++ goto skip_ext;
+ /* Check for enough room 2 for extension type, 2 for len
+ * rest for ticket
+ */
+@@ -189,6 +211,7 @@ unsigned char *ssl_add_clienthello_tlsex
+ ret += ticklen;
+ }
+ }
++ skip_ext:
+
+ if ((extdatalen = ret-p-2)== 0)
+ return p;
+@@ -543,6 +566,8 @@ int tls1_process_ticket(SSL *s, unsigned
+ s->tlsext_ticket_expected = 1;
+ return 0; /* Cache miss */
+ }
++ if (s->tls_session_secret_cb)
++ return 0;
+ return tls_decrypt_ticket(s, p, size, session_id, len,
+ ret);
+ }
+diff -upr openssl-0.9.8g.orig/ssl/tls1.h openssl-0.9.8g/ssl/tls1.h
+--- openssl-0.9.8g.orig/ssl/tls1.h 2007-08-27 18:12:44.000000000 -0700
++++ openssl-0.9.8g/ssl/tls1.h 2007-11-01 20:08:08.000000000 -0700
+@@ -365,6 +365,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SER
+ #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
+ #endif
+
++/* TLS extension struct */
++struct tls_extension_st
++{
++ unsigned short type;
++ unsigned short length;
++ void *data;
++};
++
+ #ifdef __cplusplus
+ }
+ #endif
+diff -upr openssl-0.9.8g.orig/util/ssleay.num openssl-0.9.8g/util/ssleay.num
+--- openssl-0.9.8g.orig/util/ssleay.num 2007-08-12 15:31:16.000000000 -0700
++++ openssl-0.9.8g/util/ssleay.num 2007-11-01 20:08:08.000000000 -0700
+@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb
+ SSL_set_SSL_CTX 290 EXIST::FUNCTION:
+ SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
+ SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
++SSL_set_hello_extension 305 EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb 306 EXIST::FUNCTION:TLSEXT
Added: wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch (added)
+++ wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch Sat Nov 3 08:40:37 2007
@@ -1,0 +1,342 @@
+This patch adds support for TLS SessionTicket extension (RFC 4507) for
+the parts used by EAP-FAST (RFC 4851).
+
+This is based on the patch from Alexey Kobozev <akobozev at cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+
+
+diff -upr openssl-SNAP-20071101.orig/ssl/s3_clnt.c openssl-SNAP-20071101/ssl/s3_clnt.c
+--- openssl-SNAP-20071101.orig/ssl/s3_clnt.c 2007-10-26 06:00:28.000000000 -0700
++++ openssl-SNAP-20071101/ssl/s3_clnt.c 2007-11-01 19:19:43.000000000 -0700
+@@ -715,7 +715,7 @@ int ssl3_get_server_hello(SSL *s)
+ STACK_OF(SSL_CIPHER) *sk;
+ SSL_CIPHER *c;
+ unsigned char *p,*d;
+- int i,al,ok;
++ int i,al,ok,pre_shared;
+ unsigned int j;
+ long n;
+ #ifndef OPENSSL_NO_COMP
+@@ -782,7 +782,26 @@ int ssl3_get_server_hello(SSL *s)
+ goto f_err;
+ }
+
+- if (j != 0 && j == s->session->session_id_length
++ /* check if we want to resume the session based on external pre-shared secret */
++ pre_shared = 0;
++#ifndef OPENSSL_NO_TLSEXT
++ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++ {
++ SSL_CIPHER *pref_cipher=NULL;
++ s->session->master_key_length=sizeof(s->session->master_key);
++ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++ {
++ s->hit=1;
++ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
++ s->session->session_id_length = j;
++ memcpy(s->session->session_id, p, j);
++ pre_shared = 1;
++ }
++ }
++#endif /* OPENSSL_NO_TLSEXT */
++
++ if ((pre_shared || j != 0) && j == s->session->session_id_length
+ && memcmp(p,s->session->session_id,j) == 0)
+ {
+ if(s->sid_ctx_length != s->session->sid_ctx_length
+diff -upr openssl-SNAP-20071101.orig/ssl/s3_srvr.c openssl-SNAP-20071101/ssl/s3_srvr.c
+--- openssl-SNAP-20071101.orig/ssl/s3_srvr.c 2007-10-26 06:00:29.000000000 -0700
++++ openssl-SNAP-20071101/ssl/s3_srvr.c 2007-11-01 19:19:43.000000000 -0700
+@@ -992,6 +992,59 @@ int ssl3_get_client_hello(SSL *s)
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ goto err;
+ }
++
++ /* Check if we want to use external pre-shared secret for this
++ * handshake for not reused session only. We need to generate
++ * server_random before calling tls_session_secret_cb in order to allow
++ * SessionTicket processing to use it in key derivation. */
++ {
++ unsigned long Time;
++ unsigned char *pos;
++ Time=(unsigned long)time(NULL); /* Time */
++ pos=s->s3->server_random;
++ l2n(Time,pos);
++ if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
++ {
++ al=SSL_AD_INTERNAL_ERROR;
++ goto f_err;
++ }
++ }
++
++ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++ {
++ SSL_CIPHER *pref_cipher=NULL;
++
++ s->session->master_key_length=sizeof(s->session->master_key);
++ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++ {
++ s->hit=1;
++ s->session->ciphers=ciphers;
++ s->session->verify_result=X509_V_OK;
++
++ ciphers=NULL;
++
++ /* check if some cipher was preferred by call back */
++ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++ if (pref_cipher == NULL)
++ {
++ al=SSL_AD_HANDSHAKE_FAILURE;
++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++ goto f_err;
++ }
++
++ s->session->cipher=pref_cipher;
++
++ if (s->cipher_list)
++ sk_SSL_CIPHER_free(s->cipher_list);
++
++ if (s->cipher_list_by_id)
++ sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++ }
++ }
+ #endif
+
+ /* Worst case, we will use the NULL compression, but if we have other
+@@ -1118,16 +1171,22 @@ int ssl3_send_server_hello(SSL *s)
+ unsigned char *buf;
+ unsigned char *p,*d;
+ int i,sl;
+- unsigned long l,Time;
++ unsigned long l;
++#ifdef OPENSSL_NO_TLSEXT
++ unsigned long Time;
++#endif
+
+ if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ {
+ buf=(unsigned char *)s->init_buf->data;
++#ifdef OPENSSL_NO_TLSEXT
+ p=s->s3->server_random;
++ /* Generate server_random if it was not needed previously */
+ Time=(unsigned long)time(NULL); /* Time */
+ l2n(Time,p);
+ if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+ return -1;
++#endif
+ /* Do the message type and length last */
+ d=p= &(buf[4]);
+
+diff -upr openssl-SNAP-20071101.orig/ssl/ssl.h openssl-SNAP-20071101/ssl/ssl.h
+--- openssl-SNAP-20071101.orig/ssl/ssl.h 2007-10-26 17:01:28.000000000 -0700
++++ openssl-SNAP-20071101/ssl/ssl.h 2007-11-01 19:20:47.000000000 -0700
+@@ -353,6 +353,7 @@ extern "C" {
+ * 'struct ssl_st *' function parameters used to prototype callbacks
+ * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -379,6 +380,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ {
+@@ -1121,6 +1124,13 @@ struct ssl_st
+ void *tlsext_opaque_prf_input;
+ size_t tlsext_opaque_prf_input_len;
+
++ /* TLS extensions */
++ TLS_EXTENSION *tls_extension;
++
++ /* TLS pre-shared secret session resumption */
++ tls_session_secret_cb_fn tls_session_secret_cb;
++ void *tls_session_secret_cb_arg;
++
+ SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+ #define session_ctx initial_ctx
+ #else
+@@ -1721,6 +1731,12 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+@@ -1920,6 +1936,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_PRF 284
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
+ #define SSL_F_WRITE_PENDING 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION 213
+
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE 100
+diff -upr openssl-SNAP-20071101.orig/ssl/ssl_err.c openssl-SNAP-20071101/ssl/ssl_err.c
+--- openssl-SNAP-20071101.orig/ssl/ssl_err.c 2007-10-26 17:01:29.000000000 -0700
++++ openssl-SNAP-20071101/ssl/ssl_err.c 2007-11-01 19:19:43.000000000 -0700
+@@ -260,6 +260,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
+ {0,NULL}
+ };
+
+diff -upr openssl-SNAP-20071101.orig/ssl/ssl_sess.c openssl-SNAP-20071101/ssl/ssl_sess.c
+--- openssl-SNAP-20071101.orig/ssl/ssl_sess.c 2007-10-17 11:00:45.000000000 -0700
++++ openssl-SNAP-20071101/ssl/ssl_sess.c 2007-11-01 19:19:43.000000000 -0700
+@@ -831,6 +831,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ return(s->session_timeout);
+ }
+
++#ifndef OPENSSL_NO_TLSEXT
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
++ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++{
++ if (s == NULL) return(0);
++ s->tls_session_secret_cb = tls_session_secret_cb;
++ s->tls_session_secret_cb_arg = arg;
++ return(1);
++}
++
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
++{
++ if(s->version >= TLS1_VERSION)
++ {
++ if(s->tls_extension)
++ {
++ OPENSSL_free(s->tls_extension);
++ s->tls_extension = NULL;
++ }
++
++ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
++ if(!s->tls_extension)
++ {
++ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
++ return 0;
++ }
++
++ s->tls_extension->type = ext_type;
++
++ if(ext_data)
++ {
++ s->tls_extension->length = ext_len;
++ s->tls_extension->data = s->tls_extension + 1;
++ memcpy(s->tls_extension->data, ext_data, ext_len);
++ } else {
++ s->tls_extension->length = 0;
++ s->tls_extension->data = NULL;
++ }
++
++ return 1;
++ }
++
++ return 0;
++}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ typedef struct timeout_param_st
+ {
+ SSL_CTX *ctx;
+diff -upr openssl-SNAP-20071101.orig/ssl/t1_lib.c openssl-SNAP-20071101/ssl/t1_lib.c
+--- openssl-SNAP-20071101.orig/ssl/t1_lib.c 2007-10-26 06:00:29.000000000 -0700
++++ openssl-SNAP-20071101/ssl/t1_lib.c 2007-11-01 19:19:43.000000000 -0700
+@@ -154,6 +154,12 @@ int tls1_new(SSL *s)
+
+ void tls1_free(SSL *s)
+ {
++#ifndef OPENSSL_NO_TLSEXT
++ if(s->tls_extension)
++ {
++ OPENSSL_free(s->tls_extension);
++ }
++#endif
+ ssl3_free(s);
+ }
+
+@@ -355,8 +361,24 @@ unsigned char *ssl_add_clienthello_tlsex
+ int ticklen;
+ if (s->session && s->session->tlsext_tick)
+ ticklen = s->session->tlsext_ticklen;
++ else if (s->session && s->tls_extension &&
++ s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++ s->tls_extension->data)
++ {
++ ticklen = s->tls_extension->length;
++ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
++ if (!s->session->tlsext_tick)
++ return NULL;
++ memcpy(s->session->tlsext_tick, s->tls_extension->data,
++ ticklen);
++ s->session->tlsext_ticklen = ticklen;
++ }
+ else
+ ticklen = 0;
++ if (ticklen == 0 && s->tls_extension &&
++ s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++ s->tls_extension->data == NULL)
++ goto skip_ext;
+ /* Check for enough room 2 for extension type, 2 for len
+ * rest for ticket
+ */
+@@ -369,6 +391,7 @@ unsigned char *ssl_add_clienthello_tlsex
+ ret += ticklen;
+ }
+ }
++ skip_ext:
+
+ #ifdef TLSEXT_TYPE_opaque_prf_input
+ if (s->s3->client_opaque_prf_input != NULL)
+@@ -1422,6 +1445,8 @@ int tls1_process_ticket(SSL *s, unsigned
+ s->tlsext_ticket_expected = 1;
+ return 0; /* Cache miss */
+ }
++ if (s->tls_session_secret_cb)
++ return 0;
+ return tls_decrypt_ticket(s, p, size, session_id, len,
+ ret);
+ }
+diff -upr openssl-SNAP-20071101.orig/ssl/tls1.h openssl-SNAP-20071101/ssl/tls1.h
+--- openssl-SNAP-20071101.orig/ssl/tls1.h 2007-09-26 15:01:39.000000000 -0700
++++ openssl-SNAP-20071101/ssl/tls1.h 2007-11-01 19:19:43.000000000 -0700
+@@ -509,6 +509,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPA
+ #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
+ #endif
+
++/* TLS extension struct */
++struct tls_extension_st
++{
++ unsigned short type;
++ unsigned short length;
++ void *data;
++};
++
+ #ifdef __cplusplus
+ }
+ #endif
+diff -upr openssl-SNAP-20071101.orig/util/ssleay.num openssl-SNAP-20071101/util/ssleay.num
+--- openssl-SNAP-20071101.orig/util/ssleay.num 2007-08-31 06:03:14.000000000 -0700
++++ openssl-SNAP-20071101/util/ssleay.num 2007-11-01 19:19:43.000000000 -0700
+@@ -253,3 +253,5 @@ PEM_write_bio_SSL_SESSION
+ PEM_read_SSL_SESSION 302 EXIST:!WIN16:FUNCTION:
+ PEM_read_bio_SSL_SESSION 303 EXIST::FUNCTION:
+ PEM_write_SSL_SESSION 304 EXIST:!WIN16:FUNCTION:
++SSL_set_hello_extension 305 EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb 306 EXIST::FUNCTION:TLSEXT
Modified: wpasupplicant/branches/upstream/current/src/common/defs.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/defs.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/defs.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/defs.h Sat Nov 3 08:40:37 2007
@@ -50,7 +50,7 @@
typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP,
- WPA_ALG_IGTK } wpa_alg;
+ WPA_ALG_IGTK, WPA_ALG_PMK } wpa_alg;
typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
CIPHER_WEP104 } wpa_cipher;
typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
Modified: wpasupplicant/branches/upstream/current/src/common/wpa_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/wpa_common.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/wpa_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/common/wpa_common.c Sat Nov 3 08:40:37 2007
@@ -396,7 +396,7 @@
/**
* wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
*
- * IEEE 802.11r/D5.0 - 8.5.1.5.3
+ * IEEE 802.11r/D8.0 - 8.5.1.5.3
*/
void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
const u8 *ssid, size_t ssid_len,
@@ -410,7 +410,7 @@
size_t len[2];
/*
- * R0-Key-Data = KDF-384(XXKey, "R0 Key Derivation",
+ * R0-Key-Data = KDF-384(XXKey, "FT-R0",
* SSIDlength || SSID || MDID || R0KHlength ||
* R0KH-ID || S0KH-ID)
* XXKey is either the second 256 bits of MSK or PSK.
@@ -431,15 +431,15 @@
os_memcpy(pos, s0kh_id, ETH_ALEN);
pos += ETH_ALEN;
- sha256_prf(xxkey, xxkey_len, "R0 Key Derivation", buf, pos - buf,
+ sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
r0_key_data, sizeof(r0_key_data));
os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
/*
- * PMKR0Name = Truncate-128(SHA-256("R0 Key Name" || PMK-R0Name-Salt)
+ * PMKR0Name = Truncate-128(SHA-256("FT-R0" || PMK-R0Name-Salt)
*/
- addr[0] = (const u8 *) "R0 Key Name";
- len[0] = 11;
+ addr[0] = (const u8 *) "FT-R0";
+ len[0] = 5;
addr[1] = r0_key_data + PMK_LEN;
len[1] = 16;
@@ -451,7 +451,7 @@
/**
* wpa_derive_pmk_r1_name - Derive PMKR1Name
*
- * IEEE 802.11r/D5.0 - 8.5.1.5.4
+ * IEEE 802.11r/D8.0 - 8.5.1.5.4
*/
void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
const u8 *s1kh_id, u8 *pmk_r1_name)
@@ -461,11 +461,11 @@
size_t len[4];
/*
- * PMKR1Name = Truncate-128(SHA-256("R1 Key Name" || PMKR0Name ||
+ * PMKR1Name = Truncate-128(SHA-256("FT-R1" || PMKR0Name ||
* R1KH-ID || S1KH-ID))
*/
- addr[0] = (const u8 *) "R1 Key Name";
- len[0] = 11;
+ addr[0] = (const u8 *) "FT-R1";
+ len[0] = 5;
addr[1] = pmk_r0_name;
len[1] = WPA_PMK_NAME_LEN;
addr[2] = r1kh_id;
@@ -481,7 +481,7 @@
/**
* wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
*
- * IEEE 802.11r/D5.0 - 8.5.1.5.4
+ * IEEE 802.11r/D8.0 - 8.5.1.5.4
*/
void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
const u8 *r1kh_id, const u8 *s1kh_id,
@@ -490,15 +490,14 @@
u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
u8 *pos;
- /* PMK-R1 = KDF-256(PMK-R0, "R1 Key Derivation", R1KH-ID || S1KH-ID) */
+ /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
pos = buf;
os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
pos += FT_R1KH_ID_LEN;
os_memcpy(pos, s1kh_id, ETH_ALEN);
pos += ETH_ALEN;
- sha256_prf(pmk_r0, PMK_LEN, "R1 Key Derivation", buf, pos - buf,
- pmk_r1, PMK_LEN);
+ sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
}
@@ -507,7 +506,7 @@
/**
* wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
*
- * IEEE 802.11r/D5.0 - 8.5.1.5.5
+ * IEEE 802.11r/D8.0 - 8.5.1.5.5
*/
void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
const u8 *sta_addr, const u8 *bssid,
@@ -520,7 +519,7 @@
size_t len[6];
/*
- * PTK = KDF-PTKLen(PMK-R1, "PTK Key derivation", SNonce || ANonce ||
+ * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
* BSSID || STA-ADDR)
*/
pos = buf;
@@ -533,17 +532,16 @@
os_memcpy(pos, sta_addr, ETH_ALEN);
pos += ETH_ALEN;
- sha256_prf(pmk_r1, PMK_LEN, "PTK Key derivation", buf, pos - buf,
- ptk, ptk_len);
+ sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
/*
- * PTKName = Truncate-128(SHA-256(PMKR1Name || "PTK Name" || SNonce ||
+ * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTK" || SNonce ||
* ANonce || BSSID || STA-ADDR))
*/
addr[0] = pmk_r1_name;
len[0] = WPA_PMK_NAME_LEN;
- addr[1] = (const u8 *) "PTK Name";
- len[1] = 8;
+ addr[1] = (const u8 *) "FT-PTK";
+ len[1] = 6;
addr[2] = snonce;
len[2] = WPA_NONCE_LEN;
addr[3] = anonce;
Modified: wpasupplicant/branches/upstream/current/src/common/wpa_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/wpa_common.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/wpa_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/wpa_common.h Sat Nov 3 08:40:37 2007
@@ -281,9 +281,8 @@
u8 ft_capab;
} STRUCT_PACKED;
-#define RSN_FT_CAPAB_FT_OVER_AIR BIT(0)
-#define RSN_FT_CAPAB_FT_OVER_DS BIT(1)
-#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(2)
+#define RSN_FT_CAPAB_FT_OVER_DS BIT(0)
+#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1)
struct rsn_ftie {
u8 mic_control[2];
Modified: wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.c Sat Nov 3 08:40:37 2007
@@ -7,7 +7,7 @@
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
*
- * Copyright (c) 2003-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -29,10 +29,11 @@
/**
* aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
- * @kek: Key encryption key (KEK)
- * @n: Length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
- * @plain: Plaintext key to be wrapped, n * 64 bit
- * @cipher: Wrapped key, (n + 1) * 64 bit
+ * @kek: 16-octet Key encryption key (KEK)
+ * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
+ * bytes
+ * @plain: Plaintext key to be wrapped, n * 64 bits
+ * @cipher: Wrapped key, (n + 1) * 64 bits
* Returns: 0 on success, -1 on failure
*/
int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
@@ -88,9 +89,10 @@
/**
* aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
* @kek: Key encryption key (KEK)
- * @n: Length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
- * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bit
- * @plain: Plaintext key, n * 64 bit
+ * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
+ * bytes
+ * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits
+ * @plain: Plaintext key, n * 64 bits
* Returns: 0 on success, -1 on failure (e.g., integrity verification failed)
*/
int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
@@ -162,10 +164,11 @@
/**
- * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
+ * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
* @key: 128-bit key for the hash operation
- * @data: Data buffer for which a MAC is determined
- * @data: Length of data buffer in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
* @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
* Returns: 0 on success, -1 on failure
*
@@ -173,21 +176,37 @@
* OMAC1 was standardized with the name CMAC by NIST in a Special Publication
* (SP) 800-38B.
*/
-int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
void *ctx;
u8 cbc[BLOCK_SIZE], pad[BLOCK_SIZE];
- const u8 *pos = data;
- size_t i, left = data_len;
+ const u8 *pos, *end;
+ size_t i, e, left, total_len;
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
os_memset(cbc, 0, BLOCK_SIZE);
+ total_len = 0;
+ for (e = 0; e < num_elem; e++)
+ total_len += len[e];
+ left = total_len;
+
+ e = 0;
+ pos = addr[0];
+ end = pos + len[0];
+
while (left >= BLOCK_SIZE) {
- for (i = 0; i < BLOCK_SIZE; i++)
+ for (i = 0; i < BLOCK_SIZE; i++) {
cbc[i] ^= *pos++;
+ if (pos >= end) {
+ e++;
+ pos = addr[e];
+ end = pos + len[e];
+ }
+ }
if (left > BLOCK_SIZE)
aes_encrypt(ctx, cbc, cbc);
left -= BLOCK_SIZE;
@@ -197,9 +216,15 @@
aes_encrypt(ctx, pad, pad);
gf_mulx(pad);
- if (left || data_len == 0) {
- for (i = 0; i < left; i++)
+ if (left || total_len == 0) {
+ for (i = 0; i < left; i++) {
cbc[i] ^= *pos++;
+ if (pos >= end) {
+ e++;
+ pos = addr[e];
+ end = pos + len[e];
+ }
+ }
cbc[left] ^= 0x80;
gf_mulx(pad);
}
@@ -209,6 +234,24 @@
aes_encrypt(ctx, pad, mac);
aes_encrypt_deinit(ctx);
return 0;
+}
+
+
+/**
+ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
+ * @key: 128-bit key for the hash operation
+ * @data: Data buffer for which a MAC is determined
+ * @data_len: Length of data buffer in bytes
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
}
#endif /* CONFIG_NO_AES_OMAC1 */
Modified: wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.h (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/aes_wrap.h Sat Nov 3 08:40:37 2007
@@ -7,7 +7,7 @@
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
*
- * Copyright (c) 2003-2005, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2003-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,6 +24,8 @@
int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher);
int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain);
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac);
int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac);
int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
Modified: wpasupplicant/branches/upstream/current/src/crypto/crypto.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/crypto.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/crypto.h (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/crypto.h Sat Nov 3 08:40:37 2007
@@ -316,6 +316,23 @@
int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen);
+
+/**
+ * crypto_private_key_decrypt_pkcs1_v15 - Private key decryption (PKCS #1 v1.5)
+ * @key: Private key
+ * @in: Encrypted buffer
+ * @inlen: Length of encrypted buffer in bytes
+ * @out: Output buffer for encrypted data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen);
/**
* crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1)
Modified: wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c Sat Nov 3 08:40:37 2007
@@ -539,6 +539,39 @@
}
+int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen)
+{
+ struct crypto_rsa_key *rkey = (struct crypto_rsa_key *) key;
+ int res;
+ u8 *pos, *end;
+
+ res = crypto_rsa_exptmod(in, inlen, out, outlen, rkey, 1);
+ if (res)
+ return res;
+
+ if (*outlen < 2 || out[0] != 0 || out[1] != 2)
+ return -1;
+
+ /* Skip PS (pseudorandom non-zero octets) */
+ pos = out + 2;
+ end = out + *outlen;
+ while (*pos && pos < end)
+ pos++;
+ if (pos == end)
+ return -1;
+ pos++;
+
+ *outlen -= pos - out;
+
+ /* Strip PKCS #1 header */
+ os_memmove(out, pos, *outlen);
+
+ return 0;
+}
+
+
int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
@@ -576,21 +609,39 @@
* PKCS #1 v1.5, 8.1:
*
* EB = 00 || BT || PS || 00 || D
- * BT = 01
- * PS = k-3-||D|| times FF
+ * BT = 00 or 01
+ * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01)
* k = length of modulus in octets
*/
if (len < 3 + 8 + 16 /* min hash len */ ||
- plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
+ plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
"structure");
return -1;
}
pos = plain + 3;
- while (pos < plain + len && *pos == 0xff)
- pos++;
+ if (plain[1] == 0x00) {
+ /* BT = 00 */
+ if (plain[2] != 0x00) {
+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
+ "PS (BT=00)");
+ return -1;
+ }
+ while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00)
+ pos++;
+ } else {
+ /* BT = 01 */
+ if (plain[2] != 0xff) {
+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
+ "PS (BT=01)");
+ return -1;
+ }
+ while (pos < plain + len && *pos == 0xff)
+ pos++;
+ }
+
if (pos - plain - 2 < 8) {
/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
Modified: wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c Sat Nov 3 08:40:37 2007
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -411,9 +411,8 @@
* @block: 16-octet Block (IN)
* @cypher: 16-octer Cypher (OUT)
*/
-static void nt_password_hash_encrypted_with_block(const u8 *password_hash,
- const u8 *block,
- u8 *cypher)
+void nt_password_hash_encrypted_with_block(const u8 *password_hash,
+ const u8 *block, u8 *cypher)
{
des_encrypt(password_hash, block, cypher);
des_encrypt(password_hash + 8, block + 7, cypher + 8);
Modified: wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.h (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.h Sat Nov 3 08:40:37 2007
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
- * Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -47,10 +47,15 @@
void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
size_t session_key_len, int is_send,
int is_server);
+int encrypt_pw_block_with_password_hash(
+ const u8 *password, size_t password_len,
+ const u8 *password_hash, u8 *pw_block);
void new_password_encrypted_with_old_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
u8 *encrypted_pw_block);
+void nt_password_hash_encrypted_with_block(const u8 *password_hash,
+ const u8 *block, u8 *cypher);
void old_nt_password_hash_encrypted_with_new_nt_password_hash(
const u8 *new_password, size_t new_password_len,
const u8 *old_password, size_t old_password_len,
Modified: wpasupplicant/branches/upstream/current/src/crypto/sha256.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/sha256.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/sha256.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/sha256.c Sat Nov 3 08:40:37 2007
@@ -107,7 +107,7 @@
/**
- * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5a.3)
+ * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
* @key: Key for PRF
* @key_len: Length of the key in bytes
* @label: A unique label for each purpose of the PRF
@@ -132,7 +132,7 @@
addr[0] = counter_le;
len[0] = 2;
addr[1] = (u8 *) label;
- len[1] = os_strlen(label) + 1;
+ len[1] = os_strlen(label);
addr[2] = data;
len[2] = data_len;
addr[3] = length_le;
Modified: wpasupplicant/branches/upstream/current/src/crypto/tls.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls.h (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls.h Sat Nov 3 08:40:37 2007
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / SSL/TLS interface definition
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -364,17 +364,6 @@
*/
int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn);
-/**
- * tls_connection_set_master_key - Configure master secret for TLS connection
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @key: TLS pre-master-secret
- * @key_len: length of key in bytes
- * Returns: 0 on success, -1 on failure
- */
-int tls_connection_set_master_key(void *tls_ctx, struct tls_connection *conn,
- const u8 *key, size_t key_len);
-
enum {
TLS_CIPHER_NONE,
TLS_CIPHER_RC4_SHA /* 0x0005 */,
@@ -518,4 +507,13 @@
struct tls_connection *conn,
const u8 *key, size_t key_len);
+typedef int (*tls_session_ticket_cb)
+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
+ const u8 *server_random, u8 *master_secret);
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+ struct tls_connection *conn,
+ tls_session_ticket_cb cb,
+ void *ctx);
+
#endif /* TLS_H */
Modified: wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_gnutls.c Sat Nov 3 08:40:37 2007
@@ -1157,14 +1157,6 @@
}
-int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
- const u8 *key, size_t key_len)
-{
- /* TODO */
- return -1;
-}
-
-
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
Modified: wpasupplicant/branches/upstream/current/src/crypto/tls_internal.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls_internal.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_internal.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_internal.c Sat Nov 3 08:40:37 2007
@@ -20,16 +20,20 @@
#include "common.h"
#include "tls.h"
#include "tls/tlsv1_client.h"
+#include "tls/tlsv1_server.h"
static int tls_ref_count = 0;
struct tls_global {
- int dummy;
+ int server;
+ struct tlsv1_credentials *server_cred;
+ int check_crl;
};
struct tls_connection {
struct tlsv1_client *client;
+ struct tlsv1_server *server;
};
@@ -38,8 +42,14 @@
struct tls_global *global;
if (tls_ref_count == 0) {
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (tlsv1_client_global_init())
return NULL;
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (tlsv1_server_global_init())
+ return NULL;
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
}
tls_ref_count++;
@@ -55,7 +65,13 @@
struct tls_global *global = ssl_ctx;
tls_ref_count--;
if (tls_ref_count == 0) {
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
tlsv1_client_global_deinit();
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ tlsv1_cred_free(global->server_cred);
+ tlsv1_server_global_deinit();
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
}
os_free(global);
}
@@ -70,16 +86,30 @@
struct tls_connection * tls_connection_init(void *tls_ctx)
{
struct tls_connection *conn;
+ struct tls_global *global = tls_ctx;
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
- conn->client = tlsv1_client_init();
- if (conn->client == NULL) {
- os_free(conn);
- return NULL;
- }
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (!global->server) {
+ conn->client = tlsv1_client_init();
+ if (conn->client == NULL) {
+ os_free(conn);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (global->server) {
+ conn->server = tlsv1_server_init(global->server_cred);
+ if (conn->server == NULL) {
+ os_free(conn);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
return conn;
}
@@ -89,74 +119,170 @@
{
if (conn == NULL)
return;
- tlsv1_client_deinit(conn->client);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client)
+ tlsv1_client_deinit(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ tlsv1_server_deinit(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
os_free(conn);
}
int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
{
- return tlsv1_client_established(conn->client);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client)
+ return tlsv1_client_established(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_established(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+ return 0;
}
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
{
- return tlsv1_client_shutdown(conn->client);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client)
+ return tlsv1_client_shutdown(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_shutdown(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+ return -1;
}
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
- if (tlsv1_client_set_ca_cert(conn->client, params->ca_cert,
- params->ca_cert_blob,
- params->ca_cert_blob_len,
- params->ca_path)) {
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ struct tlsv1_credentials *cred;
+
+ if (conn->client == NULL)
+ return -1;
+
+ cred = tlsv1_cred_alloc();
+ if (cred == NULL)
+ return -1;
+
+ if (tlsv1_set_ca_cert(cred, params->ca_cert,
+ params->ca_cert_blob, params->ca_cert_blob_len,
+ params->ca_path)) {
wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
"certificates");
- return -1;
- }
-
- if (tlsv1_client_set_client_cert(conn->client, params->client_cert,
- params->client_cert_blob,
- params->client_cert_blob_len)) {
+ tlsv1_cred_free(cred);
+ return -1;
+ }
+
+ if (tlsv1_set_cert(cred, params->client_cert,
+ params->client_cert_blob,
+ params->client_cert_blob_len)) {
wpa_printf(MSG_INFO, "TLS: Failed to configure client "
"certificate");
- return -1;
- }
-
- if (tlsv1_client_set_private_key(conn->client,
- params->private_key,
- params->private_key_passwd,
- params->private_key_blob,
- params->private_key_blob_len)) {
+ tlsv1_cred_free(cred);
+ return -1;
+ }
+
+ if (tlsv1_set_private_key(cred, params->private_key,
+ params->private_key_passwd,
+ params->private_key_blob,
+ params->private_key_blob_len)) {
wpa_printf(MSG_INFO, "TLS: Failed to load private key");
- return -1;
- }
-
- return 0;
+ tlsv1_cred_free(cred);
+ return -1;
+ }
+
+ if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
+ params->dh_blob_len)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
+ tlsv1_cred_free(cred);
+ return -1;
+ }
+
+ if (tlsv1_client_set_cred(conn->client, cred) < 0) {
+ tlsv1_cred_free(cred);
+ return -1;
+ }
+
+ return 0;
+#else /* CONFIG_TLS_INTERNAL_CLIENT */
+ return -1;
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
}
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
- wpa_printf(MSG_INFO, "TLS: not implemented - %s", __func__);
- return -1;
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ struct tls_global *global = tls_ctx;
+ struct tlsv1_credentials *cred;
+
+ /* Currently, global parameters are only set when running in server
+ * mode. */
+ global->server = 1;
+ tlsv1_cred_free(global->server_cred);
+ global->server_cred = cred = tlsv1_cred_alloc();
+ if (cred == NULL)
+ return -1;
+
+ if (tlsv1_set_ca_cert(cred, params->ca_cert, params->ca_cert_blob,
+ params->ca_cert_blob_len, params->ca_path)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
+ "certificates");
+ return -1;
+ }
+
+ if (tlsv1_set_cert(cred, params->client_cert, params->client_cert_blob,
+ params->client_cert_blob_len)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to configure server "
+ "certificate");
+ return -1;
+ }
+
+ if (tlsv1_set_private_key(cred, params->private_key,
+ params->private_key_passwd,
+ params->private_key_blob,
+ params->private_key_blob_len)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load private key");
+ return -1;
+ }
+
+ if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
+ params->dh_blob_len)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
+ return -1;
+ }
+
+ return 0;
+#else /* CONFIG_TLS_INTERNAL_SERVER */
+ return -1;
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
}
int tls_global_set_verify(void *tls_ctx, int check_crl)
{
- wpa_printf(MSG_INFO, "TLS: not implemented - %s", __func__);
- return -1;
+ struct tls_global *global = tls_ctx;
+ global->check_crl = check_crl;
+ return 0;
}
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
int verify_peer)
{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_set_verify(conn->server, verify_peer);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
@@ -171,7 +297,15 @@
int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
- return tlsv1_client_get_keys(conn->client, keys);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client)
+ return tlsv1_client_get_keys(conn->client, keys);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_keys(conn->server, keys);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+ return -1;
}
@@ -179,8 +313,21 @@
const char *label, int server_random_first,
u8 *out, size_t out_len)
{
- return tlsv1_client_prf(conn->client, label, server_random_first,
- out, out_len);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client) {
+ return tlsv1_client_prf(conn->client, label,
+ server_random_first,
+ out, out_len);
+ }
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server) {
+ return tlsv1_server_prf(conn->server, label,
+ server_random_first,
+ out, out_len);
+ }
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+ return -1;
}
@@ -189,6 +336,10 @@
size_t *out_len, u8 **appl_data,
size_t *appl_data_len)
{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client == NULL)
+ return NULL;
+
if (appl_data)
*appl_data = NULL;
@@ -196,6 +347,9 @@
__func__, in_data, (unsigned long) in_len);
return tlsv1_client_handshake(conn->client, in_data, in_len, out_len,
appl_data, appl_data_len);
+#else /* CONFIG_TLS_INTERNAL_CLIENT */
+ return NULL;
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
}
@@ -204,8 +358,20 @@
const u8 *in_data, size_t in_len,
size_t *out_len)
{
- wpa_printf(MSG_INFO, "TLS: not implemented - %s", __func__);
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ u8 *out;
+ if (conn->server == NULL)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "TLS: %s(in_data=%p in_len=%lu)",
+ __func__, in_data, (unsigned long) in_len);
+ out = tlsv1_server_handshake(conn->server, in_data, in_len, out_len);
+ if (out == NULL && tlsv1_server_established(conn->server))
+ out = os_malloc(1);
+ return out;
+#else /* CONFIG_TLS_INTERNAL_SERVER */
return NULL;
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
}
@@ -213,8 +379,19 @@
const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len)
{
- return tlsv1_client_encrypt(conn->client, in_data, in_len, out_data,
- out_len);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client) {
+ return tlsv1_client_encrypt(conn->client, in_data, in_len,
+ out_data, out_len);
+ }
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server) {
+ return tlsv1_server_encrypt(conn->server, in_data, in_len,
+ out_data, out_len);
+ }
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+ return -1;
}
@@ -222,28 +399,48 @@
const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len)
{
- return tlsv1_client_decrypt(conn->client, in_data, in_len, out_data,
- out_len);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client) {
+ return tlsv1_client_decrypt(conn->client, in_data, in_len,
+ out_data, out_len);
+ }
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server) {
+ return tlsv1_server_decrypt(conn->server, in_data, in_len,
+ out_data, out_len);
+ }
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+ return -1;
}
int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
{
- return tlsv1_client_resumed(conn->client);
-}
-
-
-int tls_connection_set_master_key(void *tls_ctx, struct tls_connection *conn,
- const u8 *key, size_t key_len)
-{
- return tlsv1_client_set_master_key(conn->client, key, key_len);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client)
+ return tlsv1_client_resumed(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_resumed(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+ return -1;
}
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
- return tlsv1_client_set_cipher_list(conn->client, ciphers);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client)
+ return tlsv1_client_set_cipher_list(conn->client, ciphers);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_set_cipher_list(conn->server, ciphers);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+ return -1;
}
@@ -252,7 +449,15 @@
{
if (conn == NULL)
return -1;
- return tlsv1_client_get_cipher(conn->client, buf, buflen);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client)
+ return tlsv1_client_get_cipher(conn->client, buf, buflen);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_cipher(conn->server, buf, buflen);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+ return -1;
}
@@ -267,7 +472,13 @@
int ext_type, const u8 *data,
size_t data_len)
{
- return tlsv1_client_hello_ext(conn->client, ext_type, data, data_len);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client) {
+ return tlsv1_client_hello_ext(conn->client, ext_type,
+ data, data_len);
+ }
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+ return -1;
}
@@ -293,7 +504,15 @@
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn)
{
- return tlsv1_client_get_keyblock_size(conn->client);
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client)
+ return tlsv1_client_get_keyblock_size(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_keyblock_size(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+ return -1;
}
@@ -325,3 +544,24 @@
{
return -1;
}
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+ struct tls_connection *conn,
+ tls_session_ticket_cb cb,
+ void *ctx)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client) {
+ tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx);
+ return 0;
+ }
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server) {
+ tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx);
+ return 0;
+ }
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+ return -1;
+}
Modified: wpasupplicant/branches/upstream/current/src/crypto/tls_none.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls_none.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_none.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_none.c Sat Nov 3 08:40:37 2007
@@ -147,13 +147,6 @@
}
-int tls_connection_set_master_key(void *tls_ctx, struct tls_connection *conn,
- const u8 *key, size_t key_len)
-{
- return -1;
-}
-
-
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
Modified: wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c Sat Nov 3 08:40:37 2007
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / SSL/TLS interface functions for openssl
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -49,8 +49,12 @@
char *subject_match, *altsubject_match;
int read_alerts, write_alerts, failed;
- u8 *pre_shared_secret;
- size_t pre_shared_secret_len;
+ tls_session_ticket_cb session_ticket_cb;
+ void *session_ticket_cb_ctx;
+
+ /* SessionTicket received from OpenSSL hello_extension_cb (server) */
+ u8 *session_ticket;
+ size_t session_ticket_len;
};
@@ -919,11 +923,11 @@
{
if (conn == NULL)
return;
- os_free(conn->pre_shared_secret);
SSL_free(conn->ssl);
tls_engine_deinit(conn);
os_free(conn->subject_match);
os_free(conn->altsubject_match);
+ os_free(conn->session_ticket);
os_free(conn);
}
@@ -1760,6 +1764,80 @@
}
+static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
+{
+#ifdef OPENSSL_NO_DH
+ if (dh_file == NULL)
+ return 0;
+ wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
+ "dh_file specified");
+ return -1;
+#else /* OPENSSL_NO_DH */
+ DH *dh;
+ BIO *bio;
+
+ /* TODO: add support for dh_blob */
+ if (dh_file == NULL)
+ return 0;
+ if (ssl_ctx == NULL)
+ return -1;
+
+ bio = BIO_new_file(dh_file, "r");
+ if (bio == NULL) {
+ wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
+ dh_file, ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+#ifndef OPENSSL_NO_DSA
+ while (dh == NULL) {
+ DSA *dsa;
+ wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
+ " trying to parse as DSA params", dh_file,
+ ERR_error_string(ERR_get_error(), NULL));
+ bio = BIO_new_file(dh_file, "r");
+ if (bio == NULL)
+ break;
+ dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ if (!dsa) {
+ wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
+ "'%s': %s", dh_file,
+ ERR_error_string(ERR_get_error(), NULL));
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
+ dh = DSA_dup_DH(dsa);
+ DSA_free(dsa);
+ if (dh == NULL) {
+ wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
+ "params into DH params");
+ break;
+ }
+ break;
+ }
+#endif /* !OPENSSL_NO_DSA */
+ if (dh == NULL) {
+ wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
+ "'%s'", dh_file);
+ return -1;
+ }
+
+ if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) {
+ wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
+ "%s", dh_file,
+ ERR_error_string(ERR_get_error(), NULL));
+ DH_free(dh);
+ return -1;
+ }
+ DH_free(dh);
+ return 0;
+#endif /* OPENSSL_NO_DH */
+}
+
+
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
@@ -1998,57 +2076,6 @@
{
return conn ? conn->ssl->hit : 0;
}
-
-
-#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC)
-/* Pre-shared secred requires a patch to openssl, so this function is
- * commented out unless explicitly needed for EAP-FAST in order to be able to
- * build this file with unmodified openssl. */
-
-static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
- STACK_OF(SSL_CIPHER) *peer_ciphers,
- SSL_CIPHER **cipher, void *arg)
-{
- struct tls_connection *conn = arg;
-
- if (conn == NULL || conn->pre_shared_secret == 0)
- return 0;
-
- os_memcpy(secret, conn->pre_shared_secret,
- conn->pre_shared_secret_len);
- *secret_len = conn->pre_shared_secret_len;
-
- return 1;
-}
-
-
-int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
- const u8 *key, size_t key_len)
-{
- if (conn == NULL || key_len > SSL_MAX_MASTER_KEY_LENGTH)
- return -1;
-
- os_free(conn->pre_shared_secret);
- conn->pre_shared_secret = NULL;
- conn->pre_shared_secret_len = 0;
-
- if (key) {
- conn->pre_shared_secret = os_malloc(key_len);
- if (conn->pre_shared_secret) {
- os_memcpy(conn->pre_shared_secret, key, key_len);
- conn->pre_shared_secret_len = key_len;
- }
- if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
- conn) != 1)
- return -1;
- } else {
- if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
- return -1;
- }
-
- return 0;
-}
-#endif /* EAP_FAST || EAP_FAST_DYNAMIC */
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
@@ -2255,6 +2282,12 @@
params->private_key_passwd))
return -1;
+ if (tls_global_dh(ssl_ctx, params->dh_file)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
+ params->dh_file);
+ return -1;
+ }
+
return 0;
}
@@ -2272,7 +2305,11 @@
return -1;
c = conn->ssl->enc_read_ctx->cipher;
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+ h = EVP_MD_CTX_md(conn->ssl->read_hash);
+#else
h = conn->ssl->read_hash;
+#endif
return 2 * (EVP_CIPHER_key_length(c) +
EVP_MD_size(h) +
@@ -2315,3 +2352,131 @@
{
return -1;
}
+
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC)
+/* Pre-shared secred requires a patch to openssl, so this function is
+ * commented out unless explicitly needed for EAP-FAST in order to be able to
+ * build this file with unmodified openssl. */
+
+static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers,
+ SSL_CIPHER **cipher, void *arg)
+{
+ struct tls_connection *conn = arg;
+ int ret;
+
+ if (conn == NULL || conn->session_ticket_cb == NULL)
+ return 0;
+
+ ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
+ conn->session_ticket,
+ conn->session_ticket_len,
+ s->s3->client_random,
+ s->s3->server_random, secret);
+ os_free(conn->session_ticket);
+ conn->session_ticket = NULL;
+
+ if (ret <= 0)
+ return 0;
+
+ *secret_len = SSL_MAX_MASTER_KEY_LENGTH;
+ return 1;
+}
+
+
+#ifdef SSL_OP_NO_TICKET
+static void tls_hello_ext_cb(SSL *s, int client_server, int type,
+ unsigned char *data, int len, void *arg)
+{
+ struct tls_connection *conn = arg;
+
+ if (conn == NULL || conn->session_ticket_cb == NULL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
+ type, len);
+
+ if (type == TLSEXT_TYPE_session_ticket && !client_server) {
+ os_free(conn->session_ticket);
+ conn->session_ticket = NULL;
+
+ wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
+ "extension", data, len);
+ conn->session_ticket = os_malloc(len);
+ if (conn->session_ticket == NULL)
+ return;
+
+ os_memcpy(conn->session_ticket, data, len);
+ conn->session_ticket_len = len;
+ }
+}
+#else /* SSL_OP_NO_TICKET */
+static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg)
+{
+ struct tls_connection *conn = arg;
+
+ if (conn == NULL || conn->session_ticket_cb == NULL)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
+ ext->type, ext->length);
+
+ os_free(conn->session_ticket);
+ conn->session_ticket = NULL;
+
+ if (ext->type == 35) {
+ wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
+ "extension", ext->data, ext->length);
+ conn->session_ticket = os_malloc(ext->length);
+ if (conn->session_ticket == NULL)
+ return SSL_AD_INTERNAL_ERROR;
+
+ os_memcpy(conn->session_ticket, ext->data, ext->length);
+ conn->session_ticket_len = ext->length;
+ }
+
+ return 0;
+}
+#endif /* SSL_OP_NO_TICKET */
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC */
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+ struct tls_connection *conn,
+ tls_session_ticket_cb cb,
+ void *ctx)
+{
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC)
+ conn->session_ticket_cb = cb;
+ conn->session_ticket_cb_ctx = ctx;
+
+ if (cb) {
+ if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
+ conn) != 1)
+ return -1;
+#ifdef SSL_OP_NO_TICKET
+ SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb);
+ SSL_set_tlsext_debug_arg(conn->ssl, conn);
+#else /* SSL_OP_NO_TICKET */
+ if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb,
+ conn) != 1)
+ return -1;
+#endif /* SSL_OP_NO_TICKET */
+ } else {
+ if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
+ return -1;
+#ifdef SSL_OP_NO_TICKET
+ SSL_set_tlsext_debug_callback(conn->ssl, NULL);
+ SSL_set_tlsext_debug_arg(conn->ssl, conn);
+#else /* SSL_OP_NO_TICKET */
+ if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1)
+ return -1;
+#endif /* SSL_OP_NO_TICKET */
+ }
+
+ return 0;
+#else /* EAP_FAST || EAP_FAST_DYNAMIC */
+ return -1;
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC */
+}
Modified: wpasupplicant/branches/upstream/current/src/crypto/tls_schannel.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls_schannel.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_schannel.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_schannel.c Sat Nov 3 08:40:37 2007
@@ -654,13 +654,6 @@
}
-int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
- const u8 *key, size_t key_len)
-{
- return -1;
-}
-
-
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
Added: wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h Sat Nov 3 08:40:37 2007
@@ -1,0 +1,156 @@
+#ifndef APPLE80211_H
+#define APPLE80211_H
+
+/*
+ * Apple80211 framework definitions
+ * This is an undocumented interface and the definitions here are based on
+ * information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and
+ * whatever related information can be found with google and experiments ;-).
+ */
+
+typedef struct __WirelessRef *WirelessRef;
+typedef SInt32 WirelessError;
+#define errWirelessNoError 0
+
+typedef struct WirelessInfo {
+ UInt16 link_qual;
+ UInt16 comms_qual;
+ UInt16 signal;
+ UInt16 noise;
+ UInt16 port_stat;
+ UInt16 client_mode;
+ UInt16 res1;
+ UInt16 power;
+ UInt16 res2;
+ UInt8 bssID[6];
+ UInt8 ssid[34];
+} WirelessInfo;
+
+typedef struct WirelessInfo2 {
+ /* TODO - these are probably not in correct order or complete */
+ WirelessInfo info1;
+ UInt8 macAddress[6];
+} WirelessInfo2;
+
+typedef struct WirelessNetworkInfo {
+ UInt16 channel;
+ UInt16 noise;
+ UInt16 signal;
+ UInt8 bssid[6];
+ UInt16 beacon_int;
+ UInt16 capability;
+ UInt16 ssid_len;
+ UInt8 ssid[32];
+} WirelessNetworkInfo;
+
+typedef int wirelessKeyType; /* TODO */
+
+int WirelessIsAvailable(void);
+WirelessError WirelessAttach(WirelessRef *ref, UInt32 res);
+WirelessError WirelessDetach(WirelessRef ref);
+WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes,
+ void *out_ptr, int out_bytes);
+WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled);
+WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled);
+WirelessError WirelessSetPower(WirelessRef ref, UInt8 power);
+WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power);
+WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info);
+WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info);
+WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results,
+ UInt32 strip_dups);
+WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results,
+ CFArrayRef *ibss_results, UInt32 strip_dups);
+WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results,
+ UInt32 strip_dups, CFStringRef ssid);
+WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid,
+ UInt32 strip_dups, CFArrayRef *results);
+WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid);
+WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid,
+ CFStringRef passwd);
+WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid);
+/*
+ * Set WEP key
+ * ref: wireless reference from WirelessAttach()
+ * type: ?
+ * key_idx: 0..3
+ * key_len: 13 for WEP-104 or 0 for clearing the key
+ * key: Pointer to the key or %NULL if key_len = 0
+ */
+WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type,
+ int key_idx, int key_len,
+ const unsigned char *key);
+/*
+ * Set WPA key (e.g., PMK for 4-way handshake)
+ * ref: wireless reference from WirelessAttach()
+ * type: 0..4; 1 = PMK
+ * key_len: 16, 32, or 0
+ * key: Pointer to the key or %NULL if key_len = 0
+ */
+WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type,
+ int key_len, const unsigned char *key);
+WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid,
+ CFStringRef key);
+WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res,
+ CFStringRef key);
+WirelessError WirelessDisassociate(WirelessRef ref);
+
+/*
+ * Get a copy of scan results for the given SSID
+ * The returned dictionary includes following entries:
+ * beaconInterval: CFNumber(kCFNumberSInt32Type)
+ * SSID: CFData buffer of the SSID
+ * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2
+ * name: Name of the network (SSID string)
+ * BSSID: CFData buffer of the BSSID
+ * channel: CFNumber(kCFNumberSInt32Type)
+ * signal: CFNumber(kCFNumberSInt32Type)
+ * appleIE: CFData
+ * WPSNOPINRequired: CFBoolean
+ * noise: CFNumber(kCFNumberSInt32Type)
+ * capability: CFNumber(kCFNumberSInt32Type)
+ * uniCipher: CFArray of CFNumber(kCFNumberSInt32Type)
+ * appleIE_Version: CFNumber(kCFNumberSInt32Type)
+ * appleIE_Robust: CFBoolean
+ * WPSConfigured: CFBoolean
+ * scanWasDirected: CFBoolean
+ * appleIE_Product: CFNumber(kCFNumberSInt32Type)
+ * authModes: CFArray of CFNumber(kCFNumberSInt32Type)
+ * multiCipher: CFNumber(kCFNumberSInt32Type)
+ */
+CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid);
+
+/*
+ * Get information about the current association
+ * The returned dictionary includes following entries:
+ * keyData: CFData buffer of the key (e.g., 32-octet PSK)
+ * multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP?
+ * channel: CFNumber(kCFNumberSInt32Type)
+ * isIBSS: CFBoolean
+ * authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open,
+ * 129 = WPA2-Enterprise
+ * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2
+ * SSID: CFData buffer of the SSID
+ * cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP?
+ */
+CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref);
+
+WirelessError WirelessConfigure(WirelessRef ref);
+
+/*
+ * Get ASP information
+ * The returned dictionary includes following entries:
+ * Version: version number (e.g., 3.0)
+ * Channel: channel (e.g., 1)
+ * Vendor: vendor (e.g., 2)
+ */
+CFDictionaryRef WirelessGetInfoASP(void);
+
+/*
+ * Get a copy of the interface dictionary
+ * The returned dictionary has a key,value pairs for wireless interfaces.
+ * The key is the interface name and the value is the driver identifier, e.g.,
+ * en1: com.apple.driver.AirPort.Atheros
+ */
+CFDictionaryRef WirelessCopyInterfaceDict(void);
+
+#endif /* APPLE80211_H */
Added: wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.c (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.c Sat Nov 3 08:40:37 2007
@@ -1,0 +1,189 @@
+#include "includes.h"
+#include <dlfcn.h>
+
+#include "common.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include "MobileApple80211.h"
+
+/*
+ * Code for dynamically loading Apple80211 functions from Aeropuerto to avoid
+ * having to link with full Preferences.framework.
+ */
+
+static void *aeropuerto = NULL;
+
+
+int _Apple80211Initialized(void)
+{
+ return aeropuerto ? 1 : 0;
+}
+
+
+static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL;
+
+int Apple80211Open(Apple80211Ref *ctx)
+{
+ return __Apple80211Open(ctx);
+}
+
+
+static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL;
+
+int Apple80211Close(Apple80211Ref ctx)
+{
+ return __Apple80211Close(ctx);
+}
+
+
+static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list)
+ = NULL;
+
+int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list)
+{
+ return __Apple80211GetIfListCopy(handle, list);
+}
+
+
+static int (*__Apple80211BindToInterface)(Apple80211Ref handle,
+ CFStringRef interface) = NULL;
+
+int Apple80211BindToInterface(Apple80211Ref handle,
+ CFStringRef interface)
+{
+ return __Apple80211BindToInterface(handle, interface);
+}
+
+
+static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle,
+ CFStringRef *name) = NULL;
+
+int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
+ CFStringRef *name)
+{
+ return __Apple80211GetInterfaceNameCopy(handle, name);
+}
+
+
+static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle,
+ CFDictionaryRef *info) = NULL;
+
+int Apple80211GetInfoCopy(Apple80211Ref handle,
+ CFDictionaryRef *info)
+{
+ return __Apple80211GetInfoCopy(handle, info);
+}
+
+
+static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL;
+
+int Apple80211GetPower(Apple80211Ref handle, char *pwr)
+{
+ return __Apple80211GetPower(handle, pwr);
+}
+
+
+static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL;
+
+int Apple80211SetPower(Apple80211Ref handle, char pwr)
+{
+ return __Apple80211SetPower(handle, pwr);
+}
+
+
+static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list,
+ CFDictionaryRef parameters) = NULL;
+
+int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
+ CFDictionaryRef parameters)
+{
+ return __Apple80211Scan(handle, list, parameters);
+}
+
+
+static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef arg) = NULL;
+
+int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef arg)
+{
+ return __Apple80211Associate(handle, bss, arg);
+}
+
+
+static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle,
+ CFDictionaryRef bss,
+ CFStringRef arg,
+ CFDictionaryRef *info) =
+ NULL;
+
+int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef arg, CFDictionaryRef *info)
+{
+ return __Apple80211AssociateAndCopyInfo(handle, bss, arg, info);
+}
+
+
+static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field,
+ int unused, void *value) = NULL;
+
+int Apple80211CopyValue(Apple80211Ref handle, int field, int unused,
+ void *value)
+{
+ return __Apple80211CopyValue(handle, field, unused, value);
+}
+
+
+#define DLSYM(s) \
+do { \
+ __ ## s = dlsym(aeropuerto, #s); \
+ if (__ ## s == NULL) { \
+ wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \
+ "symbol '" #s "' (%s)", dlerror()); \
+ err = 1; \
+ } \
+} while (0)
+
+
+__attribute__ ((constructor))
+void _Apple80211_constructor(void)
+{
+ const char *fname = "/System/Library/SystemConfiguration/"
+ "Aeropuerto.bundle/Aeropuerto";
+ int err = 0;
+
+ aeropuerto = dlopen(fname, RTLD_LAZY);
+ if (!aeropuerto) {
+ wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s "
+ "for symbols", fname);
+ return;
+ }
+
+ DLSYM(Apple80211Open);
+ DLSYM(Apple80211Close);
+ DLSYM(Apple80211GetIfListCopy);
+ DLSYM(Apple80211BindToInterface);
+ DLSYM(Apple80211GetInterfaceNameCopy);
+ DLSYM(Apple80211GetInfoCopy);
+ DLSYM(Apple80211GetPower);
+ DLSYM(Apple80211SetPower);
+ DLSYM(Apple80211Scan);
+ DLSYM(Apple80211Associate);
+ DLSYM(Apple80211AssociateAndCopyInfo);
+ DLSYM(Apple80211CopyValue);
+
+ if (err) {
+ dlclose(aeropuerto);
+ aeropuerto = NULL;
+ }
+}
+
+
+__attribute__ ((destructor))
+void _Apple80211_destructor(void)
+{
+ if (aeropuerto) {
+ dlclose(aeropuerto);
+ aeropuerto = NULL;
+ }
+}
Added: wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.h (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/MobileApple80211.h Sat Nov 3 08:40:37 2007
@@ -1,0 +1,42 @@
+#ifndef MOBILEAPPLE80211_H
+#define MOBILEAPPLE80211_H
+
+/*
+ * MobileApple80211 interface for iPhone/iPod touch
+ * These functions are available from Aeropuerto.
+ */
+
+struct Apple80211;
+typedef struct Apple80211 *Apple80211Ref;
+
+int Apple80211Open(Apple80211Ref *ctx);
+int Apple80211Close(Apple80211Ref ctx);
+int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list);
+int Apple80211BindToInterface(Apple80211Ref handle,
+ CFStringRef interface);
+int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
+ CFStringRef *name);
+int Apple80211GetInfoCopy(Apple80211Ref handle,
+ CFDictionaryRef *info);
+int Apple80211GetPower(Apple80211Ref handle, char *pwr);
+int Apple80211SetPower(Apple80211Ref handle, char pwr);
+
+/* parameters can be NULL; returns scan results in CFArrayRef *list;
+ * caller will need to free with CFRelease() */
+int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
+ CFDictionaryRef parameters);
+
+int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef arg);
+int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef arg, CFDictionaryRef *info);
+
+enum {
+ APPLE80211_VALUE_SSID = 1,
+ APPLE80211_VALUE_BSSID = 9
+};
+
+int Apple80211CopyValue(Apple80211Ref handle, int field, int unused,
+ void *value);
+
+#endif /* MOBILEAPPLE80211_H */
Modified: wpasupplicant/branches/upstream/current/src/drivers/driver.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver.h (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver.h Sat Nov 3 08:40:37 2007
@@ -197,6 +197,14 @@
* mobility domain is currently active.
*/
const u8 *ft_md;
+
+ /**
+ * passphrase - RSN passphrase for PSK
+ *
+ * This value is made available only for WPA/WPA2-Personal (PSK) and
+ * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE.
+ */
+ const char *passphrase;
};
/**
@@ -227,6 +235,9 @@
#define WPA_DRIVER_FLAGS_DRIVER_IE 0x00000001
#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
#define WPA_DRIVER_FLAGS_USER_SPACE_MLME 0x00000004
+/* Driver takes care of RSN 4-way handshake internally; PMK is configured with
+ * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
+#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
unsigned int flags;
};
@@ -347,7 +358,8 @@
* set_key - Configure encryption key
* @priv: private driver interface data
* @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
- * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_DHV);
+ * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_DHV,
+ * %WPA_ALG_PMK);
* %WPA_ALG_NONE clears the key.
* @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for
* broadcast/default keys
Added: wpasupplicant/branches/upstream/current/src/drivers/driver_iphone.m
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_iphone.m?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_iphone.m (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_iphone.m Sat Nov 3 08:40:37 2007
@@ -1,0 +1,466 @@
+/*
+ * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
+ * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#define Boolean __DummyBoolean
+#include <CoreFoundation/CoreFoundation.h>
+#undef Boolean
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+
+#include "MobileApple80211.h"
+
+struct wpa_driver_iphone_data {
+ void *ctx;
+ Apple80211Ref wireless_ctx;
+ CFArrayRef scan_results;
+ int ctrl_power;
+};
+
+
+static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
+{
+ const void *res;
+ CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
+ kCFStringEncodingMacRoman);
+ if (str == NULL)
+ return NULL;
+
+ res = CFDictionaryGetValue(dict, str);
+ CFRelease(str);
+ return res;
+}
+
+
+static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ CFDataRef data;
+ int err, len;
+
+ err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
+ &data);
+ if (err != 0) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
+ "failed: %d", err);
+ return -1;
+ }
+
+ len = CFDataGetLength(data);
+ if (len > 32) {
+ CFRelease(data);
+ return -1;
+ }
+ os_memcpy(ssid, CFDataGetBytePtr(data), len);
+ CFRelease(data);
+
+ return len;
+}
+
+
+static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ CFStringRef data;
+ int err;
+ int a1, a2, a3, a4, a5, a6;
+
+ err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
+ &data);
+ if (err != 0) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
+ "failed: %d", err);
+ return -1;
+ }
+
+ sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
+ "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
+ bssid[0] = a1;
+ bssid[1] = a2;
+ bssid[2] = a3;
+ bssid[3] = a4;
+ bssid[4] = a5;
+ bssid[5] = a6;
+
+ CFRelease(data);
+
+ return 0;
+}
+
+
+static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ int err;
+
+ if (drv->scan_results) {
+ CFRelease(drv->scan_results);
+ drv->scan_results = NULL;
+ }
+
+ err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
+ err);
+ return -1;
+ }
+
+ eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
+ drv->ctx);
+ return 0;
+}
+
+
+static int wpa_driver_iphone_get_scan_results(void *priv,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ size_t i, num;
+
+ if (drv->scan_results == NULL)
+ return 0;
+
+ num = CFArrayGetCount(drv->scan_results);
+ if (num > max_size)
+ num = max_size;
+ os_memset(results, 0, num * sizeof(struct wpa_scan_result));
+
+ for (i = 0; i < num; i++) {
+ struct wpa_scan_result *res = &results[i];
+ CFDictionaryRef dict =
+ CFArrayGetValueAtIndex(drv->scan_results, i);
+ CFDataRef data;
+ CFStringRef str;
+ CFNumberRef num;
+ int val;
+
+ data = cfdict_get_key_str(dict, "SSID");
+ if (data) {
+ res->ssid_len = CFDataGetLength(data);
+ if (res->ssid_len > 32)
+ res->ssid_len = 32;
+ os_memcpy(res->ssid, CFDataGetBytePtr(data),
+ res->ssid_len);
+ }
+
+ str = cfdict_get_key_str(dict, "BSSID");
+ if (str) {
+ int a1, a2, a3, a4, a5, a6;
+ sscanf(CFStringGetCStringPtr(
+ str, kCFStringEncodingMacRoman),
+ "%x:%x:%x:%x:%x:%x",
+ &a1, &a2, &a3, &a4, &a5, &a6);
+ res->bssid[0] = a1;
+ res->bssid[1] = a2;
+ res->bssid[2] = a3;
+ res->bssid[3] = a4;
+ res->bssid[4] = a5;
+ res->bssid[5] = a6;
+ }
+
+ num = cfdict_get_key_str(dict, "CAPABILITIES");
+ if (num) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+ res->caps = val;
+ }
+
+ num = cfdict_get_key_str(dict, "CHANNEL");
+ if (num) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+ res->freq = 2407 + val * 5;
+ }
+
+ num = cfdict_get_key_str(dict, "RSSI");
+ if (num) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+ res->level = val;
+ }
+
+ num = cfdict_get_key_str(dict, "NOISE");
+ if (num) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+ res->noise = val;
+ }
+
+ data = cfdict_get_key_str(dict, "IE");
+ if (data) {
+ u8 *ptr = (u8 *) CFDataGetBytePtr(data);
+ int len = CFDataGetLength(data);
+ u8 *pos = ptr, *end = ptr + len;
+
+ while (pos + 2 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_RSN &&
+ pos[1] <= SSID_MAX_WPA_IE_LEN) {
+ os_memcpy(res->rsn_ie, pos,
+ 2 + pos[1]);
+ res->rsn_ie_len = 2 + pos[1];
+ }
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+ pos[1] > 4 && pos[2] == 0x00 &&
+ pos[3] == 0x50 && pos[4] == 0xf2 &&
+ pos[5] == 0x01) {
+ os_memcpy(res->wpa_ie, pos,
+ 2 + pos[1]);
+ res->wpa_ie_len = 2 + pos[1];
+ }
+
+ pos = pos + 2 + pos[1];
+ }
+ }
+ }
+
+ return num;
+}
+
+
+static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_driver_iphone_data *drv = eloop_ctx;
+ u8 bssid[ETH_ALEN];
+
+ if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
+ eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
+ drv, drv->ctx);
+ return;
+ }
+
+ wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
+}
+
+
+static int wpa_driver_iphone_associate(
+ void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ int i, num, err;
+ size_t ssid_len;
+ CFDictionaryRef bss = NULL;
+
+ /*
+ * TODO: Consider generating parameters instead of just using an entry
+ * from scan results in order to support ap_scan=2.
+ */
+
+ if (drv->scan_results == NULL) {
+ wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
+ "associate");
+ return -1;
+ }
+
+ num = CFArrayGetCount(drv->scan_results);
+
+ for (i = 0; i < num; i++) {
+ CFDictionaryRef dict =
+ CFArrayGetValueAtIndex(drv->scan_results, i);
+ CFDataRef data;
+
+ data = cfdict_get_key_str(dict, "SSID");
+ if (data == NULL)
+ continue;
+
+ ssid_len = CFDataGetLength(data);
+ if (ssid_len != params->ssid_len ||
+ os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
+ != 0)
+ continue;
+
+ bss = dict;
+ break;
+ }
+
+ if (bss == NULL) {
+ wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
+ "results - cannot associate");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
+ "from scan results");
+
+ err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
+ "%d", err);
+ return -1;
+ }
+
+ /*
+ * Driver is actually already associated; report association from an
+ * eloop callback.
+ */
+ eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
+ eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
+ drv->ctx);
+
+ return 0;
+}
+
+
+static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx, const u8 *seq,
+ size_t seq_len, const u8 *key,
+ size_t key_len)
+{
+ /*
+ * TODO: Need to either support configuring PMK for 4-way handshake or
+ * PTK for TKIP/CCMP.
+ */
+ return -1;
+}
+
+
+static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+
+ capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
+ WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
+ capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+ capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+
+ return 0;
+}
+
+
+static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_iphone_data *drv;
+ int err;
+ char power;
+ CFStringRef name;
+ CFDictionaryRef dict;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ err = Apple80211Open(&drv->wireless_ctx);
+ if (err) {
+ wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
+ err);
+ os_free(drv);
+ return NULL;
+ }
+
+ name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
+ kCFStringEncodingISOLatin1);
+ if (name == NULL) {
+ wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
+ Apple80211Close(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+
+ err = Apple80211BindToInterface(drv->wireless_ctx, name);
+ CFRelease(name);
+
+ if (err) {
+ wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
+ "failed: %d", err);
+ Apple80211Close(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+
+ err = Apple80211GetPower(drv->wireless_ctx, &power);
+ if (err)
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
+ err);
+
+ wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
+
+ if (!power) {
+ drv->ctrl_power = 1;
+ err = Apple80211SetPower(drv->wireless_ctx, 1);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
+ "failed: %d", err);
+ Apple80211Close(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+ }
+
+ err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
+ if (err == 0) {
+ CFShow(dict);
+ CFRelease(dict);
+ } else {
+ printf("Apple80211GetInfoCopy: %d\n", err);
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_iphone_deinit(void *priv)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ int err;
+
+ eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
+ eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
+
+ if (drv->ctrl_power) {
+ wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
+ err = Apple80211SetPower(drv->wireless_ctx, 0);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
+ "failed: %d", err);
+ }
+ }
+
+ err = Apple80211Close(drv->wireless_ctx);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
+ err);
+ }
+
+ if (drv->scan_results)
+ CFRelease(drv->scan_results);
+
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_iphone_ops = {
+ .name = "iphone",
+ .desc = "iPhone/iPod touch Apple80211 driver",
+ .get_ssid = wpa_driver_iphone_get_ssid,
+ .get_bssid = wpa_driver_iphone_get_bssid,
+ .init = wpa_driver_iphone_init,
+ .deinit = wpa_driver_iphone_deinit,
+ .scan = wpa_driver_iphone_scan,
+ .get_scan_results = wpa_driver_iphone_get_scan_results,
+ .associate = wpa_driver_iphone_associate,
+ .set_key = wpa_driver_iphone_set_key,
+ .get_capa = wpa_driver_iphone_get_capa,
+};
Added: wpasupplicant/branches/upstream/current/src/drivers/driver_osx.m
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_osx.m?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_osx.m (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_osx.m Sat Nov 3 08:40:37 2007
@@ -1,0 +1,432 @@
+/*
+ * WPA Supplicant - Mac OS X Apple80211 driver interface
+ * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#define Boolean __DummyBoolean
+#include <CoreFoundation/CoreFoundation.h>
+#undef Boolean
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+
+#include "Apple80211.h"
+
+struct wpa_driver_osx_data {
+ void *ctx;
+ WirelessRef wireless_ctx;
+ CFArrayRef scan_results;
+};
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+extern int wpa_debug_level;
+
+static void dump_dict_cb(const void *key, const void *value, void *context)
+{
+ if (MSG_DEBUG < wpa_debug_level)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Key:");
+ CFShow(key);
+ wpa_printf(MSG_DEBUG, "Value:");
+ CFShow(value);
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries",
+ title, (unsigned int) CFDictionaryGetCount(dict));
+ CFDictionaryApplyFunction(dict, dump_dict_cb, NULL);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+ WirelessInfo info;
+ int len;
+
+ err = WirelessGetInfo(drv->wireless_ctx, &info);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
+ (int) err);
+ return -1;
+ }
+ if (!info.power) {
+ wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
+ return -1;
+ }
+
+ for (len = 0; len < 32; len++)
+ if (info.ssid[len] == 0)
+ break;
+
+ os_memcpy(ssid, info.ssid, len);
+ return len;
+}
+
+
+static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+ WirelessInfo info;
+
+ err = WirelessGetInfo(drv->wireless_ctx, &info);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
+ (int) err);
+ return -1;
+ }
+ if (!info.power) {
+ wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
+ return -1;
+ }
+
+ os_memcpy(bssid, info.bssID, ETH_ALEN);
+ return 0;
+}
+
+
+static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static int wpa_driver_osx_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+
+ if (drv->scan_results) {
+ CFRelease(drv->scan_results);
+ drv->scan_results = NULL;
+ }
+
+ if (ssid) {
+ CFStringRef data;
+ data = CFStringCreateWithBytes(kCFAllocatorDefault,
+ ssid, ssid_len,
+ kCFStringEncodingISOLatin1,
+ FALSE);
+ if (data == NULL) {
+ wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes "
+ "failed");
+ return -1;
+ }
+
+ err = WirelessDirectedScan(drv->wireless_ctx,
+ &drv->scan_results, 0, data);
+ CFRelease(data);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan "
+ "failed: 0x%08x", (unsigned int) err);
+ return -1;
+ }
+ } else {
+ err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: "
+ "0x%08x", (unsigned int) err);
+ return -1;
+ }
+ }
+
+ eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv,
+ drv->ctx);
+ return 0;
+}
+
+
+static int wpa_driver_osx_get_scan_results(void *priv,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ size_t i, num;
+
+ if (drv->scan_results == NULL)
+ return 0;
+
+ num = CFArrayGetCount(drv->scan_results);
+ if (num > max_size)
+ num = max_size;
+ os_memset(results, 0, num * sizeof(struct wpa_scan_result));
+
+ for (i = 0; i < num; i++) {
+ struct wpa_scan_result *res = &results[i];
+ WirelessNetworkInfo *info;
+ info = (WirelessNetworkInfo *)
+ CFDataGetBytePtr(CFArrayGetValueAtIndex(
+ drv->scan_results, i));
+
+ os_memcpy(res->bssid, info->bssid, ETH_ALEN);
+ if (info->ssid_len > 32) {
+ wpa_printf(MSG_DEBUG, "OSX: Invalid SSID length %d in "
+ "scan results", (int) info->ssid_len);
+ continue;
+ }
+ os_memcpy(res->ssid, info->ssid, info->ssid_len);
+ res->ssid_len = info->ssid_len;
+ res->caps = info->capability;
+ res->freq = 2407 + info->channel * 5;
+ res->level = info->signal;
+ res->noise = info->noise;
+ }
+
+ return num;
+}
+
+
+static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_driver_osx_data *drv = eloop_ctx;
+ u8 bssid[ETH_ALEN];
+ CFDictionaryRef ai;
+
+ if (wpa_driver_osx_get_bssid(drv, bssid) != 0) {
+ eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout,
+ drv, drv->ctx);
+ return;
+ }
+
+ ai = WirelessGetAssociationInfo(drv->wireless_ctx);
+ if (ai) {
+ wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo");
+ CFRelease(ai);
+ } else {
+ wpa_printf(MSG_DEBUG, "OSX: Failed to get association info");
+ }
+
+ wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
+}
+
+
+static int wpa_driver_osx_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+ CFDataRef ssid;
+ CFStringRef key;
+ int assoc_type;
+
+ ssid = CFDataCreate(kCFAllocatorDefault, params->ssid,
+ params->ssid_len);
+ if (ssid == NULL)
+ return -1;
+
+ /* TODO: support for WEP */
+ if (params->key_mgmt_suite == KEY_MGMT_PSK) {
+ if (params->passphrase == NULL)
+ return -1;
+ key = CFStringCreateWithCString(kCFAllocatorDefault,
+ params->passphrase,
+ kCFStringEncodingISOLatin1);
+ if (key == NULL) {
+ CFRelease(ssid);
+ return -1;
+ }
+ } else
+ key = NULL;
+
+ if (params->key_mgmt_suite == KEY_MGMT_NONE)
+ assoc_type = 0;
+ else
+ assoc_type = 4;
+
+ wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)",
+ assoc_type, key);
+ err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key);
+ CFRelease(ssid);
+ if (key)
+ CFRelease(key);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x",
+ (unsigned int) err);
+ return -1;
+ }
+
+ /*
+ * Driver is actually already associated; report association from an
+ * eloop callback.
+ */
+ eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
+ eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv,
+ drv->ctx);
+
+ return 0;
+}
+
+
+static int wpa_driver_osx_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx, const u8 *seq,
+ size_t seq_len, const u8 *key,
+ size_t key_len)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+
+ if (alg == WPA_ALG_WEP) {
+ err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len,
+ key);
+ if (err != 0) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: "
+ "0x%08x", (unsigned int) err);
+ return -1;
+ }
+
+ return 0;
+ }
+
+ if (alg == WPA_ALG_PMK) {
+ err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key);
+ if (err != 0) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: "
+ "0x%08x", (unsigned int) err);
+ return -1;
+ }
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg);
+ return -1;
+}
+
+
+static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+
+ capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
+ WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
+ capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+ capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+
+ return 0;
+}
+
+
+static void * wpa_driver_osx_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_osx_data *drv;
+ WirelessError err;
+ u8 enabled, power;
+
+ if (!WirelessIsAvailable()) {
+ wpa_printf(MSG_ERROR, "OSX: No wireless interface available");
+ return NULL;
+ }
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ err = WirelessAttach(&drv->wireless_ctx, 0);
+ if (err) {
+ wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d",
+ (int) err);
+ os_free(drv);
+ return NULL;
+ }
+
+ err = WirelessGetEnabled(drv->wireless_ctx, &enabled);
+ if (err)
+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x",
+ (unsigned int) err);
+ err = WirelessGetPower(drv->wireless_ctx, &power);
+ if (err)
+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x",
+ (unsigned int) err);
+
+ wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power);
+
+ if (!enabled) {
+ err = WirelessSetEnabled(drv->wireless_ctx, 1);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:"
+ " 0x%08x", (unsigned int) err);
+ WirelessDetach(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+ }
+
+ if (!power) {
+ err = WirelessSetPower(drv->wireless_ctx, 1);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: "
+ "0x%08x", (unsigned int) err);
+ WirelessDetach(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_osx_deinit(void *priv)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+
+ eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx);
+ eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
+
+ err = WirelessSetPower(drv->wireless_ctx, 0);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: "
+ "0x%08x", (unsigned int) err);
+ }
+
+ err = WirelessDetach(drv->wireless_ctx);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x",
+ (unsigned int) err);
+ }
+
+ if (drv->scan_results)
+ CFRelease(drv->scan_results);
+
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_osx_ops = {
+ .name = "osx",
+ .desc = "Mac OS X Apple80211 driver",
+ .get_ssid = wpa_driver_osx_get_ssid,
+ .get_bssid = wpa_driver_osx_get_bssid,
+ .init = wpa_driver_osx_init,
+ .deinit = wpa_driver_osx_deinit,
+ .scan = wpa_driver_osx_scan,
+ .get_scan_results = wpa_driver_osx_get_scan_results,
+ .associate = wpa_driver_osx_associate,
+ .set_key = wpa_driver_osx_set_key,
+ .get_capa = wpa_driver_osx_get_capa,
+};
Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c Sat Nov 3 08:40:37 2007
@@ -1380,6 +1380,7 @@
wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes);
return;
}
+ bytes /= 2;
hexstr2bin(spos, bin, bytes);
res->tsf += WPA_GET_BE64(bin);
}
Modified: wpasupplicant/branches/upstream/current/src/drivers/drivers.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/drivers.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/drivers.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/drivers.c Sat Nov 3 08:40:37 2007
@@ -58,6 +58,12 @@
#ifdef CONFIG_DRIVER_RALINK
extern struct wpa_driver_ops wpa_driver_ralink_ops; /* driver_ralink.c */
#endif /* CONFIG_DRIVER_RALINK */
+#ifdef CONFIG_DRIVER_OSX
+extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */
+#endif /* CONFIG_DRIVER_OSX */
+#ifdef CONFIG_DRIVER_IPHONE
+extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */
+#endif /* CONFIG_DRIVER_IPHONE */
struct wpa_driver_ops *wpa_supplicant_drivers[] =
@@ -104,5 +110,11 @@
#ifdef CONFIG_DRIVER_RALINK
&wpa_driver_ralink_ops,
#endif /* CONFIG_DRIVER_RALINK */
+#ifdef CONFIG_DRIVER_OSX
+ &wpa_driver_osx_ops,
+#endif /* CONFIG_DRIVER_OSX */
+#ifdef CONFIG_DRIVER_IPHONE
+ &wpa_driver_iphone_ops,
+#endif /* CONFIG_DRIVER_IPHONE */
NULL
};
Added: wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h (added)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h Sat Nov 3 08:40:37 2007
@@ -1,0 +1,85 @@
+/*
+ * EAP-FAST definitions (RFC 4851)
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef EAP_FAST_H
+#define EAP_FAST_H
+
+#define EAP_FAST_VERSION 1
+#define EAP_FAST_KEY_LEN 64
+#define EAP_FAST_SIMCK_LEN 40
+#define EAP_FAST_SKS_LEN 40
+
+#define TLS_EXT_PAC_OPAQUE 35
+
+/*
+ * draft-cam-winget-eap-fast-provisioning-04.txt:
+ * Section 4.2.1 - Formats for PAC TLV Attributes / Type Field
+ * Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined
+ * in the general PAC TLV format (Section 4.2).
+ */
+#define PAC_TYPE_PAC_KEY 1
+#define PAC_TYPE_PAC_OPAQUE 2
+#define PAC_TYPE_CRED_LIFETIME 3
+#define PAC_TYPE_A_ID 4
+#define PAC_TYPE_I_ID 5
+/*
+ * 6 was previous assigned for SERVER_PROTECTED_DATA, but
+ * draft-cam-winget-eap-fast-provisioning-02.txt changed this to Reserved.
+ */
+#define PAC_TYPE_A_ID_INFO 7
+#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8
+#define PAC_TYPE_PAC_INFO 9
+#define PAC_TYPE_PAC_TYPE 10
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct pac_tlv_hdr {
+ be16 type;
+ be16 len;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+#define EAP_FAST_PAC_KEY_LEN 32
+
+/* draft-cam-winget-eap-fast-provisioning-04.txt: 4.2.6 PAC-Type TLV
+ * Note: Machine Authentication PAC and User Authorization PAC were removed in
+ * draft-cam-winget-eap-fast-provisioning-03.txt
+ */
+#define PAC_TYPE_TUNNEL_PAC 1
+/* Application Specific Short Lived PACs (only in volatile storage) */
+/* User Authorization PAC */
+#define PAC_TYPE_USER_AUTHORIZATION 3
+/* Application Specific Long Lived PACs */
+/* Machine Authentication PAC */
+#define PAC_TYPE_MACHINE_AUTHENTICATION 2
+
+
+/*
+ * draft-cam-winget-eap-fast-provisioning-04.txt:
+ * Section 3.4 - Key Derivations Used in the EAP-FAST Provisioning Exchange
+ */
+struct eap_fast_key_block_provisioning {
+ /* Extra key material after TLS key_block */
+ u8 session_key_seed[EAP_FAST_SKS_LEN];
+ u8 server_challenge[16]; /* MSCHAPv2 ServerChallenge */
+ u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */
+};
+
+#endif /* EAP_FAST_H */
Modified: wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.c Sat Nov 3 08:40:37 2007
@@ -18,7 +18,9 @@
#include "eap_defs.h"
#include "aes_wrap.h"
#include "crypto.h"
+#ifdef EAP_GPSK_SHA256
#include "sha256.h"
+#endif /* EAP_GPSK_SHA256 */
#include "eap_gpsk_common.h"
@@ -42,31 +44,29 @@
}
-static int eap_gpsk_gkdf(const u8 *psk /* Y */, size_t psk_len,
- const u8 *data /* Z */, size_t data_len,
- u8 *buf, size_t len /* X */)
+static int eap_gpsk_gkdf_cmac(const u8 *psk /* Y */,
+ const u8 *data /* Z */, size_t data_len,
+ u8 *buf, size_t len /* X */)
{
u8 *opos;
size_t i, n, hashlen, left, clen;
- u8 ibuf[2], hash[SHA256_MAC_LEN];
- const u8 *addr[3];
- size_t vlen[3];
-
- hashlen = SHA256_MAC_LEN;
- /* M_i = Hash-Function (i || Y || Z); */
+ u8 ibuf[2], hash[16];
+ const u8 *addr[2];
+ size_t vlen[2];
+
+ hashlen = sizeof(hash);
+ /* M_i = MAC_Y (i || Z); (MAC = AES-CMAC-128) */
addr[0] = ibuf;
vlen[0] = sizeof(ibuf);
- addr[1] = psk;
- vlen[1] = psk_len;
- addr[2] = data;
- vlen[2] = data_len;
+ addr[1] = data;
+ vlen[1] = data_len;
opos = buf;
left = len;
n = (len + hashlen - 1) / hashlen;
for (i = 1; i <= n; i++) {
WPA_PUT_BE16(ibuf, i);
- sha256_vector(3, addr, vlen, hash);
+ omac1_aes_128_vector(psk, 2, addr, vlen, hash);
clen = left > hashlen ? hashlen : left;
os_memcpy(opos, hash, clen);
opos += clen;
@@ -77,7 +77,42 @@
}
-static int eap_gpsk_derive_keys_helper(u32 csuite_specified,
+#ifdef EAP_GPSK_SHA256
+static int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */,
+ const u8 *data /* Z */, size_t data_len,
+ u8 *buf, size_t len /* X */)
+{
+ u8 *opos;
+ size_t i, n, hashlen, left, clen;
+ u8 ibuf[2], hash[SHA256_MAC_LEN];
+ const u8 *addr[2];
+ size_t vlen[2];
+
+ hashlen = SHA256_MAC_LEN;
+ /* M_i = MAC_Y (i || Z); (MAC = HMAC-SHA256) */
+ addr[0] = ibuf;
+ vlen[0] = sizeof(ibuf);
+ addr[1] = data;
+ vlen[1] = data_len;
+
+ opos = buf;
+ left = len;
+ n = (len + hashlen - 1) / hashlen;
+ for (i = 1; i <= n; i++) {
+ WPA_PUT_BE16(ibuf, i);
+ hmac_sha256_vector(psk, 32, 2, addr, vlen, hash);
+ clen = left > hashlen ? hashlen : left;
+ os_memcpy(opos, hash, clen);
+ opos += clen;
+ left -= clen;
+ }
+
+ return 0;
+}
+#endif /* EAP_GPSK_SHA256 */
+
+
+static int eap_gpsk_derive_keys_helper(u32 csuite_specifier,
u8 *kdf_out, size_t kdf_out_len,
const u8 *psk, size_t psk_len,
const u8 *seed, size_t seed_len,
@@ -85,10 +120,28 @@
u8 *sk, size_t sk_len,
u8 *pk, size_t pk_len)
{
- u8 zero, mk[32], *pos, *data;
- size_t data_len;
-
- zero = 0;
+ u8 zero[32], mk[32], *pos, *data;
+ size_t data_len, mk_len;
+ int (*gkdf)(const u8 *psk, const u8 *data, size_t data_len,
+ u8 *buf, size_t len);
+
+ gkdf = NULL;
+ switch (csuite_specifier) {
+ case EAP_GPSK_CIPHER_AES:
+ gkdf = eap_gpsk_gkdf_cmac;
+ mk_len = 16;
+ break;
+#ifdef EAP_GPSK_SHA256
+ case EAP_GPSK_CIPHER_SHA256:
+ gkdf = eap_gpsk_gkdf_sha256;
+ mk_len = SHA256_MAC_LEN;
+ break;
+#endif /* EAP_GPSK_SHA256 */
+ default:
+ return -1;
+ }
+
+ os_memset(zero, 0, sizeof(zero));
data_len = 2 + psk_len + 6 + seed_len;
data = os_malloc(data_len);
@@ -99,23 +152,22 @@
pos += 2;
os_memcpy(pos, psk, psk_len);
pos += psk_len;
- WPA_PUT_BE24(pos, 0); /* CSuite/Vendor = IETF */
- pos += 3;
- WPA_PUT_BE24(pos, csuite_specified); /* CSuite/Specifier */
- pos += 3;
+ WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */
+ pos += 4;
+ WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */
+ pos += 2;
os_memcpy(pos, seed, seed_len); /* inputString */
wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation",
data, data_len);
- if (eap_gpsk_gkdf(&zero, 1, data, data_len, mk, sizeof(mk)) < 0) {
+ if (gkdf(zero, data, data_len, mk, mk_len) < 0) {
os_free(data);
return -1;
}
os_free(data);
- wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, sizeof(mk));
-
- if (eap_gpsk_gkdf(mk, sizeof(mk), seed, seed_len,
- kdf_out, kdf_out_len) < 0)
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, mk_len);
+
+ if (gkdf(mk, seed, seed_len, kdf_out, kdf_out_len) < 0)
return -1;
pos = kdf_out;
@@ -153,16 +205,15 @@
/*
* inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
* (= seed)
- * KS = 16, PL = psk_len, CSuite_Sel = 0x000000 0x000001
- * MK = GKDF-32 (0x00, PL || PSK || CSuite_Sel || inputString)
+ * KS = 16, PL = psk_len, CSuite_Sel = 0x00000000 0x0001
+ * zero = 0x00 || 0x00 || ... || 0x00 (16 times)
+ * MK = GKDF-16 (zero, PL || PSK || CSuite_Sel || inputString)
* MSK = GKDF-160 (MK, inputString)[0..63]
* EMSK = GKDF-160 (MK, inputString)[64..127]
* SK = GKDF-160 (MK, inputString)[128..143]
* PK = GKDF-160 (MK, inputString)[144..159]
- * MID = GKDF-16(0x00, "Method ID" || EAP_Method_Type || CSuite_Sel ||
- * inputString)
- * Hash-Function = SHA256 (see [RFC4634])
- * hashlen = 32 octets (256 bits)
+ * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
+ * CSuite_Sel || inputString)
*/
*sk_len = EAP_GPSK_SK_LEN_AES;
@@ -190,15 +241,14 @@
/*
* inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
* (= seed)
- * KS = 32, PL = psk_len, CSuite_Sel = 0x000000 0x000002
- * MK = GKDF-32 (0x00, PL || PSK || CSuite_Sel || inputString)
- * MSK = GKDF-192 (MK, inputString)[0..63]
- * EMSK = GKDF-192 (MK, inputString)[64..127]
- * SK = GKDF-192 (MK, inputString)[128..159]
- * MID = GKDF-16(0x00, "Method ID" || EAP_Method_Type || CSuite_Sel ||
- * inputString)
- * Hash-Function = SHA256 (see [RFC4634])
- * hashlen = 32 octets (256 bits)
+ * KS = 32, PL = psk_len, CSuite_Sel = 0x00000000 0x0002
+ * zero = 0x00 || 0x00 || ... || 0x00 (32 times)
+ * MK = GKDF-32 (zero, PL || PSK || CSuite_Sel || inputString)
+ * MSK = GKDF-160 (MK, inputString)[0..63]
+ * EMSK = GKDF-160 (MK, inputString)[64..127]
+ * SK = GKDF-160 (MK, inputString)[128..159]
+ * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
+ * CSuite_Sel || inputString)
*/
*sk_len = EAP_GPSK_SK_LEN_SHA256;
Modified: wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_gpsk_common.h Sat Nov 3 08:40:37 2007
@@ -32,7 +32,7 @@
#define EAP_GPSK_MAX_PK_LEN 32
#define EAP_GPSK_MAX_MIC_LEN 32
-#define EAP_GPSK_VENDOR_IETF 0x000000
+#define EAP_GPSK_VENDOR_IETF 0x00000000
#define EAP_GPSK_CIPHER_RESERVED 0x000000
#define EAP_GPSK_CIPHER_AES 0x000001
#define EAP_GPSK_CIPHER_SHA256 0x000002
@@ -43,8 +43,8 @@
#endif /* _MSC_VER */
struct eap_gpsk_csuite {
- u8 vendor[3];
- u8 specifier[3];
+ u8 vendor[4];
+ u8 specifier[2];
} STRUCT_PACKED;
#ifdef _MSC_VER
Added: wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h (added)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h Sat Nov 3 08:40:37 2007
@@ -1,0 +1,116 @@
+/*
+ * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-07.txt)
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef EAP_TLV_COMMON_H
+#define EAP_TLV_COMMON_H
+
+/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-07.txt) */
+#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
+#define EAP_TLV_NAK_TLV 4
+/* Note: RFC 4851, Section 4.2.4 defines 5 as Error TLV */
+#define EAP_TLV_CRYPTO_BINDING_TLV 5
+#define EAP_TLV_CONNECTION_BINDING_TLV 6
+#define EAP_TLV_VENDOR_SPECIFIC_TLV 7
+#define EAP_TLV_URI_TLV 8
+#define EAP_TLV_EAP_PAYLOAD_TLV 9
+#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
+#define EAP_TLV_PAC_TLV 11 /* draft-cam-winget-eap-fast-provisioning-04.txt,
+ * Section 4.2 */
+#define EAP_TLV_CRYPTO_BINDING_TLV_ 12 /* RFC 4851, Section 4.2.8 */
+/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.3.1 */
+#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18
+#define EAP_TLV_REQUEST_ACTION_TLV 19 /* RFC 4851, Section 4.2.9 */
+/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.3.2 */
+#define EAP_TLV_PKCS7_TLV 20
+
+#define EAP_TLV_RESULT_SUCCESS 1
+#define EAP_TLV_RESULT_FAILURE 2
+
+#define EAP_TLV_TYPE_MANDATORY 0x8000
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_tlv_hdr {
+ be16 tlv_type;
+ be16 length;
+} STRUCT_PACKED;
+
+struct eap_tlv_nak_tlv {
+ be16 tlv_type;
+ be16 length;
+ be32 vendor_id;
+ be16 nak_type;
+} STRUCT_PACKED;
+
+struct eap_tlv_result_tlv {
+ be16 tlv_type;
+ be16 length;
+ be16 status;
+} STRUCT_PACKED;
+
+/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */
+struct eap_tlv_intermediate_result_tlv {
+ be16 tlv_type;
+ be16 length;
+ be16 status;
+ /* Followed by optional TLVs */
+} STRUCT_PACKED;
+
+/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */
+struct eap_tlv_crypto_binding__tlv {
+ be16 tlv_type;
+ be16 length;
+ u8 reserved;
+ u8 version;
+ u8 received_version;
+ u8 subtype;
+ u8 nonce[32];
+ u8 compound_mac[20];
+} STRUCT_PACKED;
+
+struct eap_tlv_pac_ack_tlv {
+ be16 tlv_type;
+ be16 length;
+ be16 pac_type;
+ be16 pac_len;
+ be16 result;
+} STRUCT_PACKED;
+
+/* RFC 4851, Section 4.2.9 - Request-Action TLV */
+struct eap_tlv_request_action_tlv {
+ be16 tlv_type;
+ be16 length;
+ be16 action;
+} STRUCT_PACKED;
+
+/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.2.6 - PAC-Type TLV */
+struct eap_tlv_pac_type_tlv {
+ be16 tlv_type; /* PAC_TYPE_PAC_TYPE */
+ be16 length;
+ be16 pac_type;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0
+#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
+
+#define EAP_TLV_ACTION_PROCESS_TLV 1
+#define EAP_TLV_ACTION_NEGOTIATE_EAP 2
+
+#endif /* EAP_TLV_COMMON_H */
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap.c Sat Nov 3 08:40:37 2007
@@ -1,6 +1,6 @@
/*
* EAP peer state machines (RFC 4137)
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -1788,6 +1788,27 @@
/**
+ * eap_get_config_password2 - Get password from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Buffer for the length of the password
+ * @hash: Buffer for returning whether the password is stored as a
+ * NtPasswordHash instead of plaintext password; can be %NULL if this
+ * information is not needed
+ * Returns: Pointer to the password or %NULL if not found
+ */
+const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ if (config == NULL)
+ return NULL;
+ *len = config->password_len;
+ if (hash)
+ *hash = !!(config->flags & WPA_CONFIG_FLAGS_PASSWORD_NTHASH);
+ return config->password;
+}
+
+
+/**
* eap_get_config_new_password - Get new password from network configuration
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @len: Buffer for the length of the new password
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c Sat Nov 3 08:40:37 2007
@@ -32,27 +32,8 @@
* - password change (pending mschapv2 packet; replay decrypted packet)
*/
-#define EAP_FAST_VERSION 1
-#define EAP_FAST_KEY_LEN 64
-#define EAP_FAST_SIMCK_LEN 40
-#define EAP_FAST_SKS_LEN 40
-
-#define TLS_EXT_PAC_OPAQUE 35
-
static void eap_fast_deinit(struct eap_sm *sm, void *priv);
-
-
-/*
- * draft-cam-winget-eap-fast-provisioning-04.txt:
- * Section 3.4 - Key Derivations Used in the EAP-FAST Provisioning Exchange
- */
-struct eap_fast_key_block_provisioning {
- /* Extra key material after TLS key_block */
- u8 session_key_seed[EAP_FAST_SKS_LEN];
- u8 server_challenge[16]; /* MSCHAPv2 ServerChallenge */
- u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */
-};
struct eap_fast_data {
@@ -75,6 +56,7 @@
int provisioning; /* doing PAC provisioning (not the normal auth) */
int anon_provisioning; /* doing anonymous (unauthenticated)
* provisioning */
+ int session_ticket_used;
u8 key_data[EAP_FAST_KEY_LEN];
u8 emsk[EAP_EMSK_LEN];
@@ -85,14 +67,71 @@
size_t max_pac_list_len;
int use_pac_binary_format;
- int tls_master_secret_set;
-
u8 simck[EAP_FAST_SIMCK_LEN];
int simck_idx;
u8 *pending_phase2_req;
size_t pending_phase2_req_len;
};
+
+
+static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
+ const u8 *client_random,
+ const u8 *server_random,
+ u8 *master_secret)
+{
+ struct eap_fast_data *data = ctx;
+#define TLS_RANDOM_LEN 32
+#define TLS_MASTER_SECRET_LEN 48
+ u8 seed[2 * TLS_RANDOM_LEN];
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
+
+ if (client_random == NULL || server_random == NULL ||
+ master_secret == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket failed - fall "
+ "back to full TLS handshake");
+ data->session_ticket_used = 0;
+ if (data->provisioning_allowed) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Try to provision a "
+ "new PAC-Key");
+ data->provisioning = 1;
+ data->current_pac = NULL;
+ }
+ return 0;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket", ticket, len);
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
+ client_random, TLS_RANDOM_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
+ server_random, TLS_RANDOM_LEN);
+
+ if (data->current_pac == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key available for "
+ "using SessionTicket");
+ data->session_ticket_used = 0;
+ return 0;
+ }
+
+ /*
+ * RFC 4851, Section 5.1:
+ * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
+ * server_random + client_random, 48)
+ */
+ os_memcpy(seed, server_random, TLS_RANDOM_LEN);
+ os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
+ sha1_t_prf(data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN,
+ "PAC to master secret label hash",
+ seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
+ master_secret, TLS_MASTER_SECRET_LEN);
+
+ data->session_ticket_used = 1;
+
+ return 1;
+}
static int eap_fast_parse_phase1(struct eap_fast_data *data,
@@ -160,6 +199,15 @@
return NULL;
}
+ if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+ eap_fast_session_ticket_cb,
+ data) < 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
+ "callback");
+ eap_fast_deinit(sm, data);
+ return NULL;
+ }
+
/*
* The local RADIUS server in a Cisco AP does not seem to like empty
* fragments before data, so disable that workaround for CBC.
@@ -234,83 +282,6 @@
data->success = 1;
return 0;
-}
-
-
-static int eap_fast_set_tls_master_secret(struct eap_sm *sm,
- struct eap_fast_data *data,
- const u8 *tls, size_t tls_len)
-{
- struct tls_keys keys;
- u8 master_secret[48], *seed;
- const u8 *server_random;
- size_t seed_len, server_random_len;
-
- if (data->tls_master_secret_set || !data->current_pac ||
- tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
- keys.client_random == NULL) {
- return 0;
- }
-
- wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
- keys.client_random, keys.client_random_len);
-
- /*
- * TLS master secret is needed before TLS library has processed this
- * message which includes both ServerHello and an encrypted handshake
- * message, so we need to parse server_random from this message before
- * passing it to TLS library.
- *
- * Example TLS packet header:
- * (16 03 01 00 2a 02 00 00 26 03 01 <32 bytes server_random>)
- * Content Type: Handshake: 0x16
- * Version: TLS 1.0 (0x0301)
- * Lenghth: 42 (0x002a)
- * Handshake Type: Server Hello: 0x02
- * Length: 38 (0x000026)
- * Version TLS 1.0 (0x0301)
- * Random: 32 bytes
- */
- if (tls_len < 43 || tls[0] != 0x16 ||
- tls[1] != 0x03 || tls[2] != 0x01 ||
- tls[5] != 0x02 || tls[9] != 0x03 || tls[10] != 0x01) {
- wpa_hexdump(MSG_DEBUG, "EAP-FAST: unrecognized TLS "
- "ServerHello", tls, tls_len);
- return -1;
- }
- server_random = tls + 11;
- server_random_len = 32;
- wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
- server_random, server_random_len);
-
- seed_len = keys.client_random_len + server_random_len;
- seed = os_malloc(seed_len);
- if (seed == NULL)
- return -1;
- os_memcpy(seed, server_random, server_random_len);
- os_memcpy(seed + server_random_len,
- keys.client_random, keys.client_random_len);
-
- wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: T-PRF seed", seed, seed_len);
- wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: PAC-Key",
- data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN);
- /*
- * RFC 4851, Section 5.1:
- * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
- * server_random + client_random, 48)
- */
- sha1_t_prf(data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN,
- "PAC to master secret label hash",
- seed, seed_len, master_secret, sizeof(master_secret));
- os_free(seed);
- wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: TLS pre-master-secret",
- master_secret, sizeof(master_secret));
-
- data->tls_master_secret_set = 1;
-
- return tls_connection_set_master_key(sm->ssl_ctx, data->ssl.conn,
- master_secret,
- sizeof(master_secret));
}
@@ -1719,21 +1690,6 @@
res = 1;
}
} else {
- /*
- * Try to configure the TLS master secret based on PAC-Key
- * and server/client random values. If the needed values are
- * not yet available, the function returns 0, so we only abort
- * on failure case when configuring the TLS library fails, not
- * if the key material is not yet available.
- */
- if (eap_fast_set_tls_master_secret(sm, data, pos, left) < 0) {
- wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to configure "
- "TLS master secret");
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_FAIL;
- return NULL;
- }
-
/* Continue processing TLS handshake (phase 1). */
res = eap_peer_tls_process_helper(sm, &data->ssl,
EAP_TYPE_FAST,
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast_pac.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast_pac.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast_pac.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast_pac.h Sat Nov 3 08:40:37 2007
@@ -15,54 +15,7 @@
#ifndef EAP_FAST_PAC_H
#define EAP_FAST_PAC_H
-/*
- * draft-cam-winget-eap-fast-provisioning-04.txt:
- * Section 4.2.1 - Formats for PAC TLV Attributes / Type Field
- * Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined
- * in the general PAC TLV format (Section 4.2).
- */
-#define PAC_TYPE_PAC_KEY 1
-#define PAC_TYPE_PAC_OPAQUE 2
-#define PAC_TYPE_CRED_LIFETIME 3
-#define PAC_TYPE_A_ID 4
-#define PAC_TYPE_I_ID 5
-/*
- * 6 was previous assigned for SERVER_PROTECTED_DATA, but
- * draft-cam-winget-eap-fast-provisioning-02.txt changed this to Reserved.
- */
-#define PAC_TYPE_A_ID_INFO 7
-#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8
-#define PAC_TYPE_PAC_INFO 9
-#define PAC_TYPE_PAC_TYPE 10
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct pac_tlv_hdr {
- be16 type;
- be16 len;
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-
-#define EAP_FAST_PAC_KEY_LEN 32
-
-/* draft-cam-winget-eap-fast-provisioning-04.txt: 4.2.6 PAC-Type TLV
- * Note: Machine Authentication PAC and User Authorization PAC were removed in
- * draft-cam-winget-eap-fast-provisioning-03.txt
- */
-#define PAC_TYPE_TUNNEL_PAC 1
-/* Application Specific Short Lived PACs (only in volatile storage) */
-/* User Authorization PAC */
-#define PAC_TYPE_USER_AUTHORIZATION 3
-/* Application Specific Long Lived PACs */
-/* Machine Authentication PAC */
-#define PAC_TYPE_MACHINE_AUTHENTICATION 2
-
+#include "eap_common/eap_fast_common.h"
struct eap_fast_pac {
struct eap_fast_pac *next;
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c Sat Nov 3 08:40:37 2007
@@ -1,5 +1,5 @@
/*
- * EAP peer method: EAP-GPSK (draft-ietf-emu-eap-gpsk-04.txt)
+ * EAP peer method: EAP-GPSK (draft-ietf-emu-eap-gpsk-06.txt)
* Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -196,8 +196,8 @@
csuite = (struct eap_gpsk_csuite *) csuite_list;
for (i = 0; i < count; i++) {
int vendor, specifier;
- vendor = WPA_GET_BE24(csuite->vendor);
- specifier = WPA_GET_BE24(csuite->specifier);
+ vendor = WPA_GET_BE32(csuite->vendor);
+ specifier = WPA_GET_BE16(csuite->specifier);
wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
i, vendor, specifier);
if (data->vendor == EAP_GPSK_VENDOR_IETF &&
@@ -356,8 +356,8 @@
rpos += csuite_list_len;
csuite = (struct eap_gpsk_csuite *) rpos;
- WPA_PUT_BE24(csuite->vendor, data->vendor);
- WPA_PUT_BE24(csuite->specifier, data->specifier);
+ WPA_PUT_BE32(csuite->vendor, data->vendor);
+ WPA_PUT_BE16(csuite->specifier, data->specifier);
rpos = (u8 *) (csuite + 1);
if (eap_gpsk_derive_keys(data->psk, data->psk_len,
@@ -444,8 +444,8 @@
return NULL;
}
csuite = (const struct eap_gpsk_csuite *) pos;
- vendor = WPA_GET_BE24(csuite->vendor);
- specifier = WPA_GET_BE24(csuite->specifier);
+ vendor = WPA_GET_BE32(csuite->vendor);
+ specifier = WPA_GET_BE16(csuite->specifier);
pos += sizeof(*csuite);
if (vendor != data->vendor || specifier != data->specifier) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_gtc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_gtc.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_gtc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_gtc.c Sat Nov 3 08:40:37 2007
@@ -30,7 +30,8 @@
if (data == NULL)
return NULL;
- if (sm->m && sm->m->method == EAP_TYPE_FAST) {
+ if (sm->m && sm->m->vendor == EAP_VENDOR_IETF &&
+ sm->m->method == EAP_TYPE_FAST) {
wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
"with challenge/response");
data->prefix = 1;
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h Sat Nov 3 08:40:37 2007
@@ -340,6 +340,7 @@
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len);
+const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash);
const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len);
const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len);
void eap_clear_config_otp(struct eap_sm *sm);
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_leap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_leap.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_leap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_leap.c Sat Nov 3 08:40:37 2007
@@ -1,6 +1,6 @@
/*
* EAP peer method: LEAP
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -72,11 +72,12 @@
const u8 *pos, *challenge, *identity, *password;
u8 challenge_len, *rpos;
size_t identity_len, password_len;
+ int pwhash;
wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
identity = eap_get_config_identity(sm, &identity_len);
- password = eap_get_config_password(sm, &password_len);
+ password = eap_get_config_password2(sm, &password_len, &pwhash);
if (identity == NULL || password == NULL)
return NULL;
@@ -123,7 +124,10 @@
*rpos++ = LEAP_VERSION;
*rpos++ = 0; /* unused */
*rpos++ = LEAP_RESPONSE_LEN;
- nt_challenge_response(challenge, password, password_len, rpos);
+ if (pwhash)
+ challenge_response(challenge, password, rpos);
+ else
+ nt_challenge_response(challenge, password, password_len, rpos);
os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response",
rpos, LEAP_RESPONSE_LEN);
@@ -199,10 +203,11 @@
u8 response_len, pw_hash[16], pw_hash_hash[16],
expected[LEAP_RESPONSE_LEN];
size_t password_len;
+ int pwhash;
wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
- password = eap_get_config_password(sm, &password_len);
+ password = eap_get_config_password2(sm, &password_len, &pwhash);
if (password == NULL)
return NULL;
@@ -239,8 +244,12 @@
pos, LEAP_RESPONSE_LEN);
os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN);
- nt_password_hash(password, password_len, pw_hash);
- hash_nt_password_hash(pw_hash, pw_hash_hash);
+ if (pwhash) {
+ hash_nt_password_hash(password, pw_hash_hash);
+ } else {
+ nt_password_hash(password, password_len, pw_hash);
+ hash_nt_password_hash(pw_hash, pw_hash_hash);
+ }
challenge_response(data->ap_challenge, pw_hash_hash, expected);
ret->methodState = METHOD_DONE;
@@ -333,11 +342,12 @@
u8 *key, pw_hash_hash[16], pw_hash[16];
const u8 *addr[5], *password;
size_t elen[5], password_len;
+ int pwhash;
if (data->state != LEAP_DONE)
return NULL;
- password = eap_get_config_password(sm, &password_len);
+ password = eap_get_config_password2(sm, &password_len, &pwhash);
if (password == NULL)
return NULL;
@@ -345,8 +355,12 @@
if (key == NULL)
return NULL;
- nt_password_hash(password, password_len, pw_hash);
- hash_nt_password_hash(pw_hash, pw_hash_hash);
+ if (pwhash)
+ hash_nt_password_hash(password, pw_hash_hash);
+ else {
+ nt_password_hash(password, password_len, pw_hash);
+ hash_nt_password_hash(pw_hash, pw_hash_hash);
+ }
wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash",
pw_hash_hash, 16);
wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge",
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c Sat Nov 3 08:40:37 2007
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt)
- * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -180,7 +180,7 @@
static void eap_mschapv2_derive_response(
struct eap_mschapv2_data *data,
const u8 *username, size_t username_len,
- const u8 *password, size_t password_len,
+ const u8 *password, size_t password_len, int pwhash,
const u8 *auth_challenge, const u8 *peer_challenge,
u8 *nt_response)
{
@@ -192,25 +192,45 @@
peer_challenge, MSCHAPV2_CHAL_LEN);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
username, username_len);
- wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: password",
- password, password_len);
- generate_nt_response(auth_challenge, peer_challenge,
- username, username_len,
- password, password_len, nt_response);
+ if (pwhash) {
+ wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: password hash",
+ password, password_len);
+ generate_nt_response_pwhash(auth_challenge, peer_challenge,
+ username, username_len,
+ password, nt_response);
+ } else {
+ wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: password",
+ password, password_len);
+ generate_nt_response(auth_challenge, peer_challenge,
+ username, username_len,
+ password, password_len, nt_response);
+ }
wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: response", nt_response,
MSCHAPV2_NT_RESPONSE_LEN);
/* Authenticator response is not really needed yet, but calculate it
* here so that challenges need not be saved. */
- generate_authenticator_response(password, password_len,
- peer_challenge, auth_challenge,
- username, username_len, nt_response,
- data->auth_response);
+ if (pwhash) {
+ generate_authenticator_response_pwhash(
+ password, peer_challenge, auth_challenge,
+ username, username_len, nt_response,
+ data->auth_response);
+ } else {
+ generate_authenticator_response(password, password_len,
+ peer_challenge, auth_challenge,
+ username, username_len,
+ nt_response,
+ data->auth_response);
+ }
data->auth_response_valid = 1;
/* Likewise, generate master_key here since we have the needed data
* available. */
- nt_password_hash(password, password_len, password_hash);
- hash_nt_password_hash(password_hash, password_hash_hash);
+ if (pwhash) {
+ hash_nt_password_hash(password, password_hash_hash);
+ } else {
+ nt_password_hash(password, password_len, password_hash);
+ hash_nt_password_hash(password_hash, password_hash_hash);
+ }
get_master_key(password_hash_hash, nt_response, data->master_key);
data->master_key_valid = 1;
}
@@ -229,11 +249,12 @@
struct ms_response *r;
size_t username_len, identity_len, password_len;
const u8 *username, *identity, *password;
+ int pwhash;
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response");
identity = eap_get_config_identity(sm, &identity_len);
- password = eap_get_config_password(sm, &password_len);
+ password = eap_get_config_password2(sm, &password_len, &pwhash);
if (identity == NULL || password == NULL)
return NULL;
@@ -281,7 +302,7 @@
auth_challenge = data->auth_challenge;
}
eap_mschapv2_derive_response(data, username, username_len,
- password, password_len,
+ password, password_len, pwhash,
auth_challenge, peer_challenge,
r->nt_response);
@@ -375,9 +396,20 @@
"EAP-MSCHAPV2: Password changed successfully");
data->prev_error = 0;
os_free(config->password);
- config->password = config->new_password;
+ if (config->flags & WPA_CONFIG_FLAGS_PASSWORD_NTHASH) {
+ config->password = os_malloc(16);
+ config->password_len = 16;
+ if (config->password) {
+ nt_password_hash(config->new_password,
+ config->new_password_len,
+ config->password);
+ }
+ os_free(config->new_password);
+ } else {
+ config->password = config->new_password;
+ config->password_len = config->new_password_len;
+ }
config->new_password = NULL;
- config->password_len = config->new_password_len;
config->new_password_len = 0;
}
}
@@ -574,9 +606,10 @@
struct eap_mschapv2_hdr *ms;
struct ms_change_password *cp;
u8 password_hash[16], password_hash_hash[16];
+ int pwhash;
username = eap_get_config_identity(sm, &username_len);
- password = eap_get_config_password(sm, &password_len);
+ password = eap_get_config_password2(sm, &password_len, &pwhash);
new_password = eap_get_config_new_password(sm, &new_password_len);
if (username == NULL || password == NULL || new_password == NULL)
return NULL;
@@ -601,14 +634,29 @@
cp = (struct ms_change_password *) (ms + 1);
/* Encrypted-Password */
- new_password_encrypted_with_old_nt_password_hash(
- new_password, new_password_len,
- password, password_len, cp->encr_password);
+ if (pwhash) {
+ encrypt_pw_block_with_password_hash(
+ new_password, new_password_len,
+ password, cp->encr_password);
+ } else {
+ new_password_encrypted_with_old_nt_password_hash(
+ new_password, new_password_len,
+ password, password_len, cp->encr_password);
+ }
/* Encrypted-Hash */
- old_nt_password_hash_encrypted_with_new_nt_password_hash(
- new_password, new_password_len,
- password, password_len, cp->encr_hash);
+ if (pwhash) {
+ u8 new_password_hash[16];
+ nt_password_hash(new_password, new_password_len,
+ new_password_hash);
+ nt_password_hash_encrypted_with_block(password,
+ new_password_hash,
+ cp->encr_hash);
+ } else {
+ old_nt_password_hash_encrypted_with_new_nt_password_hash(
+ new_password, new_password_len,
+ password, password_len, cp->encr_hash);
+ }
/* Peer-Challenge */
if (os_get_random(cp->peer_challenge, MSCHAPV2_CHAL_LEN)) {
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.h Sat Nov 3 08:40:37 2007
@@ -15,104 +15,7 @@
#ifndef EAP_TLV_H
#define EAP_TLV_H
-/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-07.txt) */
-#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
-#define EAP_TLV_NAK_TLV 4
-/* Note: RFC 4851, Section 4.2.4 defines 5 as Error TLV */
-#define EAP_TLV_CRYPTO_BINDING_TLV 5
-#define EAP_TLV_CONNECTION_BINDING_TLV 6
-#define EAP_TLV_VENDOR_SPECIFIC_TLV 7
-#define EAP_TLV_URI_TLV 8
-#define EAP_TLV_EAP_PAYLOAD_TLV 9
-#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
-#define EAP_TLV_PAC_TLV 11 /* draft-cam-winget-eap-fast-provisioning-04.txt,
- * Section 4.2 */
-#define EAP_TLV_CRYPTO_BINDING_TLV_ 12 /* RFC 4851, Section 4.2.8 */
-/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.3.1 */
-#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18
-#define EAP_TLV_REQUEST_ACTION_TLV 19 /* RFC 4851, Section 4.2.9 */
-/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.3.2 */
-#define EAP_TLV_PKCS7_TLV 20
-
-#define EAP_TLV_RESULT_SUCCESS 1
-#define EAP_TLV_RESULT_FAILURE 2
-
-#define EAP_TLV_TYPE_MANDATORY 0x8000
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct eap_tlv_hdr {
- be16 tlv_type;
- be16 length;
-} STRUCT_PACKED;
-
-struct eap_tlv_nak_tlv {
- be16 tlv_type;
- be16 length;
- be32 vendor_id;
- be16 nak_type;
-} STRUCT_PACKED;
-
-struct eap_tlv_result_tlv {
- be16 tlv_type;
- be16 length;
- be16 status;
-} STRUCT_PACKED;
-
-/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */
-struct eap_tlv_intermediate_result_tlv {
- be16 tlv_type;
- be16 length;
- be16 status;
- /* Followed by optional TLVs */
-} STRUCT_PACKED;
-
-/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */
-struct eap_tlv_crypto_binding__tlv {
- be16 tlv_type;
- be16 length;
- u8 reserved;
- u8 version;
- u8 received_version;
- u8 subtype;
- u8 nonce[32];
- u8 compound_mac[20];
-} STRUCT_PACKED;
-
-struct eap_tlv_pac_ack_tlv {
- be16 tlv_type;
- be16 length;
- be16 pac_type;
- be16 pac_len;
- be16 result;
-} STRUCT_PACKED;
-
-/* RFC 4851, Section 4.2.9 - Request-Action TLV */
-struct eap_tlv_request_action_tlv {
- be16 tlv_type;
- be16 length;
- be16 action;
-} STRUCT_PACKED;
-
-/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.2.6 - PAC-Type TLV */
-struct eap_tlv_pac_type_tlv {
- be16 tlv_type; /* PAC_TYPE_PAC_TYPE */
- be16 length;
- be16 pac_type;
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0
-#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
-
-#define EAP_TLV_ACTION_PROCESS_TLV 1
-#define EAP_TLV_ACTION_NEGOTIATE_EAP 2
-
+#include "eap_common/eap_tlv_common.h"
u8 * eap_tlv_build_nak(int id, u16 nak_type, size_t *resp_len);
u8 * eap_tlv_build_result(int id, u16 status, size_t *resp_len);
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c Sat Nov 3 08:40:37 2007
@@ -198,7 +198,7 @@
static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code,
u32 vendor_id, int mandatory,
- u8 *data, size_t len)
+ const u8 *data, size_t len)
{
u8 *pos;
pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len);
@@ -615,13 +615,23 @@
#if EAP_TTLS_VERSION > 0
u8 pw_hash[16], pw_hash_hash[16], master_key[16];
u8 session_key[2 * MSCHAPV2_KEY_LEN];
- struct wpa_ssid *config = eap_get_config(sm);
+ const u8 *password;
+ size_t password_len;
+ int pwhash;
if (data->ttls_version == 0)
return;
- nt_password_hash(config->password, config->password_len, pw_hash);
- hash_nt_password_hash(pw_hash, pw_hash_hash);
+ password = eap_get_config_password2(sm, &password_len, &pwhash);
+ if (password == NULL)
+ return;
+
+ if (pwhash)
+ hash_nt_password_hash(password, pw_hash_hash);
+ else {
+ nt_password_hash(password, password_len, pw_hash);
+ hash_nt_password_hash(pw_hash, pw_hash_hash);
+ }
get_master_key(pw_hash_hash, nt_response, master_key);
get_asymetric_start_key(master_key, session_key,
MSCHAPV2_KEY_LEN, 0, 0);
@@ -638,18 +648,22 @@
struct eap_method_ret *ret,
u8 **resp, size_t *resp_len)
{
- struct wpa_ssid *config = eap_get_config(sm);
- u8 *buf, *pos, *challenge, *username, *peer_challenge;
- size_t username_len, i;
+ u8 *buf, *pos, *challenge, *peer_challenge;
+ const u8 *identity, *username, *password;
+ size_t identity_len, password_len, username_len, i;
+ int pwhash;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request");
/* MSCHAPv2 does not include optional domain name in the
* challenge-response calculation, so remove domain prefix
* (if present). */
- username = config->identity;
- username_len = config->identity_len;
- pos = username;
+ identity = eap_get_config_identity(sm, &identity_len);
+ password = eap_get_config_password2(sm, &password_len, &pwhash);
+ if (identity == NULL || password == NULL)
+ return -1;
+ username = identity;
+ username_len = identity_len;
for (i = 0; i < username_len; i++) {
if (username[i] == '\\') {
username_len -= i + 1;
@@ -658,7 +672,7 @@
}
}
- pos = buf = os_malloc(config->identity_len + 1000);
+ pos = buf = os_malloc(identity_len + 1000);
if (buf == NULL) {
wpa_printf(MSG_ERROR,
"EAP-TTLS/MSCHAPV2: Failed to allocate memory");
@@ -667,7 +681,7 @@
/* User-Name */
pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
- config->identity, config->identity_len);
+ identity, identity_len);
/* MS-CHAP-Challenge */
challenge = eap_ttls_implicit_challenge(
@@ -701,17 +715,28 @@
peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 username",
username, username_len);
- wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 password",
- config->password, config->password_len);
- generate_nt_response(challenge, peer_challenge,
- username, username_len,
- config->password, config->password_len,
- pos);
- wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 response", pos, 24);
- generate_authenticator_response(config->password, config->password_len,
- peer_challenge, challenge,
- username, username_len,
- pos, data->auth_response);
+ if (pwhash) {
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 password hash",
+ password, 16);
+ generate_nt_response_pwhash(challenge, peer_challenge,
+ username, username_len,
+ password, pos);
+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 response", pos, 24);
+ generate_authenticator_response_pwhash(
+ password, peer_challenge, challenge,
+ username, username_len, pos, data->auth_response);
+ } else {
+ wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 password",
+ password, password_len);
+ generate_nt_response(challenge, peer_challenge,
+ username, username_len,
+ password, password_len, pos);
+ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAPV2 response", pos, 24);
+ generate_authenticator_response(password, password_len,
+ peer_challenge, challenge,
+ username, username_len,
+ pos, data->auth_response);
+ }
data->auth_response_valid = 1;
eap_ttlsv1_permute_inner(sm, data, pos);
@@ -742,12 +767,19 @@
struct eap_method_ret *ret,
u8 **resp, size_t *resp_len)
{
- struct wpa_ssid *config = eap_get_config(sm);
u8 *buf, *pos, *challenge;
+ const u8 *identity, *password;
+ size_t identity_len, password_len;
+ int pwhash;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request");
- pos = buf = os_malloc(config->identity_len + 1000);
+ identity = eap_get_config_identity(sm, &identity_len);
+ password = eap_get_config_password2(sm, &password_len, &pwhash);
+ if (identity == NULL || password == NULL)
+ return -1;
+
+ pos = buf = os_malloc(identity_len + 1000);
if (buf == NULL) {
wpa_printf(MSG_ERROR,
"EAP-TTLS/MSCHAP: Failed to allocate memory");
@@ -756,7 +788,7 @@
/* User-Name */
pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
- config->identity, config->identity_len);
+ identity, identity_len);
/* MS-CHAP-Challenge */
challenge = eap_ttls_implicit_challenge(sm, data, EAP_TLS_KEY_LEN);
@@ -780,11 +812,16 @@
*pos++ = 1; /* Flags: Use NT style passwords */
os_memset(pos, 0, 24); /* LM-Response */
pos += 24;
- nt_challenge_response(challenge,
- config->password, config->password_len,
- pos); /* NT-Response */
- wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password",
- config->password, config->password_len);
+ if (pwhash) {
+ challenge_response(challenge, password, pos); /* NT-Response */
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash",
+ password, 16);
+ } else {
+ nt_challenge_response(challenge, password, password_len,
+ pos); /* NT-Response */
+ wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password",
+ password, password_len);
+ }
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge",
challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24);
@@ -816,14 +853,19 @@
struct eap_method_ret *ret,
u8 **resp, size_t *resp_len)
{
- struct wpa_ssid *config = eap_get_config(sm);
u8 *buf, *pos;
size_t pad;
+ const u8 *identity, *password;
+ size_t identity_len, password_len;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request");
- pos = buf = os_malloc(config->identity_len + config->password_len +
- 100);
+ identity = eap_get_config_identity(sm, &identity_len);
+ password = eap_get_config_password(sm, &password_len);
+ if (identity == NULL || password == NULL)
+ return -1;
+
+ pos = buf = os_malloc(identity_len + password_len + 100);
if (buf == NULL) {
wpa_printf(MSG_ERROR,
"EAP-TTLS/PAP: Failed to allocate memory");
@@ -832,16 +874,16 @@
/* User-Name */
pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
- config->identity, config->identity_len);
+ identity, identity_len);
/* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts
* the data, so no separate encryption is used in the AVP itself.
* However, the password is padded to obfuscate its length. */
- pad = (16 - (config->password_len & 15)) & 15;
+ pad = (16 - (password_len & 15)) & 15;
pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1,
- config->password_len + pad);
- os_memcpy(pos, config->password, config->password_len);
- pos += config->password_len;
+ password_len + pad);
+ os_memcpy(pos, password, password_len);
+ pos += password_len;
os_memset(pos, 0, pad);
pos += pad;
AVP_PAD(buf, pos);
@@ -870,14 +912,20 @@
struct eap_method_ret *ret,
u8 **resp, size_t *resp_len)
{
- struct wpa_ssid *config = eap_get_config(sm);
u8 *buf, *pos, *challenge;
const u8 *addr[3];
size_t len[3];
+ const u8 *identity, *password;
+ size_t identity_len, password_len;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request");
- pos = buf = os_malloc(config->identity_len + 1000);
+ identity = eap_get_config_identity(sm, &identity_len);
+ password = eap_get_config_password(sm, &password_len);
+ if (identity == NULL || password == NULL)
+ return -1;
+
+ pos = buf = os_malloc(identity_len + 1000);
if (buf == NULL) {
wpa_printf(MSG_ERROR,
"EAP-TTLS/CHAP: Failed to allocate memory");
@@ -886,7 +934,7 @@
/* User-Name */
pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
- config->identity, config->identity_len);
+ identity, identity_len);
/* CHAP-Challenge */
challenge = eap_ttls_implicit_challenge(sm, data, EAP_TLS_KEY_LEN);
@@ -909,16 +957,16 @@
/* MD5(Ident + Password + Challenge) */
addr[0] = &data->ident;
len[0] = 1;
- addr[1] = config->password;
- len[1] = config->password_len;
+ addr[1] = password;
+ len[1] = password_len;
addr[2] = challenge;
len[2] = EAP_TTLS_CHAP_CHALLENGE_LEN;
md5_vector(3, addr, len, pos);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username",
- config->identity, config->identity_len);
+ identity, identity_len);
wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password",
- config->password, config->password_len);
+ password, password_len);
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge",
challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password",
Modified: wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c Sat Nov 3 08:40:37 2007
@@ -684,9 +684,7 @@
}
pos += 6;
- while (*pos == ' ')
- pos++;
- type = atoi(pos);
+ type = strtoul(pos, NULL, 16);
wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
pos = os_strstr(start, "<Base64>");
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap.c Sat Nov 3 08:40:37 2007
@@ -941,6 +941,15 @@
sm->ssl_ctx = conf->ssl_ctx;
sm->eap_sim_db_priv = conf->eap_sim_db_priv;
sm->backend_auth = conf->backend_auth;
+ if (conf->pac_opaque_encr_key) {
+ sm->pac_opaque_encr_key = os_malloc(16);
+ if (sm->pac_opaque_encr_key) {
+ os_memcpy(sm->pac_opaque_encr_key,
+ conf->pac_opaque_encr_key, 16);
+ }
+ }
+ if (conf->eap_fast_a_id)
+ sm->eap_fast_a_id = strdup(conf->eap_fast_a_id);
wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
@@ -967,6 +976,8 @@
free(sm->lastReqData);
free(sm->eapRespData);
free(sm->identity);
+ free(sm->pac_opaque_encr_key);
+ free(sm->eap_fast_a_id);
eap_user_free(sm->user);
free(sm);
}
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap.h Sat Nov 3 08:40:37 2007
@@ -57,6 +57,8 @@
void *ssl_ctx;
void *eap_sim_db_priv;
Boolean backend_auth;
+ u8 *pac_opaque_encr_key;
+ char *eap_fast_a_id;
};
Added: wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c (added)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c Sat Nov 3 08:40:37 2007
@@ -1,0 +1,1715 @@
+/*
+ * EAP-FAST server (RFC 4851)
+ * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes_wrap.h"
+#include "sha1.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "tls.h"
+#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_fast_common.h"
+
+
+static void eap_fast_reset(struct eap_sm *sm, void *priv);
+
+
+/* Private PAC-Opaque TLV types */
+#define PAC_OPAQUE_TYPE_PAD 0
+#define PAC_OPAQUE_TYPE_KEY 1
+#define PAC_OPAQUE_TYPE_LIFETIME 2
+
+/* PAC-Key lifetime in seconds (hard limit) */
+#define PAC_KEY_LIFETIME (7 * 24 * 60 * 60)
+
+/*
+ * PAC-Key refresh time in seconds (soft limit on remaining hard limit). The
+ * server will generate a new PAC-Key when this number of seconds (or fewer)
+ * of the lifetime.
+ */
+#define PAC_KEY_REFRESH_TIME (1 * 24 * 60 * 60)
+
+
+struct eap_fast_data {
+ struct eap_ssl_data ssl;
+ enum {
+ START, PHASE1, PHASE2_START, PHASE2_ID, PHASE2_METHOD,
+ CRYPTO_BINDING, REQUEST_PAC, SUCCESS, FAILURE
+ } state;
+
+ int fast_version;
+ const struct eap_method *phase2_method;
+ void *phase2_priv;
+ int force_version;
+ int peer_version;
+
+ u8 crypto_binding_nonce[32];
+ int final_result;
+
+ struct eap_fast_key_block_provisioning *key_block_p;
+
+ u8 simck[EAP_FAST_SIMCK_LEN];
+ u8 cmk[20];
+ int simck_idx;
+
+ u8 pac_opaque_encr[16];
+ char *srv_id;
+
+ int anon_provisioning;
+ int send_new_pac; /* server triggered re-keying of Tunnel PAC */
+};
+
+
+static const char * eap_fast_state_txt(int state)
+{
+ switch (state) {
+ case START:
+ return "START";
+ case PHASE1:
+ return "PHASE1";
+ case PHASE2_START:
+ return "PHASE2_START";
+ case PHASE2_ID:
+ return "PHASE2_ID";
+ case PHASE2_METHOD:
+ return "PHASE2_METHOD";
+ case CRYPTO_BINDING:
+ return "CRYPTO_BINDING";
+ case REQUEST_PAC:
+ return "REQUEST_PAC";
+ case SUCCESS:
+ return "SUCCESS";
+ case FAILURE:
+ return "FAILURE";
+ default:
+ return "Unknown?!";
+ }
+}
+
+
+static void eap_fast_state(struct eap_fast_data *data, int state)
+{
+ wpa_printf(MSG_DEBUG, "EAP-FAST: %s -> %s",
+ eap_fast_state_txt(data->state),
+ eap_fast_state_txt(state));
+ data->state = state;
+}
+
+
+static EapType eap_fast_req_failure(struct eap_sm *sm,
+ struct eap_fast_data *data)
+{
+ /* TODO: send Result TLV(FAILURE) */
+ eap_fast_state(data, FAILURE);
+ return EAP_TYPE_NONE;
+}
+
+
+static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
+ const u8 *client_random,
+ const u8 *server_random,
+ u8 *master_secret)
+{
+ struct eap_fast_data *data = ctx;
+#define TLS_RANDOM_LEN 32
+#define TLS_MASTER_SECRET_LEN 48
+ u8 seed[2 * TLS_RANDOM_LEN];
+ const u8 *pac_opaque;
+ size_t pac_opaque_len;
+ u8 *buf, *pos, *end, *pac_key = NULL;
+ os_time_t lifetime = 0;
+ struct os_time now;
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket (PAC-Opaque)",
+ ticket, len);
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
+ client_random, TLS_RANDOM_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
+ server_random, TLS_RANDOM_LEN);
+
+ if (len < 4 || WPA_GET_BE16(ticket) != PAC_TYPE_PAC_OPAQUE) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid "
+ "SessionTicket");
+ return 0;
+ }
+
+ pac_opaque_len = WPA_GET_BE16(ticket + 2);
+ pac_opaque = ticket + 4;
+ if (pac_opaque_len < 8 || pac_opaque_len % 8 ||
+ pac_opaque_len > len - 4) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid PAC-Opaque "
+ "(len=%lu left=%lu)",
+ (unsigned long) pac_opaque_len,
+ (unsigned long) len);
+ return 0;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: Received PAC-Opaque",
+ pac_opaque, pac_opaque_len);
+
+ buf = os_malloc(pac_opaque_len - 8);
+ if (buf == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
+ "for decrypting PAC-Opaque");
+ return 0;
+ }
+
+ if (aes_unwrap(data->pac_opaque_encr, (pac_opaque_len - 8) / 8,
+ pac_opaque, buf) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to decrypt "
+ "PAC-Opaque");
+ os_free(buf);
+ /*
+ * This may have been caused by server changing the PAC-Opaque
+ * encryption key, so just ignore this PAC-Opaque instead of
+ * failing the authentication completely. Provisioning can now
+ * be used to provision a new PAC.
+ */
+ return 0;
+ }
+
+ end = buf + pac_opaque_len - 8;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Decrypted PAC-Opaque",
+ buf, end - buf);
+
+ pos = buf;
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+
+ switch (*pos) {
+ case PAC_OPAQUE_TYPE_PAD:
+ pos = end;
+ break;
+ case PAC_OPAQUE_TYPE_KEY:
+ if (pos[1] != EAP_FAST_PAC_KEY_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
+ "PAC-Key length %d", pos[1]);
+ os_free(buf);
+ return -1;
+ }
+ pac_key = pos + 2;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key from "
+ "decrypted PAC-Opaque",
+ pac_key, EAP_FAST_PAC_KEY_LEN);
+ break;
+ case PAC_OPAQUE_TYPE_LIFETIME:
+ if (pos[1] != 4) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid "
+ "PAC-Key lifetime length %d",
+ pos[1]);
+ os_free(buf);
+ return -1;
+ }
+ lifetime = WPA_GET_BE32(pos + 2);
+ break;
+ }
+
+ pos += 2 + pos[1];
+ }
+
+ if (pac_key == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key included in "
+ "PAC-Opaque");
+ os_free(buf);
+ return -1;
+ }
+
+ if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key not valid anymore "
+ "(lifetime=%ld now=%ld)", lifetime, now.sec);
+ os_free(buf);
+ return 0;
+ }
+
+ if (lifetime - now.sec < PAC_KEY_REFRESH_TIME)
+ data->send_new_pac = 1;
+
+ /*
+ * RFC 4851, Section 5.1:
+ * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash",
+ * server_random + client_random, 48)
+ */
+ os_memcpy(seed, server_random, TLS_RANDOM_LEN);
+ os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
+ sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN,
+ "PAC to master secret label hash",
+ seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
+ master_secret, TLS_MASTER_SECRET_LEN);
+
+ os_free(buf);
+
+ return 1;
+}
+
+
+static u8 * eap_fast_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
+ char *label, size_t len)
+{
+ struct tls_keys keys;
+ u8 *rnd = NULL, *out;
+ int block_size;
+
+ block_size = tls_connection_get_keyblock_size(sm->ssl_ctx, data->conn);
+ if (block_size < 0)
+ return NULL;
+
+ out = os_malloc(block_size + len);
+ if (out == NULL)
+ return NULL;
+
+ if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 1, out,
+ block_size + len) == 0) {
+ os_memmove(out, out + block_size, len);
+ return out;
+ }
+
+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ goto fail;
+
+ rnd = os_malloc(keys.client_random_len + keys.server_random_len);
+ if (rnd == NULL)
+ goto fail;
+
+ os_memcpy(rnd, keys.server_random, keys.server_random_len);
+ os_memcpy(rnd + keys.server_random_len, keys.client_random,
+ keys.client_random_len);
+
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
+ "expansion", keys.master_key, keys.master_key_len);
+ if (tls_prf(keys.master_key, keys.master_key_len,
+ label, rnd, keys.client_random_len +
+ keys.server_random_len, out, block_size + len))
+ goto fail;
+ os_free(rnd);
+ os_memmove(out, out + block_size, len);
+ return out;
+
+fail:
+ os_free(rnd);
+ os_free(out);
+ return NULL;
+}
+
+
+static void eap_fast_derive_key_auth(struct eap_sm *sm,
+ struct eap_fast_data *data)
+{
+ u8 *sks;
+
+ /* RFC 4851, Section 5.1:
+ * Extra key material after TLS key_block: session_key_seed[40]
+ */
+
+ sks = eap_fast_derive_key(sm, &data->ssl, "key expansion",
+ EAP_FAST_SKS_LEN);
+ if (sks == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
+ "session_key_seed");
+ return;
+ }
+
+ /*
+ * RFC 4851, Section 5.2:
+ * S-IMCK[0] = session_key_seed
+ */
+ wpa_hexdump_key(MSG_DEBUG,
+ "EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
+ sks, EAP_FAST_SKS_LEN);
+ data->simck_idx = 0;
+ os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
+ os_free(sks);
+}
+
+
+static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
+ struct eap_fast_data *data)
+{
+ os_free(data->key_block_p);
+ data->key_block_p = (struct eap_fast_key_block_provisioning *)
+ eap_fast_derive_key(sm, &data->ssl, "key expansion",
+ sizeof(*data->key_block_p));
+ if (data->key_block_p == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
+ return;
+ }
+ /*
+ * RFC 4851, Section 5.2:
+ * S-IMCK[0] = session_key_seed
+ */
+ wpa_hexdump_key(MSG_DEBUG,
+ "EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
+ data->key_block_p->session_key_seed,
+ sizeof(data->key_block_p->session_key_seed));
+ data->simck_idx = 0;
+ os_memcpy(data->simck, data->key_block_p->session_key_seed,
+ EAP_FAST_SIMCK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",
+ data->key_block_p->server_challenge,
+ sizeof(data->key_block_p->server_challenge));
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",
+ data->key_block_p->client_challenge,
+ sizeof(data->key_block_p->client_challenge));
+}
+
+
+static int eap_fast_get_phase2_key(struct eap_sm *sm,
+ struct eap_fast_data *data,
+ u8 *isk, size_t isk_len)
+{
+ u8 *key;
+ size_t key_len;
+
+ os_memset(isk, 0, isk_len);
+
+ if (data->phase2_method == NULL || data->phase2_priv == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
+ "available");
+ return -1;
+ }
+
+ if (data->phase2_method->getKey == NULL)
+ return 0;
+
+ if ((key = data->phase2_method->getKey(sm, data->phase2_priv,
+ &key_len)) == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material "
+ "from Phase 2");
+ return -1;
+ }
+
+ if (key_len > isk_len)
+ key_len = isk_len;
+ os_memcpy(isk, key, key_len);
+ os_free(key);
+
+ return 0;
+}
+
+
+static int eap_fast_update_icmk(struct eap_sm *sm, struct eap_fast_data *data)
+{
+ u8 isk[32], imck[60];
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Deriving ICMK[%d] (S-IMCK and CMK)",
+ data->simck_idx + 1);
+
+ /*
+ * RFC 4851, Section 5.2:
+ * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
+ * MSK[j], 60)
+ * S-IMCK[j] = first 40 octets of IMCK[j]
+ * CMK[j] = last 20 octets of IMCK[j]
+ */
+
+ if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk));
+ sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+ "Inner Methods Compound Keys",
+ isk, sizeof(isk), imck, sizeof(imck));
+ data->simck_idx++;
+ os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
+ data->simck, EAP_FAST_SIMCK_LEN);
+ os_memcpy(data->cmk, imck + EAP_FAST_SIMCK_LEN, 20);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", data->cmk, 20);
+
+ return 0;
+}
+
+
+static void * eap_fast_init(struct eap_sm *sm)
+{
+ struct eap_fast_data *data;
+ u8 ciphers[5] = {
+ TLS_CIPHER_ANON_DH_AES128_SHA,
+ TLS_CIPHER_AES128_SHA,
+ TLS_CIPHER_RSA_DHE_AES128_SHA,
+ TLS_CIPHER_RC4_SHA,
+ TLS_CIPHER_NONE
+ };
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ data->fast_version = EAP_FAST_VERSION;
+ data->force_version = -1;
+ if (sm->user && sm->user->force_version >= 0) {
+ data->force_version = sm->user->force_version;
+ wpa_printf(MSG_DEBUG, "EAP-FAST: forcing version %d",
+ data->force_version);
+ data->fast_version = data->force_version;
+ }
+ data->state = START;
+
+ if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
+ eap_fast_reset(sm, data);
+ return NULL;
+ }
+
+ if (tls_connection_set_cipher_list(sm->ssl_ctx, data->ssl.conn,
+ ciphers) < 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to set TLS cipher "
+ "suites");
+ eap_fast_reset(sm, data);
+ return NULL;
+ }
+
+ if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
+ eap_fast_session_ticket_cb,
+ data) < 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "
+ "callback");
+ eap_fast_reset(sm, data);
+ return NULL;
+ }
+
+ if (sm->pac_opaque_encr_key == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: No PAC-Opaque encryption key "
+ "configured");
+ eap_fast_reset(sm, data);
+ return NULL;
+ }
+ os_memcpy(data->pac_opaque_encr, sm->pac_opaque_encr_key,
+ sizeof(data->pac_opaque_encr));
+
+ if (sm->eap_fast_a_id == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: No A-ID configured");
+ eap_fast_reset(sm, data);
+ return NULL;
+ }
+ data->srv_id = os_strdup(sm->eap_fast_a_id);
+ if (data->srv_id == NULL) {
+ eap_fast_reset(sm, data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
+static void eap_fast_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_fast_data *data = priv;
+ if (data == NULL)
+ return;
+ if (data->phase2_priv && data->phase2_method)
+ data->phase2_method->reset(sm, data->phase2_priv);
+ eap_server_tls_ssl_deinit(sm, &data->ssl);
+ free(data->srv_id);
+ free(data);
+}
+
+
+static u8 * eap_fast_build_start(struct eap_sm *sm, struct eap_fast_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_hdr *req;
+ u8 *pos;
+ struct pac_tlv_hdr *a_id;
+ size_t srv_id_len = os_strlen(data->srv_id);
+
+ *reqDataLen = sizeof(*req) + 2 + sizeof(*a_id) + srv_id_len;
+ req = malloc(*reqDataLen);
+ if (req == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-FAST: Failed to allocate memory for"
+ " request");
+ eap_fast_state(data, FAILURE);
+ return NULL;
+ }
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ req->length = host_to_be16(*reqDataLen);
+ pos = (u8 *) (req + 1);
+ *pos++ = EAP_TYPE_FAST;
+ *pos++ = EAP_TLS_FLAGS_START | data->fast_version;
+ a_id = (struct pac_tlv_hdr *) pos;
+ a_id->type = host_to_be16(PAC_TYPE_A_ID);
+ a_id->len = host_to_be16(srv_id_len);
+ pos = (u8 *) (a_id + 1);
+ os_memcpy(pos, data->srv_id, srv_id_len);
+
+ eap_fast_state(data, PHASE1);
+
+ return (u8 *) req;
+}
+
+
+static int eap_fast_phase1_done(struct eap_sm *sm, struct eap_fast_data *data)
+{
+ char cipher[64];
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase1 done, starting Phase2");
+
+ if (tls_get_cipher(sm->ssl_ctx, data->ssl.conn, cipher, sizeof(cipher))
+ < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to get cipher "
+ "information");
+ eap_fast_state(data, FAILURE);
+ return -1;
+ }
+ data->anon_provisioning = os_strstr(cipher, "ADH") != NULL;
+
+ if (data->anon_provisioning) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Anonymous provisioning");
+ eap_fast_derive_key_provisioning(sm, data);
+ } else
+ eap_fast_derive_key_auth(sm, data);
+
+ eap_fast_state(data, PHASE2_START);
+
+ return 0;
+}
+
+
+static u8 * eap_fast_build_req(struct eap_sm *sm, struct eap_fast_data *data,
+ int id, size_t *reqDataLen)
+{
+ int res;
+ u8 *req;
+
+ res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_FAST,
+ data->fast_version, id, &req,
+ reqDataLen);
+
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (eap_fast_phase1_done(sm, data) < 0) {
+ os_free(req);
+ return NULL;
+ }
+ }
+
+ if (res == 1)
+ return eap_server_tls_build_ack(reqDataLen, id, EAP_TYPE_FAST,
+ data->fast_version);
+ return req;
+}
+
+
+static u8 * eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data,
+ int id, u8 *plain, size_t plain_len,
+ size_t *out_len)
+{
+ int res;
+ u8 *pos;
+ struct eap_hdr *req;
+
+ /* TODO: add support for fragmentation, if needed. This will need to
+ * add TLS Message Length field, if the frame is fragmented. */
+ req = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
+ if (req == NULL)
+ return NULL;
+
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+
+ pos = (u8 *) (req + 1);
+ *pos++ = EAP_TYPE_FAST;
+ *pos++ = data->fast_version;
+
+ res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
+ plain, plain_len,
+ pos, data->ssl.tls_out_limit);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt Phase 2 "
+ "data");
+ free(req);
+ return NULL;
+ }
+
+ *out_len = sizeof(struct eap_hdr) + 2 + res;
+ req->length = host_to_be16(*out_len);
+ return (u8 *) req;
+}
+
+
+static u8 * eap_fast_tlv_eap_payload(u8 *buf, size_t *len)
+{
+ struct eap_tlv_hdr *tlv;
+
+ if (buf == NULL)
+ return NULL;
+
+ /* Encapsulate EAP packet in EAP-Payload TLV */
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV");
+ tlv = os_malloc(sizeof(*tlv) + *len);
+ if (tlv == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
+ "allocate memory for TLV "
+ "encapsulation");
+ os_free(buf);
+ return NULL;
+ }
+ tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+ EAP_TLV_EAP_PAYLOAD_TLV);
+ tlv->length = host_to_be16(*len);
+ os_memcpy(tlv + 1, buf, *len);
+ os_free(buf);
+ *len += sizeof(*tlv);
+ return (u8 *) tlv;
+}
+
+
+static u8 * eap_fast_build_phase2_req(struct eap_sm *sm,
+ struct eap_fast_data *data,
+ int id, size_t *req_len)
+{
+ u8 *req;
+
+ req = data->phase2_method->buildReq(sm, data->phase2_priv, id,
+ req_len);
+ if (req == NULL)
+ return NULL;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: Phase 2 EAP-Request",
+ req, *req_len);
+ return eap_fast_tlv_eap_payload(req, req_len);
+}
+
+
+static u8 * eap_fast_build_crypto_binding(struct eap_sm *sm,
+ struct eap_fast_data *data,
+ size_t *req_len)
+{
+ struct eap_tlv_result_tlv *result;
+ struct eap_tlv_crypto_binding__tlv *binding;
+ int type;
+
+ *req_len = sizeof(*result) + sizeof(*binding);
+ result = os_zalloc(*req_len);
+ if (result == NULL)
+ return NULL;
+ binding = (struct eap_tlv_crypto_binding__tlv *) (result + 1);
+
+ if (data->send_new_pac || data->anon_provisioning) {
+ type = EAP_TLV_INTERMEDIATE_RESULT_TLV;
+ data->final_result = 0;
+ } else {
+ type = EAP_TLV_RESULT_TLV;
+ data->final_result = 1;
+ }
+
+ /* Result TLV */
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)");
+ result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | type);
+ result->length = host_to_be16(2);
+ result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
+
+ /* Crypto-Binding TLV */
+ binding->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+ EAP_TLV_CRYPTO_BINDING_TLV_);
+ binding->length = host_to_be16(sizeof(*binding) -
+ sizeof(struct eap_tlv_hdr));
+ binding->version = EAP_FAST_VERSION;
+ binding->received_version = data->peer_version;
+ binding->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST;
+ if (os_get_random(binding->nonce, sizeof(binding->nonce)) < 0) {
+ os_free(result);
+ return NULL;
+ }
+
+ /*
+ * RFC 4851, Section 4.2.8:
+ * The nonce in a request MUST have its least significant bit set to 0.
+ */
+ binding->nonce[sizeof(binding->nonce) - 1] &= ~0x01;
+
+ os_memcpy(data->crypto_binding_nonce, binding->nonce,
+ sizeof(binding->nonce));
+
+ /*
+ * RFC 4851, Section 5.3:
+ * CMK = CMK[j]
+ * Compound-MAC = HMAC-SHA1( CMK, Crypto-Binding TLV )
+ */
+
+ hmac_sha1(data->cmk, 20, (u8 *) binding, sizeof(*binding),
+ binding->compound_mac);
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add Crypto-Binding TLV: Version %d "
+ "Received Version %d SubType %d",
+ binding->version, binding->received_version,
+ binding->subtype);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
+ binding->nonce, sizeof(binding->nonce));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
+ binding->compound_mac, sizeof(binding->compound_mac));
+
+ return (u8 *) result;
+}
+
+
+static u8 * eap_fast_build_pac(struct eap_sm *sm,
+ struct eap_fast_data *data,
+ size_t *reqDataLen)
+{
+ u8 pac_key[2 + EAP_FAST_PAC_KEY_LEN + 6];
+ u8 pac_opaque[8 + EAP_FAST_PAC_KEY_LEN + 8];
+ u8 *buf, *pos;
+ size_t buf_len, srv_id_len;
+ struct eap_tlv_hdr *pac_tlv;
+ struct pac_tlv_hdr *hdr, *pac_info;
+ struct eap_tlv_result_tlv *result;
+ struct os_time now;
+
+ srv_id_len = os_strlen(data->srv_id);
+
+ pac_key[0] = PAC_OPAQUE_TYPE_KEY;
+ pac_key[1] = EAP_FAST_PAC_KEY_LEN;
+ if (os_get_random(pac_key + 2, EAP_FAST_PAC_KEY_LEN) < 0)
+ return NULL;
+ if (os_get_time(&now) < 0)
+ return NULL;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key",
+ pac_key + 2, EAP_FAST_PAC_KEY_LEN);
+ pos = pac_key + 2 + EAP_FAST_PAC_KEY_LEN;
+ *pos++ = PAC_OPAQUE_TYPE_LIFETIME;
+ *pos++ = 4;
+ WPA_PUT_BE32(pos, now.sec + PAC_KEY_LIFETIME);
+
+ if (aes_wrap(data->pac_opaque_encr, sizeof(pac_key) / 8, pac_key,
+ pac_opaque) < 0)
+ return NULL;
+
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
+ pac_opaque, sizeof(pac_opaque));
+
+ buf_len = sizeof(*pac_tlv) +
+ sizeof(*hdr) + EAP_FAST_PAC_KEY_LEN +
+ sizeof(*hdr) + sizeof(pac_opaque) +
+ 2 * srv_id_len + 100 + sizeof(*result);
+ buf = os_zalloc(buf_len);
+ if (buf == NULL)
+ return NULL;
+
+ pos = buf;
+
+ /* PAC TLV */
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV");
+ pac_tlv = (struct eap_tlv_hdr *) pos;
+ pac_tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+ EAP_TLV_PAC_TLV);
+ pos = (u8 *) (pac_tlv + 1);
+
+ /* PAC-Key */
+ hdr = (struct pac_tlv_hdr *) pos;
+ hdr->type = host_to_be16(PAC_TYPE_PAC_KEY);
+ hdr->len = host_to_be16(EAP_FAST_PAC_KEY_LEN);
+ pos = (u8 *) (hdr + 1);
+ os_memcpy(pos, pac_key + 2, EAP_FAST_PAC_KEY_LEN);
+ pos += EAP_FAST_PAC_KEY_LEN;
+
+ /* PAC-Opaque */
+ hdr = (struct pac_tlv_hdr *) pos;
+ hdr->type = host_to_be16(PAC_TYPE_PAC_OPAQUE);
+ hdr->len = host_to_be16(sizeof(pac_opaque));
+ pos = (u8 *) (hdr + 1);
+ os_memcpy(pos, pac_opaque, sizeof(pac_opaque));
+ pos += sizeof(pac_opaque);
+
+ /* PAC-Info */
+ pac_info = (struct pac_tlv_hdr *) pos;
+ pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO);
+ pos = (u8 *) (pac_info + 1);
+
+ /* PAC-Lifetime (inside PAC-Info) */
+ hdr = (struct pac_tlv_hdr *) pos;
+ hdr->type = host_to_be16(PAC_TYPE_CRED_LIFETIME);
+ hdr->len = host_to_be16(4);
+ pos = (u8 *) (hdr + 1);
+ WPA_PUT_BE32(pos, now.sec + PAC_KEY_LIFETIME);
+ pos += 4;
+
+ /* A-ID (inside PAC-Info) */
+ hdr = (struct pac_tlv_hdr *) pos;
+ hdr->type = host_to_be16(PAC_TYPE_A_ID);
+ hdr->len = host_to_be16(srv_id_len);
+ pos = (u8 *) (hdr + 1);
+ os_memcpy(pos, data->srv_id, srv_id_len);
+ pos += srv_id_len;
+
+ /* Note: headers may be misaligned after A-ID */
+
+ /* A-ID-Info (inside PAC-Info) */
+ hdr = (struct pac_tlv_hdr *) pos;
+ WPA_PUT_BE16((u8 *) &hdr->type, PAC_TYPE_A_ID_INFO);
+ WPA_PUT_BE16((u8 *) &hdr->len, srv_id_len);
+ pos = (u8 *) (hdr + 1);
+ os_memcpy(pos, data->srv_id, srv_id_len);
+ pos += srv_id_len;
+
+ /* PAC-Type (inside PAC-Info) */
+ hdr = (struct pac_tlv_hdr *) pos;
+ WPA_PUT_BE16((u8 *) &hdr->type, PAC_TYPE_PAC_TYPE);
+ WPA_PUT_BE16((u8 *) &hdr->len, 2);
+ pos = (u8 *) (hdr + 1);
+ WPA_PUT_BE16(pos, PAC_TYPE_TUNNEL_PAC);
+ pos += 2;
+
+ /* Update PAC-Info and PAC TLV Length fields */
+ pac_info->len = host_to_be16(pos - (u8 *) (pac_info + 1));
+ pac_tlv->length = host_to_be16(pos - (u8 *) (pac_tlv + 1));
+
+ /* Result TLV */
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)");
+ result = (struct eap_tlv_result_tlv *) pos;
+ WPA_PUT_BE16((u8 *) &result->tlv_type,
+ EAP_TLV_TYPE_MANDATORY | EAP_TLV_RESULT_TLV);
+ WPA_PUT_BE16((u8 *) &result->length, 2);
+ WPA_PUT_BE16((u8 *) &result->status, EAP_TLV_RESULT_SUCCESS);
+ pos = (u8 *) (result + 1);
+
+ *reqDataLen = pos - buf;
+
+ return buf;
+}
+
+
+static u8 * eap_fast_buildReq(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen)
+{
+ struct eap_fast_data *data = priv;
+ u8 *req, *encr;
+ size_t req_len;
+
+ if (data->state == START)
+ return eap_fast_build_start(sm, data, id, reqDataLen);
+
+ if (data->state == PHASE1)
+ return eap_fast_build_req(sm, data, id, reqDataLen);
+
+ switch (data->state) {
+ case PHASE2_ID:
+ case PHASE2_METHOD:
+ req = eap_fast_build_phase2_req(sm, data, id, &req_len);
+ break;
+ case CRYPTO_BINDING:
+ req = eap_fast_build_crypto_binding(sm, data, &req_len);
+ break;
+ case REQUEST_PAC:
+ req = eap_fast_build_pac(sm, data, &req_len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d",
+ __func__, data->state);
+ return NULL;
+ }
+
+ if (req == NULL)
+ return NULL;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs",
+ (u8 *) req, req_len);
+ encr = eap_fast_encrypt(sm, data, id, req, req_len, reqDataLen);
+ free(req);
+
+ return encr;
+}
+
+
+static Boolean eap_fast_check(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_hdr *resp;
+ u8 *pos;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_FAST ||
+ (be_to_host16(resp->length)) > respDataLen) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data,
+ EapType eap_type)
+{
+ if (data->phase2_priv && data->phase2_method) {
+ data->phase2_method->reset(sm, data->phase2_priv);
+ data->phase2_method = NULL;
+ data->phase2_priv = NULL;
+ }
+ data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
+ eap_type);
+ if (!data->phase2_method)
+ return -1;
+
+ if (data->key_block_p) {
+ sm->auth_challenge = data->key_block_p->server_challenge;
+ sm->peer_challenge = data->key_block_p->client_challenge;
+ }
+ sm->init_phase2 = 1;
+ data->phase2_priv = data->phase2_method->init(sm);
+ sm->init_phase2 = 0;
+ sm->auth_challenge = NULL;
+ sm->peer_challenge = NULL;
+
+ return data->phase2_priv == NULL ? -1 : 0;
+}
+
+
+static void eap_fast_process_phase2_response(struct eap_sm *sm,
+ struct eap_fast_data *data,
+ u8 *in_data, size_t in_len)
+{
+ u8 next_type = EAP_TYPE_NONE;
+ struct eap_hdr *hdr;
+ u8 *pos;
+ size_t left;
+
+ if (data->phase2_priv == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: %s - Phase2 not "
+ "initialized?!", __func__);
+ return;
+ }
+
+ hdr = (struct eap_hdr *) in_data;
+ pos = (u8 *) (hdr + 1);
+
+ if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
+ left = in_len - sizeof(*hdr);
+ wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; "
+ "allowed types", pos + 1, left - 1);
+ eap_sm_process_nak(sm, pos + 1, left - 1);
+ if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
+ sm->user->methods[sm->user_eap_method_index].method !=
+ EAP_TYPE_NONE) {
+ next_type = sm->user->methods[
+ sm->user_eap_method_index++].method;
+ wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d",
+ next_type);
+ } else {
+ next_type = eap_fast_req_failure(sm, data);
+ }
+ eap_fast_phase2_init(sm, data, next_type);
+ return;
+ }
+
+ if (data->phase2_method->check(sm, data->phase2_priv, in_data,
+ in_len)) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to "
+ "ignore the packet");
+ next_type = eap_fast_req_failure(sm, data);
+ return;
+ }
+
+ data->phase2_method->process(sm, data->phase2_priv, in_data, in_len);
+
+ if (!data->phase2_method->isDone(sm, data->phase2_priv))
+ return;
+
+ if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed");
+ next_type = eap_fast_req_failure(sm, data);
+ eap_fast_phase2_init(sm, data, next_type);
+ return;
+ }
+
+ switch (data->state) {
+ case PHASE2_ID:
+ if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Phase2 "
+ "Identity not found in the user "
+ "database",
+ sm->identity, sm->identity_len);
+ next_type = eap_fast_req_failure(sm, data);
+ break;
+ }
+
+ eap_fast_state(data, PHASE2_METHOD);
+ if (data->anon_provisioning) {
+ /*
+ * Only EAP-MSCHAPv2 is allowed for anonymous
+ * provisioning.
+ */
+ next_type = EAP_TYPE_MSCHAPV2;
+ sm->user_eap_method_index = 0;
+ } else {
+ next_type = sm->user->methods[0].method;
+ sm->user_eap_method_index = 1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type);
+ break;
+ case PHASE2_METHOD:
+ eap_fast_update_icmk(sm, data);
+ eap_fast_state(data, CRYPTO_BINDING);
+ next_type = EAP_TYPE_NONE;
+ break;
+ case FAILURE:
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d",
+ __func__, data->state);
+ break;
+ }
+
+ eap_fast_phase2_init(sm, data, next_type);
+}
+
+
+static void eap_fast_process_phase2_eap(struct eap_sm *sm,
+ struct eap_fast_data *data,
+ u8 *in_data, size_t in_len)
+{
+ struct eap_hdr *hdr;
+ size_t len;
+
+ hdr = (struct eap_hdr *) in_data;
+ if (in_len < (int) sizeof(*hdr)) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
+ "EAP frame (len=%d)", in_len);
+ eap_fast_req_failure(sm, data);
+ return;
+ }
+ len = be_to_host16(hdr->length);
+ if (len > in_len) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Length mismatch in "
+ "Phase 2 EAP frame (len=%d hdr->length=%d)",
+ in_len, len);
+ eap_fast_req_failure(sm, data);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: code=%d "
+ "identifier=%d length=%d", hdr->code, hdr->identifier, len);
+ switch (hdr->code) {
+ case EAP_CODE_RESPONSE:
+ eap_fast_process_phase2_response(sm, data, (u8 *) hdr, len);
+ break;
+ default:
+ wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
+ "Phase 2 EAP header", hdr->code);
+ break;
+ }
+}
+
+
+struct eap_fast_tlv_parse {
+ u8 *eap_payload_tlv;
+ size_t eap_payload_tlv_len;
+ struct eap_tlv_crypto_binding__tlv *crypto_binding;
+ size_t crypto_binding_len;
+ int iresult;
+ int result;
+ int request_action;
+ u8 *pac;
+ size_t pac_len;
+};
+
+
+static int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
+ int tlv_type, u8 *pos, int len)
+{
+ switch (tlv_type) {
+ case EAP_TLV_EAP_PAYLOAD_TLV:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV",
+ pos, len);
+ if (tlv->eap_payload_tlv) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+ "EAP-Payload TLV in the message");
+ tlv->iresult = EAP_TLV_RESULT_FAILURE;
+ return -2;
+ }
+ tlv->eap_payload_tlv = pos;
+ tlv->eap_payload_tlv_len = len;
+ break;
+ case EAP_TLV_RESULT_TLV:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len);
+ if (tlv->result) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+ "Result TLV in the message");
+ tlv->result = EAP_TLV_RESULT_FAILURE;
+ return -2;
+ }
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+ "Result TLV");
+ tlv->result = EAP_TLV_RESULT_FAILURE;
+ break;
+ }
+ tlv->result = WPA_GET_BE16(pos);
+ if (tlv->result != EAP_TLV_RESULT_SUCCESS &&
+ tlv->result != EAP_TLV_RESULT_FAILURE) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d",
+ tlv->result);
+ tlv->result = EAP_TLV_RESULT_FAILURE;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
+ tlv->result == EAP_TLV_RESULT_SUCCESS ?
+ "Success" : "Failure");
+ break;
+ case EAP_TLV_INTERMEDIATE_RESULT_TLV:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV",
+ pos, len);
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+ "Intermediate-Result TLV");
+ tlv->iresult = EAP_TLV_RESULT_FAILURE;
+ break;
+ }
+ if (tlv->iresult) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+ "Intermediate-Result TLV in the message");
+ tlv->iresult = EAP_TLV_RESULT_FAILURE;
+ return -2;
+ }
+ tlv->iresult = WPA_GET_BE16(pos);
+ if (tlv->iresult != EAP_TLV_RESULT_SUCCESS &&
+ tlv->iresult != EAP_TLV_RESULT_FAILURE) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate "
+ "Result %d", tlv->iresult);
+ tlv->iresult = EAP_TLV_RESULT_FAILURE;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s",
+ tlv->iresult == EAP_TLV_RESULT_SUCCESS ?
+ "Success" : "Failure");
+ break;
+ case EAP_TLV_CRYPTO_BINDING_TLV_:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV",
+ pos, len);
+ if (tlv->crypto_binding) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+ "Crypto-Binding TLV in the message");
+ tlv->iresult = EAP_TLV_RESULT_FAILURE;
+ return -2;
+ }
+ tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
+ if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+ "Crypto-Binding TLV");
+ tlv->iresult = EAP_TLV_RESULT_FAILURE;
+ return -2;
+ }
+ tlv->crypto_binding = (struct eap_tlv_crypto_binding__tlv *)
+ (pos - sizeof(struct eap_tlv_hdr));
+ break;
+ case EAP_TLV_REQUEST_ACTION_TLV:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV",
+ pos, len);
+ if (tlv->request_action) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+ "Request-Action TLV in the message");
+ tlv->iresult = EAP_TLV_RESULT_FAILURE;
+ return -2;
+ }
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+ "Request-Action TLV");
+ tlv->iresult = EAP_TLV_RESULT_FAILURE;
+ break;
+ }
+ tlv->request_action = WPA_GET_BE16(pos);
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d",
+ tlv->request_action);
+ break;
+ case EAP_TLV_PAC_TLV:
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len);
+ if (tlv->pac) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+ "PAC TLV in the message");
+ tlv->iresult = EAP_TLV_RESULT_FAILURE;
+ return -2;
+ }
+ tlv->pac = pos;
+ tlv->pac_len = len;
+ break;
+ default:
+ /* Unknown TLV */
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int eap_fast_parse_tlvs(u8 *data, size_t data_len,
+ struct eap_fast_tlv_parse *tlv)
+{
+ int mandatory, tlv_type, len, res;
+ u8 *pos, *end;
+
+ os_memset(tlv, 0, sizeof(*tlv));
+
+ pos = data;
+ end = data + data_len;
+ while (pos + 4 < end) {
+ mandatory = pos[0] & 0x80;
+ tlv_type = WPA_GET_BE16(pos) & 0x3fff;
+ pos += 2;
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (pos + len > end) {
+ wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: "
+ "TLV type %d length %d%s",
+ tlv_type, len, mandatory ? " (mandatory)" : "");
+
+ res = eap_fast_parse_tlv(tlv, tlv_type, pos, len);
+ if (res == -2)
+ break;
+ if (res < 0) {
+ if (mandatory) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown "
+ "mandatory TLV type %d", tlv_type);
+ /* TODO: generate Nak TLV */
+ break;
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored "
+ "unknown optional TLV type %d",
+ tlv_type);
+ }
+ }
+
+ pos += len;
+ }
+
+ return 0;
+}
+
+
+static int eap_fast_validate_crypto_binding(
+ struct eap_fast_data *data, struct eap_tlv_crypto_binding__tlv *b,
+ size_t bind_len)
+{
+ u8 cmac[20];
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: "
+ "Version %d Received Version %d SubType %d",
+ b->version, b->received_version, b->subtype);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
+ b->nonce, sizeof(b->nonce));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
+ b->compound_mac, sizeof(b->compound_mac));
+
+ if (b->version != EAP_FAST_VERSION ||
+ b->received_version != EAP_FAST_VERSION) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected version "
+ "in Crypto-Binding: version %d "
+ "received_version %d", b->version,
+ b->received_version);
+ return -1;
+ }
+
+ if (b->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected subtype in "
+ "Crypto-Binding: %d", b->subtype);
+ return -1;
+ }
+
+ if (os_memcmp(data->crypto_binding_nonce, b->nonce, 31) != 0 ||
+ (data->crypto_binding_nonce[31] | 1) != b->nonce[31]) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in "
+ "Crypto-Binding");
+ return -1;
+ }
+
+ os_memcpy(cmac, b->compound_mac, sizeof(cmac));
+ os_memset(b->compound_mac, 0, sizeof(cmac));
+ wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for "
+ "Compound MAC calculation",
+ (u8 *) b, bind_len);
+ hmac_sha1(data->cmk, 20, (u8 *) b, bind_len, b->compound_mac);
+ if (os_memcmp(cmac, b->compound_mac, sizeof(cmac)) != 0) {
+ wpa_hexdump(MSG_MSGDUMP,
+ "EAP-FAST: Calculated Compound MAC",
+ b->compound_mac, sizeof(cmac));
+ wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not "
+ "match");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int eap_fast_pac_type(u8 *pac, size_t len, u16 type)
+{
+ struct eap_tlv_pac_type_tlv *tlv;
+
+ if (pac == NULL || len != sizeof(*tlv))
+ return 0;
+
+ tlv = (struct eap_tlv_pac_type_tlv *) pac;
+
+ return be_to_host16(tlv->tlv_type) == PAC_TYPE_PAC_TYPE &&
+ be_to_host16(tlv->length) == 2 &&
+ be_to_host16(tlv->pac_type) == type;
+}
+
+
+static void eap_fast_process_phase2_tlvs(struct eap_sm *sm,
+ struct eap_fast_data *data,
+ u8 *in_data, size_t in_len)
+{
+ struct eap_fast_tlv_parse tlv;
+ int check_crypto_binding = data->state == CRYPTO_BINDING;
+
+ if (eap_fast_parse_tlvs(in_data, in_len, &tlv) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to parse receivede "
+ "Phase 2 TLVs");
+ return;
+ }
+
+ if (tlv.result == EAP_TLV_RESULT_FAILURE) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Result TLV indicated "
+ "failure");
+ eap_fast_state(data, FAILURE);
+ return;
+ }
+
+ if (data->state == REQUEST_PAC) {
+ u16 type, len, res;
+ if (tlv.pac == NULL || tlv.pac_len < 6) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC "
+ "Acknowledgement received");
+ eap_fast_state(data, FAILURE);
+ return;
+ }
+
+ type = WPA_GET_BE16(tlv.pac);
+ len = WPA_GET_BE16(tlv.pac + 2);
+ res = WPA_GET_BE16(tlv.pac + 4);
+
+ if (type != PAC_TYPE_PAC_ACKNOWLEDGEMENT || len != 2 ||
+ res != EAP_TLV_RESULT_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV did not "
+ "contain acknowledgement");
+ eap_fast_state(data, FAILURE);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Acknowledgement received "
+ "- PAC provisioning succeeded");
+ eap_fast_state(data, data->anon_provisioning ?
+ FAILURE : SUCCESS);
+ return;
+ }
+
+ if (tlv.eap_payload_tlv) {
+ eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv,
+ tlv.eap_payload_tlv_len);
+ }
+
+ if (check_crypto_binding) {
+ if (tlv.crypto_binding == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: No Crypto-Binding "
+ "TLV received");
+ eap_fast_state(data, FAILURE);
+ return;
+ }
+
+ if (data->final_result &&
+ tlv.result != EAP_TLV_RESULT_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV "
+ "without Success Result");
+ eap_fast_state(data, FAILURE);
+ return;
+ }
+
+ if (!data->final_result &&
+ tlv.iresult != EAP_TLV_RESULT_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV "
+ "without intermediate Success Result");
+ eap_fast_state(data, FAILURE);
+ return;
+ }
+
+ if (eap_fast_validate_crypto_binding(data, tlv.crypto_binding,
+ tlv.crypto_binding_len)) {
+ eap_fast_state(data, FAILURE);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Valid Crypto-Binding TLV "
+ "received - authentication completed successfully");
+
+ if (data->anon_provisioning ||
+ (tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
+ eap_fast_pac_type(tlv.pac, tlv.pac_len,
+ PAC_TYPE_TUNNEL_PAC))) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Requested a new "
+ "Tunnel PAC");
+ eap_fast_state(data, REQUEST_PAC);
+ } else if (data->send_new_pac) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Server triggered "
+ "re-keying of Tunnel PAC");
+ eap_fast_state(data, REQUEST_PAC);
+ } else
+ eap_fast_state(data, SUCCESS);
+ }
+}
+
+
+static void eap_fast_process_phase2(struct eap_sm *sm,
+ struct eap_fast_data *data,
+ struct eap_hdr *resp,
+ u8 *in_data, size_t in_len)
+{
+ u8 *in_decrypted;
+ int len_decrypted, res;
+ size_t buf_len;
+
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for"
+ " Phase 2", (unsigned long) in_len);
+
+ res = eap_server_tls_data_reassemble(sm, &data->ssl, &in_data,
+ &in_len);
+ if (res < 0 || res == 1)
+ return;
+
+ buf_len = in_len;
+ if (data->ssl.tls_in_total > buf_len)
+ buf_len = data->ssl.tls_in_total;
+ in_decrypted = malloc(buf_len);
+ if (in_decrypted == NULL) {
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ wpa_printf(MSG_WARNING, "EAP-FAST: Failed to allocate memory "
+ "for decryption");
+ return;
+ }
+
+ len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ in_data, in_len,
+ in_decrypted, buf_len);
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ if (len_decrypted < 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
+ "data");
+ free(in_decrypted);
+ eap_fast_state(data, FAILURE);
+ return;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Decrypted Phase 2 TLVs",
+ in_decrypted, len_decrypted);
+
+ eap_fast_process_phase2_tlvs(sm, data, in_decrypted, len_decrypted);
+
+ free(in_decrypted);
+}
+
+
+static void eap_fast_process(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_fast_data *data = priv;
+ struct eap_hdr *resp;
+ u8 *pos, flags;
+ int left;
+ unsigned int tls_msg_len;
+ int peer_version;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ pos++;
+ flags = *pos++;
+ left = be_to_host16(resp->length) - sizeof(struct eap_hdr) - 2;
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Received packet(len=%lu) - "
+ "Flags 0x%02x", (unsigned long) respDataLen, flags);
+ data->peer_version = peer_version = flags & EAP_PEAP_VERSION_MASK;
+ if (data->force_version >= 0 && peer_version != data->force_version) {
+ wpa_printf(MSG_INFO, "EAP-FAST: peer did not select the forced"
+ " version (forced=%d peer=%d) - reject",
+ data->force_version, peer_version);
+ eap_fast_state(data, FAILURE);
+ return;
+ }
+ if (peer_version < data->fast_version) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: peer ver=%d, own ver=%d; "
+ "use version %d",
+ peer_version, data->fast_version, peer_version);
+ data->fast_version = peer_version;
+ }
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+ if (left < 4) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Short frame with TLS "
+ "length");
+ eap_fast_state(data, FAILURE);
+ return;
+ }
+ tls_msg_len = WPA_GET_BE32(pos);
+ wpa_printf(MSG_DEBUG, "EAP-FAST: TLS Message Length: %d",
+ tls_msg_len);
+ if (data->ssl.tls_in_left == 0) {
+ data->ssl.tls_in_total = tls_msg_len;
+ data->ssl.tls_in_left = tls_msg_len;
+ free(data->ssl.tls_in);
+ data->ssl.tls_in = NULL;
+ data->ssl.tls_in_len = 0;
+ }
+ pos += 4;
+ left -= 4;
+ }
+
+ switch (data->state) {
+ case PHASE1:
+ if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) <
+ 0) {
+ wpa_printf(MSG_INFO, "EAP-FAST: TLS processing "
+ "failed");
+ eap_fast_state(data, FAILURE);
+ }
+
+ if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+ data->ssl.tls_out_len > 0)
+ break;
+
+ /*
+ * Phase 1 was completed with the received message (e.g., when
+ * using abbreviated handshake), so Phase 2 can be started
+ * immediately without having to send through an empty message
+ * to the peer.
+ */
+
+ if (eap_fast_phase1_done(sm, data) < 0)
+ break;
+
+ /* fall through to PHASE2_START */
+ case PHASE2_START:
+ eap_fast_state(data, PHASE2_ID);
+ eap_fast_phase2_init(sm, data, EAP_TYPE_IDENTITY);
+ break;
+ case PHASE2_ID:
+ case PHASE2_METHOD:
+ case CRYPTO_BINDING:
+ case REQUEST_PAC:
+ eap_fast_process_phase2(sm, data, resp, pos, left);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected state %d in %s",
+ data->state, __func__);
+ break;
+ }
+
+ if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Locally detected fatal error "
+ "in TLS processing");
+ eap_fast_state(data, FAILURE);
+ }
+}
+
+
+static Boolean eap_fast_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_fast_data *data = priv;
+ return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_fast_data *data = priv;
+ u8 *eapKeyData;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ /*
+ * RFC 4851, Section 5.4: EAP Master Session Key Genreration
+ * MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64)
+ */
+
+ eapKeyData = os_malloc(EAP_FAST_KEY_LEN);
+ if (eapKeyData == NULL)
+ return NULL;
+
+ sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+ "Session Key Generating Function", (u8 *) "", 0,
+ eapKeyData, EAP_FAST_KEY_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
+ eapKeyData, EAP_FAST_KEY_LEN);
+ *len = EAP_FAST_KEY_LEN;
+
+ return eapKeyData;
+}
+
+
+static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_fast_data *data = priv;
+ u8 *eapKeyData;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ /*
+ * RFC 4851, Section 5.4: EAP Master Session Key Genreration
+ * EMSK = T-PRF(S-IMCK[j],
+ * "Extended Session Key Generating Function", 64)
+ */
+
+ eapKeyData = os_malloc(EAP_EMSK_LEN);
+ if (eapKeyData == NULL)
+ return NULL;
+
+ sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+ "Extended Session Key Generating Function",
+ (u8 *) "", 0, eapKeyData, EAP_EMSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
+ eapKeyData, EAP_EMSK_LEN);
+
+ *len = EAP_EMSK_LEN;
+
+ return eapKeyData;
+}
+
+
+static Boolean eap_fast_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_fast_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+int eap_server_fast_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_fast_init;
+ eap->reset = eap_fast_reset;
+ eap->buildReq = eap_fast_buildReq;
+ eap->check = eap_fast_check;
+ eap->process = eap_fast_process;
+ eap->isDone = eap_fast_isDone;
+ eap->getKey = eap_fast_getKey;
+ eap->get_emsk = eap_fast_get_emsk;
+ eap->isSuccess = eap_fast_isSuccess;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_gpsk.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_gpsk.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_gpsk.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_gpsk.c Sat Nov 3 08:40:37 2007
@@ -1,5 +1,5 @@
/*
- * hostapd / EAP-GPSK (draft-ietf-emu-eap-gpsk-04.txt) server
+ * hostapd / EAP-GPSK (draft-ietf-emu-eap-gpsk-06.txt) server
* Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -84,17 +84,17 @@
data->csuite_count = 0;
if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
EAP_GPSK_CIPHER_AES)) {
- WPA_PUT_BE24(data->csuite_list[data->csuite_count].vendor,
+ WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor,
EAP_GPSK_VENDOR_IETF);
- WPA_PUT_BE24(data->csuite_list[data->csuite_count].specifier,
+ WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier,
EAP_GPSK_CIPHER_AES);
data->csuite_count++;
}
if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
EAP_GPSK_CIPHER_SHA256)) {
- WPA_PUT_BE24(data->csuite_list[data->csuite_count].vendor,
+ WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor,
EAP_GPSK_VENDOR_IETF);
- WPA_PUT_BE24(data->csuite_list[data->csuite_count].specifier,
+ WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier,
EAP_GPSK_CIPHER_SHA256);
data->csuite_count++;
}
@@ -192,8 +192,8 @@
memcpy(pos, data->rand_server, EAP_GPSK_RAND_LEN);
pos += EAP_GPSK_RAND_LEN;
csuite = (struct eap_gpsk_csuite *) pos;
- WPA_PUT_BE24(csuite->vendor, data->vendor);
- WPA_PUT_BE24(csuite->specifier, data->specifier);
+ WPA_PUT_BE32(csuite->vendor, data->vendor);
+ WPA_PUT_BE16(csuite->specifier, data->specifier);
pos += sizeof(*csuite);
/* no PD_Payload_2 */
@@ -396,13 +396,13 @@
if (i == data->csuite_count) {
wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported "
"ciphersuite %d:%d",
- WPA_GET_BE24(csuite->vendor),
- WPA_GET_BE24(csuite->specifier));
- eap_gpsk_state(data, FAILURE);
- return;
- }
- data->vendor = WPA_GET_BE24(csuite->vendor);
- data->specifier = WPA_GET_BE24(csuite->specifier);
+ WPA_GET_BE32(csuite->vendor),
+ WPA_GET_BE16(csuite->specifier));
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ data->vendor = WPA_GET_BE32(csuite->vendor);
+ data->specifier = WPA_GET_BE16(csuite->specifier);
wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d",
data->vendor, data->specifier);
pos += sizeof(*csuite);
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c Sat Nov 3 08:40:37 2007
@@ -20,6 +20,7 @@
struct eap_gtc_data {
enum { CONTINUE, SUCCESS, FAILURE } state;
+ int prefix;
};
@@ -32,6 +33,15 @@
return NULL;
data->state = CONTINUE;
+#ifdef EAP_FAST
+ if (sm->m && sm->m->vendor == EAP_VENDOR_IETF &&
+ sm->m->method == EAP_TYPE_FAST) {
+ wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
+ "with challenge/response");
+ data->prefix = 1;
+ }
+#endif /* EAP_FAST */
+
return data;
}
@@ -49,8 +59,10 @@
struct eap_gtc_data *data = priv;
struct eap_hdr *req;
u8 *pos;
- char *msg = "Password";
+ char *msg;
size_t msg_len;
+
+ msg = data->prefix ? "CHALLENGE=Password" : "Password";
msg_len = strlen(msg);
req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqDataLen,
@@ -94,6 +106,64 @@
const u8 *pos;
size_t rlen;
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC,
+ respData, respDataLen, &rlen);
+ if (pos == NULL || rlen < 1)
+ return; /* Should not happen - frame already validated */
+
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen);
+
+#ifdef EAP_FAST
+ if (data->prefix) {
+ const u8 *pos2, *end;
+ /* "RESPONSE=<user>\0<password>" */
+ if (rlen < 10) {
+ wpa_printf(MSG_DEBUG, "EAP-GTC: Too short response "
+ "for EAP-FAST prefix");
+ data->state = FAILURE;
+ return;
+ }
+
+ end = pos + rlen;
+ pos += 9;
+ pos2 = pos;
+ while (pos2 < end && *pos2)
+ pos2++;
+ if (pos2 == end) {
+ wpa_printf(MSG_DEBUG, "EAP-GTC: No password in "
+ "response to EAP-FAST prefix");
+ data->state = FAILURE;
+ return;
+ }
+
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Response user",
+ pos, pos2 - pos);
+ os_free(sm->identity);
+ sm->identity_len = pos2 - pos;
+ sm->identity = os_malloc(sm->identity_len);
+ if (sm->identity == NULL) {
+ data->state = FAILURE;
+ return;
+ }
+ os_memcpy(sm->identity, pos, sm->identity_len);
+
+ if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 "
+ "Identity not found in the user "
+ "database",
+ sm->identity, sm->identity_len);
+ data->state = FAILURE;
+ return;
+ }
+
+ pos = pos2 + 1;
+ rlen = end - pos;
+ wpa_hexdump_ascii_key(MSG_MSGDUMP,
+ "EAP-GTC: Response password",
+ pos, rlen);
+ }
+#endif /* EAP_FAST */
+
if (sm->user == NULL || sm->user->password == NULL ||
sm->user->password_hash) {
wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not "
@@ -101,13 +171,6 @@
data->state = FAILURE;
return;
}
-
- pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC,
- respData, respDataLen, &rlen);
- if (pos == NULL || rlen < 1)
- return; /* Should not happen - frame already validated */
-
- wpa_hexdump_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen);
if (rlen != sm->user->password_len ||
memcmp(pos, sm->user->password, rlen) != 0) {
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h Sat Nov 3 08:40:37 2007
@@ -179,6 +179,12 @@
enum {
METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT
} method_pending;
+
+ u8 *auth_challenge;
+ u8 *peer_challenge;
+
+ u8 *pac_opaque_encr_key;
+ char *eap_fast_a_id;
};
int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c Sat Nov 3 08:40:37 2007
@@ -247,6 +247,13 @@
}
#endif /* EAP_VENDOR_TEST */
+#ifdef EAP_FAST
+ if (ret == 0) {
+ int eap_server_fast_register(void);
+ ret = eap_server_fast_register();
+ }
+#endif /* EAP_FAST */
+
return ret;
}
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c Sat Nov 3 08:40:37 2007
@@ -50,6 +50,8 @@
struct eap_mschapv2_data {
u8 auth_challenge[CHALLENGE_LEN];
+ int auth_challenge_from_tls;
+ u8 *peer_challenge;
u8 auth_response[20];
enum { CHALLENGE, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE } state;
u8 resp_mschapv2_id;
@@ -67,6 +69,22 @@
return NULL;
data->state = CHALLENGE;
+ if (sm->auth_challenge) {
+ os_memcpy(data->auth_challenge, sm->auth_challenge,
+ CHALLENGE_LEN);
+ data->auth_challenge_from_tls = 1;
+ }
+
+ if (sm->peer_challenge) {
+ data->peer_challenge = os_malloc(CHALLENGE_LEN);
+ if (data->peer_challenge == NULL) {
+ os_free(data);
+ return NULL;
+ }
+ os_memcpy(data->peer_challenge, sm->peer_challenge,
+ CHALLENGE_LEN);
+ }
+
return data;
}
@@ -74,6 +92,10 @@
static void eap_mschapv2_reset(struct eap_sm *sm, void *priv)
{
struct eap_mschapv2_data *data = priv;
+ if (data == NULL)
+ return;
+
+ free(data->peer_challenge);
free(data);
}
@@ -88,7 +110,8 @@
char *name = "hostapd"; /* TODO: make this configurable */
size_t ms_len;
- if (hostapd_get_rand(data->auth_challenge, CHALLENGE_LEN)) {
+ if (!data->auth_challenge_from_tls &&
+ hostapd_get_rand(data->auth_challenge, CHALLENGE_LEN)) {
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random "
"data");
data->state = FAILURE;
@@ -112,7 +135,8 @@
pos = (u8 *) (ms + 1);
*pos++ = CHALLENGE_LEN;
- memcpy(pos, data->auth_challenge, CHALLENGE_LEN);
+ if (!data->auth_challenge_from_tls)
+ memcpy(pos, data->auth_challenge, CHALLENGE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge", pos,
CHALLENGE_LEN);
pos += CHALLENGE_LEN;
@@ -306,6 +330,11 @@
name = pos;
name_len = end - name;
+ if (data->peer_challenge) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using pre-configured "
+ "Peer-Challenge");
+ peer_challenge = data->peer_challenge;
+ }
wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge",
peer_challenge, 16);
wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: NT-Response", nt_response, 24);
Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_tlv.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_tlv.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_tlv.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_tlv.c Sat Nov 3 08:40:37 2007
@@ -16,20 +16,7 @@
#include "common.h"
#include "eap_i.h"
-
-
-/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-07.txt) */
-#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
-#define EAP_TLV_NAK_TLV 4
-#define EAP_TLV_CRYPTO_BINDING_TLV 5
-#define EAP_TLV_CONNECTION_BINDING_TLV 6
-#define EAP_TLV_VENDOR_SPECIFIC_TLV 7
-#define EAP_TLV_URI_TLV 8
-#define EAP_TLV_EAP_PAYLOAD_TLV 9
-#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
-
-#define EAP_TLV_RESULT_SUCCESS 1
-#define EAP_TLV_RESULT_FAILURE 2
+#include "eap_common/eap_tlv_common.h"
struct eap_tlv_data {
Modified: wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_freebsd.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_freebsd.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_freebsd.c (original)
+++ wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_freebsd.c Sat Nov 3 08:40:37 2007
@@ -14,6 +14,9 @@
*/
#include "includes.h"
+#ifdef __APPLE__
+#include <net/bpf.h>
+#endif /* __APPLE__ */
#include <pcap.h>
#include <sys/ioctl.h>
@@ -231,8 +234,11 @@
void l2_packet_deinit(struct l2_packet_data *l2)
{
if (l2 != NULL) {
- if (l2->pcap)
+ if (l2->pcap) {
+ eloop_unregister_read_sock(
+ pcap_get_selectable_fd(l2->pcap));
pcap_close(l2->pcap);
+ }
os_free(l2);
}
}
Modified: wpasupplicant/branches/upstream/current/src/radius/radius_client.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius_client.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_client.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_client.c Sat Nov 3 08:40:37 2007
@@ -142,7 +142,8 @@
#ifndef CONFIG_NATIVE_WINDOWS
int _errno = errno;
perror("send[RADIUS]");
- if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL) {
+ if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
+ _errno == EBADF) {
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Send failed - maybe interface status changed -"
Modified: wpasupplicant/branches/upstream/current/src/radius/radius_server.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius_server.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_server.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_server.c Sat Nov 3 08:40:37 2007
@@ -87,6 +87,8 @@
int num_sess;
void *eap_sim_db_priv;
void *ssl_ctx;
+ u8 *pac_opaque_encr_key;
+ char *eap_fast_a_id;
int ipv6;
struct os_time start_time;
struct radius_server_counters counters;
@@ -309,6 +311,8 @@
eap_conf.ssl_ctx = data->ssl_ctx;
eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
eap_conf.backend_auth = TRUE;
+ eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
+ eap_conf.eap_fast_a_id = data->eap_fast_a_id;
sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
&eap_conf);
if (sess->eap == NULL) {
@@ -999,6 +1003,13 @@
data->eap_sim_db_priv = conf->eap_sim_db_priv;
data->ssl_ctx = conf->ssl_ctx;
data->ipv6 = conf->ipv6;
+ if (conf->pac_opaque_encr_key) {
+ data->pac_opaque_encr_key = os_malloc(16);
+ os_memcpy(data->pac_opaque_encr_key, conf->pac_opaque_encr_key,
+ 16);
+ }
+ if (conf->eap_fast_a_id)
+ data->eap_fast_a_id = os_strdup(conf->eap_fast_a_id);
data->get_eap_user = conf->get_eap_user;
data->clients = radius_server_read_clients(conf->client_file,
Modified: wpasupplicant/branches/upstream/current/src/radius/radius_server.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius_server.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_server.h (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_server.h Sat Nov 3 08:40:37 2007
@@ -24,6 +24,8 @@
void *conf_ctx;
void *eap_sim_db_priv;
void *ssl_ctx;
+ u8 *pac_opaque_encr_key;
+ char *eap_fast_a_id;
int ipv6;
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
int phase2, struct eap_user *user);
Modified: wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c Sat Nov 3 08:40:37 2007
@@ -229,7 +229,7 @@
pos += sizeof(*mdie);
os_memcpy(mdie->mobility_domain, sm->mobility_domain,
MOBILITY_DOMAIN_ID_LEN);
- mdie->ft_capab = RSN_FT_CAPAB_FT_OVER_AIR;
+ mdie->ft_capab = 0; /* FIX: copy from the target AP's MDIE */
/* FTIE[SNonce, R0KH-ID] */
*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
@@ -747,7 +747,8 @@
if (parse.gtk[1] != keylen) {
wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d "
- "negotiated %d", parse.gtk[1], keylen);
+ "negotiated %lu",
+ parse.gtk[1], (unsigned long) keylen);
return -1;
}
Modified: wpasupplicant/branches/upstream/current/src/tls/asn1.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/asn1.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/asn1.c (original)
+++ wpasupplicant/branches/upstream/current/src/tls/asn1.c Sat Nov 3 08:40:37 2007
@@ -58,6 +58,10 @@
}
tmp &= 0x7f; /* number of subsequent octets */
hdr->length = 0;
+ if (tmp > 4) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
+ return -1;
+ }
while (tmp--) {
if (pos >= end) {
wpa_printf(MSG_DEBUG, "ASN.1: Length "
@@ -71,7 +75,7 @@
hdr->length = tmp;
}
- if (pos + hdr->length > end) {
+ if (end < pos || hdr->length > (unsigned int) (end - pos)) {
wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
return -1;
}
Modified: wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c (original)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c Sat Nov 3 08:40:37 2007
@@ -1,6 +1,6 @@
/*
- * wpa_supplicant: TLSv1 client (RFC 2246)
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ * TLSv1 client (RFC 2246)
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,614 +15,26 @@
#include "includes.h"
#include "common.h"
-#include "base64.h"
-#include "md5.h"
#include "sha1.h"
-#include "crypto.h"
#include "tls.h"
#include "tlsv1_common.h"
+#include "tlsv1_record.h"
#include "tlsv1_client.h"
-#include "x509v3.h"
+#include "tlsv1_client_i.h"
/* TODO:
* Support for a message fragmented across several records (RFC 2246, 6.2.1)
*/
-struct tlsv1_client {
- enum {
- CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,
- SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,
- SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,
- SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,
- ESTABLISHED, FAILED
- } state;
-
- struct tlsv1_record_layer rl;
-
- u8 session_id[TLS_SESSION_ID_MAX_LEN];
- size_t session_id_len;
- u8 client_random[TLS_RANDOM_LEN];
- u8 server_random[TLS_RANDOM_LEN];
- u8 master_secret[TLS_MASTER_SECRET_LEN];
-
- u8 alert_level;
- u8 alert_description;
-
- unsigned int certificate_requested:1;
- unsigned int session_resumed:1;
- unsigned int ticket:1;
- unsigned int ticket_key:1;
-
- struct crypto_public_key *server_rsa_key;
-
- struct crypto_hash *verify_md5_client;
- struct crypto_hash *verify_sha1_client;
- struct crypto_hash *verify_md5_server;
- struct crypto_hash *verify_sha1_server;
- struct crypto_hash *verify_md5_cert;
- struct crypto_hash *verify_sha1_cert;
-
-#define MAX_CIPHER_COUNT 30
- u16 cipher_suites[MAX_CIPHER_COUNT];
- size_t num_cipher_suites;
-
- u16 prev_cipher_suite;
-
- u8 *client_hello_ext;
- size_t client_hello_ext_len;
-
- /* The prime modulus used for Diffie-Hellman */
- u8 *dh_p;
- size_t dh_p_len;
- /* The generator used for Diffie-Hellman */
- u8 *dh_g;
- size_t dh_g_len;
- /* The server's Diffie-Hellman public value */
- u8 *dh_ys;
- size_t dh_ys_len;
-
- struct x509_certificate *trusted_certs;
- struct x509_certificate *client_cert;
- struct crypto_private_key *client_key;
-};
-
-
-static int tls_derive_keys(struct tlsv1_client *conn,
- const u8 *pre_master_secret,
- size_t pre_master_secret_len);
-static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len);
-static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len);
-static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len);
-
-
-static void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)
+
+void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)
{
conn->alert_level = level;
conn->alert_description = description;
}
-static void tls_verify_hash_add(struct tlsv1_client *conn, const u8 *buf,
- size_t len)
-{
- if (conn->verify_md5_client && conn->verify_sha1_client) {
- crypto_hash_update(conn->verify_md5_client, buf, len);
- crypto_hash_update(conn->verify_sha1_client, buf, len);
- }
- if (conn->verify_md5_server && conn->verify_sha1_server) {
- crypto_hash_update(conn->verify_md5_server, buf, len);
- crypto_hash_update(conn->verify_sha1_server, buf, len);
- }
- if (conn->verify_md5_cert && conn->verify_sha1_cert) {
- crypto_hash_update(conn->verify_md5_cert, buf, len);
- crypto_hash_update(conn->verify_sha1_cert, buf, len);
- }
-}
-
-
-static u8 * tls_send_alert(struct tlsv1_client *conn,
- u8 level, u8 description,
- size_t *out_len)
-{
- u8 *alert, *pos, *length;
-
- wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
- *out_len = 0;
-
- alert = os_malloc(10);
- if (alert == NULL)
- return NULL;
-
- pos = alert;
-
- /* TLSPlaintext */
- /* ContentType type */
- *pos++ = TLS_CONTENT_TYPE_ALERT;
- /* ProtocolVersion version */
- WPA_PUT_BE16(pos, TLS_VERSION);
- pos += 2;
- /* uint16 length (to be filled) */
- length = pos;
- pos += 2;
- /* opaque fragment[TLSPlaintext.length] */
-
- /* Alert */
- /* AlertLevel level */
- *pos++ = level;
- /* AlertDescription description */
- *pos++ = description;
-
- WPA_PUT_BE16(length, pos - length - 2);
- *out_len = pos - alert;
-
- return alert;
-}
-
-
-static u8 * tls_send_client_hello(struct tlsv1_client *conn,
- size_t *out_len)
-{
- u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
- struct os_time now;
- size_t len, i;
-
- wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
- *out_len = 0;
-
- os_get_time(&now);
- WPA_PUT_BE32(conn->client_random, now.sec);
- if (os_get_random(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
- wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
- "client_random");
- return NULL;
- }
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
- conn->client_random, TLS_RANDOM_LEN);
-
- len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
- hello = os_malloc(len);
- if (hello == NULL)
- return NULL;
- end = hello + len;
-
- rhdr = hello;
- pos = rhdr + TLS_RECORD_HEADER_LEN;
-
- /* opaque fragment[TLSPlaintext.length] */
-
- /* Handshake */
- hs_start = pos;
- /* HandshakeType msg_type */
- *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO;
- /* uint24 length (to be filled) */
- hs_length = pos;
- pos += 3;
- /* body - ClientHello */
- /* ProtocolVersion client_version */
- WPA_PUT_BE16(pos, TLS_VERSION);
- pos += 2;
- /* Random random: uint32 gmt_unix_time, opaque random_bytes */
- os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN);
- pos += TLS_RANDOM_LEN;
- /* SessionID session_id */
- *pos++ = conn->session_id_len;
- os_memcpy(pos, conn->session_id, conn->session_id_len);
- pos += conn->session_id_len;
- /* CipherSuite cipher_suites<2..2^16-1> */
- WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites);
- pos += 2;
- for (i = 0; i < conn->num_cipher_suites; i++) {
- WPA_PUT_BE16(pos, conn->cipher_suites[i]);
- pos += 2;
- }
- /* CompressionMethod compression_methods<1..2^8-1> */
- *pos++ = 1;
- *pos++ = TLS_COMPRESSION_NULL;
-
- if (conn->client_hello_ext) {
- os_memcpy(pos, conn->client_hello_ext,
- conn->client_hello_ext_len);
- pos += conn->client_hello_ext_len;
- }
-
- WPA_PUT_BE24(hs_length, pos - hs_length - 3);
- tls_verify_hash_add(conn, hs_start, pos - hs_start);
-
- if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, out_len) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- os_free(hello);
- return NULL;
- }
-
- conn->state = SERVER_HELLO;
-
- return hello;
-}
-
-
-static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len)
-{
- const u8 *pos, *end;
- size_t left, len, i;
- u16 cipher_suite;
-
- if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- pos = in_data;
- left = *in_len;
-
- if (left < 4)
- goto decode_error;
-
- /* HandshakeType msg_type */
- if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected ServerHello)", *pos);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello");
- pos++;
- /* uint24 length */
- len = WPA_GET_BE24(pos);
- pos += 3;
- left -= 4;
-
- if (len > left)
- goto decode_error;
-
- /* body - ServerHello */
-
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len);
- end = pos + len;
-
- /* ProtocolVersion server_version */
- if (end - pos < 2)
- goto decode_error;
- if (WPA_GET_BE16(pos) != TLS_VERSION) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
- "ServerHello");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_PROTOCOL_VERSION);
- return -1;
- }
- pos += 2;
-
- /* Random random */
- if (end - pos < TLS_RANDOM_LEN)
- goto decode_error;
-
- os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN);
- pos += TLS_RANDOM_LEN;
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
- conn->server_random, TLS_RANDOM_LEN);
-
- /* SessionID session_id */
- if (end - pos < 1)
- goto decode_error;
- if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
- goto decode_error;
- if (conn->session_id_len && conn->session_id_len == *pos &&
- os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) {
- pos += 1 + conn->session_id_len;
- wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session");
- conn->session_resumed = 1;
- } else {
- conn->session_id_len = *pos;
- pos++;
- os_memcpy(conn->session_id, pos, conn->session_id_len);
- pos += conn->session_id_len;
- }
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
- conn->session_id, conn->session_id_len);
-
- /* CipherSuite cipher_suite */
- if (end - pos < 2)
- goto decode_error;
- cipher_suite = WPA_GET_BE16(pos);
- pos += 2;
- for (i = 0; i < conn->num_cipher_suites; i++) {
- if (cipher_suite == conn->cipher_suites[i])
- break;
- }
- if (i == conn->num_cipher_suites) {
- wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
- "cipher suite 0x%04x", cipher_suite);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_ILLEGAL_PARAMETER);
- return -1;
- }
-
- if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) {
- wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different "
- "cipher suite for a resumed connection (0x%04x != "
- "0x%04x)", cipher_suite, conn->prev_cipher_suite);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_ILLEGAL_PARAMETER);
- return -1;
- }
-
- if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
- "record layer");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
-
- conn->prev_cipher_suite = cipher_suite;
-
- if (conn->session_resumed || conn->ticket_key)
- tls_derive_keys(conn, NULL, 0);
-
- /* CompressionMethod compression_method */
- if (end - pos < 1)
- goto decode_error;
- if (*pos != TLS_COMPRESSION_NULL) {
- wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
- "compression 0x%02x", *pos);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_ILLEGAL_PARAMETER);
- return -1;
- }
- pos++;
-
- if (end != pos) {
- wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
- "end of ServerHello", pos, end - pos);
- goto decode_error;
- }
-
- *in_len = end - in_data;
-
- conn->state = (conn->session_resumed || conn->ticket) ?
- SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE;
-
- return 0;
-
-decode_error:
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
-}
-
-
-static int tls_server_key_exchange_allowed(struct tlsv1_client *conn)
-{
- const struct tls_cipher_suite *suite;
-
- /* RFC 2246, Section 7.4.3 */
- suite = tls_get_cipher_suite(conn->rl.cipher_suite);
- if (suite == NULL)
- return 0;
-
- switch (suite->key_exchange) {
- case TLS_KEY_X_DHE_DSS:
- case TLS_KEY_X_DHE_DSS_EXPORT:
- case TLS_KEY_X_DHE_RSA:
- case TLS_KEY_X_DHE_RSA_EXPORT:
- case TLS_KEY_X_DH_anon_EXPORT:
- case TLS_KEY_X_DH_anon:
- return 1;
- case TLS_KEY_X_RSA_EXPORT:
- return 1 /* FIX: public key len > 512 bits */;
- default:
- return 0;
- }
-}
-
-
-static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len)
-{
- const u8 *pos, *end;
- size_t left, len, list_len, cert_len, idx;
- u8 type;
- struct x509_certificate *chain = NULL, *last = NULL, *cert;
- int reason;
-
- if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- pos = in_data;
- left = *in_len;
-
- if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
- "(len=%lu)", (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
-
- type = *pos++;
- len = WPA_GET_BE24(pos);
- pos += 3;
- left -= 4;
-
- if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
-
- if (type == TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE)
- return tls_process_server_key_exchange(conn, ct, in_data,
- in_len);
- if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
- return tls_process_certificate_request(conn, ct, in_data,
- in_len);
- if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
- return tls_process_server_hello_done(conn, ct, in_data,
- in_len);
- if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected Certificate/"
- "ServerKeyExchange/CertificateRequest/"
- "ServerHelloDone)", type);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG,
- "TLSv1: Received Certificate (certificate_list len %lu)",
- (unsigned long) len);
-
- /*
- * opaque ASN.1Cert<2^24-1>;
- *
- * struct {
- * ASN.1Cert certificate_list<1..2^24-1>;
- * } Certificate;
- */
-
- end = pos + len;
-
- if (end - pos < 3) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
- "(left=%lu)", (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
-
- list_len = WPA_GET_BE24(pos);
- pos += 3;
-
- if ((size_t) (end - pos) != list_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
- "length (len=%lu left=%lu)",
- (unsigned long) list_len,
- (unsigned long) (end - pos));
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
-
- idx = 0;
- while (pos < end) {
- if (end - pos < 3) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "certificate_list");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- x509_certificate_chain_free(chain);
- return -1;
- }
-
- cert_len = WPA_GET_BE24(pos);
- pos += 3;
-
- if ((size_t) (end - pos) < cert_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
- "length (len=%lu left=%lu)",
- (unsigned long) cert_len,
- (unsigned long) (end - pos));
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- x509_certificate_chain_free(chain);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
- (unsigned long) idx, (unsigned long) cert_len);
-
- if (idx == 0) {
- crypto_public_key_free(conn->server_rsa_key);
- if (tls_parse_cert(pos, cert_len,
- &conn->server_rsa_key)) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "the certificate");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_BAD_CERTIFICATE);
- x509_certificate_chain_free(chain);
- return -1;
- }
- }
-
- cert = x509_certificate_parse(pos, cert_len);
- if (cert == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
- "the certificate");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_BAD_CERTIFICATE);
- x509_certificate_chain_free(chain);
- return -1;
- }
-
- if (last == NULL)
- chain = cert;
- else
- last->next = cert;
- last = cert;
-
- idx++;
- pos += cert_len;
- }
-
- if (x509_certificate_chain_validate(conn->trusted_certs, chain,
- &reason) < 0) {
- int tls_reason;
- wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
- "validation failed (reason=%d)", reason);
- switch (reason) {
- case X509_VALIDATE_BAD_CERTIFICATE:
- tls_reason = TLS_ALERT_BAD_CERTIFICATE;
- break;
- case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
- tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
- break;
- case X509_VALIDATE_CERTIFICATE_REVOKED:
- tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
- break;
- case X509_VALIDATE_CERTIFICATE_EXPIRED:
- tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
- break;
- case X509_VALIDATE_CERTIFICATE_UNKNOWN:
- tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
- break;
- case X509_VALIDATE_UNKNOWN_CA:
- tls_reason = TLS_ALERT_UNKNOWN_CA;
- break;
- default:
- tls_reason = TLS_ALERT_BAD_CERTIFICATE;
- break;
- }
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
- x509_certificate_chain_free(chain);
- return -1;
- }
-
- x509_certificate_chain_free(chain);
-
- *in_len = end - in_data;
-
- conn->state = SERVER_KEY_EXCHANGE;
-
- return 0;
-}
-
-
-static void tlsv1_client_free_dh(struct tlsv1_client *conn)
+void tlsv1_client_free_dh(struct tlsv1_client *conn)
{
os_free(conn->dh_p);
os_free(conn->dh_g);
@@ -631,438 +43,7 @@
}
-static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
- const u8 *buf, size_t len)
-{
- const u8 *pos, *end;
-
- tlsv1_client_free_dh(conn);
-
- pos = buf;
- end = buf + len;
-
- if (end - pos < 3)
- goto fail;
- conn->dh_p_len = WPA_GET_BE16(pos);
- pos += 2;
- if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len)
- goto fail;
- conn->dh_p = os_malloc(conn->dh_p_len);
- if (conn->dh_p == NULL)
- goto fail;
- os_memcpy(conn->dh_p, pos, conn->dh_p_len);
- pos += conn->dh_p_len;
- wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
- conn->dh_p, conn->dh_p_len);
-
- if (end - pos < 3)
- goto fail;
- conn->dh_g_len = WPA_GET_BE16(pos);
- pos += 2;
- if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
- goto fail;
- conn->dh_g = os_malloc(conn->dh_g_len);
- if (conn->dh_g == NULL)
- goto fail;
- os_memcpy(conn->dh_g, pos, conn->dh_g_len);
- pos += conn->dh_g_len;
- wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
- conn->dh_g, conn->dh_g_len);
- if (conn->dh_g_len == 1 && conn->dh_g[0] < 2)
- goto fail;
-
- if (end - pos < 3)
- goto fail;
- conn->dh_ys_len = WPA_GET_BE16(pos);
- pos += 2;
- if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
- goto fail;
- conn->dh_ys = os_malloc(conn->dh_ys_len);
- if (conn->dh_ys == NULL)
- goto fail;
- os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
- pos += conn->dh_ys_len;
- wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
- conn->dh_ys, conn->dh_ys_len);
-
- return 0;
-
-fail:
- tlsv1_client_free_dh(conn);
- return -1;
-}
-
-
-static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len)
-{
- const u8 *pos, *end;
- size_t left, len;
- u8 type;
- const struct tls_cipher_suite *suite;
-
- if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- pos = in_data;
- left = *in_len;
-
- if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerKeyExchange "
- "(Left=%lu)", (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
-
- type = *pos++;
- len = WPA_GET_BE24(pos);
- pos += 3;
- left -= 4;
-
- if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerKeyExchange "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
-
- end = pos + len;
-
- if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
- return tls_process_certificate_request(conn, ct, in_data,
- in_len);
- if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
- return tls_process_server_hello_done(conn, ct, in_data,
- in_len);
- if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected ServerKeyExchange/"
- "CertificateRequest/ServerHelloDone)", type);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange");
-
- if (!tls_server_key_exchange_allowed(conn)) {
- wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed "
- "with the selected cipher suite");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
- suite = tls_get_cipher_suite(conn->rl.cipher_suite);
- if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
- if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- } else {
- wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- *in_len = end - in_data;
-
- conn->state = SERVER_CERTIFICATE_REQUEST;
-
- return 0;
-}
-
-
-static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len)
-{
- const u8 *pos, *end;
- size_t left, len;
- u8 type;
-
- if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- pos = in_data;
- left = *in_len;
-
- if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateRequest "
- "(left=%lu)", (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
-
- type = *pos++;
- len = WPA_GET_BE24(pos);
- pos += 3;
- left -= 4;
-
- if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in CertificateRequest "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
-
- end = pos + len;
-
- if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
- return tls_process_server_hello_done(conn, ct, in_data,
- in_len);
- if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected CertificateRequest/"
- "ServerHelloDone)", type);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateRequest");
-
- conn->certificate_requested = 1;
-
- *in_len = end - in_data;
-
- conn->state = SERVER_HELLO_DONE;
-
- return 0;
-}
-
-
-static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len)
-{
- const u8 *pos, *end;
- size_t left, len;
- u8 type;
-
- if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- pos = in_data;
- left = *in_len;
-
- if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerHelloDone "
- "(left=%lu)", (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
-
- type = *pos++;
- len = WPA_GET_BE24(pos);
- pos += 3;
- left -= 4;
-
- if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerHelloDone "
- "length (len=%lu != left=%lu)",
- (unsigned long) len, (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- end = pos + len;
-
- if (type != TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
- "message %d (expected ServerHelloDone)", type);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
-
- *in_len = end - in_data;
-
- conn->state = CLIENT_KEY_EXCHANGE;
-
- return 0;
-}
-
-
-static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,
- u8 ct, const u8 *in_data,
- size_t *in_len)
-{
- const u8 *pos;
- size_t left;
-
- if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- pos = in_data;
- left = *in_len;
-
- if (left < 1) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- return -1;
- }
-
- if (*pos != TLS_CHANGE_CIPHER_SPEC) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
- "received data 0x%x", *pos);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
- if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
- "for record layer");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
-
- *in_len = pos + 1 - in_data;
-
- conn->state = SERVER_FINISHED;
-
- return 0;
-}
-
-
-static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len)
-{
- const u8 *pos, *end;
- size_t left, len, hlen;
- u8 verify_data[TLS_VERIFY_DATA_LEN];
- u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
-
- if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- pos = in_data;
- left = *in_len;
-
- if (left < 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
- "Finished",
- (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- return -1;
- }
-
- if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
- "type 0x%x", pos[0]);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- len = WPA_GET_BE24(pos + 1);
-
- pos += 4;
- left -= 4;
-
- if (len > left) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
- "(len=%lu > left=%lu)",
- (unsigned long) len, (unsigned long) left);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- end = pos + len;
- if (len != TLS_VERIFY_DATA_LEN) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
- "in Finished: %lu (expected %d)",
- (unsigned long) len, TLS_VERIFY_DATA_LEN);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
- pos, TLS_VERIFY_DATA_LEN);
-
- hlen = MD5_MAC_LEN;
- if (conn->verify_md5_server == NULL ||
- crypto_hash_finish(conn->verify_md5_server, hash, &hlen) < 0) {
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- conn->verify_md5_server = NULL;
- crypto_hash_finish(conn->verify_sha1_server, NULL, NULL);
- conn->verify_sha1_server = NULL;
- return -1;
- }
- conn->verify_md5_server = NULL;
- hlen = SHA1_MAC_LEN;
- if (conn->verify_sha1_server == NULL ||
- crypto_hash_finish(conn->verify_sha1_server, hash + MD5_MAC_LEN,
- &hlen) < 0) {
- conn->verify_sha1_server = NULL;
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- conn->verify_sha1_server = NULL;
-
- if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
- "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
- verify_data, TLS_VERIFY_DATA_LEN)) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECRYPT_ERROR);
- return -1;
- }
- wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
- verify_data, TLS_VERIFY_DATA_LEN);
-
- if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
- wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
-
- *in_len = end - in_data;
-
- conn->state = (conn->session_resumed || conn->ticket) ?
- CHANGE_CIPHER_SPEC : ACK_FINISHED;
-
- return 0;
-}
-
-
-static int tls_derive_pre_master_secret(u8 *pre_master_secret)
+int tls_derive_pre_master_secret(u8 *pre_master_secret)
{
WPA_PUT_BE16(pre_master_secret, TLS_VERSION);
if (os_get_random(pre_master_secret + 2,
@@ -1072,9 +53,8 @@
}
-static int tls_derive_keys(struct tlsv1_client *conn,
- const u8 *pre_master_secret,
- size_t pre_master_secret_len)
+int tls_derive_keys(struct tlsv1_client *conn,
+ const u8 *pre_master_secret, size_t pre_master_secret_len)
{
u8 seed[2 * TLS_RANDOM_LEN];
u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
@@ -1138,718 +118,6 @@
}
-static int tls_write_client_certificate(struct tlsv1_client *conn,
- u8 **msgpos, u8 *end)
-{
- u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
- size_t rlen;
- struct x509_certificate *cert;
-
- pos = *msgpos;
-
- wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
- rhdr = pos;
- pos += TLS_RECORD_HEADER_LEN;
-
- /* opaque fragment[TLSPlaintext.length] */
-
- /* Handshake */
- hs_start = pos;
- /* HandshakeType msg_type */
- *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
- /* uint24 length (to be filled) */
- hs_length = pos;
- pos += 3;
- /* body - Certificate */
- /* uint24 length (to be filled) */
- cert_start = pos;
- pos += 3;
- cert = conn->client_cert;
- while (cert) {
- if (pos + 3 + cert->cert_len > end) {
- wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
- "for Certificate (cert_len=%lu left=%lu)",
- (unsigned long) cert->cert_len,
- (unsigned long) (end - pos));
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- WPA_PUT_BE24(pos, cert->cert_len);
- pos += 3;
- os_memcpy(pos, cert->cert_start, cert->cert_len);
- pos += cert->cert_len;
-
- if (x509_certificate_self_signed(cert))
- break;
- cert = x509_certificate_get_subject(conn->trusted_certs,
- &cert->issuer);
- }
- if (cert == conn->client_cert || cert == NULL) {
- /*
- * Client was not configured with all the needed certificates
- * to form a full certificate chain. The server may fail to
- * validate the chain unless it is configured with all the
- * missing CA certificates.
- */
- wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain "
- "not configured - validation may fail");
- }
- WPA_PUT_BE24(cert_start, pos - cert_start - 3);
-
- WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
- if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- pos = rhdr + rlen;
-
- tls_verify_hash_add(conn, hs_start, pos - hs_start);
-
- *msgpos = pos;
-
- return 0;
-}
-
-
-static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
-{
-#ifdef EAP_FAST
- /* ClientDiffieHellmanPublic */
- u8 *csecret, *csecret_start, *dh_yc, *shared;
- size_t csecret_len, dh_yc_len, shared_len;
-
- csecret_len = conn->dh_p_len;
- csecret = os_malloc(csecret_len);
- if (csecret == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
- "memory for Yc (Diffie-Hellman)");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- if (os_get_random(csecret, csecret_len)) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
- "data for Diffie-Hellman");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- os_free(csecret);
- return -1;
- }
-
- if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0)
- csecret[0] = 0; /* make sure Yc < p */
-
- csecret_start = csecret;
- while (csecret_len > 1 && *csecret_start == 0) {
- csecret_start++;
- csecret_len--;
- }
- wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value",
- csecret_start, csecret_len);
-
- /* Yc = g^csecret mod p */
- dh_yc_len = conn->dh_p_len;
- dh_yc = os_malloc(dh_yc_len);
- if (dh_yc == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
- "memory for Diffie-Hellman");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- os_free(csecret);
- return -1;
- }
- crypto_mod_exp(conn->dh_g, conn->dh_g_len,
- csecret_start, csecret_len,
- conn->dh_p, conn->dh_p_len,
- dh_yc, &dh_yc_len);
-
- wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
- dh_yc, dh_yc_len);
-
- WPA_PUT_BE16(*pos, dh_yc_len);
- *pos += 2;
- if (*pos + dh_yc_len > end) {
- wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
- "message buffer for Yc");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- os_free(csecret);
- os_free(dh_yc);
- return -1;
- }
- os_memcpy(*pos, dh_yc, dh_yc_len);
- *pos += dh_yc_len;
- os_free(dh_yc);
-
- shared_len = conn->dh_p_len;
- shared = os_malloc(shared_len);
- if (shared == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
- "DH");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- os_free(csecret);
- return -1;
- }
-
- /* shared = Ys^csecret mod p */
- crypto_mod_exp(conn->dh_ys, conn->dh_ys_len,
- csecret_start, csecret_len,
- conn->dh_p, conn->dh_p_len,
- shared, &shared_len);
- wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
- shared, shared_len);
-
- os_memset(csecret_start, 0, csecret_len);
- os_free(csecret);
- if (tls_derive_keys(conn, shared, shared_len)) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- os_free(shared);
- return -1;
- }
- os_memset(shared, 0, shared_len);
- os_free(shared);
- tlsv1_client_free_dh(conn);
- return 0;
-#else /* EAP_FAST */
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR);
- return -1;
-#endif /* EAP_FAST */
-}
-
-
-static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)
-{
- u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN];
- size_t clen;
- int res;
-
- if (tls_derive_pre_master_secret(pre_master_secret) < 0 ||
- tls_derive_keys(conn, pre_master_secret,
- TLS_PRE_MASTER_SECRET_LEN)) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
-
- /* EncryptedPreMasterSecret */
- if (conn->server_rsa_key == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to "
- "use for encrypting pre-master secret");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
-
- /* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */
- *pos += 2;
- clen = end - *pos;
- res = crypto_public_key_encrypt_pkcs1_v15(
- conn->server_rsa_key,
- pre_master_secret, TLS_PRE_MASTER_SECRET_LEN,
- *pos, &clen);
- os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN);
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- WPA_PUT_BE16(*pos - 2, clen);
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret",
- *pos, clen);
- *pos += clen;
-
- return 0;
-}
-
-
-static int tls_write_client_key_exchange(struct tlsv1_client *conn,
- u8 **msgpos, u8 *end)
-{
- u8 *pos, *rhdr, *hs_start, *hs_length;
- size_t rlen;
- tls_key_exchange keyx;
- const struct tls_cipher_suite *suite;
-
- suite = tls_get_cipher_suite(conn->rl.cipher_suite);
- if (suite == NULL)
- keyx = TLS_KEY_X_NULL;
- else
- keyx = suite->key_exchange;
-
- pos = *msgpos;
-
- wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange");
-
- rhdr = pos;
- pos += TLS_RECORD_HEADER_LEN;
-
- /* opaque fragment[TLSPlaintext.length] */
-
- /* Handshake */
- hs_start = pos;
- /* HandshakeType msg_type */
- *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE;
- /* uint24 length (to be filled) */
- hs_length = pos;
- pos += 3;
- /* body - ClientKeyExchange */
- if (keyx == TLS_KEY_X_DH_anon) {
- if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
- return -1;
- } else {
- if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
- return -1;
- }
-
- WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
- if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- pos = rhdr + rlen;
- tls_verify_hash_add(conn, hs_start, pos - hs_start);
-
- *msgpos = pos;
-
- return 0;
-}
-
-
-static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
- u8 **msgpos, u8 *end)
-{
- u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
- size_t rlen, hlen, clen;
- u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
- enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
-
- pos = *msgpos;
-
- wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify");
- rhdr = pos;
- pos += TLS_RECORD_HEADER_LEN;
-
- /* Handshake */
- hs_start = pos;
- /* HandshakeType msg_type */
- *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY;
- /* uint24 length (to be filled) */
- hs_length = pos;
- pos += 3;
-
- /*
- * RFC 2246: 7.4.3 and 7.4.8:
- * Signature signature
- *
- * RSA:
- * digitally-signed struct {
- * opaque md5_hash[16];
- * opaque sha_hash[20];
- * };
- *
- * DSA:
- * digitally-signed struct {
- * opaque sha_hash[20];
- * };
- *
- * The hash values are calculated over all handshake messages sent or
- * received starting at ClientHello up to, but not including, this
- * CertificateVerify message, including the type and length fields of
- * the handshake messages.
- */
-
- hpos = hash;
-
- if (alg == SIGN_ALG_RSA) {
- hlen = MD5_MAC_LEN;
- if (conn->verify_md5_cert == NULL ||
- crypto_hash_finish(conn->verify_md5_cert, hpos, &hlen) < 0)
- {
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- conn->verify_md5_cert = NULL;
- crypto_hash_finish(conn->verify_sha1_cert, NULL, NULL);
- conn->verify_sha1_cert = NULL;
- return -1;
- }
- hpos += MD5_MAC_LEN;
- } else
- crypto_hash_finish(conn->verify_md5_cert, NULL, NULL);
-
- conn->verify_md5_cert = NULL;
- hlen = SHA1_MAC_LEN;
- if (conn->verify_sha1_cert == NULL ||
- crypto_hash_finish(conn->verify_sha1_cert, hpos, &hlen) < 0) {
- conn->verify_sha1_cert = NULL;
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- conn->verify_sha1_cert = NULL;
-
- if (alg == SIGN_ALG_RSA)
- hlen += MD5_MAC_LEN;
-
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
-
- /*
- * RFC 2246, 4.7:
- * In digital signing, one-way hash functions are used as input for a
- * signing algorithm. A digitally-signed element is encoded as an
- * opaque vector <0..2^16-1>, where the length is specified by the
- * signing algorithm and key.
- *
- * In RSA signing, a 36-byte structure of two hashes (one SHA and one
- * MD5) is signed (encrypted with the private key). It is encoded with
- * PKCS #1 block type 0 or type 1 as described in [PKCS1].
- */
- signed_start = pos; /* length to be filled */
- pos += 2;
- clen = end - pos;
- if (crypto_private_key_sign_pkcs1(conn->client_key, hash, hlen,
- pos, &clen) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- WPA_PUT_BE16(signed_start, clen);
-
- pos += clen;
-
- WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
- if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- pos = rhdr + rlen;
-
- tls_verify_hash_add(conn, hs_start, pos - hs_start);
-
- *msgpos = pos;
-
- return 0;
-}
-
-
-static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
- u8 **msgpos, u8 *end)
-{
- u8 *pos, *rhdr;
- size_t rlen;
-
- pos = *msgpos;
-
- wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
- rhdr = pos;
- pos += TLS_RECORD_HEADER_LEN;
- *pos = TLS_CHANGE_CIPHER_SPEC;
- if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
- rhdr, end - rhdr, 1, &rlen) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
-
- if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
- "record layer");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
-
- *msgpos = rhdr + rlen;
-
- return 0;
-}
-
-
-static int tls_write_client_finished(struct tlsv1_client *conn,
- u8 **msgpos, u8 *end)
-{
- u8 *pos, *rhdr, *hs_start, *hs_length;
- size_t rlen, hlen;
- u8 verify_data[TLS_VERIFY_DATA_LEN];
- u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
-
- pos = *msgpos;
-
- wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
-
- /* Encrypted Handshake Message: Finished */
-
- hlen = MD5_MAC_LEN;
- if (conn->verify_md5_client == NULL ||
- crypto_hash_finish(conn->verify_md5_client, hash, &hlen) < 0) {
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- conn->verify_md5_client = NULL;
- crypto_hash_finish(conn->verify_sha1_client, NULL, NULL);
- conn->verify_sha1_client = NULL;
- return -1;
- }
- conn->verify_md5_client = NULL;
- hlen = SHA1_MAC_LEN;
- if (conn->verify_sha1_client == NULL ||
- crypto_hash_finish(conn->verify_sha1_client, hash + MD5_MAC_LEN,
- &hlen) < 0) {
- conn->verify_sha1_client = NULL;
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- conn->verify_sha1_client = NULL;
-
- if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
- "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
- verify_data, TLS_VERIFY_DATA_LEN)) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
- wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
- verify_data, TLS_VERIFY_DATA_LEN);
-
- rhdr = pos;
- pos += TLS_RECORD_HEADER_LEN;
- /* Handshake */
- hs_start = pos;
- /* HandshakeType msg_type */
- *pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
- /* uint24 length (to be filled) */
- hs_length = pos;
- pos += 3;
- os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
- pos += TLS_VERIFY_DATA_LEN;
- WPA_PUT_BE24(hs_length, pos - hs_length - 3);
- tls_verify_hash_add(conn, hs_start, pos - hs_start);
-
- if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
- rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_INTERNAL_ERROR);
- return -1;
- }
-
- pos = rhdr + rlen;
-
- *msgpos = pos;
-
- return 0;
-}
-
-
-static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)
-{
- size_t len = 0;
- struct x509_certificate *cert;
-
- cert = conn->client_cert;
- while (cert) {
- len += 3 + cert->cert_len;
- if (x509_certificate_self_signed(cert))
- break;
- cert = x509_certificate_get_subject(conn->trusted_certs,
- &cert->issuer);
- }
-
- return len;
-}
-
-
-static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,
- size_t *out_len)
-{
- u8 *msg, *end, *pos;
- size_t msglen;
-
- *out_len = 0;
-
- msglen = 1000;
- if (conn->certificate_requested)
- msglen += tls_client_cert_chain_der_len(conn);
-
- msg = os_malloc(msglen);
- if (msg == NULL)
- return NULL;
-
- pos = msg;
- end = msg + msglen;
-
- if (conn->certificate_requested) {
- if (tls_write_client_certificate(conn, &pos, end) < 0) {
- os_free(msg);
- return NULL;
- }
- }
-
- if (tls_write_client_key_exchange(conn, &pos, end) < 0 ||
- (conn->certificate_requested && conn->client_key &&
- tls_write_client_certificate_verify(conn, &pos, end) < 0) ||
- tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
- tls_write_client_finished(conn, &pos, end) < 0) {
- os_free(msg);
- return NULL;
- }
-
- *out_len = pos - msg;
-
- conn->state = SERVER_CHANGE_CIPHER_SPEC;
-
- return msg;
-}
-
-
-static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
- size_t *out_len)
-{
- u8 *msg, *end, *pos;
-
- *out_len = 0;
-
- msg = os_malloc(1000);
- if (msg == NULL)
- return NULL;
-
- pos = msg;
- end = msg + 1000;
-
- if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
- tls_write_client_finished(conn, &pos, end) < 0) {
- os_free(msg);
- return NULL;
- }
-
- *out_len = pos - msg;
-
- wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
- "successfully");
- conn->state = ESTABLISHED;
-
- return msg;
-}
-
-
-static int tls_process_application_data(struct tlsv1_client *conn, u8 ct,
- const u8 *in_data, size_t *in_len,
- u8 **out_data, size_t *out_len)
-{
- const u8 *pos;
- size_t left;
-
- if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
- wpa_printf(MSG_DEBUG, "TLSv1: Expected Application Data; "
- "received content type 0x%x", ct);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
- pos = in_data;
- left = *in_len;
-
- wpa_hexdump(MSG_DEBUG, "TLSv1: Application Data included in Handshake",
- pos, left);
-
- *out_data = os_malloc(left);
- if (*out_data) {
- os_memcpy(*out_data, pos, left);
- *out_len = left;
- }
-
- return 0;
-}
-
-
-static int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
- const u8 *buf, size_t *len,
- u8 **out_data, size_t *out_len)
-{
- if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 &&
- buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) {
- size_t hr_len = WPA_GET_BE24(buf + 1);
- if (hr_len > *len - 4) {
- wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow");
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_DECODE_ERROR);
- return -1;
- }
- wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest");
- *len = 4 + hr_len;
- return 0;
- }
-
- switch (conn->state) {
- case SERVER_HELLO:
- if (tls_process_server_hello(conn, ct, buf, len))
- return -1;
- break;
- case SERVER_CERTIFICATE:
- if (tls_process_certificate(conn, ct, buf, len))
- return -1;
- break;
- case SERVER_KEY_EXCHANGE:
- if (tls_process_server_key_exchange(conn, ct, buf, len))
- return -1;
- break;
- case SERVER_CERTIFICATE_REQUEST:
- if (tls_process_certificate_request(conn, ct, buf, len))
- return -1;
- break;
- case SERVER_HELLO_DONE:
- if (tls_process_server_hello_done(conn, ct, buf, len))
- return -1;
- break;
- case SERVER_CHANGE_CIPHER_SPEC:
- if (tls_process_server_change_cipher_spec(conn, ct, buf, len))
- return -1;
- break;
- case SERVER_FINISHED:
- if (tls_process_server_finished(conn, ct, buf, len))
- return -1;
- break;
- case ACK_FINISHED:
- if (out_data &&
- tls_process_application_data(conn, ct, buf, len, out_data,
- out_len))
- return -1;
- break;
- default:
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
- "while processing received message",
- conn->state);
- return -1;
- }
-
- if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
- tls_verify_hash_add(conn, buf, *len);
-
- return 0;
-}
-
-
/**
* tlsv1_client_handshake - Process TLS handshake
* @conn: TLSv1 client connection data from tlsv1_client_init()
@@ -1866,6 +134,7 @@
const u8 *pos, *end;
u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
size_t in_msg_len;
+ int no_appl_data;
if (conn->state == CLIENT_HELLO) {
if (in_len)
@@ -1915,36 +184,20 @@
os_free(in_msg);
in_msg = NULL;
- switch (conn->state) {
- case CLIENT_KEY_EXCHANGE:
- msg = tls_send_client_key_exchange(conn, out_len);
- break;
- case CHANGE_CIPHER_SPEC:
- msg = tls_send_change_cipher_spec(conn, out_len);
- break;
- case ACK_FINISHED:
- wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed "
- "successfully");
- conn->state = ESTABLISHED;
- if (appl_data == NULL || *appl_data == NULL) {
- /* Need to return something to get final TLS ACK. */
- msg = os_malloc(1);
- }
- *out_len = 0;
- break;
- default:
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
- "generating reply", conn->state);
- break;
- }
+ no_appl_data = appl_data == NULL || *appl_data == NULL;
+ msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data);
failed:
os_free(in_msg);
if (conn->alert_level) {
conn->state = FAILED;
os_free(msg);
- msg = tls_send_alert(conn, conn->alert_level,
- conn->alert_description, out_len);
+ msg = tlsv1_client_send_alert(conn, conn->alert_level,
+ conn->alert_description,
+ out_len);
+ } else if (msg == NULL) {
+ msg = os_zalloc(1);
+ *out_len = 0;
}
return msg;
@@ -2071,49 +324,6 @@
}
-static void tlsv1_client_free_verify_hashes(struct tlsv1_client *conn)
-{
- crypto_hash_finish(conn->verify_md5_client, NULL, NULL);
- crypto_hash_finish(conn->verify_md5_server, NULL, NULL);
- crypto_hash_finish(conn->verify_md5_cert, NULL, NULL);
- crypto_hash_finish(conn->verify_sha1_client, NULL, NULL);
- crypto_hash_finish(conn->verify_sha1_server, NULL, NULL);
- crypto_hash_finish(conn->verify_sha1_cert, NULL, NULL);
- conn->verify_md5_client = NULL;
- conn->verify_md5_server = NULL;
- conn->verify_md5_cert = NULL;
- conn->verify_sha1_client = NULL;
- conn->verify_sha1_server = NULL;
- conn->verify_sha1_cert = NULL;
-}
-
-
-static int tlsv1_client_init_verify_hashes(struct tlsv1_client *conn)
-{
- conn->verify_md5_client = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL,
- 0);
- conn->verify_md5_server = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL,
- 0);
- conn->verify_md5_cert = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
- conn->verify_sha1_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL,
- 0);
- conn->verify_sha1_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL,
- 0);
- conn->verify_sha1_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL,
- 0);
- if (conn->verify_md5_client == NULL ||
- conn->verify_md5_server == NULL ||
- conn->verify_md5_cert == NULL ||
- conn->verify_sha1_client == NULL ||
- conn->verify_sha1_server == NULL ||
- conn->verify_sha1_cert == NULL) {
- tlsv1_client_free_verify_hashes(conn);
- return -1;
- }
- return 0;
-}
-
-
/**
* tlsv1_client_init - Initialize TLSv1 client connection
* Returns: Pointer to TLSv1 client connection data or %NULL on failure
@@ -2130,7 +340,7 @@
conn->state = CLIENT_HELLO;
- if (tlsv1_client_init_verify_hashes(conn) < 0) {
+ if (tls_verify_hash_init(&conn->verify) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
"hash");
os_free(conn);
@@ -2162,12 +372,10 @@
tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
tlsv1_record_change_write_cipher(&conn->rl);
tlsv1_record_change_read_cipher(&conn->rl);
- tlsv1_client_free_verify_hashes(conn);
+ tls_verify_hash_free(&conn->verify);
os_free(conn->client_hello_ext);
tlsv1_client_free_dh(conn);
- x509_certificate_chain_free(conn->trusted_certs);
- x509_certificate_chain_free(conn->client_cert);
- crypto_private_key_free(conn->client_key);
+ tlsv1_cred_free(conn->cred);
os_free(conn);
}
@@ -2271,8 +479,7 @@
{
conn->state = CLIENT_HELLO;
- tlsv1_client_free_verify_hashes(conn);
- if (tlsv1_client_init_verify_hashes(conn) < 0) {
+ if (tls_verify_hash_init(&conn->verify) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
"hash");
return -1;
@@ -2315,7 +522,7 @@
{
u8 *pos;
- conn->ticket = 0;
+ conn->session_ticket_included = 0;
os_free(conn->client_hello_ext);
conn->client_hello_ext = NULL;
conn->client_hello_ext_len = 0;
@@ -2337,7 +544,7 @@
conn->client_hello_ext_len = 6 + data_len;
if (ext_type == TLS_EXT_PAC_OPAQUE) {
- conn->ticket = 1;
+ conn->session_ticket_included = 1;
wpa_printf(MSG_DEBUG, "TLSv1: Using session ticket");
}
@@ -2372,27 +579,6 @@
/**
- * tlsv1_client_set_master_key - Configure master secret for TLS connection
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @key: TLS pre-master-secret
- * @key_len: length of key in bytes
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_client_set_master_key(struct tlsv1_client *conn,
- const u8 *key, size_t key_len)
-{
- if (key_len > TLS_MASTER_SECRET_LEN)
- return -1;
- wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret from session "
- "ticket", key, key_len);
- os_memcpy(conn->master_secret, key, key_len);
- conn->ticket_key = 1;
-
- return 0;
-}
-
-
-/**
* tlsv1_client_get_keyblock_size - Get TLS key_block size
* @conn: TLSv1 client connection data from tlsv1_client_init()
* Returns: Size of the key_block for the negotiated cipher suite or -1 on
@@ -2425,7 +611,9 @@
if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
count = 0;
suites = conn->cipher_suites;
+#ifndef CONFIG_CRYPTO_INTERNAL
suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
+#endif /* CONFIG_CRYPTO_INTERNAL */
suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
@@ -2440,223 +628,31 @@
}
-static int tlsv1_client_add_cert_der(struct x509_certificate **chain,
- const u8 *buf, size_t len)
-{
- struct x509_certificate *cert;
- char name[128];
-
- cert = x509_certificate_parse(buf, len);
- if (cert == NULL) {
- wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
- __func__);
- return -1;
- }
-
- cert->next = *chain;
- *chain = cert;
-
- x509_name_string(&cert->subject, name, sizeof(name));
- wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
-
- return 0;
-}
-
-
-static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
-static const char *pem_cert_end = "-----END CERTIFICATE-----";
-
-
-static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
-{
- size_t i, plen;
-
- plen = os_strlen(tag);
- if (len < plen)
- return NULL;
-
- for (i = 0; i < len - plen; i++) {
- if (os_memcmp(buf + i, tag, plen) == 0)
- return buf + i;
- }
-
- return NULL;
-}
-
-
-static int tlsv1_client_add_cert(struct x509_certificate **chain,
- const u8 *buf, size_t len)
-{
- const u8 *pos, *end;
- unsigned char *der;
- size_t der_len;
-
- pos = search_tag(pem_cert_begin, buf, len);
- if (!pos) {
- wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
- "assume DER format");
- return tlsv1_client_add_cert_der(chain, buf, len);
- }
-
- wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
- "DER format");
-
- while (pos) {
- pos += os_strlen(pem_cert_begin);
- end = search_tag(pem_cert_end, pos, buf + len - pos);
- if (end == NULL) {
- wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
- "certificate end tag (%s)", pem_cert_end);
- return -1;
- }
-
- der = base64_decode(pos, end - pos, &der_len);
- if (der == NULL) {
- wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
- "certificate");
- return -1;
- }
-
- if (tlsv1_client_add_cert_der(chain, der, der_len) < 0) {
- wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
- "certificate after DER conversion");
- os_free(der);
- return -1;
- }
-
- os_free(der);
-
- end += os_strlen(pem_cert_end);
- pos = search_tag(pem_cert_begin, end, buf + len - end);
- }
-
- return 0;
-}
-
-
-static int tlsv1_client_set_cert_chain(struct x509_certificate **chain,
- const char *cert, const u8 *cert_blob,
- size_t cert_blob_len)
-{
- if (cert_blob)
- return tlsv1_client_add_cert(chain, cert_blob, cert_blob_len);
-
- if (cert) {
- u8 *buf;
- size_t len;
- int ret;
-
- buf = (u8 *) os_readfile(cert, &len);
- if (buf == NULL) {
- wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
- cert);
- return -1;
- }
-
- ret = tlsv1_client_add_cert(chain, buf, len);
- os_free(buf);
- return ret;
- }
-
- return 0;
-}
-
-
-/**
- * tlsv1_client_set_ca_cert - Set trusted CA certificate(s)
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @cert: File or reference name for X.509 certificate in PEM or DER format
- * @cert_blob: cert as inlined data or %NULL if not used
- * @cert_blob_len: ca_cert_blob length
- * @path: Path to CA certificates (not yet supported)
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_client_set_ca_cert(struct tlsv1_client *conn, const char *cert,
- const u8 *cert_blob, size_t cert_blob_len,
- const char *path)
-{
- if (tlsv1_client_set_cert_chain(&conn->trusted_certs, cert,
- cert_blob, cert_blob_len) < 0)
- return -1;
-
- if (path) {
- /* TODO: add support for reading number of certificate files */
- wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
- "not yet supported");
- return -1;
- }
-
- return 0;
-}
-
-
-/**
- * tlsv1_client_set_client_cert - Set client certificate
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @cert: File or reference name for X.509 certificate in PEM or DER format
- * @cert_blob: cert as inlined data or %NULL if not used
- * @cert_blob_len: ca_cert_blob length
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_client_set_client_cert(struct tlsv1_client *conn, const char *cert,
- const u8 *cert_blob, size_t cert_blob_len)
-{
- return tlsv1_client_set_cert_chain(&conn->client_cert, cert,
- cert_blob, cert_blob_len);
-}
-
-
-static int tlsv1_client_set_key(struct tlsv1_client *conn,
- const u8 *key, size_t len)
-{
- conn->client_key = crypto_private_key_import(key, len);
- if (conn->client_key == NULL) {
- wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
- return -1;
- }
- return 0;
-}
-
-
-/**
- * tlsv1_client_set_private_key - Set client private key
- * @conn: TLSv1 client connection data from tlsv1_client_init()
- * @private_key: File or reference name for the key in PEM or DER format
- * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
- * passphrase is used.
- * @private_key_blob: private_key as inlined data or %NULL if not used
- * @private_key_blob_len: private_key_blob length
- * Returns: 0 on success, -1 on failure
- */
-int tlsv1_client_set_private_key(struct tlsv1_client *conn,
- const char *private_key,
- const char *private_key_passwd,
- const u8 *private_key_blob,
- size_t private_key_blob_len)
-{
- crypto_private_key_free(conn->client_key);
- conn->client_key = NULL;
-
- if (private_key_blob)
- return tlsv1_client_set_key(conn, private_key_blob,
- private_key_blob_len);
-
- if (private_key) {
- u8 *buf;
- size_t len;
- int ret;
-
- buf = (u8 *) os_readfile(private_key, &len);
- if (buf == NULL) {
- wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
- private_key);
- return -1;
- }
-
- ret = tlsv1_client_set_key(conn, buf, len);
- os_free(buf);
- return ret;
- }
-
- return 0;
-}
+/**
+ * tlsv1_client_set_cred - Set client credentials
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @cred: Credentials from tlsv1_cred_alloc()
+ * Returns: 0 on success, -1 on failure
+ *
+ * On success, the client takes ownership of the credentials block and caller
+ * must not free it. On failure, caller is responsible for freeing the
+ * credential block.
+ */
+int tlsv1_client_set_cred(struct tlsv1_client *conn,
+ struct tlsv1_credentials *cred)
+{
+ tlsv1_cred_free(conn->cred);
+ conn->cred = cred;
+ return 0;
+}
+
+
+void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
+ tlsv1_client_session_ticket_cb cb,
+ void *ctx)
+{
+ wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
+ cb, ctx);
+ conn->session_ticket_cb = cb;
+ conn->session_ticket_cb_ctx = ctx;
+}
Modified: wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.h (original)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.h Sat Nov 3 08:40:37 2007
@@ -1,6 +1,6 @@
/*
- * wpa_supplicant: TLSv1 client (RFC 2246)
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ * TLSv1 client (RFC 2246)
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -14,6 +14,8 @@
#ifndef TLSV1_CLIENT_H
#define TLSV1_CLIENT_H
+
+#include "tlsv1_cred.h"
struct tlsv1_client;
@@ -41,19 +43,17 @@
int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
const u8 *data, size_t data_len);
int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys);
-int tlsv1_client_set_master_key(struct tlsv1_client *conn,
- const u8 *key, size_t key_len);
int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn);
int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers);
-int tlsv1_client_set_ca_cert(struct tlsv1_client *conn, const char *cert,
- const u8 *cert_blob, size_t cert_blob_len,
- const char *path);
-int tlsv1_client_set_client_cert(struct tlsv1_client *conn, const char *cert,
- const u8 *cert_blob, size_t cert_blob_len);
-int tlsv1_client_set_private_key(struct tlsv1_client *conn,
- const char *private_key,
- const char *private_key_passwd,
- const u8 *private_key_blob,
- size_t private_key_blob_len);
+int tlsv1_client_set_cred(struct tlsv1_client *conn,
+ struct tlsv1_credentials *cred);
+
+typedef int (*tlsv1_client_session_ticket_cb)
+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
+ const u8 *server_random, u8 *master_secret);
+
+void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
+ tlsv1_client_session_ticket_cb cb,
+ void *ctx);
#endif /* TLSV1_CLIENT_H */
Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_i.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_i.h (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_i.h Sat Nov 3 08:40:37 2007
@@ -1,0 +1,87 @@
+/*
+ * TLSv1 client - internal structures
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef TLSV1_CLIENT_I_H
+#define TLSV1_CLIENT_I_H
+
+struct tlsv1_client {
+ enum {
+ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,
+ SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,
+ SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,
+ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,
+ ESTABLISHED, FAILED
+ } state;
+
+ struct tlsv1_record_layer rl;
+
+ u8 session_id[TLS_SESSION_ID_MAX_LEN];
+ size_t session_id_len;
+ u8 client_random[TLS_RANDOM_LEN];
+ u8 server_random[TLS_RANDOM_LEN];
+ u8 master_secret[TLS_MASTER_SECRET_LEN];
+
+ u8 alert_level;
+ u8 alert_description;
+
+ unsigned int certificate_requested:1;
+ unsigned int session_resumed:1;
+ unsigned int session_ticket_included:1;
+ unsigned int use_session_ticket:1;
+
+ struct crypto_public_key *server_rsa_key;
+
+ struct tls_verify_hash verify;
+
+#define MAX_CIPHER_COUNT 30
+ u16 cipher_suites[MAX_CIPHER_COUNT];
+ size_t num_cipher_suites;
+
+ u16 prev_cipher_suite;
+
+ u8 *client_hello_ext;
+ size_t client_hello_ext_len;
+
+ /* The prime modulus used for Diffie-Hellman */
+ u8 *dh_p;
+ size_t dh_p_len;
+ /* The generator used for Diffie-Hellman */
+ u8 *dh_g;
+ size_t dh_g_len;
+ /* The server's Diffie-Hellman public value */
+ u8 *dh_ys;
+ size_t dh_ys_len;
+
+ struct tlsv1_credentials *cred;
+
+ tlsv1_client_session_ticket_cb session_ticket_cb;
+ void *session_ticket_cb_ctx;
+};
+
+
+void tls_alert(struct tlsv1_client *conn, u8 level, u8 description);
+void tlsv1_client_free_dh(struct tlsv1_client *conn);
+int tls_derive_pre_master_secret(u8 *pre_master_secret);
+int tls_derive_keys(struct tlsv1_client *conn,
+ const u8 *pre_master_secret, size_t pre_master_secret_len);
+u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len);
+u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
+ u8 description, size_t *out_len);
+u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,
+ int no_appl_data);
+int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
+ const u8 *buf, size_t *len,
+ u8 **out_data, size_t *out_len);
+
+#endif /* TLSV1_CLIENT_I_H */
Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_read.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_read.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_read.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_read.c Sat Nov 3 08:40:37 2007
@@ -1,0 +1,976 @@
+/*
+ * TLSv1 client - read handshake message
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "x509v3.h"
+#include "tls.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
+
+static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len);
+static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len);
+static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len);
+
+
+static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len, i;
+ u16 cipher_suite;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4)
+ goto decode_error;
+
+ /* HandshakeType msg_type */
+ if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected ServerHello)", *pos);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello");
+ pos++;
+ /* uint24 length */
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left)
+ goto decode_error;
+
+ /* body - ServerHello */
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len);
+ end = pos + len;
+
+ /* ProtocolVersion server_version */
+ if (end - pos < 2)
+ goto decode_error;
+ if (WPA_GET_BE16(pos) != TLS_VERSION) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
+ "ServerHello");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_PROTOCOL_VERSION);
+ return -1;
+ }
+ pos += 2;
+
+ /* Random random */
+ if (end - pos < TLS_RANDOM_LEN)
+ goto decode_error;
+
+ os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN);
+ pos += TLS_RANDOM_LEN;
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
+ conn->server_random, TLS_RANDOM_LEN);
+
+ /* SessionID session_id */
+ if (end - pos < 1)
+ goto decode_error;
+ if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
+ goto decode_error;
+ if (conn->session_id_len && conn->session_id_len == *pos &&
+ os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) {
+ pos += 1 + conn->session_id_len;
+ wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session");
+ conn->session_resumed = 1;
+ } else {
+ conn->session_id_len = *pos;
+ pos++;
+ os_memcpy(conn->session_id, pos, conn->session_id_len);
+ pos += conn->session_id_len;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
+ conn->session_id, conn->session_id_len);
+
+ /* CipherSuite cipher_suite */
+ if (end - pos < 2)
+ goto decode_error;
+ cipher_suite = WPA_GET_BE16(pos);
+ pos += 2;
+ for (i = 0; i < conn->num_cipher_suites; i++) {
+ if (cipher_suite == conn->cipher_suites[i])
+ break;
+ }
+ if (i == conn->num_cipher_suites) {
+ wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
+ "cipher suite 0x%04x", cipher_suite);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_ILLEGAL_PARAMETER);
+ return -1;
+ }
+
+ if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different "
+ "cipher suite for a resumed connection (0x%04x != "
+ "0x%04x)", cipher_suite, conn->prev_cipher_suite);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_ILLEGAL_PARAMETER);
+ return -1;
+ }
+
+ if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
+ "record layer");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ conn->prev_cipher_suite = cipher_suite;
+
+ /* CompressionMethod compression_method */
+ if (end - pos < 1)
+ goto decode_error;
+ if (*pos != TLS_COMPRESSION_NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
+ "compression 0x%02x", *pos);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_ILLEGAL_PARAMETER);
+ return -1;
+ }
+ pos++;
+
+ if (end != pos) {
+ /* TODO: ServerHello extensions */
+ wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
+ "end of ServerHello", pos, end - pos);
+ goto decode_error;
+ }
+
+ if (conn->session_ticket_included && conn->session_ticket_cb) {
+ /* TODO: include SessionTicket extension if one was included in
+ * ServerHello */
+ int res = conn->session_ticket_cb(
+ conn->session_ticket_cb_ctx, NULL, 0,
+ conn->client_random, conn->server_random,
+ conn->master_secret);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
+ "indicated failure");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_HANDSHAKE_FAILURE);
+ return -1;
+ }
+ conn->use_session_ticket = !!res;
+ }
+
+ if ((conn->session_resumed || conn->use_session_ticket) &&
+ tls_derive_keys(conn, NULL, 0)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ *in_len = end - in_data;
+
+ conn->state = (conn->session_resumed || conn->use_session_ticket) ?
+ SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE;
+
+ return 0;
+
+decode_error:
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+}
+
+
+static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len, list_len, cert_len, idx;
+ u8 type;
+ struct x509_certificate *chain = NULL, *last = NULL, *cert;
+ int reason;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
+ "(len=%lu)", (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
+ "length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ if (type == TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE)
+ return tls_process_server_key_exchange(conn, ct, in_data,
+ in_len);
+ if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
+ return tls_process_certificate_request(conn, ct, in_data,
+ in_len);
+ if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
+ return tls_process_server_hello_done(conn, ct, in_data,
+ in_len);
+ if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected Certificate/"
+ "ServerKeyExchange/CertificateRequest/"
+ "ServerHelloDone)", type);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Received Certificate (certificate_list len %lu)",
+ (unsigned long) len);
+
+ /*
+ * opaque ASN.1Cert<2^24-1>;
+ *
+ * struct {
+ * ASN.1Cert certificate_list<1..2^24-1>;
+ * } Certificate;
+ */
+
+ end = pos + len;
+
+ if (end - pos < 3) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
+ "(left=%lu)", (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ list_len = WPA_GET_BE24(pos);
+ pos += 3;
+
+ if ((size_t) (end - pos) != list_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
+ "length (len=%lu left=%lu)",
+ (unsigned long) list_len,
+ (unsigned long) (end - pos));
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ idx = 0;
+ while (pos < end) {
+ if (end - pos < 3) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+ "certificate_list");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ cert_len = WPA_GET_BE24(pos);
+ pos += 3;
+
+ if ((size_t) (end - pos) < cert_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
+ "length (len=%lu left=%lu)",
+ (unsigned long) cert_len,
+ (unsigned long) (end - pos));
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
+ (unsigned long) idx, (unsigned long) cert_len);
+
+ if (idx == 0) {
+ crypto_public_key_free(conn->server_rsa_key);
+ if (tls_parse_cert(pos, cert_len,
+ &conn->server_rsa_key)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+ "the certificate");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+ }
+
+ cert = x509_certificate_parse(pos, cert_len);
+ if (cert == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+ "the certificate");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ if (last == NULL)
+ chain = cert;
+ else
+ last->next = cert;
+ last = cert;
+
+ idx++;
+ pos += cert_len;
+ }
+
+ if (conn->cred &&
+ x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
+ &reason) < 0) {
+ int tls_reason;
+ wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
+ "validation failed (reason=%d)", reason);
+ switch (reason) {
+ case X509_VALIDATE_BAD_CERTIFICATE:
+ tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+ break;
+ case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
+ tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
+ break;
+ case X509_VALIDATE_CERTIFICATE_REVOKED:
+ tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
+ break;
+ case X509_VALIDATE_CERTIFICATE_EXPIRED:
+ tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
+ break;
+ case X509_VALIDATE_CERTIFICATE_UNKNOWN:
+ tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
+ break;
+ case X509_VALIDATE_UNKNOWN_CA:
+ tls_reason = TLS_ALERT_UNKNOWN_CA;
+ break;
+ default:
+ tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+ break;
+ }
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ x509_certificate_chain_free(chain);
+
+ *in_len = end - in_data;
+
+ conn->state = SERVER_KEY_EXCHANGE;
+
+ return 0;
+}
+
+
+static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
+ const u8 *buf, size_t len)
+{
+ const u8 *pos, *end;
+
+ tlsv1_client_free_dh(conn);
+
+ pos = buf;
+ end = buf + len;
+
+ if (end - pos < 3)
+ goto fail;
+ conn->dh_p_len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %d",
+ conn->dh_p_len);
+ goto fail;
+ }
+ conn->dh_p = os_malloc(conn->dh_p_len);
+ if (conn->dh_p == NULL)
+ goto fail;
+ os_memcpy(conn->dh_p, pos, conn->dh_p_len);
+ pos += conn->dh_p_len;
+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
+ conn->dh_p, conn->dh_p_len);
+
+ if (end - pos < 3)
+ goto fail;
+ conn->dh_g_len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
+ goto fail;
+ conn->dh_g = os_malloc(conn->dh_g_len);
+ if (conn->dh_g == NULL)
+ goto fail;
+ os_memcpy(conn->dh_g, pos, conn->dh_g_len);
+ pos += conn->dh_g_len;
+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
+ conn->dh_g, conn->dh_g_len);
+ if (conn->dh_g_len == 1 && conn->dh_g[0] < 2)
+ goto fail;
+
+ if (end - pos < 3)
+ goto fail;
+ conn->dh_ys_len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
+ goto fail;
+ conn->dh_ys = os_malloc(conn->dh_ys_len);
+ if (conn->dh_ys == NULL)
+ goto fail;
+ os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
+ pos += conn->dh_ys_len;
+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
+ conn->dh_ys, conn->dh_ys_len);
+
+ return 0;
+
+fail:
+ wpa_printf(MSG_DEBUG, "TLSv1: Processing DH params failed");
+ tlsv1_client_free_dh(conn);
+ return -1;
+}
+
+
+static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len;
+ u8 type;
+ const struct tls_cipher_suite *suite;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerKeyExchange "
+ "(Left=%lu)", (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerKeyExchange "
+ "length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ end = pos + len;
+
+ if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
+ return tls_process_certificate_request(conn, ct, in_data,
+ in_len);
+ if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
+ return tls_process_server_hello_done(conn, ct, in_data,
+ in_len);
+ if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected ServerKeyExchange/"
+ "CertificateRequest/ServerHelloDone)", type);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange");
+
+ if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed "
+ "with the selected cipher suite");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
+ suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+ if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
+ if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ *in_len = end - in_data;
+
+ conn->state = SERVER_CERTIFICATE_REQUEST;
+
+ return 0;
+}
+
+
+static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len;
+ u8 type;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateRequest "
+ "(left=%lu)", (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in CertificateRequest "
+ "length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ end = pos + len;
+
+ if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
+ return tls_process_server_hello_done(conn, ct, in_data,
+ in_len);
+ if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected CertificateRequest/"
+ "ServerHelloDone)", type);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateRequest");
+
+ conn->certificate_requested = 1;
+
+ *in_len = end - in_data;
+
+ conn->state = SERVER_HELLO_DONE;
+
+ return 0;
+}
+
+
+static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len;
+ u8 type;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerHelloDone "
+ "(left=%lu)", (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerHelloDone "
+ "length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ end = pos + len;
+
+ if (type != TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected ServerHelloDone)", type);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
+
+ *in_len = end - in_data;
+
+ conn->state = CLIENT_KEY_EXCHANGE;
+
+ return 0;
+}
+
+
+static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,
+ u8 ct, const u8 *in_data,
+ size_t *in_len)
+{
+ const u8 *pos;
+ size_t left;
+
+ if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+ "received content type 0x%x", ct);
+ if (conn->use_session_ticket) {
+ int res;
+ wpa_printf(MSG_DEBUG, "TLSv1: Server may have "
+ "rejected SessionTicket");
+ conn->use_session_ticket = 0;
+
+ /* Notify upper layers that SessionTicket failed */
+ res = conn->session_ticket_cb(
+ conn->session_ticket_cb_ctx, NULL, 0, NULL,
+ NULL, NULL);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket "
+ "callback indicated failure");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_HANDSHAKE_FAILURE);
+ return -1;
+ }
+
+ conn->state = SERVER_CERTIFICATE;
+ return tls_process_certificate(conn, ct, in_data,
+ in_len);
+ }
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 1) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ if (*pos != TLS_CHANGE_CIPHER_SPEC) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+ "received data 0x%x", *pos);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
+ if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
+ "for record layer");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ *in_len = pos + 1 - in_data;
+
+ conn->state = SERVER_FINISHED;
+
+ return 0;
+}
+
+
+static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len, hlen;
+ u8 verify_data[TLS_VERIFY_DATA_LEN];
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
+ "Finished",
+ (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
+ "type 0x%x", pos[0]);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ len = WPA_GET_BE24(pos + 1);
+
+ pos += 4;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
+ "(len=%lu > left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ end = pos + len;
+ if (len != TLS_VERIFY_DATA_LEN) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
+ "in Finished: %lu (expected %d)",
+ (unsigned long) len, TLS_VERIFY_DATA_LEN);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
+ pos, TLS_VERIFY_DATA_LEN);
+
+ hlen = MD5_MAC_LEN;
+ if (conn->verify.md5_server == NULL ||
+ crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.md5_server = NULL;
+ crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
+ conn->verify.sha1_server = NULL;
+ return -1;
+ }
+ conn->verify.md5_server = NULL;
+ hlen = SHA1_MAC_LEN;
+ if (conn->verify.sha1_server == NULL ||
+ crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
+ &hlen) < 0) {
+ conn->verify.sha1_server = NULL;
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ conn->verify.sha1_server = NULL;
+
+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+ verify_data, TLS_VERIFY_DATA_LEN)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECRYPT_ERROR);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
+ verify_data, TLS_VERIFY_DATA_LEN);
+
+ if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+ wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
+
+ *in_len = end - in_data;
+
+ conn->state = (conn->session_resumed || conn->use_session_ticket) ?
+ CHANGE_CIPHER_SPEC : ACK_FINISHED;
+
+ return 0;
+}
+
+
+static int tls_process_application_data(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len,
+ u8 **out_data, size_t *out_len)
+{
+ const u8 *pos;
+ size_t left;
+
+ if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Application Data; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ wpa_hexdump(MSG_DEBUG, "TLSv1: Application Data included in Handshake",
+ pos, left);
+
+ *out_data = os_malloc(left);
+ if (*out_data) {
+ os_memcpy(*out_data, pos, left);
+ *out_len = left;
+ }
+
+ return 0;
+}
+
+
+int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
+ const u8 *buf, size_t *len,
+ u8 **out_data, size_t *out_len)
+{
+ if (ct == TLS_CONTENT_TYPE_ALERT) {
+ if (*len < 2) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+ buf[0], buf[1]);
+ *len = 2;
+ conn->state = FAILED;
+ return -1;
+ }
+
+ if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 &&
+ buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) {
+ size_t hr_len = WPA_GET_BE24(buf + 1);
+ if (hr_len > *len - 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest");
+ *len = 4 + hr_len;
+ return 0;
+ }
+
+ switch (conn->state) {
+ case SERVER_HELLO:
+ if (tls_process_server_hello(conn, ct, buf, len))
+ return -1;
+ break;
+ case SERVER_CERTIFICATE:
+ if (tls_process_certificate(conn, ct, buf, len))
+ return -1;
+ break;
+ case SERVER_KEY_EXCHANGE:
+ if (tls_process_server_key_exchange(conn, ct, buf, len))
+ return -1;
+ break;
+ case SERVER_CERTIFICATE_REQUEST:
+ if (tls_process_certificate_request(conn, ct, buf, len))
+ return -1;
+ break;
+ case SERVER_HELLO_DONE:
+ if (tls_process_server_hello_done(conn, ct, buf, len))
+ return -1;
+ break;
+ case SERVER_CHANGE_CIPHER_SPEC:
+ if (tls_process_server_change_cipher_spec(conn, ct, buf, len))
+ return -1;
+ break;
+ case SERVER_FINISHED:
+ if (tls_process_server_finished(conn, ct, buf, len))
+ return -1;
+ break;
+ case ACK_FINISHED:
+ if (out_data &&
+ tls_process_application_data(conn, ct, buf, len, out_data,
+ out_len))
+ return -1;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
+ "while processing received message",
+ conn->state);
+ return -1;
+ }
+
+ if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
+ tls_verify_hash_add(&conn->verify, buf, *len);
+
+ return 0;
+}
Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_write.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_write.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_write.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_client_write.c Sat Nov 3 08:40:37 2007
@@ -1,0 +1,790 @@
+/*
+ * TLSv1 client - write handshake message
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "x509v3.h"
+#include "tls.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
+
+
+static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)
+{
+ size_t len = 0;
+ struct x509_certificate *cert;
+
+ if (conn->cred == NULL)
+ return 0;
+
+ cert = conn->cred->cert;
+ while (cert) {
+ len += 3 + cert->cert_len;
+ if (x509_certificate_self_signed(cert))
+ break;
+ cert = x509_certificate_get_subject(conn->cred->trusted_certs,
+ &cert->issuer);
+ }
+
+ return len;
+}
+
+
+u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
+{
+ u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
+ struct os_time now;
+ size_t len, i;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
+ *out_len = 0;
+
+ os_get_time(&now);
+ WPA_PUT_BE32(conn->client_random, now.sec);
+ if (os_get_random(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
+ wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
+ "client_random");
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
+ conn->client_random, TLS_RANDOM_LEN);
+
+ len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
+ hello = os_malloc(len);
+ if (hello == NULL)
+ return NULL;
+ end = hello + len;
+
+ rhdr = hello;
+ pos = rhdr + TLS_RECORD_HEADER_LEN;
+
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+ /* body - ClientHello */
+ /* ProtocolVersion client_version */
+ WPA_PUT_BE16(pos, TLS_VERSION);
+ pos += 2;
+ /* Random random: uint32 gmt_unix_time, opaque random_bytes */
+ os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN);
+ pos += TLS_RANDOM_LEN;
+ /* SessionID session_id */
+ *pos++ = conn->session_id_len;
+ os_memcpy(pos, conn->session_id, conn->session_id_len);
+ pos += conn->session_id_len;
+ /* CipherSuite cipher_suites<2..2^16-1> */
+ WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites);
+ pos += 2;
+ for (i = 0; i < conn->num_cipher_suites; i++) {
+ WPA_PUT_BE16(pos, conn->cipher_suites[i]);
+ pos += 2;
+ }
+ /* CompressionMethod compression_methods<1..2^8-1> */
+ *pos++ = 1;
+ *pos++ = TLS_COMPRESSION_NULL;
+
+ if (conn->client_hello_ext) {
+ os_memcpy(pos, conn->client_hello_ext,
+ conn->client_hello_ext_len);
+ pos += conn->client_hello_ext_len;
+ }
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, out_len) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(hello);
+ return NULL;
+ }
+
+ conn->state = SERVER_HELLO;
+
+ return hello;
+}
+
+
+static int tls_write_client_certificate(struct tlsv1_client *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
+ size_t rlen;
+ struct x509_certificate *cert;
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+ /* body - Certificate */
+ /* uint24 length (to be filled) */
+ cert_start = pos;
+ pos += 3;
+ cert = conn->cred ? conn->cred->cert : NULL;
+ while (cert) {
+ if (pos + 3 + cert->cert_len > end) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
+ "for Certificate (cert_len=%lu left=%lu)",
+ (unsigned long) cert->cert_len,
+ (unsigned long) (end - pos));
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ WPA_PUT_BE24(pos, cert->cert_len);
+ pos += 3;
+ os_memcpy(pos, cert->cert_start, cert->cert_len);
+ pos += cert->cert_len;
+
+ if (x509_certificate_self_signed(cert))
+ break;
+ cert = x509_certificate_get_subject(conn->cred->trusted_certs,
+ &cert->issuer);
+ }
+ if (conn->cred == NULL || cert == conn->cred->cert || cert == NULL) {
+ /*
+ * Client was not configured with all the needed certificates
+ * to form a full certificate chain. The server may fail to
+ * validate the chain unless it is configured with all the
+ * missing CA certificates.
+ */
+ wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain "
+ "not configured - validation may fail");
+ }
+ WPA_PUT_BE24(cert_start, pos - cert_start - 3);
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos = rhdr + rlen;
+
+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
+{
+#ifdef EAP_FAST
+ /* ClientDiffieHellmanPublic */
+ u8 *csecret, *csecret_start, *dh_yc, *shared;
+ size_t csecret_len, dh_yc_len, shared_len;
+
+ csecret_len = conn->dh_p_len;
+ csecret = os_malloc(csecret_len);
+ if (csecret == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+ "memory for Yc (Diffie-Hellman)");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ if (os_get_random(csecret, csecret_len)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
+ "data for Diffie-Hellman");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(csecret);
+ return -1;
+ }
+
+ if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0)
+ csecret[0] = 0; /* make sure Yc < p */
+
+ csecret_start = csecret;
+ while (csecret_len > 1 && *csecret_start == 0) {
+ csecret_start++;
+ csecret_len--;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value",
+ csecret_start, csecret_len);
+
+ /* Yc = g^csecret mod p */
+ dh_yc_len = conn->dh_p_len;
+ dh_yc = os_malloc(dh_yc_len);
+ if (dh_yc == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+ "memory for Diffie-Hellman");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(csecret);
+ return -1;
+ }
+ crypto_mod_exp(conn->dh_g, conn->dh_g_len,
+ csecret_start, csecret_len,
+ conn->dh_p, conn->dh_p_len,
+ dh_yc, &dh_yc_len);
+
+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
+ dh_yc, dh_yc_len);
+
+ WPA_PUT_BE16(*pos, dh_yc_len);
+ *pos += 2;
+ if (*pos + dh_yc_len > end) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
+ "message buffer for Yc");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(csecret);
+ os_free(dh_yc);
+ return -1;
+ }
+ os_memcpy(*pos, dh_yc, dh_yc_len);
+ *pos += dh_yc_len;
+ os_free(dh_yc);
+
+ shared_len = conn->dh_p_len;
+ shared = os_malloc(shared_len);
+ if (shared == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
+ "DH");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(csecret);
+ return -1;
+ }
+
+ /* shared = Ys^csecret mod p */
+ crypto_mod_exp(conn->dh_ys, conn->dh_ys_len,
+ csecret_start, csecret_len,
+ conn->dh_p, conn->dh_p_len,
+ shared, &shared_len);
+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
+ shared, shared_len);
+
+ os_memset(csecret_start, 0, csecret_len);
+ os_free(csecret);
+ if (tls_derive_keys(conn, shared, shared_len)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(shared);
+ return -1;
+ }
+ os_memset(shared, 0, shared_len);
+ os_free(shared);
+ tlsv1_client_free_dh(conn);
+ return 0;
+#else /* EAP_FAST */
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+#endif /* EAP_FAST */
+}
+
+
+static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)
+{
+ u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN];
+ size_t clen;
+ int res;
+
+ if (tls_derive_pre_master_secret(pre_master_secret) < 0 ||
+ tls_derive_keys(conn, pre_master_secret,
+ TLS_PRE_MASTER_SECRET_LEN)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /* EncryptedPreMasterSecret */
+ if (conn->server_rsa_key == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to "
+ "use for encrypting pre-master secret");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */
+ *pos += 2;
+ clen = end - *pos;
+ res = crypto_public_key_encrypt_pkcs1_v15(
+ conn->server_rsa_key,
+ pre_master_secret, TLS_PRE_MASTER_SECRET_LEN,
+ *pos, &clen);
+ os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ WPA_PUT_BE16(*pos - 2, clen);
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret",
+ *pos, clen);
+ *pos += clen;
+
+ return 0;
+}
+
+
+static int tls_write_client_key_exchange(struct tlsv1_client *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length;
+ size_t rlen;
+ tls_key_exchange keyx;
+ const struct tls_cipher_suite *suite;
+
+ suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+ if (suite == NULL)
+ keyx = TLS_KEY_X_NULL;
+ else
+ keyx = suite->key_exchange;
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange");
+
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+ /* body - ClientKeyExchange */
+ if (keyx == TLS_KEY_X_DH_anon) {
+ if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
+ return -1;
+ } else {
+ if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
+ return -1;
+ }
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos = rhdr + rlen;
+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
+ size_t rlen, hlen, clen;
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
+ enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify");
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+
+ /*
+ * RFC 2246: 7.4.3 and 7.4.8:
+ * Signature signature
+ *
+ * RSA:
+ * digitally-signed struct {
+ * opaque md5_hash[16];
+ * opaque sha_hash[20];
+ * };
+ *
+ * DSA:
+ * digitally-signed struct {
+ * opaque sha_hash[20];
+ * };
+ *
+ * The hash values are calculated over all handshake messages sent or
+ * received starting at ClientHello up to, but not including, this
+ * CertificateVerify message, including the type and length fields of
+ * the handshake messages.
+ */
+
+ hpos = hash;
+
+ if (alg == SIGN_ALG_RSA) {
+ hlen = MD5_MAC_LEN;
+ if (conn->verify.md5_cert == NULL ||
+ crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
+ {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.md5_cert = NULL;
+ crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+ conn->verify.sha1_cert = NULL;
+ return -1;
+ }
+ hpos += MD5_MAC_LEN;
+ } else
+ crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+
+ conn->verify.md5_cert = NULL;
+ hlen = SHA1_MAC_LEN;
+ if (conn->verify.sha1_cert == NULL ||
+ crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
+ conn->verify.sha1_cert = NULL;
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ conn->verify.sha1_cert = NULL;
+
+ if (alg == SIGN_ALG_RSA)
+ hlen += MD5_MAC_LEN;
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
+
+ /*
+ * RFC 2246, 4.7:
+ * In digital signing, one-way hash functions are used as input for a
+ * signing algorithm. A digitally-signed element is encoded as an
+ * opaque vector <0..2^16-1>, where the length is specified by the
+ * signing algorithm and key.
+ *
+ * In RSA signing, a 36-byte structure of two hashes (one SHA and one
+ * MD5) is signed (encrypted with the private key). It is encoded with
+ * PKCS #1 block type 0 or type 1 as described in [PKCS1].
+ */
+ signed_start = pos; /* length to be filled */
+ pos += 2;
+ clen = end - pos;
+ if (conn->cred == NULL ||
+ crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
+ pos, &clen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ WPA_PUT_BE16(signed_start, clen);
+
+ pos += clen;
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos = rhdr + rlen;
+
+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr;
+ size_t rlen;
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+ *pos = TLS_CHANGE_CIPHER_SPEC;
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
+ rhdr, end - rhdr, 1, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
+ "record layer");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ *msgpos = rhdr + rlen;
+
+ return 0;
+}
+
+
+static int tls_write_client_finished(struct tlsv1_client *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length;
+ size_t rlen, hlen;
+ u8 verify_data[TLS_VERIFY_DATA_LEN];
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
+
+ /* Encrypted Handshake Message: Finished */
+
+ hlen = MD5_MAC_LEN;
+ if (conn->verify.md5_client == NULL ||
+ crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.md5_client = NULL;
+ crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
+ conn->verify.sha1_client = NULL;
+ return -1;
+ }
+ conn->verify.md5_client = NULL;
+ hlen = SHA1_MAC_LEN;
+ if (conn->verify.sha1_client == NULL ||
+ crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
+ &hlen) < 0) {
+ conn->verify.sha1_client = NULL;
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ conn->verify.sha1_client = NULL;
+
+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+ verify_data, TLS_VERIFY_DATA_LEN)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
+ verify_data, TLS_VERIFY_DATA_LEN);
+
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+ os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
+ pos += TLS_VERIFY_DATA_LEN;
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ pos = rhdr + rlen;
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,
+ size_t *out_len)
+{
+ u8 *msg, *end, *pos;
+ size_t msglen;
+
+ *out_len = 0;
+
+ msglen = 1000;
+ if (conn->certificate_requested)
+ msglen += tls_client_cert_chain_der_len(conn);
+
+ msg = os_malloc(msglen);
+ if (msg == NULL)
+ return NULL;
+
+ pos = msg;
+ end = msg + msglen;
+
+ if (conn->certificate_requested) {
+ if (tls_write_client_certificate(conn, &pos, end) < 0) {
+ os_free(msg);
+ return NULL;
+ }
+ }
+
+ if (tls_write_client_key_exchange(conn, &pos, end) < 0 ||
+ (conn->certificate_requested && conn->cred && conn->cred->key &&
+ tls_write_client_certificate_verify(conn, &pos, end) < 0) ||
+ tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
+ tls_write_client_finished(conn, &pos, end) < 0) {
+ os_free(msg);
+ return NULL;
+ }
+
+ *out_len = pos - msg;
+
+ conn->state = SERVER_CHANGE_CIPHER_SPEC;
+
+ return msg;
+}
+
+
+static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
+ size_t *out_len)
+{
+ u8 *msg, *end, *pos;
+
+ *out_len = 0;
+
+ msg = os_malloc(1000);
+ if (msg == NULL)
+ return NULL;
+
+ pos = msg;
+ end = msg + 1000;
+
+ if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
+ tls_write_client_finished(conn, &pos, end) < 0) {
+ os_free(msg);
+ return NULL;
+ }
+
+ *out_len = pos - msg;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
+ "successfully");
+ conn->state = ESTABLISHED;
+
+ return msg;
+}
+
+
+u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,
+ int no_appl_data)
+{
+ switch (conn->state) {
+ case CLIENT_KEY_EXCHANGE:
+ return tls_send_client_key_exchange(conn, out_len);
+ case CHANGE_CIPHER_SPEC:
+ return tls_send_change_cipher_spec(conn, out_len);
+ case ACK_FINISHED:
+ wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed "
+ "successfully");
+ conn->state = ESTABLISHED;
+ *out_len = 0;
+ if (no_appl_data) {
+ /* Need to return something to get final TLS ACK. */
+ return os_malloc(1);
+ }
+ return NULL;
+ default:
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
+ "generating reply", conn->state);
+ return NULL;
+ }
+}
+
+
+u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
+ u8 description, size_t *out_len)
+{
+ u8 *alert, *pos, *length;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
+ *out_len = 0;
+
+ alert = os_malloc(10);
+ if (alert == NULL)
+ return NULL;
+
+ pos = alert;
+
+ /* TLSPlaintext */
+ /* ContentType type */
+ *pos++ = TLS_CONTENT_TYPE_ALERT;
+ /* ProtocolVersion version */
+ WPA_PUT_BE16(pos, TLS_VERSION);
+ pos += 2;
+ /* uint16 length (to be filled) */
+ length = pos;
+ pos += 2;
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Alert */
+ /* AlertLevel level */
+ *pos++ = level;
+ /* AlertDescription description */
+ *pos++ = description;
+
+ WPA_PUT_BE16(length, pos - length - 2);
+ *out_len = pos - alert;
+
+ return alert;
+}
Modified: wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.c Sat Nov 3 08:40:37 2007
@@ -1,6 +1,6 @@
/*
- * wpa_supplicant/hostapd: TLSv1 common routines
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ * TLSv1 common routines
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,9 +15,6 @@
#include "includes.h"
#include "common.h"
-#include "md5.h"
-#include "sha1.h"
-#include "crypto.h"
#include "x509v3.h"
#include "tlsv1_common.h"
@@ -101,13 +98,38 @@
}
-static const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher)
+const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher)
{
size_t i;
for (i = 0; i < NUM_TLS_CIPHER_DATA; i++)
if (tls_ciphers[i].cipher == cipher)
return &tls_ciphers[i];
return NULL;
+}
+
+
+int tls_server_key_exchange_allowed(tls_cipher cipher)
+{
+ const struct tls_cipher_suite *suite;
+
+ /* RFC 2246, Section 7.4.3 */
+ suite = tls_get_cipher_suite(cipher);
+ if (suite == NULL)
+ return 0;
+
+ switch (suite->key_exchange) {
+ case TLS_KEY_X_DHE_DSS:
+ case TLS_KEY_X_DHE_DSS_EXPORT:
+ case TLS_KEY_X_DHE_RSA:
+ case TLS_KEY_X_DHE_RSA_EXPORT:
+ case TLS_KEY_X_DH_anon_EXPORT:
+ case TLS_KEY_X_DH_anon:
+ return 1;
+ case TLS_KEY_X_RSA_EXPORT:
+ return 1 /* FIX: public key len > 512 bits */;
+ default:
+ return 0;
+ }
}
@@ -165,388 +187,55 @@
}
-/**
- * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite
- * @rl: Pointer to TLS record layer data
- * @cipher_suite: New cipher suite
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to prepare TLS record layer for cipher suite change.
- * tlsv1_record_change_write_cipher() and
- * tlsv1_record_change_read_cipher() functions can then be used to change the
- * currently used ciphers.
- */
-int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
- u16 cipher_suite)
-{
- const struct tls_cipher_suite *suite;
- const struct tls_cipher_data *data;
-
- wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x",
- cipher_suite);
- rl->cipher_suite = cipher_suite;
-
- suite = tls_get_cipher_suite(cipher_suite);
- if (suite == NULL)
+int tls_verify_hash_init(struct tls_verify_hash *verify)
+{
+ tls_verify_hash_free(verify);
+ verify->md5_client = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+ verify->md5_server = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+ verify->md5_cert = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+ verify->sha1_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
+ verify->sha1_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
+ verify->sha1_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
+ if (verify->md5_client == NULL || verify->md5_server == NULL ||
+ verify->md5_cert == NULL || verify->sha1_client == NULL ||
+ verify->sha1_server == NULL || verify->sha1_cert == NULL) {
+ tls_verify_hash_free(verify);
return -1;
-
- if (suite->hash == TLS_HASH_MD5) {
- rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5;
- rl->hash_size = MD5_MAC_LEN;
- } else if (suite->hash == TLS_HASH_SHA) {
- rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
- rl->hash_size = SHA1_MAC_LEN;
- }
-
- data = tls_get_cipher_data(suite->cipher);
- if (data == NULL)
- return -1;
-
- rl->key_material_len = data->key_material;
- rl->iv_size = data->block_size;
- rl->cipher_alg = data->alg;
-
+ }
return 0;
}
-/**
- * tlsv1_record_change_write_cipher - TLS record layer: Change write cipher
- * @rl: Pointer to TLS record layer data
- * Returns: 0 on success (cipher changed), -1 on failure
- *
- * This function changes TLS record layer to use the new cipher suite
- * configured with tlsv1_record_set_cipher_suite() for writing.
- */
-int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
-{
- wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite "
- "0x%04x", rl->cipher_suite);
- rl->write_cipher_suite = rl->cipher_suite;
- os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN);
-
- if (rl->write_cbc) {
- crypto_cipher_deinit(rl->write_cbc);
- rl->write_cbc = NULL;
- }
- if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
- rl->write_cbc = crypto_cipher_init(rl->cipher_alg,
- rl->write_iv, rl->write_key,
- rl->key_material_len);
- if (rl->write_cbc == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
- "cipher");
- return -1;
- }
- }
-
- return 0;
-}
-
-
-/**
- * tlsv1_record_change_read_cipher - TLS record layer: Change read cipher
- * @rl: Pointer to TLS record layer data
- * Returns: 0 on success (cipher changed), -1 on failure
- *
- * This function changes TLS record layer to use the new cipher suite
- * configured with tlsv1_record_set_cipher_suite() for reading.
- */
-int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
-{
- wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
- "0x%04x", rl->cipher_suite);
- rl->read_cipher_suite = rl->cipher_suite;
- os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
-
- if (rl->read_cbc) {
- crypto_cipher_deinit(rl->read_cbc);
- rl->read_cbc = NULL;
- }
- if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
- rl->read_cbc = crypto_cipher_init(rl->cipher_alg,
- rl->read_iv, rl->read_key,
- rl->key_material_len);
- if (rl->read_cbc == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
- "cipher");
- return -1;
- }
- }
-
- return 0;
-}
-
-
-/**
- * tlsv1_record_send - TLS record layer: Send a message
- * @rl: Pointer to TLS record layer data
- * @content_type: Content type (TLS_CONTENT_TYPE_*)
- * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the
- * beginning for record layer to fill in; payload filled in after this and
- * extra space in the end for HMAC).
- * @buf_size: Maximum buf size
- * @payload_len: Length of the payload
- * @out_len: Buffer for returning the used buf length
- * Returns: 0 on success, -1 on failure
- *
- * This function fills in the TLS record layer header, adds HMAC, and encrypts
- * the data using the current write cipher.
- */
-int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
- size_t buf_size, size_t payload_len, size_t *out_len)
-{
- u8 *pos, *ct_start, *length, *payload;
- struct crypto_hash *hmac;
- size_t clen;
-
- pos = buf;
- /* ContentType type */
- ct_start = pos;
- *pos++ = content_type;
- /* ProtocolVersion version */
- WPA_PUT_BE16(pos, TLS_VERSION);
- pos += 2;
- /* uint16 length */
- length = pos;
- WPA_PUT_BE16(length, payload_len);
- pos += 2;
-
- /* opaque fragment[TLSPlaintext.length] */
- payload = pos;
- pos += payload_len;
-
- if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
- hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
- rl->hash_size);
- if (hmac == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
- "to initialize HMAC");
- return -1;
- }
- crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
- /* type + version + length + fragment */
- crypto_hash_update(hmac, ct_start, pos - ct_start);
- clen = buf + buf_size - pos;
- if (clen < rl->hash_size) {
- wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
- "enough room for MAC");
- crypto_hash_finish(hmac, NULL, NULL);
- return -1;
- }
-
- if (crypto_hash_finish(hmac, pos, &clen) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
- "to calculate HMAC");
- return -1;
- }
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
- pos, clen);
- pos += clen;
- if (rl->iv_size) {
- size_t len = pos - payload;
- size_t pad;
- pad = (len + 1) % rl->iv_size;
- if (pad)
- pad = rl->iv_size - pad;
- if (pos + pad + 1 > buf + buf_size) {
- wpa_printf(MSG_DEBUG, "TLSv1: No room for "
- "block cipher padding");
- return -1;
- }
- os_memset(pos, pad, pad + 1);
- pos += pad + 1;
- }
-
- if (crypto_cipher_encrypt(rl->write_cbc, payload,
- payload, pos - payload) < 0)
- return -1;
- }
-
- WPA_PUT_BE16(length, pos - length - 2);
- inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);
-
- *out_len = pos - buf;
-
- return 0;
-}
-
-
-/**
- * tlsv1_record_receive - TLS record layer: Process a received message
- * @rl: Pointer to TLS record layer data
- * @in_data: Received data
- * @in_len: Length of the received data
- * @out_data: Buffer for output data (must be at least as long as in_data)
- * @out_len: Set to maximum out_data length by caller; used to return the
- * length of the used data
- * @alert: Buffer for returning an alert value on failure
- * Returns: 0 on success, -1 on failure
- *
- * This function decrypts the received message, verifies HMAC and TLS record
- * layer header.
- */
-int tlsv1_record_receive(struct tlsv1_record_layer *rl,
- const u8 *in_data, size_t in_len,
- u8 *out_data, size_t *out_len, u8 *alert)
-{
- size_t i, rlen, hlen;
- u8 padlen;
- struct crypto_hash *hmac;
- u8 len[2], hash[100];
-
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
- in_data, in_len);
-
- if (in_len < TLS_RECORD_HEADER_LEN) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
- (unsigned long) in_len);
- *alert = TLS_ALERT_DECODE_ERROR;
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
- "length %d", in_data[0], in_data[1], in_data[2],
- WPA_GET_BE16(in_data + 3));
-
- if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
- in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
- in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
- in_data[0]);
- *alert = TLS_ALERT_UNEXPECTED_MESSAGE;
- return -1;
- }
-
- if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
- "%d.%d", in_data[1], in_data[2]);
- *alert = TLS_ALERT_PROTOCOL_VERSION;
- return -1;
- }
-
- rlen = WPA_GET_BE16(in_data + 3);
-
- /* TLSCiphertext must not be more than 2^14+2048 bytes */
- if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
- wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
- (unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
- *alert = TLS_ALERT_RECORD_OVERFLOW;
- return -1;
- }
-
- in_data += TLS_RECORD_HEADER_LEN;
- in_len -= TLS_RECORD_HEADER_LEN;
-
- if (rlen > in_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
- "(rlen=%lu > in_len=%lu)",
- (unsigned long) rlen, (unsigned long) in_len);
- *alert = TLS_ALERT_DECODE_ERROR;
- return -1;
- }
-
- in_len = rlen;
-
- if (*out_len < in_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
- "processing received record");
- *alert = TLS_ALERT_INTERNAL_ERROR;
- return -1;
- }
-
- os_memcpy(out_data, in_data, in_len);
- *out_len = in_len;
-
- if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
- if (crypto_cipher_decrypt(rl->read_cbc, out_data,
- out_data, in_len) < 0) {
- *alert = TLS_ALERT_DECRYPTION_FAILED;
- return -1;
- }
- if (rl->iv_size) {
- if (in_len == 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
- " (no pad)");
- *alert = TLS_ALERT_DECODE_ERROR;
- return -1;
- }
- padlen = out_data[in_len - 1];
- if (padlen >= in_len) {
- wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
- "length (%u, in_len=%lu) in "
- "received record",
- padlen, (unsigned long) in_len);
- *alert = TLS_ALERT_DECRYPTION_FAILED;
- return -1;
- }
- for (i = in_len - padlen; i < in_len; i++) {
- if (out_data[i] != padlen) {
- wpa_hexdump(MSG_DEBUG,
- "TLSv1: Invalid pad in "
- "received record",
- out_data + in_len - padlen,
- padlen);
- *alert = TLS_ALERT_DECRYPTION_FAILED;
- return -1;
- }
- }
-
- *out_len -= padlen + 1;
- }
-
- wpa_hexdump(MSG_MSGDUMP,
- "TLSv1: Record Layer - Decrypted data",
- out_data, in_len);
-
- if (*out_len < rl->hash_size) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
- "hash value");
- *alert = TLS_ALERT_INTERNAL_ERROR;
- return -1;
- }
-
- *out_len -= rl->hash_size;
-
- hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
- rl->hash_size);
- if (hmac == NULL) {
- wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
- "to initialize HMAC");
- *alert = TLS_ALERT_INTERNAL_ERROR;
- return -1;
- }
-
- crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
- /* type + version + length + fragment */
- crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
- WPA_PUT_BE16(len, *out_len);
- crypto_hash_update(hmac, len, 2);
- crypto_hash_update(hmac, out_data, *out_len);
- hlen = sizeof(hash);
- if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
- "to calculate HMAC");
- return -1;
- }
- if (hlen != rl->hash_size ||
- os_memcmp(hash, out_data + *out_len, hlen) != 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
- "received message");
- *alert = TLS_ALERT_BAD_RECORD_MAC;
- return -1;
- }
- }
-
- /* TLSCompressed must not be more than 2^14+1024 bytes */
- if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
- wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
- (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
- *alert = TLS_ALERT_RECORD_OVERFLOW;
- return -1;
- }
-
- inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
-
- return 0;
-}
+void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
+ size_t len)
+{
+ if (verify->md5_client && verify->sha1_client) {
+ crypto_hash_update(verify->md5_client, buf, len);
+ crypto_hash_update(verify->sha1_client, buf, len);
+ }
+ if (verify->md5_server && verify->sha1_server) {
+ crypto_hash_update(verify->md5_server, buf, len);
+ crypto_hash_update(verify->sha1_server, buf, len);
+ }
+ if (verify->md5_cert && verify->sha1_cert) {
+ crypto_hash_update(verify->md5_cert, buf, len);
+ crypto_hash_update(verify->sha1_cert, buf, len);
+ }
+}
+
+
+void tls_verify_hash_free(struct tls_verify_hash *verify)
+{
+ crypto_hash_finish(verify->md5_client, NULL, NULL);
+ crypto_hash_finish(verify->md5_server, NULL, NULL);
+ crypto_hash_finish(verify->md5_cert, NULL, NULL);
+ crypto_hash_finish(verify->sha1_client, NULL, NULL);
+ crypto_hash_finish(verify->sha1_server, NULL, NULL);
+ crypto_hash_finish(verify->sha1_cert, NULL, NULL);
+ verify->md5_client = NULL;
+ verify->md5_server = NULL;
+ verify->md5_cert = NULL;
+ verify->sha1_client = NULL;
+ verify->sha1_server = NULL;
+ verify->sha1_cert = NULL;
+}
Modified: wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_common.h Sat Nov 3 08:40:37 2007
@@ -1,6 +1,6 @@
/*
- * wpa_supplicant/hostapd: TLSv1 common definitions
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ * TLSv1 common definitions
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,8 +12,10 @@
* See README and COPYING for more details.
*/
-#ifndef TLSV1_COMMON
-#define TLSV1_COMMON
+#ifndef TLSV1_COMMON_H
+#define TLSV1_COMMON_H
+
+#include "crypto.h"
#define TLS_VERSION 0x0301 /* TLSv1 */
#define TLS_RANDOM_LEN 32
@@ -21,34 +23,22 @@
#define TLS_MASTER_SECRET_LEN 48
#define TLS_SESSION_ID_MAX_LEN 32
#define TLS_VERIFY_DATA_LEN 12
-#define TLS_MAX_WRITE_MAC_SECRET_LEN 20
-#define TLS_MAX_WRITE_KEY_LEN 32
-#define TLS_MAX_IV_LEN 16
-#define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \
- TLS_MAX_WRITE_KEY_LEN + TLS_MAX_IV_LEN))
-#define TLS_SEQ_NUM_LEN 8
-#define TLS_RECORD_HEADER_LEN 5
-
-/* ContentType */
-enum {
- TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20,
- TLS_CONTENT_TYPE_ALERT = 21,
- TLS_CONTENT_TYPE_HANDSHAKE = 22,
- TLS_CONTENT_TYPE_APPLICATION_DATA = 23
-};
/* HandshakeType */
enum {
TLS_HANDSHAKE_TYPE_HELLO_REQUEST = 0,
TLS_HANDSHAKE_TYPE_CLIENT_HELLO = 1,
TLS_HANDSHAKE_TYPE_SERVER_HELLO = 2,
+ TLS_HANDSHAKE_TYPE_NEW_SESSION_TICKET = 4 /* RFC 4507 */,
TLS_HANDSHAKE_TYPE_CERTIFICATE = 11,
TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE = 12,
TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST = 13,
TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE = 14,
TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY = 15,
TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE = 16,
- TLS_HANDSHAKE_TYPE_FINISHED = 20
+ TLS_HANDSHAKE_TYPE_FINISHED = 20,
+ TLS_HANDSHAKE_TYPE_CERTIFICATE_URL = 21 /* RFC 4366 */,
+ TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS = 22 /* RFC 4366 */
};
/* CipherSuite */
@@ -124,6 +114,11 @@
#define TLS_ALERT_INTERNAL_ERROR 80
#define TLS_ALERT_USER_CANCELED 90
#define TLS_ALERT_NO_RENEGOTIATION 100
+#define TLS_ALERT_UNSUPPORTED_EXTENSION 110 /* RFC 4366 */
+#define TLS_ALERT_CERTIFICATE_UNOBTAINABLE 111 /* RFC 4366 */
+#define TLS_ALERT_UNRECOGNIZED_NAME 112 /* RFC 4366 */
+#define TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE 113 /* RFC 4366 */
+#define TLS_ALERT_BAD_CERTIFICATE_HASH_VALUE 114 /* RFC 4366 */
/* ChangeCipherSpec */
enum {
@@ -131,7 +126,15 @@
};
/* TLS Extensions */
-#define TLS_EXT_PAC_OPAQUE 35
+#define TLS_EXT_SERVER_NAME 0 /* RFC 4366 */
+#define TLS_EXT_MAX_FRAGMENT_LENGTH 1 /* RFC 4366 */
+#define TLS_EXT_CLIENT_CERTIFICATE_URL 2 /* RFC 4366 */
+#define TLS_EXT_TRUSTED_CA_KEYS 3 /* RFC 4366 */
+#define TLS_EXT_TRUNCATED_HMAC 4 /* RFC 4366 */
+#define TLS_EXT_STATUS_REQUEST 5 /* RFC 4366 */
+#define TLS_EXT_SESSION_TICKET 35 /* RFC 4507 */
+
+#define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */
typedef enum {
@@ -191,43 +194,23 @@
};
-struct tlsv1_record_layer {
- u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
- u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
- u8 write_key[TLS_MAX_WRITE_KEY_LEN];
- u8 read_key[TLS_MAX_WRITE_KEY_LEN];
- u8 write_iv[TLS_MAX_IV_LEN];
- u8 read_iv[TLS_MAX_IV_LEN];
-
- size_t hash_size;
- size_t key_material_len;
- size_t iv_size; /* also block_size */
-
- enum crypto_hash_alg hash_alg;
- enum crypto_cipher_alg cipher_alg;
-
- u8 write_seq_num[TLS_SEQ_NUM_LEN];
- u8 read_seq_num[TLS_SEQ_NUM_LEN];
-
- u16 cipher_suite;
- u16 write_cipher_suite;
- u16 read_cipher_suite;
-
- struct crypto_cipher *write_cbc;
- struct crypto_cipher *read_cbc;
+struct tls_verify_hash {
+ struct crypto_hash *md5_client;
+ struct crypto_hash *sha1_client;
+ struct crypto_hash *md5_server;
+ struct crypto_hash *sha1_server;
+ struct crypto_hash *md5_cert;
+ struct crypto_hash *sha1_cert;
};
const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite);
+const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher);
+int tls_server_key_exchange_allowed(tls_cipher cipher);
int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk);
-int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
- u16 cipher_suite);
-int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl);
-int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl);
-int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
- size_t buf_size, size_t payload_len, size_t *out_len);
-int tlsv1_record_receive(struct tlsv1_record_layer *rl,
- const u8 *in_data, size_t in_len,
- u8 *out_data, size_t *out_len, u8 *alert);
+int tls_verify_hash_init(struct tls_verify_hash *verify);
+void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
+ size_t len);
+void tls_verify_hash_free(struct tls_verify_hash *verify);
#endif /* TLSV1_COMMON_H */
Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.c Sat Nov 3 08:40:37 2007
@@ -1,0 +1,422 @@
+/*
+ * TLSv1 credentials
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "base64.h"
+#include "crypto.h"
+#include "x509v3.h"
+#include "tlsv1_cred.h"
+
+
+struct tlsv1_credentials * tlsv1_cred_alloc(void)
+{
+ struct tlsv1_credentials *cred;
+ cred = os_zalloc(sizeof(*cred));
+ return cred;
+}
+
+
+void tlsv1_cred_free(struct tlsv1_credentials *cred)
+{
+ if (cred == NULL)
+ return;
+
+ x509_certificate_chain_free(cred->trusted_certs);
+ x509_certificate_chain_free(cred->cert);
+ crypto_private_key_free(cred->key);
+ os_free(cred->dh_p);
+ os_free(cred->dh_g);
+ os_free(cred);
+}
+
+
+static int tlsv1_add_cert_der(struct x509_certificate **chain,
+ const u8 *buf, size_t len)
+{
+ struct x509_certificate *cert;
+ char name[128];
+
+ cert = x509_certificate_parse(buf, len);
+ if (cert == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
+ __func__);
+ return -1;
+ }
+
+ cert->next = *chain;
+ *chain = cert;
+
+ x509_name_string(&cert->subject, name, sizeof(name));
+ wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
+
+ return 0;
+}
+
+
+static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
+static const char *pem_cert_end = "-----END CERTIFICATE-----";
+
+
+static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
+{
+ size_t i, plen;
+
+ plen = os_strlen(tag);
+ if (len < plen)
+ return NULL;
+
+ for (i = 0; i < len - plen; i++) {
+ if (os_memcmp(buf + i, tag, plen) == 0)
+ return buf + i;
+ }
+
+ return NULL;
+}
+
+
+static int tlsv1_add_cert(struct x509_certificate **chain,
+ const u8 *buf, size_t len)
+{
+ const u8 *pos, *end;
+ unsigned char *der;
+ size_t der_len;
+
+ pos = search_tag(pem_cert_begin, buf, len);
+ if (!pos) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
+ "assume DER format");
+ return tlsv1_add_cert_der(chain, buf, len);
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
+ "DER format");
+
+ while (pos) {
+ pos += os_strlen(pem_cert_begin);
+ end = search_tag(pem_cert_end, pos, buf + len - pos);
+ if (end == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
+ "certificate end tag (%s)", pem_cert_end);
+ return -1;
+ }
+
+ der = base64_decode(pos, end - pos, &der_len);
+ if (der == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
+ "certificate");
+ return -1;
+ }
+
+ if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
+ wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
+ "certificate after DER conversion");
+ os_free(der);
+ return -1;
+ }
+
+ os_free(der);
+
+ end += os_strlen(pem_cert_end);
+ pos = search_tag(pem_cert_begin, end, buf + len - end);
+ }
+
+ return 0;
+}
+
+
+static int tlsv1_set_cert_chain(struct x509_certificate **chain,
+ const char *cert, const u8 *cert_blob,
+ size_t cert_blob_len)
+{
+ if (cert_blob)
+ return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
+
+ if (cert) {
+ u8 *buf;
+ size_t len;
+ int ret;
+
+ buf = (u8 *) os_readfile(cert, &len);
+ if (buf == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
+ cert);
+ return -1;
+ }
+
+ ret = tlsv1_add_cert(chain, buf, len);
+ os_free(buf);
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_set_ca_cert - Set trusted CA certificate(s)
+ * @cred: TLSv1 credentials from tlsv1_cred_alloc()
+ * @cert: File or reference name for X.509 certificate in PEM or DER format
+ * @cert_blob: cert as inlined data or %NULL if not used
+ * @cert_blob_len: ca_cert_blob length
+ * @path: Path to CA certificates (not yet supported)
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
+ const u8 *cert_blob, size_t cert_blob_len,
+ const char *path)
+{
+ if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
+ cert_blob, cert_blob_len) < 0)
+ return -1;
+
+ if (path) {
+ /* TODO: add support for reading number of certificate files */
+ wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
+ "not yet supported");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_set_cert - Set certificate
+ * @cred: TLSv1 credentials from tlsv1_cred_alloc()
+ * @cert: File or reference name for X.509 certificate in PEM or DER format
+ * @cert_blob: cert as inlined data or %NULL if not used
+ * @cert_blob_len: cert_blob length
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
+ const u8 *cert_blob, size_t cert_blob_len)
+{
+ return tlsv1_set_cert_chain(&cred->cert, cert,
+ cert_blob, cert_blob_len);
+}
+
+
+static int tlsv1_set_key(struct tlsv1_credentials *cred,
+ const u8 *key, size_t len)
+{
+ cred->key = crypto_private_key_import(key, len);
+ if (cred->key == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * tlsv1_set_private_key - Set private key
+ * @cred: TLSv1 credentials from tlsv1_cred_alloc()
+ * @private_key: File or reference name for the key in PEM or DER format
+ * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
+ * passphrase is used.
+ * @private_key_blob: private_key as inlined data or %NULL if not used
+ * @private_key_blob_len: private_key_blob length
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_set_private_key(struct tlsv1_credentials *cred,
+ const char *private_key,
+ const char *private_key_passwd,
+ const u8 *private_key_blob,
+ size_t private_key_blob_len)
+{
+ crypto_private_key_free(cred->key);
+ cred->key = NULL;
+
+ if (private_key_blob)
+ return tlsv1_set_key(cred, private_key_blob,
+ private_key_blob_len);
+
+ if (private_key) {
+ u8 *buf;
+ size_t len;
+ int ret;
+
+ buf = (u8 *) os_readfile(private_key, &len);
+ if (buf == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
+ private_key);
+ return -1;
+ }
+
+ ret = tlsv1_set_key(cred, buf, len);
+ os_free(buf);
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
+ const u8 *dh, size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+
+ pos = dh;
+ end = dh + len;
+
+ /*
+ * DHParameter ::= SEQUENCE {
+ * prime INTEGER, -- p
+ * base INTEGER, -- g
+ * privateValueLength INTEGER OPTIONAL }
+ */
+
+ /* DHParamer ::= SEQUENCE */
+ if (asn1_get_next(pos, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
+ "valid SEQUENCE - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+
+ /* prime INTEGER */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0)
+ return -1;
+
+ if (hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
+ "class=%d tag=0x%x", hdr.class, hdr.tag);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
+ if (hdr.length == 0)
+ return -1;
+ os_free(cred->dh_p);
+ cred->dh_p = os_malloc(hdr.length);
+ if (cred->dh_p == NULL)
+ return -1;
+ os_memcpy(cred->dh_p, hdr.payload, hdr.length);
+ cred->dh_p_len = hdr.length;
+ pos = hdr.payload + hdr.length;
+
+ /* base INTEGER */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0)
+ return -1;
+
+ if (hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
+ "class=%d tag=0x%x", hdr.class, hdr.tag);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
+ if (hdr.length == 0)
+ return -1;
+ os_free(cred->dh_g);
+ cred->dh_g = os_malloc(hdr.length);
+ if (cred->dh_g == NULL)
+ return -1;
+ os_memcpy(cred->dh_g, hdr.payload, hdr.length);
+ cred->dh_g_len = hdr.length;
+
+ return 0;
+}
+
+
+static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
+static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
+
+
+static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
+ const u8 *buf, size_t len)
+{
+ const u8 *pos, *end;
+ unsigned char *der;
+ size_t der_len;
+
+ pos = search_tag(pem_dhparams_begin, buf, len);
+ if (!pos) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
+ "assume DER format");
+ return tlsv1_set_dhparams_der(cred, buf, len);
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
+ "format");
+
+ pos += os_strlen(pem_dhparams_begin);
+ end = search_tag(pem_dhparams_end, pos, buf + len - pos);
+ if (end == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
+ "tag (%s)", pem_dhparams_end);
+ return -1;
+ }
+
+ der = base64_decode(pos, end - pos, &der_len);
+ if (der == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
+ return -1;
+ }
+
+ if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
+ wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
+ "DER conversion");
+ os_free(der);
+ return -1;
+ }
+
+ os_free(der);
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_set_dhparams - Set Diffie-Hellman parameters
+ * @cred: TLSv1 credentials from tlsv1_cred_alloc()
+ * @dh_file: File or reference name for the DH params in PEM or DER format
+ * @dh_blob: DH params as inlined data or %NULL if not used
+ * @dh_blob_len: dh_blob length
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
+ const u8 *dh_blob, size_t dh_blob_len)
+{
+ if (dh_blob)
+ return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
+
+ if (dh_file) {
+ u8 *buf;
+ size_t len;
+ int ret;
+
+ buf = (u8 *) os_readfile(dh_file, &len);
+ if (buf == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
+ dh_file);
+ return -1;
+ }
+
+ ret = tlsv1_set_dhparams_blob(cred, buf, len);
+ os_free(buf);
+ return ret;
+ }
+
+ return 0;
+}
Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.h (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_cred.h Sat Nov 3 08:40:37 2007
@@ -1,0 +1,46 @@
+/*
+ * TLSv1 credentials
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef TLSV1_CRED_H
+#define TLSV1_CRED_H
+
+struct tlsv1_credentials {
+ struct x509_certificate *trusted_certs;
+ struct x509_certificate *cert;
+ struct crypto_private_key *key;
+
+ /* Diffie-Hellman parameters */
+ u8 *dh_p; /* prime */
+ size_t dh_p_len;
+ u8 *dh_g; /* generator */
+ size_t dh_g_len;
+};
+
+
+struct tlsv1_credentials * tlsv1_cred_alloc(void);
+void tlsv1_cred_free(struct tlsv1_credentials *cred);
+int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
+ const u8 *cert_blob, size_t cert_blob_len,
+ const char *path);
+int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
+ const u8 *cert_blob, size_t cert_blob_len);
+int tlsv1_set_private_key(struct tlsv1_credentials *cred,
+ const char *private_key,
+ const char *private_key_passwd,
+ const u8 *private_key_blob,
+ size_t private_key_blob_len);
+int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
+ const u8 *dh_blob, size_t dh_blob_len);
+
+#endif /* TLSV1_CRED_H */
Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.c Sat Nov 3 08:40:37 2007
@@ -1,0 +1,409 @@
+/*
+ * TLSv1 Record Protocol
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+
+
+/**
+ * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite
+ * @rl: Pointer to TLS record layer data
+ * @cipher_suite: New cipher suite
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to prepare TLS record layer for cipher suite change.
+ * tlsv1_record_change_write_cipher() and
+ * tlsv1_record_change_read_cipher() functions can then be used to change the
+ * currently used ciphers.
+ */
+int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
+ u16 cipher_suite)
+{
+ const struct tls_cipher_suite *suite;
+ const struct tls_cipher_data *data;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x",
+ cipher_suite);
+ rl->cipher_suite = cipher_suite;
+
+ suite = tls_get_cipher_suite(cipher_suite);
+ if (suite == NULL)
+ return -1;
+
+ if (suite->hash == TLS_HASH_MD5) {
+ rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5;
+ rl->hash_size = MD5_MAC_LEN;
+ } else if (suite->hash == TLS_HASH_SHA) {
+ rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
+ rl->hash_size = SHA1_MAC_LEN;
+ }
+
+ data = tls_get_cipher_data(suite->cipher);
+ if (data == NULL)
+ return -1;
+
+ rl->key_material_len = data->key_material;
+ rl->iv_size = data->block_size;
+ rl->cipher_alg = data->alg;
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_record_change_write_cipher - TLS record layer: Change write cipher
+ * @rl: Pointer to TLS record layer data
+ * Returns: 0 on success (cipher changed), -1 on failure
+ *
+ * This function changes TLS record layer to use the new cipher suite
+ * configured with tlsv1_record_set_cipher_suite() for writing.
+ */
+int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
+{
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite "
+ "0x%04x", rl->cipher_suite);
+ rl->write_cipher_suite = rl->cipher_suite;
+ os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN);
+
+ if (rl->write_cbc) {
+ crypto_cipher_deinit(rl->write_cbc);
+ rl->write_cbc = NULL;
+ }
+ if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
+ rl->write_cbc = crypto_cipher_init(rl->cipher_alg,
+ rl->write_iv, rl->write_key,
+ rl->key_material_len);
+ if (rl->write_cbc == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
+ "cipher");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_record_change_read_cipher - TLS record layer: Change read cipher
+ * @rl: Pointer to TLS record layer data
+ * Returns: 0 on success (cipher changed), -1 on failure
+ *
+ * This function changes TLS record layer to use the new cipher suite
+ * configured with tlsv1_record_set_cipher_suite() for reading.
+ */
+int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
+{
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
+ "0x%04x", rl->cipher_suite);
+ rl->read_cipher_suite = rl->cipher_suite;
+ os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
+
+ if (rl->read_cbc) {
+ crypto_cipher_deinit(rl->read_cbc);
+ rl->read_cbc = NULL;
+ }
+ if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
+ rl->read_cbc = crypto_cipher_init(rl->cipher_alg,
+ rl->read_iv, rl->read_key,
+ rl->key_material_len);
+ if (rl->read_cbc == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
+ "cipher");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_record_send - TLS record layer: Send a message
+ * @rl: Pointer to TLS record layer data
+ * @content_type: Content type (TLS_CONTENT_TYPE_*)
+ * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the
+ * beginning for record layer to fill in; payload filled in after this and
+ * extra space in the end for HMAC).
+ * @buf_size: Maximum buf size
+ * @payload_len: Length of the payload
+ * @out_len: Buffer for returning the used buf length
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function fills in the TLS record layer header, adds HMAC, and encrypts
+ * the data using the current write cipher.
+ */
+int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
+ size_t buf_size, size_t payload_len, size_t *out_len)
+{
+ u8 *pos, *ct_start, *length, *payload;
+ struct crypto_hash *hmac;
+ size_t clen;
+
+ pos = buf;
+ /* ContentType type */
+ ct_start = pos;
+ *pos++ = content_type;
+ /* ProtocolVersion version */
+ WPA_PUT_BE16(pos, TLS_VERSION);
+ pos += 2;
+ /* uint16 length */
+ length = pos;
+ WPA_PUT_BE16(length, payload_len);
+ pos += 2;
+
+ /* opaque fragment[TLSPlaintext.length] */
+ payload = pos;
+ pos += payload_len;
+
+ if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
+ hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
+ rl->hash_size);
+ if (hmac == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+ "to initialize HMAC");
+ return -1;
+ }
+ crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
+ /* type + version + length + fragment */
+ crypto_hash_update(hmac, ct_start, pos - ct_start);
+ clen = buf + buf_size - pos;
+ if (clen < rl->hash_size) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
+ "enough room for MAC");
+ crypto_hash_finish(hmac, NULL, NULL);
+ return -1;
+ }
+
+ if (crypto_hash_finish(hmac, pos, &clen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+ "to calculate HMAC");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
+ pos, clen);
+ pos += clen;
+ if (rl->iv_size) {
+ size_t len = pos - payload;
+ size_t pad;
+ pad = (len + 1) % rl->iv_size;
+ if (pad)
+ pad = rl->iv_size - pad;
+ if (pos + pad + 1 > buf + buf_size) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No room for "
+ "block cipher padding");
+ return -1;
+ }
+ os_memset(pos, pad, pad + 1);
+ pos += pad + 1;
+ }
+
+ if (crypto_cipher_encrypt(rl->write_cbc, payload,
+ payload, pos - payload) < 0)
+ return -1;
+ }
+
+ WPA_PUT_BE16(length, pos - length - 2);
+ inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);
+
+ *out_len = pos - buf;
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_record_receive - TLS record layer: Process a received message
+ * @rl: Pointer to TLS record layer data
+ * @in_data: Received data
+ * @in_len: Length of the received data
+ * @out_data: Buffer for output data (must be at least as long as in_data)
+ * @out_len: Set to maximum out_data length by caller; used to return the
+ * length of the used data
+ * @alert: Buffer for returning an alert value on failure
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function decrypts the received message, verifies HMAC and TLS record
+ * layer header.
+ */
+int tlsv1_record_receive(struct tlsv1_record_layer *rl,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t *out_len, u8 *alert)
+{
+ size_t i, rlen, hlen;
+ u8 padlen;
+ struct crypto_hash *hmac;
+ u8 len[2], hash[100];
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+ in_data, in_len);
+
+ if (in_len < TLS_RECORD_HEADER_LEN) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
+ (unsigned long) in_len);
+ *alert = TLS_ALERT_DECODE_ERROR;
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
+ "length %d", in_data[0], in_data[1], in_data[2],
+ WPA_GET_BE16(in_data + 3));
+
+ if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
+ in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
+ in_data[0] != TLS_CONTENT_TYPE_ALERT &&
+ in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
+ in_data[0]);
+ *alert = TLS_ALERT_UNEXPECTED_MESSAGE;
+ return -1;
+ }
+
+ if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
+ "%d.%d", in_data[1], in_data[2]);
+ *alert = TLS_ALERT_PROTOCOL_VERSION;
+ return -1;
+ }
+
+ rlen = WPA_GET_BE16(in_data + 3);
+
+ /* TLSCiphertext must not be more than 2^14+2048 bytes */
+ if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
+ (unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
+ *alert = TLS_ALERT_RECORD_OVERFLOW;
+ return -1;
+ }
+
+ in_data += TLS_RECORD_HEADER_LEN;
+ in_len -= TLS_RECORD_HEADER_LEN;
+
+ if (rlen > in_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
+ "(rlen=%lu > in_len=%lu)",
+ (unsigned long) rlen, (unsigned long) in_len);
+ *alert = TLS_ALERT_DECODE_ERROR;
+ return -1;
+ }
+
+ in_len = rlen;
+
+ if (*out_len < in_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
+ "processing received record");
+ *alert = TLS_ALERT_INTERNAL_ERROR;
+ return -1;
+ }
+
+ os_memcpy(out_data, in_data, in_len);
+ *out_len = in_len;
+
+ if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
+ if (crypto_cipher_decrypt(rl->read_cbc, out_data,
+ out_data, in_len) < 0) {
+ *alert = TLS_ALERT_DECRYPTION_FAILED;
+ return -1;
+ }
+ if (rl->iv_size) {
+ if (in_len == 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
+ " (no pad)");
+ *alert = TLS_ALERT_DECODE_ERROR;
+ return -1;
+ }
+ padlen = out_data[in_len - 1];
+ if (padlen >= in_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
+ "length (%u, in_len=%lu) in "
+ "received record",
+ padlen, (unsigned long) in_len);
+ *alert = TLS_ALERT_DECRYPTION_FAILED;
+ return -1;
+ }
+ for (i = in_len - padlen; i < in_len; i++) {
+ if (out_data[i] != padlen) {
+ wpa_hexdump(MSG_DEBUG,
+ "TLSv1: Invalid pad in "
+ "received record",
+ out_data + in_len - padlen,
+ padlen);
+ *alert = TLS_ALERT_DECRYPTION_FAILED;
+ return -1;
+ }
+ }
+
+ *out_len -= padlen + 1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP,
+ "TLSv1: Record Layer - Decrypted data",
+ out_data, in_len);
+
+ if (*out_len < rl->hash_size) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
+ "hash value");
+ *alert = TLS_ALERT_INTERNAL_ERROR;
+ return -1;
+ }
+
+ *out_len -= rl->hash_size;
+
+ hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
+ rl->hash_size);
+ if (hmac == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+ "to initialize HMAC");
+ *alert = TLS_ALERT_INTERNAL_ERROR;
+ return -1;
+ }
+
+ crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
+ /* type + version + length + fragment */
+ crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
+ WPA_PUT_BE16(len, *out_len);
+ crypto_hash_update(hmac, len, 2);
+ crypto_hash_update(hmac, out_data, *out_len);
+ hlen = sizeof(hash);
+ if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+ "to calculate HMAC");
+ return -1;
+ }
+ if (hlen != rl->hash_size ||
+ os_memcmp(hash, out_data + *out_len, hlen) != 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
+ "received message");
+ *alert = TLS_ALERT_BAD_RECORD_MAC;
+ return -1;
+ }
+ }
+
+ /* TLSCompressed must not be more than 2^14+1024 bytes */
+ if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
+ (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
+ *alert = TLS_ALERT_RECORD_OVERFLOW;
+ return -1;
+ }
+
+ inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
+
+ return 0;
+}
Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.h (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_record.h Sat Nov 3 08:40:37 2007
@@ -1,0 +1,74 @@
+/*
+ * TLSv1 Record Protocol
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef TLSV1_RECORD_H
+#define TLSV1_RECORD_H
+
+#include "crypto.h"
+
+#define TLS_MAX_WRITE_MAC_SECRET_LEN 20
+#define TLS_MAX_WRITE_KEY_LEN 32
+#define TLS_MAX_IV_LEN 16
+#define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \
+ TLS_MAX_WRITE_KEY_LEN + TLS_MAX_IV_LEN))
+
+#define TLS_SEQ_NUM_LEN 8
+#define TLS_RECORD_HEADER_LEN 5
+
+/* ContentType */
+enum {
+ TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20,
+ TLS_CONTENT_TYPE_ALERT = 21,
+ TLS_CONTENT_TYPE_HANDSHAKE = 22,
+ TLS_CONTENT_TYPE_APPLICATION_DATA = 23
+};
+
+struct tlsv1_record_layer {
+ u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
+ u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
+ u8 write_key[TLS_MAX_WRITE_KEY_LEN];
+ u8 read_key[TLS_MAX_WRITE_KEY_LEN];
+ u8 write_iv[TLS_MAX_IV_LEN];
+ u8 read_iv[TLS_MAX_IV_LEN];
+
+ size_t hash_size;
+ size_t key_material_len;
+ size_t iv_size; /* also block_size */
+
+ enum crypto_hash_alg hash_alg;
+ enum crypto_cipher_alg cipher_alg;
+
+ u8 write_seq_num[TLS_SEQ_NUM_LEN];
+ u8 read_seq_num[TLS_SEQ_NUM_LEN];
+
+ u16 cipher_suite;
+ u16 write_cipher_suite;
+ u16 read_cipher_suite;
+
+ struct crypto_cipher *write_cbc;
+ struct crypto_cipher *read_cbc;
+};
+
+
+int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
+ u16 cipher_suite);
+int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl);
+int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl);
+int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
+ size_t buf_size, size_t payload_len, size_t *out_len);
+int tlsv1_record_receive(struct tlsv1_record_layer *rl,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t *out_len, u8 *alert);
+
+#endif /* TLSV1_RECORD_H */
Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.c Sat Nov 3 08:40:37 2007
@@ -1,0 +1,596 @@
+/*
+ * TLSv1 server (RFC 2246)
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "tls.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_server.h"
+#include "tlsv1_server_i.h"
+
+/* TODO:
+ * Support for a message fragmented across several records (RFC 2246, 6.2.1)
+ */
+
+
+void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)
+{
+ conn->alert_level = level;
+ conn->alert_description = description;
+}
+
+
+int tlsv1_server_derive_keys(struct tlsv1_server *conn,
+ const u8 *pre_master_secret,
+ size_t pre_master_secret_len)
+{
+ u8 seed[2 * TLS_RANDOM_LEN];
+ u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
+ u8 *pos;
+ size_t key_block_len;
+
+ if (pre_master_secret) {
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
+ pre_master_secret, pre_master_secret_len);
+ os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
+ os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
+ TLS_RANDOM_LEN);
+ if (tls_prf(pre_master_secret, pre_master_secret_len,
+ "master secret", seed, 2 * TLS_RANDOM_LEN,
+ conn->master_secret, TLS_MASTER_SECRET_LEN)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
+ "master_secret");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
+ conn->master_secret, TLS_MASTER_SECRET_LEN);
+ }
+
+ os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
+ os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
+ key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
+ conn->rl.iv_size);
+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ "key expansion", seed, 2 * TLS_RANDOM_LEN,
+ key_block, key_block_len)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
+ key_block, key_block_len);
+
+ pos = key_block;
+
+ /* client_write_MAC_secret */
+ os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
+ pos += conn->rl.hash_size;
+ /* server_write_MAC_secret */
+ os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
+ pos += conn->rl.hash_size;
+
+ /* client_write_key */
+ os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
+ pos += conn->rl.key_material_len;
+ /* server_write_key */
+ os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
+ pos += conn->rl.key_material_len;
+
+ /* client_write_IV */
+ os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
+ pos += conn->rl.iv_size;
+ /* server_write_IV */
+ os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
+ pos += conn->rl.iv_size;
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_server_handshake - Process TLS handshake
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @in_data: Input data from TLS peer
+ * @in_len: Input data length
+ * @out_len: Length of the output buffer.
+ * Returns: Pointer to output data, %NULL on failure
+ */
+u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
+ const u8 *in_data, size_t in_len,
+ size_t *out_len)
+{
+ const u8 *pos, *end;
+ u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
+ size_t in_msg_len;
+
+ if (in_data == NULL || in_len == 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No input data to server");
+ return NULL;
+ }
+
+ pos = in_data;
+ end = in_data + in_len;
+ in_msg = os_malloc(in_len);
+ if (in_msg == NULL)
+ return NULL;
+
+ /* Each received packet may include multiple records */
+ while (pos < end) {
+ in_msg_len = in_len;
+ if (tlsv1_record_receive(&conn->rl, pos, end - pos,
+ in_msg, &in_msg_len, &alert)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
+ "record failed");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ goto failed;
+ }
+ ct = pos[0];
+
+ in_pos = in_msg;
+ in_end = in_msg + in_msg_len;
+
+ /* Each received record may include multiple messages of the
+ * same ContentType. */
+ while (in_pos < in_end) {
+ in_msg_len = in_end - in_pos;
+ if (tlsv1_server_process_handshake(conn, ct, in_pos,
+ &in_msg_len) < 0)
+ goto failed;
+ in_pos += in_msg_len;
+ }
+
+ pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+ }
+
+ os_free(in_msg);
+ in_msg = NULL;
+
+ msg = tlsv1_server_handshake_write(conn, out_len);
+
+failed:
+ os_free(in_msg);
+ if (conn->alert_level) {
+ if (conn->state == FAILED) {
+ /* Avoid alert loops */
+ wpa_printf(MSG_DEBUG, "TLSv1: Drop alert loop");
+ os_free(msg);
+ return NULL;
+ }
+ conn->state = FAILED;
+ os_free(msg);
+ msg = tlsv1_server_send_alert(conn, conn->alert_level,
+ conn->alert_description,
+ out_len);
+ }
+
+ return msg;
+}
+
+
+/**
+ * tlsv1_server_encrypt - Encrypt data into TLS tunnel
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @in_data: Pointer to plaintext data to be encrypted
+ * @in_len: Input buffer length
+ * @out_data: Pointer to output buffer (encrypted TLS data)
+ * @out_len: Maximum out_data length
+ * Returns: Number of bytes written to out_data, -1 on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * send data in the encrypted tunnel.
+ */
+int tlsv1_server_encrypt(struct tlsv1_server *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len)
+{
+ size_t rlen;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
+ in_data, in_len);
+
+ os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
+ out_data, out_len, in_len, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ return rlen;
+}
+
+
+/**
+ * tlsv1_server_decrypt - Decrypt data from TLS tunnel
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @in_data: Pointer to input buffer (encrypted TLS data)
+ * @in_len: Input buffer length
+ * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
+ * @out_len: Maximum out_data length
+ * Returns: Number of bytes written to out_data, -1 on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * receive data from the encrypted tunnel.
+ */
+int tlsv1_server_decrypt(struct tlsv1_server *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len)
+{
+ const u8 *in_end, *pos;
+ int res;
+ u8 alert, *out_end, *out_pos;
+ size_t olen;
+
+ pos = in_data;
+ in_end = in_data + in_len;
+ out_pos = out_data;
+ out_end = out_data + out_len;
+
+ while (pos < in_end) {
+ if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
+ "0x%x", pos[0]);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ olen = out_end - out_pos;
+ res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+ out_pos, &olen, &alert);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
+ "failed");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ return -1;
+ }
+ out_pos += olen;
+ if (out_pos > out_end) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
+ "for processing the received record");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+ }
+
+ return out_pos - out_data;
+}
+
+
+/**
+ * tlsv1_server_global_init - Initialize TLSv1 server
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function must be called before using any other TLSv1 server functions.
+ */
+int tlsv1_server_global_init(void)
+{
+ return crypto_global_init();
+}
+
+
+/**
+ * tlsv1_server_global_deinit - Deinitialize TLSv1 server
+ *
+ * This function can be used to deinitialize the TLSv1 server that was
+ * initialized by calling tlsv1_server_global_init(). No TLSv1 server functions
+ * can be called after this before calling tlsv1_server_global_init() again.
+ */
+void tlsv1_server_global_deinit(void)
+{
+ crypto_global_deinit();
+}
+
+
+/**
+ * tlsv1_server_init - Initialize TLSv1 server connection
+ * @cred: Pointer to server credentials from tlsv1_server_cred_alloc()
+ * Returns: Pointer to TLSv1 server connection data or %NULL on failure
+ */
+struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
+{
+ struct tlsv1_server *conn;
+ size_t count;
+ u16 *suites;
+
+ conn = os_zalloc(sizeof(*conn));
+ if (conn == NULL)
+ return NULL;
+
+ conn->cred = cred;
+
+ conn->state = CLIENT_HELLO;
+
+ if (tls_verify_hash_init(&conn->verify) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
+ "hash");
+ os_free(conn);
+ return NULL;
+ }
+
+ count = 0;
+ suites = conn->cipher_suites;
+#ifndef CONFIG_CRYPTO_INTERNAL
+ suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+#endif /* CONFIG_CRYPTO_INTERNAL */
+ suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+ suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+ suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
+ suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
+ conn->num_cipher_suites = count;
+
+ return conn;
+}
+
+
+static void tlsv1_server_clear_data(struct tlsv1_server *conn)
+{
+ tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
+ tlsv1_record_change_write_cipher(&conn->rl);
+ tlsv1_record_change_read_cipher(&conn->rl);
+ tls_verify_hash_free(&conn->verify);
+
+ crypto_public_key_free(conn->client_rsa_key);
+ conn->client_rsa_key = NULL;
+
+ os_free(conn->session_ticket);
+ conn->session_ticket = NULL;
+ conn->session_ticket_len = 0;
+ conn->use_session_ticket = 0;
+
+ os_free(conn->dh_secret);
+ conn->dh_secret = NULL;
+ conn->dh_secret_len = 0;
+}
+
+
+/**
+ * tlsv1_server_deinit - Deinitialize TLSv1 server connection
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ */
+void tlsv1_server_deinit(struct tlsv1_server *conn)
+{
+ tlsv1_server_clear_data(conn);
+ os_free(conn);
+}
+
+
+/**
+ * tlsv1_server_established - Check whether connection has been established
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * Returns: 1 if connection is established, 0 if not
+ */
+int tlsv1_server_established(struct tlsv1_server *conn)
+{
+ return conn->state == ESTABLISHED;
+}
+
+
+/**
+ * tlsv1_server_prf - Use TLS-PRF to derive keying material
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @label: Label (e.g., description of the key) for PRF
+ * @server_random_first: seed is 0 = client_random|server_random,
+ * 1 = server_random|client_random
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
+ int server_random_first, u8 *out, size_t out_len)
+{
+ u8 seed[2 * TLS_RANDOM_LEN];
+
+ if (conn->state != ESTABLISHED)
+ return -1;
+
+ if (server_random_first) {
+ os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
+ os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
+ TLS_RANDOM_LEN);
+ } else {
+ os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
+ os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
+ TLS_RANDOM_LEN);
+ }
+
+ return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
+}
+
+
+/**
+ * tlsv1_server_get_cipher - Get current cipher name
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @buf: Buffer for the cipher name
+ * @buflen: buf size
+ * Returns: 0 on success, -1 on failure
+ *
+ * Get the name of the currently used cipher.
+ */
+int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
+ size_t buflen)
+{
+ char *cipher;
+
+ switch (conn->rl.cipher_suite) {
+ case TLS_RSA_WITH_RC4_128_MD5:
+ cipher = "RC4-MD5";
+ break;
+ case TLS_RSA_WITH_RC4_128_SHA:
+ cipher = "RC4-SHA";
+ break;
+ case TLS_RSA_WITH_DES_CBC_SHA:
+ cipher = "DES-CBC-SHA";
+ break;
+ case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ cipher = "DES-CBC3-SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA:
+ cipher = "ADH-AES-128-SHA";
+ break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA:
+ cipher = "AES-256-SHA";
+ break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ cipher = "AES-128-SHA";
+ break;
+ default:
+ return -1;
+ }
+
+ if (os_strlcpy(buf, cipher, buflen) >= buflen)
+ return -1;
+ return 0;
+}
+
+
+/**
+ * tlsv1_server_shutdown - Shutdown TLS connection
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_server_shutdown(struct tlsv1_server *conn)
+{
+ conn->state = CLIENT_HELLO;
+
+ if (tls_verify_hash_init(&conn->verify) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
+ "hash");
+ return -1;
+ }
+
+ tlsv1_server_clear_data(conn);
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_server_resumed - Was session resumption used
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * Returns: 1 if current session used session resumption, 0 if not
+ */
+int tlsv1_server_resumed(struct tlsv1_server *conn)
+{
+ return 0;
+}
+
+
+/**
+ * tlsv1_server_get_keys - Get master key and random data from TLS connection
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @keys: Structure of key/random data (filled on success)
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys)
+{
+ os_memset(keys, 0, sizeof(*keys));
+ if (conn->state == CLIENT_HELLO)
+ return -1;
+
+ keys->client_random = conn->client_random;
+ keys->client_random_len = TLS_RANDOM_LEN;
+
+ if (conn->state != SERVER_HELLO) {
+ keys->server_random = conn->server_random;
+ keys->server_random_len = TLS_RANDOM_LEN;
+ keys->master_key = conn->master_secret;
+ keys->master_key_len = TLS_MASTER_SECRET_LEN;
+ }
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_server_get_keyblock_size - Get TLS key_block size
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * Returns: Size of the key_block for the negotiated cipher suite or -1 on
+ * failure
+ */
+int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn)
+{
+ if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
+ return -1;
+
+ return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
+ conn->rl.iv_size);
+}
+
+
+/**
+ * tlsv1_server_set_cipher_list - Configure acceptable cipher suites
+ * @conn: TLSv1 server connection data from tlsv1_server_init()
+ * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
+ * (TLS_CIPHER_*).
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers)
+{
+#ifdef EAP_FAST
+ size_t count;
+ u16 *suites;
+
+ /* TODO: implement proper configuration of cipher suites */
+ if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
+ count = 0;
+ suites = conn->cipher_suites;
+#ifndef CONFIG_CRYPTO_INTERNAL
+ suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+#endif /* CONFIG_CRYPTO_INTERNAL */
+ suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+ suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+ suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
+ suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
+#ifndef CONFIG_CRYPTO_INTERNAL
+ suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
+#endif /* CONFIG_CRYPTO_INTERNAL */
+ suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
+ suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
+ suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
+ suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
+ conn->num_cipher_suites = count;
+ }
+
+ return 0;
+#else /* EAP_FAST */
+ return -1;
+#endif /* EAP_FAST */
+}
+
+
+int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer)
+{
+ conn->verify_peer = verify_peer;
+ return 0;
+}
+
+
+void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
+ tlsv1_server_session_ticket_cb cb,
+ void *ctx)
+{
+ wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
+ cb, ctx);
+ conn->session_ticket_cb = cb;
+ conn->session_ticket_cb_ctx = ctx;
+}
Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.h (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_server.h Sat Nov 3 08:40:37 2007
@@ -1,0 +1,54 @@
+/*
+ * TLSv1 server (RFC 2246)
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef TLSV1_SERVER_H
+#define TLSV1_SERVER_H
+
+#include "tlsv1_cred.h"
+
+struct tlsv1_server;
+
+int tlsv1_server_global_init(void);
+void tlsv1_server_global_deinit(void);
+struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred);
+void tlsv1_server_deinit(struct tlsv1_server *conn);
+int tlsv1_server_established(struct tlsv1_server *conn);
+int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
+ int server_random_first, u8 *out, size_t out_len);
+u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
+ const u8 *in_data, size_t in_len, size_t *out_len);
+int tlsv1_server_encrypt(struct tlsv1_server *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len);
+int tlsv1_server_decrypt(struct tlsv1_server *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len);
+int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
+ size_t buflen);
+int tlsv1_server_shutdown(struct tlsv1_server *conn);
+int tlsv1_server_resumed(struct tlsv1_server *conn);
+int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys);
+int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn);
+int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers);
+int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer);
+
+typedef int (*tlsv1_server_session_ticket_cb)
+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
+ const u8 *server_random, u8 *master_secret);
+
+void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
+ tlsv1_server_session_ticket_cb cb,
+ void *ctx);
+
+#endif /* TLSV1_SERVER_H */
Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_i.h?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_i.h (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_i.h Sat Nov 3 08:40:37 2007
@@ -1,0 +1,77 @@
+/*
+ * TLSv1 server - internal structures
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef TLSV1_SERVER_I_H
+#define TLSV1_SERVER_I_H
+
+struct tlsv1_server {
+ enum {
+ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,
+ SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,
+ SERVER_HELLO_DONE, CLIENT_CERTIFICATE, CLIENT_KEY_EXCHANGE,
+ CERTIFICATE_VERIFY, CHANGE_CIPHER_SPEC, CLIENT_FINISHED,
+ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED,
+ ESTABLISHED, FAILED
+ } state;
+
+ struct tlsv1_record_layer rl;
+
+ u8 session_id[TLS_SESSION_ID_MAX_LEN];
+ size_t session_id_len;
+ u8 client_random[TLS_RANDOM_LEN];
+ u8 server_random[TLS_RANDOM_LEN];
+ u8 master_secret[TLS_MASTER_SECRET_LEN];
+
+ u8 alert_level;
+ u8 alert_description;
+
+ struct crypto_public_key *client_rsa_key;
+
+ struct tls_verify_hash verify;
+
+#define MAX_CIPHER_COUNT 30
+ u16 cipher_suites[MAX_CIPHER_COUNT];
+ size_t num_cipher_suites;
+
+ u16 cipher_suite;
+
+ struct tlsv1_credentials *cred;
+
+ int verify_peer;
+ u16 client_version;
+
+ u8 *session_ticket;
+ size_t session_ticket_len;
+
+ tlsv1_server_session_ticket_cb session_ticket_cb;
+ void *session_ticket_cb_ctx;
+
+ int use_session_ticket;
+
+ u8 *dh_secret;
+ size_t dh_secret_len;
+};
+
+
+void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description);
+int tlsv1_server_derive_keys(struct tlsv1_server *conn,
+ const u8 *pre_master_secret,
+ size_t pre_master_secret_len);
+u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len);
+u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
+ u8 description, size_t *out_len);
+int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
+ const u8 *buf, size_t *len);
+
+#endif /* TLSV1_SERVER_I_H */
Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_read.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_read.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_read.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_read.c Sat Nov 3 08:40:37 2007
@@ -1,0 +1,1132 @@
+/*
+ * TLSv1 server - read handshake message
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "x509v3.h"
+#include "tls.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_server.h"
+#include "tlsv1_server_i.h"
+
+
+static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
+ const u8 *in_data, size_t *in_len);
+static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
+ u8 ct, const u8 *in_data,
+ size_t *in_len);
+
+
+static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end, *c;
+ size_t left, len, i, j;
+ u16 cipher_suite;
+ u16 num_suites;
+ int compr_null_found;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4)
+ goto decode_error;
+
+ /* HandshakeType msg_type */
+ if (*pos != TLS_HANDSHAKE_TYPE_CLIENT_HELLO) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected ClientHello)", *pos);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "TLSv1: Received ClientHello");
+ pos++;
+ /* uint24 length */
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left)
+ goto decode_error;
+
+ /* body - ClientHello */
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello", pos, len);
+ end = pos + len;
+
+ /* ProtocolVersion client_version */
+ if (end - pos < 2)
+ goto decode_error;
+ conn->client_version = WPA_GET_BE16(pos);
+ wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
+ conn->client_version >> 8, conn->client_version & 0xff);
+ if (conn->client_version < TLS_VERSION) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
+ "ClientHello");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_PROTOCOL_VERSION);
+ return -1;
+ }
+ pos += 2;
+
+ /* Random random */
+ if (end - pos < TLS_RANDOM_LEN)
+ goto decode_error;
+
+ os_memcpy(conn->client_random, pos, TLS_RANDOM_LEN);
+ pos += TLS_RANDOM_LEN;
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
+ conn->client_random, TLS_RANDOM_LEN);
+
+ /* SessionID session_id */
+ if (end - pos < 1)
+ goto decode_error;
+ if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
+ goto decode_error;
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: client session_id", pos + 1, *pos);
+ pos += 1 + *pos;
+ /* TODO: add support for session resumption */
+
+ /* CipherSuite cipher_suites<2..2^16-1> */
+ if (end - pos < 2)
+ goto decode_error;
+ num_suites = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < num_suites)
+ goto decode_error;
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: client cipher suites",
+ pos, num_suites);
+ if (num_suites & 1)
+ goto decode_error;
+ num_suites /= 2;
+
+ cipher_suite = 0;
+ for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
+ c = pos;
+ for (j = 0; j < num_suites; j++) {
+ u16 tmp = WPA_GET_BE16(c);
+ c += 2;
+ if (!cipher_suite && tmp == conn->cipher_suites[i]) {
+ cipher_suite = tmp;
+ break;
+ }
+ }
+ }
+ pos += num_suites * 2;
+ if (!cipher_suite) {
+ wpa_printf(MSG_INFO, "TLSv1: No supported cipher suite "
+ "available");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_ILLEGAL_PARAMETER);
+ return -1;
+ }
+
+ if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
+ "record layer");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ conn->cipher_suite = cipher_suite;
+
+ /* CompressionMethod compression_methods<1..2^8-1> */
+ if (end - pos < 1)
+ goto decode_error;
+ num_suites = *pos++;
+ if (end - pos < num_suites)
+ goto decode_error;
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: client compression_methods",
+ pos, num_suites);
+ compr_null_found = 0;
+ for (i = 0; i < num_suites; i++) {
+ if (*pos++ == TLS_COMPRESSION_NULL)
+ compr_null_found = 1;
+ }
+ if (!compr_null_found) {
+ wpa_printf(MSG_INFO, "TLSv1: Client does not accept NULL "
+ "compression");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_ILLEGAL_PARAMETER);
+ return -1;
+ }
+
+ if (end - pos == 1) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected extra octet in the "
+ "end of ClientHello: 0x%02x", *pos);
+ goto decode_error;
+ }
+
+ if (end - pos >= 2) {
+ u16 ext_len;
+
+ /* Extension client_hello_extension_list<0..2^16-1> */
+
+ ext_len = WPA_GET_BE16(pos);
+ pos += 2;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: %u bytes of ClientHello "
+ "extensions", ext_len);
+ if (end - pos != ext_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello "
+ "extension list length %u (expected %u)",
+ ext_len, end - pos);
+ goto decode_error;
+ }
+
+ /*
+ * struct {
+ * ExtensionType extension_type (0..65535)
+ * opaque extension_data<0..2^16-1>
+ * } Extension;
+ */
+
+ while (pos < end) {
+ u16 ext_type, ext_len;
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
+ "extension_type field");
+ goto decode_error;
+ }
+
+ ext_type = WPA_GET_BE16(pos);
+ pos += 2;
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
+ "extension_data length field");
+ goto decode_error;
+ }
+
+ ext_len = WPA_GET_BE16(pos);
+ pos += 2;
+
+ if (end - pos < ext_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
+ "extension_data field");
+ goto decode_error;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: ClientHello Extension "
+ "type %u", ext_type);
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientHello "
+ "Extension data", pos, ext_len);
+
+ if (ext_type == TLS_EXT_SESSION_TICKET) {
+ os_free(conn->session_ticket);
+ conn->session_ticket = os_malloc(ext_len);
+ if (conn->session_ticket) {
+ os_memcpy(conn->session_ticket, pos,
+ ext_len);
+ conn->session_ticket_len = ext_len;
+ }
+ }
+
+ pos += ext_len;
+ }
+ }
+
+ *in_len = end - in_data;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: ClientHello OK - proceed to "
+ "ServerHello");
+ conn->state = SERVER_HELLO;
+
+ return 0;
+
+decode_error:
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ClientHello");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+}
+
+
+static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len, list_len, cert_len, idx;
+ u8 type;
+ struct x509_certificate *chain = NULL, *last = NULL, *cert;
+ int reason;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
+ "(len=%lu)", (unsigned long) left);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
+ "length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ if (type == TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
+ if (conn->verify_peer) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
+ "Certificate");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ return tls_process_client_key_exchange(conn, ct, in_data,
+ in_len);
+ }
+ if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected Certificate/"
+ "ClientKeyExchange)", type);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Received Certificate (certificate_list len %lu)",
+ (unsigned long) len);
+
+ /*
+ * opaque ASN.1Cert<2^24-1>;
+ *
+ * struct {
+ * ASN.1Cert certificate_list<1..2^24-1>;
+ * } Certificate;
+ */
+
+ end = pos + len;
+
+ if (end - pos < 3) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
+ "(left=%lu)", (unsigned long) left);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ list_len = WPA_GET_BE24(pos);
+ pos += 3;
+
+ if ((size_t) (end - pos) != list_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
+ "length (len=%lu left=%lu)",
+ (unsigned long) list_len,
+ (unsigned long) (end - pos));
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ idx = 0;
+ while (pos < end) {
+ if (end - pos < 3) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+ "certificate_list");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ cert_len = WPA_GET_BE24(pos);
+ pos += 3;
+
+ if ((size_t) (end - pos) < cert_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
+ "length (len=%lu left=%lu)",
+ (unsigned long) cert_len,
+ (unsigned long) (end - pos));
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
+ (unsigned long) idx, (unsigned long) cert_len);
+
+ if (idx == 0) {
+ crypto_public_key_free(conn->client_rsa_key);
+ if (tls_parse_cert(pos, cert_len,
+ &conn->client_rsa_key)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+ "the certificate");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+ }
+
+ cert = x509_certificate_parse(pos, cert_len);
+ if (cert == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+ "the certificate");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ if (last == NULL)
+ chain = cert;
+ else
+ last->next = cert;
+ last = cert;
+
+ idx++;
+ pos += cert_len;
+ }
+
+ if (x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
+ &reason) < 0) {
+ int tls_reason;
+ wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
+ "validation failed (reason=%d)", reason);
+ switch (reason) {
+ case X509_VALIDATE_BAD_CERTIFICATE:
+ tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+ break;
+ case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
+ tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
+ break;
+ case X509_VALIDATE_CERTIFICATE_REVOKED:
+ tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
+ break;
+ case X509_VALIDATE_CERTIFICATE_EXPIRED:
+ tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
+ break;
+ case X509_VALIDATE_CERTIFICATE_UNKNOWN:
+ tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
+ break;
+ case X509_VALIDATE_UNKNOWN_CA:
+ tls_reason = TLS_ALERT_UNKNOWN_CA;
+ break;
+ default:
+ tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+ break;
+ }
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ x509_certificate_chain_free(chain);
+
+ *in_len = end - in_data;
+
+ conn->state = CLIENT_KEY_EXCHANGE;
+
+ return 0;
+}
+
+
+static int tls_process_client_key_exchange_rsa(
+ struct tlsv1_server *conn, const u8 *pos, const u8 *end)
+{
+ u8 *out;
+ size_t outlen, outbuflen;
+ u16 encr_len;
+ int res;
+ int use_random = 0;
+
+ if (end - pos < 2) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ encr_len = WPA_GET_BE16(pos);
+ pos += 2;
+
+ outbuflen = outlen = end - pos;
+ out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ?
+ outlen : TLS_PRE_MASTER_SECRET_LEN);
+ if (out == NULL) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /*
+ * struct {
+ * ProtocolVersion client_version;
+ * opaque random[46];
+ * } PreMasterSecret;
+ *
+ * struct {
+ * public-key-encrypted PreMasterSecret pre_master_secret;
+ * } EncryptedPreMasterSecret;
+ */
+
+ /*
+ * Note: To avoid Bleichenbacher attack, we do not report decryption or
+ * parsing errors from EncryptedPreMasterSecret processing to the
+ * client. Instead, a random pre-master secret is used to force the
+ * handshake to fail.
+ */
+
+ if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key,
+ pos, end - pos,
+ out, &outlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
+ "PreMasterSecret (encr_len=%d outlen=%lu)",
+ end - pos, (unsigned long) outlen);
+ use_random = 1;
+ }
+
+ if (outlen != TLS_PRE_MASTER_SECRET_LEN) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
+ "length %lu", (unsigned long) outlen);
+ use_random = 1;
+ }
+
+ if (WPA_GET_BE16(out) != conn->client_version) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
+ "ClientKeyExchange does not match with version in "
+ "ClientHello");
+ use_random = 1;
+ }
+
+ if (use_random) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Using random premaster secret "
+ "to avoid revealing information about private key");
+ outlen = TLS_PRE_MASTER_SECRET_LEN;
+ if (os_get_random(out, outlen)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
+ "data");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(out);
+ return -1;
+ }
+ }
+
+ res = tlsv1_server_derive_keys(conn, out, outlen);
+
+ /* Clear the pre-master secret since it is not needed anymore */
+ os_memset(out, 0, outbuflen);
+ os_free(out);
+
+ if (res) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int tls_process_client_key_exchange_dh_anon(
+ struct tlsv1_server *conn, const u8 *pos, const u8 *end)
+{
+ const u8 *dh_yc;
+ u16 dh_yc_len;
+ u8 *shared;
+ size_t shared_len;
+ int res;
+
+ /*
+ * struct {
+ * select (PublicValueEncoding) {
+ * case implicit: struct { };
+ * case explicit: opaque dh_Yc<1..2^16-1>;
+ * } dh_public;
+ * } ClientDiffieHellmanPublic;
+ */
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ClientDiffieHellmanPublic",
+ pos, end - pos);
+
+ if (end == pos) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Implicit public value encoding "
+ "not supported");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ if (end - pos < 3) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid client public value "
+ "length");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ dh_yc_len = WPA_GET_BE16(pos);
+ dh_yc = pos + 2;
+
+ if (dh_yc + dh_yc_len > end) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Client public value overflow "
+ "(length %d)", dh_yc_len);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
+ dh_yc, dh_yc_len);
+
+ if (conn->cred == NULL || conn->cred->dh_p == NULL ||
+ conn->dh_secret == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ shared_len = conn->cred->dh_p_len;
+ shared = os_malloc(shared_len);
+ if (shared == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
+ "DH");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /* shared = Yc^secret mod p */
+ crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret, conn->dh_secret_len,
+ conn->cred->dh_p, conn->cred->dh_p_len,
+ shared, &shared_len);
+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
+ shared, shared_len);
+
+ os_memset(conn->dh_secret, 0, conn->dh_secret_len);
+ os_free(conn->dh_secret);
+ conn->dh_secret = NULL;
+
+ res = tlsv1_server_derive_keys(conn, shared, shared_len);
+
+ /* Clear the pre-master secret since it is not needed anymore */
+ os_memset(shared, 0, shared_len);
+ os_free(shared);
+
+ if (res) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int tls_process_client_key_exchange(struct tlsv1_server *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len;
+ u8 type;
+ tls_key_exchange keyx;
+ const struct tls_cipher_suite *suite;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short ClientKeyExchange "
+ "(Left=%lu)", (unsigned long) left);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ClientKeyExchange "
+ "length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ end = pos + len;
+
+ if (type != TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected ClientKeyExchange)", type);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received ClientKeyExchange");
+
+ wpa_hexdump(MSG_DEBUG, "TLSv1: ClientKeyExchange", pos, len);
+
+ suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+ if (suite == NULL)
+ keyx = TLS_KEY_X_NULL;
+ else
+ keyx = suite->key_exchange;
+
+ if (keyx == TLS_KEY_X_DH_anon &&
+ tls_process_client_key_exchange_dh_anon(conn, pos, end) < 0)
+ return -1;
+
+ if (keyx != TLS_KEY_X_DH_anon &&
+ tls_process_client_key_exchange_rsa(conn, pos, end) < 0)
+ return -1;
+
+ *in_len = end - in_data;
+
+ conn->state = CERTIFICATE_VERIFY;
+
+ return 0;
+}
+
+
+static int tls_process_certificate_verify(struct tlsv1_server *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len;
+ u8 type;
+ size_t hlen, buflen;
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos, *buf;
+ enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
+ u16 slen;
+
+ if (ct == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
+ if (conn->verify_peer) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Client did not include "
+ "CertificateVerify");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ return tls_process_change_cipher_spec(conn, ct, in_data,
+ in_len);
+ }
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateVerify "
+ "message (len=%lu)", (unsigned long) left);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected CertificateVerify "
+ "message length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ end = pos + len;
+
+ if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected CertificateVerify)", type);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateVerify");
+
+ /*
+ * struct {
+ * Signature signature;
+ * } CertificateVerify;
+ */
+
+ hpos = hash;
+
+ if (alg == SIGN_ALG_RSA) {
+ hlen = MD5_MAC_LEN;
+ if (conn->verify.md5_cert == NULL ||
+ crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
+ {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.md5_cert = NULL;
+ crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
+ conn->verify.sha1_cert = NULL;
+ return -1;
+ }
+ hpos += MD5_MAC_LEN;
+ } else
+ crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
+
+ conn->verify.md5_cert = NULL;
+ hlen = SHA1_MAC_LEN;
+ if (conn->verify.sha1_cert == NULL ||
+ crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
+ conn->verify.sha1_cert = NULL;
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ conn->verify.sha1_cert = NULL;
+
+ if (alg == SIGN_ALG_RSA)
+ hlen += MD5_MAC_LEN;
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
+
+ if (end - pos < 2) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ slen = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < slen) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
+ if (conn->client_rsa_key == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No client public key to verify "
+ "signature");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ buflen = end - pos;
+ buf = os_malloc(end - pos);
+ if (crypto_public_key_decrypt_pkcs1(conn->client_rsa_key,
+ pos, end - pos, buf, &buflen) < 0)
+ {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
+ os_free(buf);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECRYPT_ERROR);
+ return -1;
+ }
+
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
+ buf, buflen);
+
+ if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
+ "CertificateVerify - did not match with calculated "
+ "hash");
+ os_free(buf);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECRYPT_ERROR);
+ return -1;
+ }
+
+ os_free(buf);
+
+ *in_len = end - in_data;
+
+ conn->state = CHANGE_CIPHER_SPEC;
+
+ return 0;
+}
+
+
+static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
+ u8 ct, const u8 *in_data,
+ size_t *in_len)
+{
+ const u8 *pos;
+ size_t left;
+
+ if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+ "received content type 0x%x", ct);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 1) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ if (*pos != TLS_CHANGE_CIPHER_SPEC) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+ "received data 0x%x", *pos);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
+ if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
+ "for record layer");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ *in_len = pos + 1 - in_data;
+
+ conn->state = CLIENT_FINISHED;
+
+ return 0;
+}
+
+
+static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len, hlen;
+ u8 verify_data[TLS_VERIFY_DATA_LEN];
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
+ "received content type 0x%x", ct);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
+ "Finished",
+ (unsigned long) left);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
+ "type 0x%x", pos[0]);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ len = WPA_GET_BE24(pos + 1);
+
+ pos += 4;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
+ "(len=%lu > left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ end = pos + len;
+ if (len != TLS_VERIFY_DATA_LEN) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
+ "in Finished: %lu (expected %d)",
+ (unsigned long) len, TLS_VERIFY_DATA_LEN);
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
+ pos, TLS_VERIFY_DATA_LEN);
+
+ hlen = MD5_MAC_LEN;
+ if (conn->verify.md5_client == NULL ||
+ crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.md5_client = NULL;
+ crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
+ conn->verify.sha1_client = NULL;
+ return -1;
+ }
+ conn->verify.md5_client = NULL;
+ hlen = SHA1_MAC_LEN;
+ if (conn->verify.sha1_client == NULL ||
+ crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
+ &hlen) < 0) {
+ conn->verify.sha1_client = NULL;
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ conn->verify.sha1_client = NULL;
+
+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+ verify_data, TLS_VERIFY_DATA_LEN)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECRYPT_ERROR);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
+ verify_data, TLS_VERIFY_DATA_LEN);
+
+ if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+ wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
+
+ *in_len = end - in_data;
+
+ if (conn->use_session_ticket) {
+ /* Abbreviated handshake using session ticket; RFC 4507 */
+ wpa_printf(MSG_DEBUG, "TLSv1: Abbreviated handshake completed "
+ "successfully");
+ conn->state = ESTABLISHED;
+ } else {
+ /* Full handshake */
+ conn->state = SERVER_CHANGE_CIPHER_SPEC;
+ }
+
+ return 0;
+}
+
+
+int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct,
+ const u8 *buf, size_t *len)
+{
+ if (ct == TLS_CONTENT_TYPE_ALERT) {
+ if (*len < 2) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Alert underflow");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+ buf[0], buf[1]);
+ *len = 2;
+ conn->state = FAILED;
+ return -1;
+ }
+
+ switch (conn->state) {
+ case CLIENT_HELLO:
+ if (tls_process_client_hello(conn, ct, buf, len))
+ return -1;
+ break;
+ case CLIENT_CERTIFICATE:
+ if (tls_process_certificate(conn, ct, buf, len))
+ return -1;
+ break;
+ case CLIENT_KEY_EXCHANGE:
+ if (tls_process_client_key_exchange(conn, ct, buf, len))
+ return -1;
+ break;
+ case CERTIFICATE_VERIFY:
+ if (tls_process_certificate_verify(conn, ct, buf, len))
+ return -1;
+ break;
+ case CHANGE_CIPHER_SPEC:
+ if (tls_process_change_cipher_spec(conn, ct, buf, len))
+ return -1;
+ break;
+ case CLIENT_FINISHED:
+ if (tls_process_client_finished(conn, ct, buf, len))
+ return -1;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
+ "while processing received message",
+ conn->state);
+ return -1;
+ }
+
+ if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
+ tls_verify_hash_add(&conn->verify, buf, *len);
+
+ return 0;
+}
Added: wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_write.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_write.c?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_write.c (added)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_server_write.c Sat Nov 3 08:40:37 2007
@@ -1,0 +1,785 @@
+/*
+ * TLSv1 server - write handshake message
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "x509v3.h"
+#include "tls.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_server.h"
+#include "tlsv1_server_i.h"
+
+
+static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
+{
+ size_t len = 0;
+ struct x509_certificate *cert;
+
+ cert = conn->cred->cert;
+ while (cert) {
+ len += 3 + cert->cert_len;
+ if (x509_certificate_self_signed(cert))
+ break;
+ cert = x509_certificate_get_subject(conn->cred->trusted_certs,
+ &cert->issuer);
+ }
+
+ return len;
+}
+
+
+static int tls_write_server_hello(struct tlsv1_server *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length;
+ struct os_time now;
+ size_t rlen;
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+
+ os_get_time(&now);
+ WPA_PUT_BE32(conn->server_random, now.sec);
+ if (os_get_random(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
+ wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
+ "server_random");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
+ conn->server_random, TLS_RANDOM_LEN);
+
+ conn->session_id_len = TLS_SESSION_ID_MAX_LEN;
+ if (os_get_random(conn->session_id, conn->session_id_len)) {
+ wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
+ "session_id");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
+ conn->session_id, conn->session_id_len);
+
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+ /* body - ServerHello */
+ /* ProtocolVersion server_version */
+ WPA_PUT_BE16(pos, TLS_VERSION);
+ pos += 2;
+ /* Random random: uint32 gmt_unix_time, opaque random_bytes */
+ os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
+ pos += TLS_RANDOM_LEN;
+ /* SessionID session_id */
+ *pos++ = conn->session_id_len;
+ os_memcpy(pos, conn->session_id, conn->session_id_len);
+ pos += conn->session_id_len;
+ /* CipherSuite cipher_suite */
+ WPA_PUT_BE16(pos, conn->cipher_suite);
+ pos += 2;
+ /* CompressionMethod compression_method */
+ *pos++ = TLS_COMPRESSION_NULL;
+
+ if (conn->session_ticket && conn->session_ticket_cb) {
+ int res = conn->session_ticket_cb(
+ conn->session_ticket_cb_ctx,
+ conn->session_ticket, conn->session_ticket_len,
+ conn->client_random, conn->server_random,
+ conn->master_secret);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
+ "indicated failure");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_HANDSHAKE_FAILURE);
+ return -1;
+ }
+ conn->use_session_ticket = res;
+
+ if (conn->use_session_ticket) {
+ if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
+ "derive keys");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ }
+
+ /*
+ * RFC 4507 specifies that server would include an empty
+ * SessionTicket extension in ServerHello and a
+ * NewSessionTicket message after the ServerHello. However,
+ * EAP-FAST (RFC 4851), i.e., the only user of SessionTicket
+ * extension at the moment, does not use such extensions.
+ *
+ * TODO: Add support for configuring RFC 4507 behavior and make
+ * EAP-FAST disable it.
+ */
+ }
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos = rhdr + rlen;
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static int tls_write_server_certificate(struct tlsv1_server *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
+ size_t rlen;
+ struct x509_certificate *cert;
+ const struct tls_cipher_suite *suite;
+
+ suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+ if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when "
+ "using anonymous DH");
+ return 0;
+ }
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+ /* body - Certificate */
+ /* uint24 length (to be filled) */
+ cert_start = pos;
+ pos += 3;
+ cert = conn->cred->cert;
+ while (cert) {
+ if (pos + 3 + cert->cert_len > end) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
+ "for Certificate (cert_len=%lu left=%lu)",
+ (unsigned long) cert->cert_len,
+ (unsigned long) (end - pos));
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ WPA_PUT_BE24(pos, cert->cert_len);
+ pos += 3;
+ os_memcpy(pos, cert->cert_start, cert->cert_len);
+ pos += cert->cert_len;
+
+ if (x509_certificate_self_signed(cert))
+ break;
+ cert = x509_certificate_get_subject(conn->cred->trusted_certs,
+ &cert->issuer);
+ }
+ if (cert == conn->cred->cert || cert == NULL) {
+ /*
+ * Server was not configured with all the needed certificates
+ * to form a full certificate chain. The client may fail to
+ * validate the chain unless it is configured with all the
+ * missing CA certificates.
+ */
+ wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain "
+ "not configured - validation may fail");
+ }
+ WPA_PUT_BE24(cert_start, pos - cert_start - 3);
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos = rhdr + rlen;
+
+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static int tls_write_server_key_exchange(struct tlsv1_server *conn,
+ u8 **msgpos, u8 *end)
+{
+ tls_key_exchange keyx;
+ const struct tls_cipher_suite *suite;
+ u8 *pos, *rhdr, *hs_start, *hs_length;
+ size_t rlen;
+ u8 *dh_ys;
+ size_t dh_ys_len;
+
+ suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+ if (suite == NULL)
+ keyx = TLS_KEY_X_NULL;
+ else
+ keyx = suite->key_exchange;
+
+ if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed");
+ return 0;
+ }
+
+ if (keyx != TLS_KEY_X_DH_anon) {
+ /* TODO? */
+ wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
+ "supported with key exchange type %d", keyx);
+ return -1;
+ }
+
+ if (conn->cred == NULL || conn->cred->dh_p == NULL ||
+ conn->cred->dh_g == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for "
+ "ServerKeyExhcange");
+ return -1;
+ }
+
+ os_free(conn->dh_secret);
+ conn->dh_secret_len = conn->cred->dh_p_len;
+ conn->dh_secret = os_malloc(conn->dh_secret_len);
+ if (conn->dh_secret == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+ "memory for secret (Diffie-Hellman)");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ if (os_get_random(conn->dh_secret, conn->dh_secret_len)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
+ "data for Diffie-Hellman");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(conn->dh_secret);
+ conn->dh_secret = NULL;
+ return -1;
+ }
+
+ if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) >
+ 0)
+ conn->dh_secret[0] = 0; /* make sure secret < p */
+
+ pos = conn->dh_secret;
+ while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0)
+ pos++;
+ if (pos != conn->dh_secret) {
+ os_memmove(conn->dh_secret, pos,
+ conn->dh_secret_len - (pos - conn->dh_secret));
+ conn->dh_secret_len -= pos - conn->dh_secret;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value",
+ conn->dh_secret, conn->dh_secret_len);
+
+ /* Ys = g^secret mod p */
+ dh_ys_len = conn->cred->dh_p_len;
+ dh_ys = os_malloc(dh_ys_len);
+ if (dh_ys == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
+ "Diffie-Hellman");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
+ conn->dh_secret, conn->dh_secret_len,
+ conn->cred->dh_p, conn->cred->dh_p_len,
+ dh_ys, &dh_ys_len);
+
+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
+ dh_ys, dh_ys_len);
+
+ /*
+ * struct {
+ * select (KeyExchangeAlgorithm) {
+ * case diffie_hellman:
+ * ServerDHParams params;
+ * Signature signed_params;
+ * case rsa:
+ * ServerRSAParams params;
+ * Signature signed_params;
+ * };
+ * } ServerKeyExchange;
+ *
+ * struct {
+ * opaque dh_p<1..2^16-1>;
+ * opaque dh_g<1..2^16-1>;
+ * opaque dh_Ys<1..2^16-1>;
+ * } ServerDHParams;
+ */
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange");
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+
+ /* body - ServerDHParams */
+ /* dh_p */
+ if (pos + 2 + conn->cred->dh_p_len > end) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
+ "dh_p");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(dh_ys);
+ return -1;
+ }
+ WPA_PUT_BE16(pos, conn->cred->dh_p_len);
+ pos += 2;
+ os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len);
+ pos += conn->cred->dh_p_len;
+
+ /* dh_g */
+ if (pos + 2 + conn->cred->dh_g_len > end) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
+ "dh_g");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(dh_ys);
+ return -1;
+ }
+ WPA_PUT_BE16(pos, conn->cred->dh_g_len);
+ pos += 2;
+ os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len);
+ pos += conn->cred->dh_g_len;
+
+ /* dh_Ys */
+ if (pos + 2 + dh_ys_len > end) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
+ "dh_Ys");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(dh_ys);
+ return -1;
+ }
+ WPA_PUT_BE16(pos, dh_ys_len);
+ pos += 2;
+ os_memcpy(pos, dh_ys, dh_ys_len);
+ pos += dh_ys_len;
+ os_free(dh_ys);
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos = rhdr + rlen;
+
+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static int tls_write_server_certificate_request(struct tlsv1_server *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length;
+ size_t rlen;
+
+ if (!conn->verify_peer) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed");
+ return 0;
+ }
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest");
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+ /* body - CertificateRequest */
+
+ /*
+ * enum {
+ * rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
+ * (255)
+ * } ClientCertificateType;
+ * ClientCertificateType certificate_types<1..2^8-1>
+ */
+ *pos++ = 1;
+ *pos++ = 1; /* rsa_sign */
+
+ /*
+ * opaque DistinguishedName<1..2^16-1>
+ * DistinguishedName certificate_authorities<3..2^16-1>
+ */
+ /* TODO: add support for listing DNs for trusted CAs */
+ WPA_PUT_BE16(pos, 0);
+ pos += 2;
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos = rhdr + rlen;
+
+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static int tls_write_server_hello_done(struct tlsv1_server *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length;
+ size_t rlen;
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+ /* body - ServerHelloDone (empty) */
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos = rhdr + rlen;
+
+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr;
+ size_t rlen;
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+ *pos = TLS_CHANGE_CIPHER_SPEC;
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
+ rhdr, end - rhdr, 1, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
+ "record layer");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ *msgpos = rhdr + rlen;
+
+ return 0;
+}
+
+
+static int tls_write_server_finished(struct tlsv1_server *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length;
+ size_t rlen, hlen;
+ u8 verify_data[TLS_VERIFY_DATA_LEN];
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
+
+ /* Encrypted Handshake Message: Finished */
+
+ hlen = MD5_MAC_LEN;
+ if (conn->verify.md5_server == NULL ||
+ crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify.md5_server = NULL;
+ crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
+ conn->verify.sha1_server = NULL;
+ return -1;
+ }
+ conn->verify.md5_server = NULL;
+ hlen = SHA1_MAC_LEN;
+ if (conn->verify.sha1_server == NULL ||
+ crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
+ &hlen) < 0) {
+ conn->verify.sha1_server = NULL;
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ conn->verify.sha1_server = NULL;
+
+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+ verify_data, TLS_VERIFY_DATA_LEN)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
+ verify_data, TLS_VERIFY_DATA_LEN);
+
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+ os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
+ pos += TLS_VERIFY_DATA_LEN;
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ pos = rhdr + rlen;
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
+{
+ u8 *msg, *end, *pos;
+ size_t msglen;
+
+ *out_len = 0;
+
+ msglen = 1000 + tls_server_cert_chain_der_len(conn);
+
+ msg = os_malloc(msglen);
+ if (msg == NULL)
+ return NULL;
+
+ pos = msg;
+ end = msg + msglen;
+
+ if (tls_write_server_hello(conn, &pos, end) < 0) {
+ os_free(msg);
+ return NULL;
+ }
+
+ if (conn->use_session_ticket) {
+ /* Abbreviated handshake using session ticket; RFC 4507 */
+ if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
+ tls_write_server_finished(conn, &pos, end) < 0) {
+ os_free(msg);
+ return NULL;
+ }
+
+ *out_len = pos - msg;
+
+ conn->state = CHANGE_CIPHER_SPEC;
+
+ return msg;
+ }
+
+ /* Full handshake */
+ if (tls_write_server_certificate(conn, &pos, end) < 0 ||
+ tls_write_server_key_exchange(conn, &pos, end) < 0 ||
+ tls_write_server_certificate_request(conn, &pos, end) < 0 ||
+ tls_write_server_hello_done(conn, &pos, end) < 0) {
+ os_free(msg);
+ return NULL;
+ }
+
+ *out_len = pos - msg;
+
+ conn->state = CLIENT_CERTIFICATE;
+
+ return msg;
+}
+
+
+static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
+ size_t *out_len)
+{
+ u8 *msg, *end, *pos;
+
+ *out_len = 0;
+
+ msg = os_malloc(1000);
+ if (msg == NULL)
+ return NULL;
+
+ pos = msg;
+ end = msg + 1000;
+
+ if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
+ tls_write_server_finished(conn, &pos, end) < 0) {
+ os_free(msg);
+ return NULL;
+ }
+
+ *out_len = pos - msg;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully");
+ conn->state = ESTABLISHED;
+
+ return msg;
+}
+
+
+u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
+{
+ switch (conn->state) {
+ case SERVER_HELLO:
+ return tls_send_server_hello(conn, out_len);
+ case SERVER_CHANGE_CIPHER_SPEC:
+ return tls_send_change_cipher_spec(conn, out_len);
+ default:
+ if (conn->state == ESTABLISHED && conn->use_session_ticket) {
+ /* Abbreviated handshake was already completed. */
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
+ "generating reply", conn->state);
+ return NULL;
+ }
+}
+
+
+u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
+ u8 description, size_t *out_len)
+{
+ u8 *alert, *pos, *length;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
+ *out_len = 0;
+
+ alert = os_malloc(10);
+ if (alert == NULL)
+ return NULL;
+
+ pos = alert;
+
+ /* TLSPlaintext */
+ /* ContentType type */
+ *pos++ = TLS_CONTENT_TYPE_ALERT;
+ /* ProtocolVersion version */
+ WPA_PUT_BE16(pos, TLS_VERSION);
+ pos += 2;
+ /* uint16 length (to be filled) */
+ length = pos;
+ pos += 2;
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Alert */
+ /* AlertLevel level */
+ *pos++ = level;
+ /* AlertDescription description */
+ *pos++ = description;
+
+ WPA_PUT_BE16(length, pos - length - 2);
+ *out_len = pos - alert;
+
+ return alert;
+}
Modified: wpasupplicant/branches/upstream/current/src/tls/x509v3.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/x509v3.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/x509v3.c (original)
+++ wpasupplicant/branches/upstream/current/src/tls/x509v3.c Sat Nov 3 08:40:37 2007
@@ -1,6 +1,6 @@
/*
* X.509v3 certificate parsing and processing (RFC 3280 profile)
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -75,8 +75,39 @@
}
+static int x509_whitespace(char c)
+{
+ return c == ' ' || c == '\t';
+}
+
+
+static void x509_str_strip_whitespace(char *a)
+{
+ char *ipos, *opos;
+ int remove_whitespace = 1;
+
+ ipos = opos = a;
+
+ while (*ipos) {
+ if (remove_whitespace && x509_whitespace(*ipos))
+ ipos++;
+ else {
+ remove_whitespace = x509_whitespace(*ipos);
+ *opos++ = *ipos++;
+ }
+ }
+
+ *opos-- = '\0';
+ if (opos > a && x509_whitespace(*opos))
+ *opos = '\0';
+}
+
+
static int x509_str_compare(const char *a, const char *b)
{
+ char *aa, *bb;
+ int ret;
+
if (!a && b)
return -1;
if (a && !b)
@@ -84,14 +115,31 @@
if (!a && !b)
return 0;
- return os_strcmp(a, b);
+ aa = os_strdup(a);
+ bb = os_strdup(b);
+
+ if (aa == NULL || bb == NULL) {
+ os_free(aa);
+ os_free(bb);
+ return os_strcasecmp(a, b);
+ }
+
+ x509_str_strip_whitespace(aa);
+ x509_str_strip_whitespace(bb);
+
+ ret = os_strcasecmp(aa, bb);
+
+ os_free(aa);
+ os_free(bb);
+
+ return ret;
}
/**
* x509_name_compare - Compare X.509 certificate names
* @a: Certificate name
- * @b: Certifiatte name
+ * @b: Certificate name
* Returns: <0, 0, or >0 based on whether a is less than, equal to, or
* greater than b
*/
@@ -553,6 +601,17 @@
if (os_mktime(year, month, day, hour, min, sec, val) < 0) {
wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time",
buf, len);
+ if (year < 1970) {
+ /*
+ * At least some test certificates have been configured
+ * to use dates prior to 1970. Set the date to
+ * beginning of 1970 to handle these case.
+ */
+ wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - "
+ "assume epoch as the time", year);
+ *val = 0;
+ return 0;
+ }
return -1;
}
@@ -720,7 +779,8 @@
return 0;
}
- if (asn1_get_next(pos, len, &hdr) < 0 ||
+ if (asn1_get_next(hdr.payload + hdr.length, len - hdr.length,
+ &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL) {
wpa_printf(MSG_DEBUG, "X509: Failed to parse "
"BasicConstraints");
@@ -1443,6 +1503,13 @@
return -1;
}
+ if (cert->version == X509_CERT_V3 &&
+ !(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) {
+ wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not "
+ "include BasicConstraints extension");
+ return -1;
+ }
+
if ((cert->extensions_present & X509_EXT_KEY_USAGE) &&
!(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) {
wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have "
@@ -1466,7 +1533,8 @@
struct x509_certificate *chain,
int *reason)
{
- int idx, chain_trusted = 0;
+ long unsigned idx;
+ int chain_trusted = 0;
struct x509_certificate *cert, *trust;
char buf[128];
struct os_time now;
@@ -1478,12 +1546,15 @@
for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
x509_name_string(&cert->subject, buf, sizeof(buf));
- wpa_printf(MSG_DEBUG, "X509: %d: %s", idx, buf);
+ wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
if (chain_trusted)
continue;
- if (now.sec < cert->not_before || now.sec > cert->not_after) {
+ if ((unsigned long) now.sec <
+ (unsigned long) cert->not_before ||
+ (unsigned long) now.sec >
+ (unsigned long) cert->not_after) {
wpa_printf(MSG_INFO, "X509: Certificate not valid "
"(now=%lu not_before=%lu not_after=%lu)",
now.sec, cert->not_before, cert->not_after);
@@ -1505,7 +1576,16 @@
return -1;
}
- /* TODO: validate pathLenConstraint */
+ if ((cert->next->extensions_present &
+ X509_EXT_PATH_LEN_CONSTRAINT) &&
+ idx > cert->next->path_len_constraint) {
+ wpa_printf(MSG_DEBUG, "X509: pathLenConstraint"
+ " not met (idx=%lu issuer "
+ "pathLenConstraint=%lu)", idx,
+ cert->next->path_len_constraint);
+ *reason = X509_VALIDATE_BAD_CERTIFICATE;
+ return -1;
+ }
if (x509_certificate_check_signature(cert->next, cert)
< 0) {
Modified: wpasupplicant/branches/upstream/current/src/utils/common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/common.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/common.h (original)
+++ wpasupplicant/branches/upstream/current/src/utils/common.h Sat Nov 3 08:40:37 2007
@@ -33,6 +33,24 @@
#define bswap_64 bswap64
#endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
* defined(__DragonFly__) */
+
+#ifdef __APPLE__
+#include <sys/types.h>
+#include <machine/endian.h>
+#define __BYTE_ORDER _BYTE_ORDER
+#define __LITTLE_ENDIAN _LITTLE_ENDIAN
+#define __BIG_ENDIAN _BIG_ENDIAN
+static inline unsigned short bswap_16(unsigned short v)
+{
+ return ((v & 0xff) << 8) | (v >> 8);
+}
+
+static inline unsigned int bswap_32(unsigned int v)
+{
+ return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
+ ((v & 0xff0000) >> 8) | (v >> 24);
+}
+#endif /* __APPLE__ */
#ifdef CONFIG_TI_COMPILER
#define __BIG_ENDIAN 4321
Modified: wpasupplicant/branches/upstream/current/src/utils/os_unix.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/os_unix.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/os_unix.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/os_unix.c Sat Nov 3 08:40:37 2007
@@ -175,7 +175,7 @@
int os_unsetenv(const char *name)
{
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
unsetenv(name);
return 0;
#else
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog Sat Nov 3 08:40:37 2007
@@ -1,4 +1,26 @@
ChangeLog for wpa_supplicant
+
+????-??-?? - v0.6.1
+ * added support for configuring password as NtPasswordHash
+ (16-byte MD4 hash of password) in hash:<32 hex digits> format
+ * added support for fallback from abbreviated TLS handshake to
+ full handshake when using EAP-FAST (e.g., due to an expired
+ PAC-Opaque)
+ * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+ draft (draft-ietf-emu-eap-gpsk-06.txt)
+ * added support for drivers that take care of RSN 4-way handshake
+ internally (WPA_DRIVER_FLAGS_4WAY_HANDSHAKE in get_capa flags and
+ WPA_ALG_PMK in set_key)
+ * added an experimental port for Mac OS X (CONFIG_DRIVER_OSX=y in
+ .config); this version supports only ap_scan=2 mode and allow the
+ driver to take care of the 4-way handshake
+ * fixed a buffer overflow in parsing TSF from scan results when using
+ driver_wext.c with a driver that includes the TSF (e.g., iwl4965)
+ [Bug 232]
+ * updated FT support to use the latest draft, IEEE 802.11r/D8.0
+ * fixed an integer overflow issue in the ASN.1 parser used by the
+ (experimental) internal TLS implementation to avoid a potential
+ buffer read overflow
2007-05-28 - v0.6.0
* added network configuration parameter 'frequency' for setting
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile Sat Nov 3 08:40:37 2007
@@ -189,6 +189,20 @@
OBJS_d += ../src/drivers/driver_test.o
endif
+ifdef CONFIG_DRIVER_OSX
+CFLAGS += -DCONFIG_DRIVER_OSX
+OBJS_d += ../src/drivers/driver_osx.o
+LDFLAGS += -framework CoreFoundation
+LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211
+endif
+
+ifdef CONFIG_DRIVER_IPHONE
+CFLAGS += -DCONFIG_DRIVER_IPHONE
+OBJS_d += ../src/drivers/driver_iphone.o
+OBJS_d += ../src/drivers/MobileApple80211.o
+LIBS += -framework CoreFoundation
+endif
+
ifndef CONFIG_L2_PACKET
CONFIG_L2_PACKET=linux
endif
@@ -393,6 +407,7 @@
else
CFLAGS += -DEAP_FAST
OBJS += ../src/eap_peer/eap_fast.o ../src/eap_peer/eap_fast_pac.o
+OBJS_h += ../src/eap_server/eap_fast.o
endif
TLS_FUNCS=y
endif
@@ -555,12 +570,15 @@
endif
ifeq ($(CONFIG_TLS), internal)
OBJS += ../src/crypto/tls_internal.o
-OBJS += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_client.o
+OBJS += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_record.o
+OBJS += ../src/tls/tlsv1_cred.o ../src/tls/tlsv1_client.o
+OBJS += ../src/tls/tlsv1_client_write.o ../src/tls/tlsv1_client_read.o
OBJS += ../src/tls/asn1.o ../src/tls/x509v3.o
OBJS_p += ../src/tls/asn1.o
OBJS_p += ../src/crypto/rc4.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o
NEED_BASE64=y
CFLAGS += -DCONFIG_TLS_INTERNAL
+CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
ifeq ($(CONFIG_CRYPTO), internal)
ifdef CONFIG_INTERNAL_LIBTOMMATH
CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config.c Sat Nov 3 08:40:37 2007
@@ -949,6 +949,86 @@
return buf;
}
+
+
+static int wpa_config_parse_password(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ u8 *hash;
+
+ if (os_strncmp(value, "hash:", 5) != 0) {
+ char *tmp;
+ size_t res_len;
+
+ tmp = wpa_config_parse_string(value, &res_len);
+ if (tmp == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to parse "
+ "password.", line);
+ return -1;
+ }
+ wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
+ (u8 *) tmp, res_len);
+
+ os_free(ssid->password);
+ ssid->password = (u8 *) tmp;
+ ssid->password_len = res_len;
+ ssid->flags &= ~WPA_CONFIG_FLAGS_PASSWORD_NTHASH;
+
+ return 0;
+ }
+
+
+ /* NtPasswordHash: hash:<32 hex digits> */
+ if (os_strlen(value + 5) != 2 * 16) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
+ "(expected 32 hex digits)", line);
+ return -1;
+ }
+
+ hash = os_malloc(16);
+ if (hash == NULL)
+ return -1;
+
+ if (hexstr2bin(value + 5, hash, 16)) {
+ os_free(hash);
+ wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line);
+ return -1;
+ }
+
+ wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
+
+ os_free(ssid->password);
+ ssid->password = hash;
+ ssid->password_len = 16;
+ ssid->flags |= WPA_CONFIG_FLAGS_PASSWORD_NTHASH;
+
+ return 0;
+}
+
+
+static char * wpa_config_write_password(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *buf;
+
+ if (ssid->password == NULL)
+ return NULL;
+
+ if (!(ssid->flags & WPA_CONFIG_FLAGS_PASSWORD_NTHASH)) {
+ return wpa_config_write_string(
+ ssid->password, ssid->password_len);
+ }
+
+ buf = os_malloc(5 + 32 + 1);
+ if (buf == NULL)
+ return NULL;
+
+ os_memcpy(buf, "hash:", 5);
+ wpa_snprintf_hex(buf + 5, 32 + 1, ssid->password, 16);
+
+ return buf;
+}
#endif /* IEEE8021X_EAPOL */
@@ -1137,7 +1217,7 @@
{ STR_LEN(anonymous_identity) },
{ STR_RANGE_KEY(eappsk, EAP_PSK_LEN_MIN, EAP_PSK_LEN_MAX) },
{ STR_LEN(nai) },
- { STR_LEN_KEY(password) },
+ { FUNC(password) },
{ STR(ca_cert) },
{ STR(ca_path) },
{ STR(client_cert) },
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config_ssid.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config_ssid.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config_ssid.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config_ssid.h Sat Nov 3 08:40:37 2007
@@ -226,6 +226,14 @@
/**
* password - Password string for EAP
+ *
+ * This field can include either the plaintext password (default
+ * option) or a NtPasswordHash (16-byte MD4 hash of the unicode
+ * presentation of the password) if flags field has
+ * WPA_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can
+ * only be used with authentication mechanism that use this hash as the
+ * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2,
+ * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
*/
u8 *password;
@@ -849,6 +857,17 @@
* will be used instead of this configured value.
*/
int frequency;
+
+#define WPA_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
+ /**
+ * flags - Network configuration flags (bitfield)
+ *
+ * This variable is used for internal flags to describe further details
+ * for the network parameters.
+ * bit 0 = password is represented as a 16-byte NtPasswordHash value
+ * instead of plaintext password
+ */
+ u32 flags;
};
int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int vendor,
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c Sat Nov 3 08:40:37 2007
@@ -1225,6 +1225,12 @@
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
+ } else if (os_strcmp(buf, "RECONNECT") == 0) {
+ if (wpa_s->disconnected) {
+ wpa_s->disconnected = 0;
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
reply_len = -1;
@@ -1257,6 +1263,7 @@
reply_len = wpa_supplicant_ctrl_iface_list_networks(
wpa_s, reply, reply_size);
} else if (os_strcmp(buf, "DISCONNECT") == 0) {
+ wpa_s->reassociate = 0;
wpa_s->disconnected = 1;
wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
} else if (os_strcmp(buf, "SCAN") == 0) {
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/ctrl_iface.doxygen
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/ctrl_iface.doxygen?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/ctrl_iface.doxygen (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/ctrl_iface.doxygen Sat Nov 3 08:40:37 2007
@@ -203,6 +203,12 @@
Force reassociation.
+\subsection ctrl_iface_RECONNECT RECONNECT
+
+Connect if disconnected (i.e., like \c REASSOCIATE, but only connect
+if in disconnected state).
+
+
\subsection ctrl_iface_PREAUTH PREAUTH <BSSID>
Start pre-authentication with the given BSSID.
@@ -255,7 +261,8 @@
\subsection ctrl_iface_DISCONNECT DISCONNECT
-Disconnect and wait for \c REASSOCIATE command before connecting.
+Disconnect and wait for \c REASSOCIATE or \c RECONNECT command before
+connecting.
\subsection ctrl_iface_SCAN SCAN
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml Sat Nov 3 08:40:37 2007
@@ -140,7 +140,7 @@
<listitem><para>Run in daemon mode executing the action file
based on events from wpa_supplicant. The specified file will
be executed with the first argument set to interface name and
- second to "CONNECT" or "DISCONNECT" depending on the event.
+ second to "CONNECTED" or "DISCONNECTED" depending on the event.
This can be used to execute networking tools required to configure
the interface.</para>
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt Sat Nov 3 08:40:37 2007
@@ -79,12 +79,12 @@
EAP-PAX - - - - - + - - - - + -
EAP-SAKE - - - - - - - - - - + -
EAP-GPSK - - - - - - - - - - + -
-EAP-FAST/MSCHAPv2(prov) - - - + - - - - - + - +
-EAP-FAST/GTC(auth) - - - + - - - - - + - +
-EAP-FAST/MSCHAPv2(aprov)- - - - - - - - - - - +
-EAP-FAST/GTC(aprov) - - - - - - - - - - - +
+EAP-FAST/MSCHAPv2(prov) - - - + - - - - - + + +
+EAP-FAST/GTC(auth) - - - + - - - - - + + +
+EAP-FAST/MSCHAPv2(aprov)- - - - - - - - - - + +
+EAP-FAST/GTC(aprov) - - - - - - - - - - + +
EAP-FAST/TLS(aprov) - - - - - - - - - - - +
-EAP-FAST/MSCHAPv2(auth) - - - - - - - - - - - +
+EAP-FAST/MSCHAPv2(auth) - - - - - - - - - - + +
EAP-FAST/TLS(auth) - - - - - - - - - - - +
LEAP + - + + + + F +6 - + - +
EAP-TNC - - - - - + - - - - - -
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c Sat Nov 3 08:40:37 2007
@@ -199,7 +199,8 @@
size_t len)
{
/* struct wpa_supplicant *wpa_s = ctx; */
- printf("WPA: eapol_test_eapol_send(type=%d len=%d)\n", type, len);
+ printf("WPA: eapol_test_eapol_send(type=%d len=%lu)\n",
+ type, (unsigned long) len);
if (type == IEEE802_1X_TYPE_EAP_PACKET) {
wpa_hexdump(MSG_DEBUG, "TX EAP -> RADIUS", buf, len);
ieee802_1x_encapsulate_radius(&eapol_test, buf, len);
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/events.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/events.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/events.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/events.c Sat Nov 3 08:40:37 2007
@@ -444,9 +444,10 @@
wpa_printf(MSG_DEBUG, " skip - disabled");
continue;
}
- if (bss->ssid_len != ssid->ssid_len ||
- os_memcmp(bss->ssid, ssid->ssid,
- bss->ssid_len) != 0) {
+ if (ssid->ssid_len != 0 &&
+ (bss->ssid_len != ssid->ssid_len ||
+ os_memcmp(bss->ssid, ssid->ssid,
+ bss->ssid_len) != 0)) {
wpa_printf(MSG_DEBUG, " skip - "
"SSID mismatch");
continue;
@@ -520,7 +521,7 @@
wpa_supplicant_dbus_notify_scan_results(wpa_s);
- if (wpa_s->conf->ap_scan == 2)
+ if (wpa_s->conf->ap_scan == 2 || wpa_s->disconnected)
return;
results = wpa_s->scan_results;
num = wpa_s->num_scan_results;
@@ -733,6 +734,19 @@
wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
}
wpa_supplicant_cancel_scan(wpa_s);
+
+ if (wpa_s->driver_4way_handshake &&
+ (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_FT_PSK)) {
+ /*
+ * We are done; the driver will take care of RSN 4-way
+ * handshake.
+ */
+ wpa_supplicant_cancel_auth_timeout(wpa_s);
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+ eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+ eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+ }
}
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c Sat Nov 3 08:40:37 2007
@@ -460,8 +460,7 @@
mdie = (struct rsn_mdie *) (bss->mdie + 2);
if (mdie &&
os_memcmp(mdie->mobility_domain, wpa_s->mlme.current_md,
- MOBILITY_DOMAIN_ID_LEN) == 0 &&
- (mdie->ft_capab & RSN_FT_CAPAB_FT_OVER_AIR)) {
+ MOBILITY_DOMAIN_ID_LEN) == 0) {
wpa_printf(MSG_DEBUG, "MLME: Trying to use FT "
"over-the-air");
wpa_s->mlme.auth_alg = WLAN_AUTH_FT;
@@ -586,15 +585,14 @@
wpa_s->mlme.auth_alg != WLAN_AUTH_FT &&
bss && bss->mdie &&
bss->mdie_len >= 2 + sizeof(struct rsn_mdie) &&
- bss->mdie[1] >= sizeof(struct rsn_mdie) &&
- bss->mdie[2 + MOBILITY_DOMAIN_ID_LEN] & RSN_FT_CAPAB_FT_OVER_AIR) {
+ bss->mdie[1] >= sizeof(struct rsn_mdie)) {
pos = buf + blen;
blen += 2 + sizeof(struct rsn_mdie);
*pos++ = WLAN_EID_MOBILITY_DOMAIN;
*pos++ = sizeof(struct rsn_mdie);
os_memcpy(pos, bss->mdie + 2, MOBILITY_DOMAIN_ID_LEN);
pos += MOBILITY_DOMAIN_ID_LEN;
- *pos++ = RSN_FT_CAPAB_FT_OVER_AIR;
+ *pos++ = 0; /* FIX: copy from the target AP's MDIE */
}
if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X ||
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_aes.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_aes.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_aes.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_aes.c Sat Nov 3 08:40:37 2007
@@ -277,6 +277,23 @@
printf("OMAC1-AES-128 test vector %d failed\n", i);
ret++;
}
+
+ if (tv->msg_len > 1) {
+ const u8 *addr[2];
+ size_t len[2];
+
+ addr[0] = tv->msg;
+ len[0] = 1;
+ addr[1] = tv->msg + 1;
+ len[1] = tv->msg_len - 1;
+
+ omac1_aes_128_vector(tv->k, 2, addr, len, result);
+ if (memcmp(result, tv->tag, 16) != 0) {
+ printf("OMAC1-AES-128(vector) test vector %d "
+ "failed\n", i);
+ ret++;
+ }
+ }
}
ret += test_eax();
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3.c Sat Nov 3 08:40:37 2007
@@ -1,6 +1,6 @@
/*
* Testing tool for X.509v3 routines
- * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2006-2007, Jouni Malinen <j at w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,8 +15,8 @@
#include "includes.h"
#include "common.h"
-#include "asn1.h"
-#include "x509v3.h"
+#include "tls/asn1.h"
+#include "tls/x509v3.h"
extern int wpa_debug_level;
@@ -43,7 +43,7 @@
return -1;
}
- cert = x509_certificate_parse(buf, len);
+ cert = x509_certificate_parse((u8 *) buf, len);
if (cert == NULL) {
printf("Failed to parse X.509 certificate\n");
return -1;
Added: wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist.sh
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist.sh?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist.sh (added)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist.sh Sat Nov 3 08:40:37 2007
@@ -1,0 +1,144 @@
+#!/bin/sh
+
+# X.509 Path Validation Test Suite, Version 1.07
+# http://csrc.nist.gov/pki/testing/x509paths_old.html
+# http://csrc.nist.gov/pki/testing/x509tests.tgz
+
+if [ -z "$1" ]; then
+ echo "usage: $0 <path to X509tests directory>"
+ exit 1
+fi
+
+TESTS=$1
+
+if [ ! -d $TESTS ]; then
+ echo "Not a directory: $TESTS"
+ exit 1
+fi
+
+X509TEST="./test_x509v3 -v"
+TMPOUT=test_x509v3_nist.out
+
+# TODO: add support for validating CRLs
+
+END="End Certificate "
+ROOT="Trust Anchor "
+ICA="Intermediate Certificate "
+
+SUCCESS=""
+FAILURE=""
+
+function run_test
+{
+ NUM=$1
+ RES=$2
+ shift 2
+ $X509TEST "$@" > $TMPOUT.$NUM
+ VALRES=$?
+ OK=0
+ if [ $RES -eq 0 ]; then
+ # expecting success
+ if [ $VALRES -eq 0 ]; then
+ OK=1
+ else
+ echo "test$NUM failed - expected validation success"
+ OK=0
+ fi
+ else
+ # expecting failure
+ if [ $VALRES -eq 0 ]; then
+ echo "test$NUM failed - expected validation failure"
+ OK=0
+ else
+ REASON=`grep "Certificate chain validation failed: " $TMPOUT.$NUM`
+ if [ $? -eq 0 ]; then
+ REASONNUM=`echo "$REASON" | colrm 1 37`
+ if [ $REASONNUM -eq $RES ]; then
+ OK=1
+ else
+ echo "test$NUM failed - expected validation result $RES; result was $REASONNUM"
+ OK=0
+ fi
+ else
+ echo "test$NUM failed - expected validation failure; other type of error detected"
+ OK=0
+ fi
+ fi
+ fi
+ if [ $OK -eq 1 ]; then
+ rm $TMPOUT.$NUM
+ SUCCESS="$SUCCESS $NUM"
+ else
+ FAILURE="$FAILURE $NUM"
+ fi
+}
+
+P=$TESTS/test
+
+run_test 1 0 "${P}1/${END}CP.01.01.crt" "${P}1/${ROOT}CP.01.01.crt"
+run_test 2 1 "${P}2/${END}CP.01.02.crt" "${P}2/${ICA}CP.01.02.crt" "${P}2/${ROOT}CP.01.01.crt"
+run_test 3 1 "${P}3/${END}CP.01.03.crt" "${P}3/${ICA}CP.01.03.crt" "${P}3/${ROOT}CP.01.01.crt"
+run_test 4 0 "${P}4/${END}CP.02.01.crt" "${P}4/${ICA}2 CP.02.01.crt" "${P}4/${ICA}1 CP.02.01.crt" "${P}4/${ROOT}CP.01.01.crt"
+run_test 5 4 "${P}5/${END}CP.02.02.crt" "${P}5/${ICA}CP.02.02.crt" "${P}5/${ROOT}CP.01.01.crt"
+run_test 6 4 "${P}6/${END}CP.02.03.crt" "${P}6/${ICA}CP.02.03.crt" "${P}6/${ROOT}CP.01.01.crt"
+run_test 7 0 "${P}7/${END}CP.02.04.crt" "${P}7/${ICA}CP.02.04.crt" "${P}7/${ROOT}CP.01.01.crt"
+run_test 8 4 "${P}8/${END}CP.02.05.crt" "${P}8/${ICA}CP.02.05.crt" "${P}8/${ROOT}CP.01.01.crt"
+run_test 9 4 "${P}9/${END}CP.03.01.crt" "${P}9/${ICA}CP.03.01.crt" "${P}9/${ROOT}CP.01.01.crt"
+run_test 10 4 "${P}10/${END}CP.03.02.crt" "${P}10/${ICA}CP.03.02.crt" "${P}10/${ROOT}CP.01.01.crt"
+run_test 11 4 "${P}11/${END}CP.03.03.crt" "${P}11/${ICA}CP.03.03.crt" "${P}11/${ROOT}CP.01.01.crt"
+run_test 12 0 "${P}12/${END}CP.03.04.crt" "${P}12/${ICA}CP.03.04.crt" "${P}12/${ROOT}CP.01.01.crt"
+run_test 13 5 "${P}13/${END}CP.04.01.crt" "${P}13/${ICA}CP.04.01.crt" "${P}13/${ROOT}CP.01.01.crt"
+run_test 14 5 "${P}14/${END}CP.04.02.crt" "${P}14/${ICA}CP.04.02.crt" "${P}14/${ROOT}CP.01.01.crt"
+run_test 15 0 "${P}15/${END}CP.04.03.crt" "${P}15/${ICA}CP.04.03.crt" "${P}15/${ROOT}CP.01.01.crt"
+run_test 16 0 "${P}16/${END}CP.04.04.crt" "${P}16/${ICA}CP.04.04.crt" "${P}16/${ROOT}CP.01.01.crt"
+run_test 17 0 "${P}17/${END}CP.04.05.crt" "${P}17/${ICA}CP.04.05.crt" "${P}17/${ROOT}CP.01.01.crt"
+run_test 18 0 "${P}18/${END}CP.04.06.crt" "${P}18/${ICA}CP.04.06.crt" "${P}18/${ROOT}CP.01.01.crt"
+run_test 19 1 "${P}19/${END}CP.05.01.crt" "${P}19/${ICA}CP.05.01.crt" "${P}19/${ROOT}CP.01.01.crt"
+run_test 20 3 "${P}20/${END}CP.06.01.crt" "${P}20/${ICA}CP.06.01.crt" "${P}20/${ROOT}CP.01.01.crt"
+run_test 21 3 "${P}21/${END}CP.06.02.crt" "${P}21/${ICA}CP.06.02.crt" "${P}21/${ROOT}CP.01.01.crt"
+run_test 22 1 "${P}22/${END}IC.01.01.crt" "${P}22/${ICA}IC.01.01.crt" "${P}22/${ROOT}CP.01.01.crt"
+run_test 23 1 "${P}23/${END}IC.02.01.crt" "${P}23/${ICA}IC.02.01.crt" "${P}23/${ROOT}CP.01.01.crt"
+run_test 24 0 "${P}24/${END}IC.02.02.crt" "${P}24/${ICA}IC.02.02.crt" "${P}24/${ROOT}CP.01.01.crt"
+run_test 25 1 "${P}25/${END}IC.02.03.crt" "${P}25/${ICA}IC.02.03.crt" "${P}25/${ROOT}CP.01.01.crt"
+run_test 26 0 "${P}26/${END}IC.02.04.crt" "${P}26/${ICA}IC.02.04.crt" "${P}26/${ROOT}CP.01.01.crt"
+run_test 27 0 "${P}27/${END}IC.04.01.crt" "${P}27/${ICA}IC.04.01.crt" "${P}27/${ROOT}CP.01.01.crt"
+run_test 28 1 "${P}28/${END}IC.05.01.crt" "${P}28/${ICA}IC.05.01.crt" "${P}28/${ROOT}CP.01.01.crt"
+run_test 29 1 "${P}29/${END}IC.05.02.crt" "${P}29/${ICA}IC.05.02.crt" "${P}29/${ROOT}CP.01.01.crt"
+run_test 30 0 "${P}30/${END}IC.05.03.crt" "${P}30/${ICA}IC.05.03.crt" "${P}30/${ROOT}CP.01.01.crt"
+run_test 31 1 "${P}31/${END}IC.06.01.crt" "${P}31/${ICA}IC.06.01.crt" "${P}31/${ROOT}CP.01.01.crt"
+run_test 32 1 "${P}32/${END}IC.06.02.crt" "${P}32/${ICA}IC.06.02.crt" "${P}32/${ROOT}CP.01.01.crt"
+run_test 33 0 "${P}33/${END}IC.06.03.crt" "${P}33/${ICA}IC.06.03.crt" "${P}33/${ROOT}CP.01.01.crt"
+run_test 34 0 "${P}34/${END}PP.01.01.crt" "${P}34/${ICA}PP.01.01.crt" "${P}34/${ROOT}CP.01.01.crt"
+run_test 35 0 "${P}35/${END}PP.01.02.crt" "${P}35/${ICA}PP.01.02.crt" "${P}35/${ROOT}CP.01.01.crt"
+run_test 36 0 "${P}36/${END}PP.01.03.crt" "${P}36/${ICA}2 PP.01.03.crt" "${P}36/${ICA}1 PP.01.03.crt" "${P}36/${ROOT}CP.01.01.crt"
+run_test 37 0 "${P}37/${END}PP.01.04.crt" "${P}37/${ICA}2 PP.01.04.crt" "${P}37/${ICA}1 PP.01.04.crt" "${P}37/${ROOT}CP.01.01.crt"
+run_test 38 0 "${P}38/${END}PP.01.05.crt" "${P}38/${ICA}2 PP.01.05.crt" "${P}38/${ICA}1 PP.01.05.crt" "${P}38/${ROOT}CP.01.01.crt"
+run_test 39 0 "${P}39/${END}PP.01.06.crt" "${P}39/${ICA}3 PP.01.06.crt" "${P}39/${ICA}2 PP.01.06.crt" "${P}39/${ICA}1 PP.01.06.crt" "${P}39/${ROOT}CP.01.01.crt"
+run_test 40 0 "${P}40/${END}PP.01.07.crt" "${P}40/${ICA}3 PP.01.07.crt" "${P}40/${ICA}2 PP.01.07.crt" "${P}40/${ICA}1 PP.01.07.crt" "${P}40/${ROOT}CP.01.01.crt"
+run_test 41 0 "${P}41/${END}PP.01.08.crt" "${P}41/${ICA}3 PP.01.08.crt" "${P}41/${ICA}2 PP.01.08.crt" "${P}41/${ICA}1 PP.01.08.crt" "${P}41/${ROOT}CP.01.01.crt"
+run_test 42 0 "${P}42/${END}PP.01.09.crt" "${P}42/${ICA}4 PP.01.09.crt" "${P}42/${ICA}3 PP.01.09.crt" "${P}42/${ICA}2 PP.01.09.crt" "${P}42/${ICA}1 PP.01.09.crt" "${P}42/${ROOT}CP.01.01.crt"
+run_test 43 0 "${P}43/${END}PP.06.01.crt" "${P}43/${ICA}4 PP.06.01.crt" "${P}43/${ICA}3 PP.06.01.crt" "${P}43/${ICA}2 PP.06.01.crt" "${P}43/${ICA}1 PP.06.01.crt" "${P}43/${ROOT}CP.01.01.crt"
+run_test 44 0 "${P}44/${END}PP.06.02.crt" "${P}44/${ICA}4 PP.06.02.crt" "${P}44/${ICA}3 PP.06.02.crt" "${P}44/${ICA}2 PP.06.02.crt" "${P}44/${ICA}1 PP.06.02.crt" "${P}44/${ROOT}CP.01.01.crt"
+run_test 45 0 "${P}45/${END}PP.06.03.crt" "${P}45/${ICA}4 PP.06.03.crt" "${P}45/${ICA}3 PP.06.03.crt" "${P}45/${ICA}2 PP.06.03.crt" "${P}45/${ICA}1 PP.06.03.crt" "${P}45/${ROOT}CP.01.01.crt"
+run_test 46 0 "${P}46/${END}PP.06.04.crt" "${P}46/${ICA}4 PP.06.04.crt" "${P}46/${ICA}3 PP.06.04.crt" "${P}46/${ICA}2 PP.06.04.crt" "${P}46/${ICA}1 PP.06.04.crt" "${P}46/${ROOT}CP.01.01.crt"
+run_test 47 0 "${P}47/${END}PP.06.05.crt" "${P}47/${ICA}4 PP.06.05.crt" "${P}47/${ICA}3 PP.06.05.crt" "${P}47/${ICA}2 PP.06.05.crt" "${P}47/${ICA}1 PP.06.05.crt" "${P}47/${ROOT}CP.01.01.crt"
+run_test 48 0 "${P}48/${END}PP.08.01.crt" "${P}48/${ICA}PP.08.01.crt" "${P}48/${ROOT}CP.01.01.crt"
+run_test 49 0 "${P}49/${END}PP.08.02.crt" "${P}49/${ICA}PP.08.02.crt" "${P}49/${ROOT}CP.01.01.crt"
+run_test 50 0 "${P}50/${END}PP.08.03.crt" "${P}50/${ICA}PP.08.03.crt" "${P}50/${ROOT}CP.01.01.crt"
+run_test 51 0 "${P}51/${END}PP.08.04.crt" "${P}51/${ICA}PP.08.04.crt" "${P}51/${ROOT}CP.01.01.crt"
+run_test 52 0 "${P}52/${END}PP.08.05.crt" "${P}52/${ICA}PP.08.05.crt" "${P}52/${ROOT}CP.01.01.crt"
+run_test 53 0 "${P}53/${END}PP.08.06.crt" "${P}53/${ICA}PP.08.06.crt" "${P}53/${ROOT}CP.01.01.crt"
+run_test 54 1 "${P}54/${END}PL.01.01.crt" "${P}54/${ICA}2 PL.01.01.crt" "${P}54/${ICA}1 PL.01.01.crt" "${P}54/${ROOT}CP.01.01.crt"
+run_test 55 1 "${P}55/${END}PL.01.02.crt" "${P}55/${ICA}2 PL.01.02.crt" "${P}55/${ICA}1 PL.01.02.crt" "${P}55/${ROOT}CP.01.01.crt"
+run_test 56 0 "${P}56/${END}PL.01.03.crt" "${P}56/${ICA}PL.01.03.crt" "${P}56/${ROOT}CP.01.01.crt"
+run_test 57 0 "${P}57/${END}PL.01.04.crt" "${P}57/${ICA}PL.01.04.crt" "${P}57/${ROOT}CP.01.01.crt"
+run_test 58 1 "${P}58/${END}PL.01.05.crt" "${P}58/${ICA}3 PL.01.05.crt" "${P}58/${ICA}2 PL.01.05.crt" "${P}58/${ICA}1 PL.01.05.crt" "${P}58/${ROOT}CP.01.01.crt"
+run_test 59 1 "${P}59/${END}PL.01.06.crt" "${P}59/${ICA}3 PL.01.06.crt" "${P}59/${ICA}2 PL.01.06.crt" "${P}59/${ICA}1 PL.01.06.crt" "${P}59/${ROOT}CP.01.01.crt"
+run_test 60 1 "${P}60/${END}PL.01.07.crt" "${P}60/${ICA}4 PL.01.07.crt" "${P}60/${ICA}3 PL.01.07.crt" "${P}60/${ICA}2 PL.01.07.crt" "${P}60/${ICA}1 PL.01.07.crt" "${P}60/${ROOT}CP.01.01.crt"
+run_test 61 1 "${P}61/${END}PL.01.08.crt" "${P}61/${ICA}4 PL.01.08.crt" "${P}61/${ICA}3 PL.01.08.crt" "${P}61/${ICA}2 PL.01.08.crt" "${P}61/${ICA}1 PL.01.08.crt" "${P}61/${ROOT}CP.01.01.crt"
+run_test 62 0 "${P}62/${END}PL.01.09.crt" "${P}62/${ICA}4 PL.01.09.crt" "${P}62/${ICA}3 PL.01.09.crt" "${P}62/${ICA}2 PL.01.09.crt" "${P}62/${ICA}1 PL.01.09.crt" "${P}62/${ROOT}CP.01.01.crt"
+run_test 63 0 "${P}63/${END}PL.01.10.crt" "${P}63/${ICA}4 PL.01.10.crt" "${P}63/${ICA}3 PL.01.10.crt" "${P}63/${ICA}2 PL.01.10.crt" "${P}63/${ICA}1 PL.01.10.crt" "${P}63/${ROOT}CP.01.01.crt"
+
+
+echo "Successful tests:$SUCCESS"
+echo "Failed tests:$FAILURE"
Propchange: wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist.sh
------------------------------------------------------------------------------
svn:executable = *
Added: wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist2.sh
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist2.sh?rev=878&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist2.sh (added)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist2.sh Sat Nov 3 08:40:37 2007
@@ -1,0 +1,165 @@
+#!/bin/sh
+
+# Public Key Interoperability Test Suite (PKITS)
+# http://csrc.nist.gov/pki/testing/x509paths.html
+# http://csrc.nist.gov/pki/testing/PKITS_data.zip
+
+if [ -z "$1" ]; then
+ echo "usage: $0 <path to root test directory>"
+ exit 1
+fi
+
+TESTS=$1
+
+if [ ! -d $TESTS ]; then
+ echo "Not a directory: $TESTS"
+ exit 1
+fi
+
+X509TEST="$PWD/test_x509v3 -v"
+TMPOUT="$PWD/test_x509v3_nist2.out"
+
+# TODO: add support for validating CRLs
+
+SUCCESS=""
+FAILURE=""
+
+function run_test
+{
+ NUM=$1
+ RES=$2
+ shift 2
+ $X509TEST "$@" TrustAnchorRootCertificate.crt > $TMPOUT.$NUM
+ VALRES=$?
+ OK=0
+ if [ $RES -eq 0 ]; then
+ # expecting success
+ if [ $VALRES -eq 0 ]; then
+ OK=1
+ else
+ echo "$NUM failed - expected validation success"
+ OK=0
+ fi
+ else
+ # expecting failure
+ if [ $VALRES -eq 0 ]; then
+ echo "$NUM failed - expected validation failure"
+ OK=0
+ else
+ REASON=`grep "Certificate chain validation failed: " $TMPOUT.$NUM`
+ if [ $? -eq 0 ]; then
+ REASONNUM=`echo "$REASON" | colrm 1 37`
+ if [ $REASONNUM -eq $RES ]; then
+ OK=1
+ else
+ echo "$NUM failed - expected validation result $RES; result was $REASONNUM"
+ OK=0
+ fi
+ else
+ echo "$NUM failed - expected validation failure; other type of error detected"
+ OK=0
+ fi
+ fi
+ fi
+ if [ $OK -eq 1 ]; then
+ rm $TMPOUT.$NUM
+ SUCCESS="$SUCCESS $NUM"
+ else
+ FAILURE="$FAILURE $NUM"
+ fi
+}
+
+pushd $TESTS/certs
+
+run_test 4.1.1 0 ValidCertificatePathTest1EE.crt GoodCACert.crt
+run_test 4.1.2 1 InvalidCASignatureTest2EE.crt BadSignedCACert.crt
+run_test 4.1.3 1 InvalidEESignatureTest3EE.crt GoodCACert.crt
+
+run_test 4.2.1 4 InvalidCAnotBeforeDateTest1EE.crt BadnotBeforeDateCACert.crt
+run_test 4.2.2 4 InvalidEEnotBeforeDateTest2EE.crt GoodCACert.crt
+run_test 4.2.3 0 Validpre2000UTCnotBeforeDateTest3EE.crt GoodCACert.crt
+run_test 4.2.4 0 ValidGeneralizedTimenotBeforeDateTest4EE.crt GoodCACert.crt
+run_test 4.2.5 4 InvalidCAnotAfterDateTest5EE.crt BadnotAfterDateCACert.crt
+run_test 4.2.6 4 InvalidEEnotAfterDateTest6EE.crt GoodCACert.crt
+run_test 4.2.7 4 Invalidpre2000UTCEEnotAfterDateTest7EE.crt GoodCACert.crt
+run_test 4.2.8 0 ValidGeneralizedTimenotAfterDateTest8EE.crt GoodCACert.crt
+
+run_test 4.3.1 5 InvalidNameChainingTest1EE.crt GoodCACert.crt
+run_test 4.3.2 5 InvalidNameChainingOrderTest2EE.crt NameOrderingCACert.crt
+run_test 4.3.3 0 ValidNameChainingWhitespaceTest3EE.crt GoodCACert.crt
+run_test 4.3.4 0 ValidNameChainingWhitespaceTest4EE.crt GoodCACert.crt
+run_test 4.3.5 0 ValidNameChainingCapitalizationTest5EE.crt GoodCACert.crt
+run_test 4.3.6 0 ValidNameUIDsTest6EE.crt UIDCACert.crt
+run_test 4.3.7 0 ValidRFC3280MandatoryAttributeTypesTest7EE.crt RFC3280MandatoryAttributeTypesCACert.crt
+run_test 4.3.8 0 ValidRFC3280OptionalAttributeTypesTest8EE.crt RFC3280OptionalAttributeTypesCACert.crt
+run_test 4.3.9 0 ValidUTF8StringEncodedNamesTest9EE.crt UTF8StringEncodedNamesCACert.crt
+run_test 4.3.10 0 ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt RolloverfromPrintableStringtoUTF8StringCACert.crt
+run_test 4.3.11 0 ValidUTF8StringCaseInsensitiveMatchTest11EE.crt UTF8StringCaseInsensitiveMatchCACert.crt
+
+run_test 4.4.1 1 InvalidMissingCRLTest1EE.crt NoCRLCACert.crt
+# skip rest of 4.4.x tests since CRLs are not yet supported
+
+run_test 4.5.1 0 ValidBasicSelfIssuedOldWithNewTest1EE.crt BasicSelfIssuedNewKeyOldWithNewCACert.crt BasicSelfIssuedNewKeyCACert.crt
+run_test 4.5.2 3 InvalidBasicSelfIssuedOldWithNewTest2EE.crt BasicSelfIssuedNewKeyOldWithNewCACert.crt BasicSelfIssuedNewKeyCACert.crt
+run_test 4.5.3 0 ValidBasicSelfIssuedNewWithOldTest3EE.crt BasicSelfIssuedOldKeyNewWithOldCACert.crt BasicSelfIssuedOldKeyCACert.crt
+run_test 4.5.4 0 ValidBasicSelfIssuedNewWithOldTest4EE.crt BasicSelfIssuedOldKeyNewWithOldCACert.crt BasicSelfIssuedOldKeyCACert.crt
+run_test 4.5.5 3 InvalidBasicSelfIssuedNewWithOldTest5EE.crt BasicSelfIssuedOldKeyNewWithOldCACert.crt BasicSelfIssuedOldKeyCACert.crt
+run_test 4.5.6 0 ValidBasicSelfIssuedCRLSigningKeyTest6EE.crt BasicSelfIssuedCRLSigningKeyCRLCert.crt BasicSelfIssuedCRLSigningKeyCACert.crt
+run_test 4.5.7 3 InvalidBasicSelfIssuedCRLSigningKeyTest7EE.crt BasicSelfIssuedCRLSigningKeyCRLCert.crt BasicSelfIssuedCRLSigningKeyCACert.crt
+run_test 4.5.8 1 InvalidBasicSelfIssuedCRLSigningKeyTest8EE.crt BasicSelfIssuedCRLSigningKeyCRLCert.crt BasicSelfIssuedCRLSigningKeyCACert.crt
+
+run_test 4.6.1 1 InvalidMissingbasicConstraintsTest1EE.crt MissingbasicConstraintsCACert.crt
+run_test 4.6.2 1 InvalidcAFalseTest2EE.crt basicConstraintsCriticalcAFalseCACert.crt
+run_test 4.6.3 1 InvalidcAFalseTest3EE.crt basicConstraintsNotCriticalcAFalseCACert.crt
+run_test 4.6.4 0 ValidbasicConstraintsNotCriticalTest4EE.crt basicConstraintsNotCriticalCACert.crt
+run_test 4.6.5 1 InvalidpathLenConstraintTest5EE.crt pathLenConstraint0subCACert.crt pathLenConstraint0CACert.crt
+run_test 4.6.6 1 InvalidpathLenConstraintTest6EE.crt pathLenConstraint0subCACert.crt pathLenConstraint0CACert.crt
+run_test 4.6.7 0 ValidpathLenConstraintTest7EE.crt pathLenConstraint0CACert.crt
+run_test 4.6.8 0 ValidpathLenConstraintTest8EE.crt pathLenConstraint0CACert.crt
+run_test 4.6.9 1 InvalidpathLenConstraintTest9EE.crt pathLenConstraint6subsubCA00Cert.crt pathLenConstraint6subCA0Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.10 1 InvalidpathLenConstraintTest10EE.crt pathLenConstraint6subsubCA00Cert.crt pathLenConstraint6subCA0Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.11 1 InvalidpathLenConstraintTest11EE.crt pathLenConstraint6subsubsubCA11XCert.crt pathLenConstraint6subsubCA11Cert.crt pathLenConstraint6subCA1Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.12 1 InvalidpathLenConstraintTest12EE.crt pathLenConstraint6subsubsubCA11XCert.crt pathLenConstraint6subsubCA11Cert.crt pathLenConstraint6subCA1Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.13 0 ValidpathLenConstraintTest13EE.crt pathLenConstraint6subsubsubCA41XCert.crt pathLenConstraint6subsubCA41Cert.crt pathLenConstraint6subCA4Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.14 0 ValidpathLenConstraintTest14EE.crt pathLenConstraint6subsubsubCA41XCert.crt pathLenConstraint6subsubCA41Cert.crt pathLenConstraint6subCA4Cert.crt pathLenConstraint6CACert.crt
+run_test 4.6.15 0 ValidSelfIssuedpathLenConstraintTest15EE.crt pathLenConstraint0SelfIssuedCACert.crt pathLenConstraint0CACert.crt
+run_test 4.6.16 1 InvalidSelfIssuedpathLenConstraintTest16EE.crt pathLenConstraint0subCA2Cert.crt pathLenConstraint0SelfIssuedCACert.crt pathLenConstraint0CACert.crt
+run_test 4.6.17 0 ValidSelfIssuedpathLenConstraintTest17EE.crt pathLenConstraint1SelfIssuedsubCACert.crt pathLenConstraint1subCACert.crt pathLenConstraint1SelfIssuedCACert.crt pathLenConstraint1CACert.crt
+
+run_test 4.7.1 1 InvalidkeyUsageCriticalkeyCertSignFalseTest1EE.crt keyUsageCriticalkeyCertSignFalseCACert.crt
+run_test 4.7.2 1 InvalidkeyUsageNotCriticalkeyCertSignFalseTest2EE.crt keyUsageNotCriticalkeyCertSignFalseCACert.crt
+run_test 4.7.3 0 ValidkeyUsageNotCriticalTest3EE.crt keyUsageNotCriticalCACert.crt
+run_test 4.7.4 1 InvalidkeyUsageCriticalcRLSignFalseTest4EE.crt keyUsageCriticalcRLSignFalseCACert.crt
+run_test 4.7.5 1 InvalidkeyUsageNotCriticalcRLSignFalseTest5EE.crt keyUsageNotCriticalcRLSignFalseCACert.crt
+
+run_test 4.8.1 0 ValidCertificatePathTest1EE.crt GoodCACert.crt
+run_test 4.8.2 0 AllCertificatesNoPoliciesTest2EE.crt NoPoliciesCACert.crt
+run_test 4.8.3 0 DifferentPoliciesTest3EE.crt PoliciesP2subCACert.crt GoodCACert.crt
+run_test 4.8.4 0 DifferentPoliciesTest4EE.crt GoodsubCACert.crt GoodCACert.crt
+run_test 4.8.5 0 DifferentPoliciesTest5EE.crt PoliciesP2subCA2Cert.crt GoodCACert.crt
+run_test 4.8.6 0 OverlappingPoliciesTest6EE.crt PoliciesP1234subsubCAP123P12Cert.crt PoliciesP1234subCAP123Cert.crt PoliciesP1234CACert.crt
+run_test 4.8.7 0 DifferentPoliciesTest7EE.crt PoliciesP123subsubCAP12P1Cert.crt PoliciesP123subCAP12Cert.crt PoliciesP123CACert.crt
+run_test 4.8.8 0 DifferentPoliciesTest8EE.crt PoliciesP12subsubCAP1P2Cert.crt PoliciesP12subCAP1Cert.crt PoliciesP12CACert.crt
+run_test 4.8.9 0 DifferentPoliciesTest9EE.crt PoliciesP123subsubsubCAP12P2P1Cert.crt PoliciesP123subsubCAP12P2Cert.crt PoliciesP123subCAP12Cert.crt PoliciesP123CACert.crt
+run_test 4.8.10 0 AllCertificatesSamePoliciesTest10EE.crt PoliciesP12CACert.crt
+run_test 4.8.11 0 AllCertificatesanyPolicyTest11EE.crt anyPolicyCACert.crt
+run_test 4.8.12 0 DifferentPoliciesTest12EE.crt PoliciesP3CACert.crt
+run_test 4.8.13 0 AllCertificatesSamePoliciesTest13EE.crt PoliciesP123CACert.crt
+run_test 4.8.14 0 AnyPolicyTest14EE.crt anyPolicyCACert.crt
+run_test 4.8.15 0 UserNoticeQualifierTest15EE.crt
+run_test 4.8.16 0 UserNoticeQualifierTest16EE.crt GoodCACert.crt
+run_test 4.8.17 0 UserNoticeQualifierTest17EE.crt GoodCACert.crt
+run_test 4.8.18 0 UserNoticeQualifierTest18EE.crt PoliciesP12CACert.crt
+run_test 4.8.19 0 UserNoticeQualifierTest19EE.crt TrustAnchorRootCertificate.crt
+run_test 4.8.20 0 CPSPointerQualifierTest20EE.crt GoodCACert.crt
+
+if false; then
+# DSA tests
+run_test 4.1.4 0 ValidDSASignaturesTest4EE.crt DSACACert.crt
+fi
+
+popd
+
+
+echo "Successful tests:$SUCCESS"
+echo "Failed tests:$FAILURE"
Propchange: wpasupplicant/branches/upstream/current/wpa_supplicant/tests/test_x509v3_nist2.sh
------------------------------------------------------------------------------
svn:executable = *
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt Sat Nov 3 08:40:37 2007
@@ -50,8 +50,6 @@
- possibility to link in WPA Authenticator state machine to wpa_supplicant
(new STAKey handshake, WPA2 IBSS)
- consider merging hostapd and wpa_supplicant PMKSA cache implementations
-- add support for configuring password for MSCHAPv2 as NtPasswordHash in
- the same way as was added to hostapd (hash:<hex value>)
- consider adding generic buffer functionality that could be used in number
of places
* allocate buffer (with default max size), allow reserving head room to
@@ -110,15 +108,16 @@
- change TLS/crypto library interface to use a structure of function
pointers and helper inline functions (like driver_ops) instead of
requiring every TLS wrapper to implement all functions
-- move from CVS to git (0.3.x, 0.4.x, 0.5.x releases will continue
- to be updated only on CVS)
-- move files into subdirectories and combine wpa_supplicant and hostapd
- into a repository that matches in directory structure with the release
- tarballs
- (subdirs: eap_common, eap_peer, eap_server, driver, driver_ap, ...)
- make it clearer that EAP server/peer can be used as a separate library
for other programs
- add support for encrypted configuration fields (e.g., password, psk,
passphrase, pin)
- wpa_gui: add support for setting and showing priority, id_str, auth_alg
(open/shared for static WEP)
+
+- cleanup TLS/PEAP/TTLS/FAST fragmentation: both the handshake and Appl. Data
+ phases should be able to use the same functions for this;
+ the last step in processing sent should be this code and rest of the code
+ should not need to care about fragmentation at all
+- test EAP-FAST peer with OpenSSL and verify that fallback to full handshake
+ (ServerHello followed by something else than ChangeCipherSpec)
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c Sat Nov 3 08:40:37 2007
@@ -120,8 +120,10 @@
" list of variables when run without arguments)\n"
" get_network <network id> <variable> = get network variables\n"
" save_config = save the current configuration\n"
-" disconnect = disconnect and wait for reassociate command before "
-"connecting\n"
+" disconnect = disconnect and wait for reassociate/reconnect command before\n "
+" connecting\n"
+" reconnect = like reassociate, but only takes effect if already "
+"disconnected\n"
" scan = request new BSS scan\n"
" scan_results = get latest scan results\n"
" get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = "
@@ -323,13 +325,13 @@
if (argc != 2) {
printf("Invalid SET command: needs two arguments (variable "
"name and value)\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long SET command.\n");
- return 0;
+ return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
@@ -363,13 +365,13 @@
if (argc != 1) {
printf("Invalid PREAUTH command: needs one argument "
"(BSSID)\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long PREAUTH command.\n");
- return 0;
+ return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
@@ -383,12 +385,12 @@
if (argc != 1) {
printf("Invalid AP_SCAN command: needs one argument (ap_scan "
"value)\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long AP_SCAN command.\n");
- return 0;
+ return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
@@ -403,13 +405,13 @@
if (argc != 1) {
printf("Invalid STKSTART command: needs one argument "
"(Peer STA MAC address)\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long STKSTART command.\n");
- return 0;
+ return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
@@ -423,13 +425,13 @@
if (argc != 1) {
printf("Invalid FT_DS command: needs one argument "
"(Target AP MAC address)\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long FT_DS command.\n");
- return 0;
+ return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
@@ -443,12 +445,12 @@
if (argc != 1) {
printf("Invalid LEVEL command: needs one argument (debug "
"level)\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long LEVEL command.\n");
- return 0;
+ return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
@@ -462,7 +464,7 @@
if (argc < 2) {
printf("Invalid IDENTITY command: needs two arguments "
"(network id and identity)\n");
- return 0;
+ return -1;
}
end = cmd + sizeof(cmd);
@@ -471,14 +473,14 @@
argv[0], argv[1]);
if (ret < 0 || ret >= end - pos) {
printf("Too long IDENTITY command.\n");
- return 0;
+ return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
if (ret < 0 || ret >= end - pos) {
printf("Too long IDENTITY command.\n");
- return 0;
+ return -1;
}
pos += ret;
}
@@ -495,7 +497,7 @@
if (argc < 2) {
printf("Invalid PASSWORD command: needs two arguments "
"(network id and password)\n");
- return 0;
+ return -1;
}
end = cmd + sizeof(cmd);
@@ -504,14 +506,14 @@
argv[0], argv[1]);
if (ret < 0 || ret >= end - pos) {
printf("Too long PASSWORD command.\n");
- return 0;
+ return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
if (ret < 0 || ret >= end - pos) {
printf("Too long PASSWORD command.\n");
- return 0;
+ return -1;
}
pos += ret;
}
@@ -529,7 +531,7 @@
if (argc < 2) {
printf("Invalid NEW_PASSWORD command: needs two arguments "
"(network id and password)\n");
- return 0;
+ return -1;
}
end = cmd + sizeof(cmd);
@@ -538,14 +540,14 @@
argv[0], argv[1]);
if (ret < 0 || ret >= end - pos) {
printf("Too long NEW_PASSWORD command.\n");
- return 0;
+ return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
if (ret < 0 || ret >= end - pos) {
printf("Too long NEW_PASSWORD command.\n");
- return 0;
+ return -1;
}
pos += ret;
}
@@ -562,7 +564,7 @@
if (argc < 2) {
printf("Invalid PIN command: needs two arguments "
"(network id and pin)\n");
- return 0;
+ return -1;
}
end = cmd + sizeof(cmd);
@@ -571,14 +573,14 @@
argv[0], argv[1]);
if (ret < 0 || ret >= end - pos) {
printf("Too long PIN command.\n");
- return 0;
+ return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
if (ret < 0 || ret >= end - pos) {
printf("Too long PIN command.\n");
- return 0;
+ return -1;
}
pos += ret;
}
@@ -594,7 +596,7 @@
if (argc < 2) {
printf("Invalid OTP command: needs two arguments (network "
"id and password)\n");
- return 0;
+ return -1;
}
end = cmd + sizeof(cmd);
@@ -603,14 +605,14 @@
argv[0], argv[1]);
if (ret < 0 || ret >= end - pos) {
printf("Too long OTP command.\n");
- return 0;
+ return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
if (ret < 0 || ret >= end - pos) {
printf("Too long OTP command.\n");
- return 0;
+ return -1;
}
pos += ret;
}
@@ -628,7 +630,7 @@
if (argc < 2) {
printf("Invalid PASSPHRASE command: needs two arguments "
"(network id and passphrase)\n");
- return 0;
+ return -1;
}
end = cmd + sizeof(cmd);
@@ -637,14 +639,14 @@
argv[0], argv[1]);
if (ret < 0 || ret >= end - pos) {
printf("Too long PASSPHRASE command.\n");
- return 0;
+ return -1;
}
pos += ret;
for (i = 2; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
if (ret < 0 || ret >= end - pos) {
printf("Too long PASSPHRASE command.\n");
- return 0;
+ return -1;
}
pos += ret;
}
@@ -661,7 +663,7 @@
if (argc < 2) {
printf("Invalid BSSID command: needs two arguments (network "
"id and BSSID)\n");
- return 0;
+ return -1;
}
end = cmd + sizeof(cmd);
@@ -669,14 +671,14 @@
ret = os_snprintf(pos, end - pos, "BSSID");
if (ret < 0 || ret >= end - pos) {
printf("Too long BSSID command.\n");
- return 0;
+ return -1;
}
pos += ret;
for (i = 0; i < argc; i++) {
ret = os_snprintf(pos, end - pos, " %s", argv[i]);
if (ret < 0 || ret >= end - pos) {
printf("Too long BSSID command.\n");
- return 0;
+ return -1;
}
pos += ret;
}
@@ -701,7 +703,7 @@
if (argc < 1) {
printf("Invalid SELECT_NETWORK command: needs one argument "
"(network id)\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
@@ -722,7 +724,7 @@
if (argc < 1) {
printf("Invalid ENABLE_NETWORK command: needs one argument "
"(network id)\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
@@ -743,7 +745,7 @@
if (argc < 1) {
printf("Invalid DISABLE_NETWORK command: needs one argument "
"(network id)\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
@@ -771,7 +773,7 @@
if (argc < 1) {
printf("Invalid REMOVE_NETWORK command: needs one argument "
"(network id)\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
@@ -818,14 +820,14 @@
if (argc != 3) {
printf("Invalid SET_NETWORK command: needs three arguments\n"
"(network id, variable name, and value)\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
argv[0], argv[1], argv[2]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long SET_NETWORK command.\n");
- return 0;
+ return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
@@ -845,14 +847,14 @@
if (argc != 2) {
printf("Invalid GET_NETWORK command: needs two arguments\n"
"(network id and variable name)\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
argv[0], argv[1]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long GET_NETWORK command.\n");
- return 0;
+ return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
@@ -862,6 +864,13 @@
char *argv[])
{
return wpa_ctrl_command(ctrl, "DISCONNECT");
+}
+
+
+static int wpa_cli_cmd_reconnect(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "RECONNECT");
}
@@ -894,13 +903,13 @@
if (argc < 1 || argc > 2) {
printf("Invalid GET_CAPABILITY command: need either one or "
"two arguments\n");
- return 0;
+ return -1;
}
if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
printf("Invalid GET_CAPABILITY command: second argument, "
"if any, must be 'strict'\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0],
@@ -972,7 +981,7 @@
"argument (interface name)\n"
"All arguments: ifname confname driver ctrl_interface "
"driver_param bridge_name\n");
- return 0;
+ return -1;
}
/*
@@ -1001,7 +1010,7 @@
if (argc != 1) {
printf("Invalid INTERFACE_REMOVE command: needs one argument "
"(interface name)\n");
- return 0;
+ return -1;
}
res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
@@ -1049,6 +1058,7 @@
{ "get_network", wpa_cli_cmd_get_network },
{ "save_config", wpa_cli_cmd_save_config },
{ "disconnect", wpa_cli_cmd_disconnect },
+ { "reconnect", wpa_cli_cmd_reconnect },
{ "scan", wpa_cli_cmd_scan },
{ "scan_results", wpa_cli_cmd_scan_results },
{ "get_capability", wpa_cli_cmd_get_capability },
@@ -1063,10 +1073,11 @@
};
-static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
+static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
struct wpa_cli_cmd *cmd, *match = NULL;
int count;
+ int ret = 0;
count = 0;
cmd = wpa_cli_commands;
@@ -1095,11 +1106,15 @@
cmd++;
}
printf("\n");
+ ret = 1;
} else if (count == 0) {
printf("Unknown command '%s'\n", argv[0]);
+ ret = 1;
} else {
- match->handler(ctrl, argc - 1, &argv[1]);
- }
+ ret = match->handler(ctrl, argc - 1, &argv[1]);
+ }
+
+ return ret;
}
@@ -1554,6 +1569,7 @@
int warning_displayed = 0;
int c;
int daemonize = 0;
+ int ret = 0;
const char *global = NULL;
if (os_program_init())
@@ -1665,12 +1681,12 @@
else if (action_file)
wpa_cli_action(ctrl_conn);
else
- wpa_request(ctrl_conn, argc - optind, &argv[optind]);
+ ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]);
os_free(ctrl_ifname);
wpa_cli_cleanup();
- return 0;
+ return ret;
}
#else /* CONFIG_CTRL_IFACE */
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c Sat Nov 3 08:40:37 2007
@@ -1512,6 +1512,11 @@
}
params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+ if (wpa_s->driver_4way_handshake &&
+ (params.key_mgmt_suite == KEY_MGMT_PSK ||
+ params.key_mgmt_suite == KEY_MGMT_FT_PSK))
+ params.passphrase = ssid->passphrase;
+
#ifdef CONFIG_IEEE80211W
switch (ssid->ieee80211w) {
case NO_IEEE80211W:
@@ -1987,7 +1992,11 @@
return;
}
- if (wpa_s->eapol_received == 0) {
+ if (wpa_s->eapol_received == 0 &&
+ (!wpa_s->driver_4way_handshake ||
+ (wpa_s->key_mgmt != WPA_KEY_MGMT_PSK &&
+ wpa_s->key_mgmt != WPA_KEY_MGMT_FT_PSK) ||
+ wpa_s->wpa_state != WPA_COMPLETED)) {
/* Timeout for completing IEEE 802.1X and WPA authentication */
wpa_supplicant_req_auth_timeout(
wpa_s,
@@ -2016,7 +2025,18 @@
eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
return;
wpa_drv_poll(wpa_s);
- wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
+ if (!wpa_s->driver_4way_handshake)
+ wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
+ else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+ /*
+ * Set portValid = TRUE here since we are going to skip 4-way
+ * handshake processing which would normally set portValid. We
+ * need this to allow the EAPOL state machines to be completed
+ * without going through EAPOL-Key handshake.
+ */
+ eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+ }
}
@@ -2220,6 +2240,57 @@
}
+#ifdef IEEE8021X_EAPOL
+static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
+ void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ int res, pmk_len;
+ u8 pmk[PMK_LEN];
+
+ wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
+ success ? "" : "un");
+
+ if (!success || !wpa_s->driver_4way_handshake)
+ return;
+
+ if (wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
+ wpa_s->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way "
+ "handshake");
+
+ pmk_len = PMK_LEN;
+ res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
+ if (res) {
+ /*
+ * EAP-LEAP is an exception from other EAP methods: it
+ * uses only 16-byte PMK.
+ */
+ res = eapol_sm_get_key(eapol, pmk, 16);
+ pmk_len = 16;
+ }
+
+ if (res) {
+ wpa_printf(MSG_DEBUG, "Failed to get PMK from EAPOL state "
+ "machines");
+ return;
+ }
+
+ if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
+ pmk_len)) {
+ wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
+ }
+
+ eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
+ wpa_supplicant_cancel_auth_timeout(wpa_s);
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+
+}
+#endif /* IEEE8021X_EAPOL */
+
+
static int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
{
#ifdef IEEE8021X_EAPOL
@@ -2243,6 +2314,8 @@
ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+ ctx->cb = wpa_supplicant_eapol_cb;
+ ctx->cb_ctx = wpa_s;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {
os_free(ctx);
@@ -2392,11 +2465,14 @@
return -1;
}
- if (wpa_drv_get_capa(wpa_s, &capa) == 0 &&
- capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
- wpa_s->use_client_mlme = 1;
- if (ieee80211_sta_init(wpa_s))
- return -1;
+ if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+ if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
+ wpa_s->use_client_mlme = 1;
+ if (ieee80211_sta_init(wpa_s))
+ return -1;
+ }
+ if (capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)
+ wpa_s->driver_4way_handshake = 1;
}
return 0;
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf Sat Nov 3 08:40:37 2007
@@ -295,7 +295,11 @@
# anonymous_identity: Anonymous identity string for EAP (to be used as the
# unencrypted identity with EAP types that support different tunnelled
# identity, e.g., EAP-TTLS)
-# password: Password string for EAP
+# password: Password string for EAP. This field can include either the
+# plaintext password (using ASCII or hex string) or a NtPasswordHash
+# (16-byte MD4 hash of password) in hash:<32 hex digits> format.
+# NtPasswordHash can only be used when the password is for MSCHAPv2 or
+# MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP)
# ca_cert: File path to CA certificate file (PEM/DER). This file can have one
# or more trusted CA certificates. If ca_cert and ca_path are not
# included, server certificate will not be verified. This is insecure and
Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h?rev=878&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h Sat Nov 3 08:40:37 2007
@@ -349,6 +349,7 @@
struct wpa_client_mlme mlme;
int use_client_mlme;
+ int driver_4way_handshake;
};
More information about the Pkg-wpa-devel
mailing list