EAP-FAST has some additional requirements for TLS that do not seem to be currently supported in OpenSSL. EAP-FAST uses ClientHello extension (RFC 3546, Section 3.1) and it does not use certificates in TLS handshake; instead, TLS pre-master-secret is set based on PAC-Key (shared secret from EAP-FAST provisioning).
I have made a proof-of-concept type of patch for OpenSSL to allow testing EAP-FAST implementation in wpa_supplicant. This seems to be enough to make EAP-FAST interoperate with Cisco ACS. However, the changes to OpenSSL are not very clean and may very well be completely incorrect. Consequently, I would be interested in finding out whether someone with better understanding of OpenSSL than I have would be interested in commenting the changes, or even better, in actually making such changes to OpenSSL distribution. I've attached the patch file showing the changes I needed to get EAP-FAST authentication completed. This adds a simple way of adding ClientHello extensions (RFC 3546, Section 3.1). More generic support for TLS extensions would of course be ok for this, too. Rest of the patch is very quick hack to allow TLS handshake to be completed without certificates; I just changed number of functions to skip certificate request and validation during the handshake. This is clearly not suitable to be applied as-is, but I hope it would be enough to generate some comments on how this should be done correctly. -- Jouni Malinen PGP id EFC895FA
This is a quick hack for testing EAP-FAST with openssl. Addition of TLS extensions to ClientHello/ServerHello is more or less ok, though not very clean in the way that the caller needs to take care of constructing set of all extensions. In addition there is not mechanism for reading the TLS extensions, i.e., this would not be enough for EAP-FAST authenticator. Rest of the changes are obviously ugly and/or incorrect for most parts, but it demonstrates the minimum set of changes to skip some of the error cases that prevented completion of TLS handshake without certificates. In other words, this is just a proof-of-concept type of example to make it possible to experiment with EAP-FAST. Cleaner patch for the needed functionality would be welcome.. diff -upr openssl-0.9.7e.orig/include/openssl/ssl.h openssl-0.9.7e/include/openssl/ssl.h --- openssl-0.9.7e.orig/include/openssl/ssl.h 2004-07-27 11:28:49.000000000 -0700 +++ openssl-0.9.7e/include/openssl/ssl.h 2004-12-24 20:29:01.000000000 -0800 @@ -929,6 +929,11 @@ struct ssl_st int first_packet; int client_version; /* what was passed, used for * SSLv3/TLS rollback check */ + + /* Optional ClientHello/ServerHello extension to be added to the end + * of the SSLv3/TLS hello message. */ + char *hello_extension; + int hello_extension_len; }; #ifdef __cplusplus diff -upr openssl-0.9.7e.orig/ssl/s3_both.c openssl-0.9.7e/ssl/s3_both.c --- openssl-0.9.7e.orig/ssl/s3_both.c 2003-02-12 09:05:17.000000000 -0800 +++ openssl-0.9.7e/ssl/s3_both.c 2004-12-31 21:18:15.556846272 -0800 @@ -199,6 +199,12 @@ int ssl3_get_finished(SSL *s, int a, int 64, /* should actually be 36+4 :-) */ &ok); + if (!ok && s->hello_extension) + { + /* Quick hack to test EAP-FAST. */ + return(1); + } + if (!ok) return((int)n); /* If this occurs, we have missed a message */ diff -upr openssl-0.9.7e.orig/ssl/s3_clnt.c openssl-0.9.7e/ssl/s3_clnt.c --- openssl-0.9.7e.orig/ssl/s3_clnt.c 2004-05-15 09:39:22.000000000 -0700 +++ openssl-0.9.7e/ssl/s3_clnt.c 2004-12-31 21:16:38.617583280 -0800 @@ -588,6 +588,12 @@ static int ssl3_client_hello(SSL *s) *(p++)=comp->id; } *(p++)=0; /* Add the NULL method */ + + if (s->hello_extension) + { + memcpy(p,s->hello_extension,s->hello_extension_len); + p+=s->hello_extension_len; + } l=(p-d); d=buf; @@ -779,6 +785,11 @@ static int ssl3_get_server_certificate(S if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE) { + if (s->hello_extension) + { + /* Quick hack to test EAP-FAST. */ + return(1); + } al=SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_BAD_MESSAGE_TYPE); goto f_err; @@ -951,6 +962,12 @@ static int ssl3_get_key_exchange(SSL *s) DH *dh=NULL; #endif + if (s->hello_extension) + { + /* Quick hack to test EAP-FAST. */ + return(1); + } + /* use same message size as in ssl3_get_certificate_request() * as ServerKeyExchange message may be skipped */ n=ssl3_get_message(s, @@ -1264,6 +1281,12 @@ static int ssl3_get_certificate_request( unsigned char *p,*d,*q; STACK_OF(X509_NAME) *ca_sk=NULL; + if (s->hello_extension) + { + /* Quick hack to test EAP-FAST. */ + return(1); + } + n=ssl3_get_message(s, SSL3_ST_CR_CERT_REQ_A, SSL3_ST_CR_CERT_REQ_B, @@ -1407,6 +1430,12 @@ static int ssl3_get_server_done(SSL *s) int ok,ret=0; long n; + if (s->hello_extension) + { + /* Quick hack to test EAP-FAST. */ + return(1); + } + n=ssl3_get_message(s, SSL3_ST_CR_SRVR_DONE_A, SSL3_ST_CR_SRVR_DONE_B, @@ -1439,6 +1468,12 @@ static int ssl3_send_client_key_exchange KSSL_ERR kssl_err; #endif /* OPENSSL_NO_KRB5 */ + if (s->hello_extension) + { + /* Quick hack to test EAP-FAST. */ + return(1); + } + if (s->state == SSL3_ST_CW_KEY_EXCH_A) { d=(unsigned char *)s->init_buf->data; @@ -1880,6 +1915,12 @@ static int ssl3_check_cert_and_algorithm DH *dh; #endif + if (s->hello_extension) + { + /* Quick hack to test EAP-FAST. */ + return(1); + } + sc=s->session->sess_cert; if (sc == NULL) diff -upr openssl-0.9.7e.orig/ssl/ssl.h openssl-0.9.7e/ssl/ssl.h --- openssl-0.9.7e.orig/ssl/ssl.h 2004-07-27 11:28:49.000000000 -0700 +++ openssl-0.9.7e/ssl/ssl.h 2004-12-24 20:29:01.000000000 -0800 @@ -929,6 +929,11 @@ struct ssl_st int first_packet; int client_version; /* what was passed, used for * SSLv3/TLS rollback check */ + + /* Optional ClientHello/ServerHello extension to be added to the end + * of the SSLv3/TLS hello message. */ + char *hello_extension; + int hello_extension_len; }; #ifdef __cplusplus diff -upr openssl-0.9.7e.orig/ssl/ssl_lib.c openssl-0.9.7e/ssl/ssl_lib.c --- openssl-0.9.7e.orig/ssl/ssl_lib.c 2004-05-11 05:46:12.000000000 -0700 +++ openssl-0.9.7e/ssl/ssl_lib.c 2004-12-24 20:35:22.000000000 -0800 @@ -478,6 +478,7 @@ void SSL_free(SSL *s) kssl_ctx_free(s->kssl_ctx); #endif /* OPENSSL_NO_KRB5 */ + OPENSSL_free(s->hello_extension); OPENSSL_free(s); }