Support TLS extensions (specifically, HostName)

Submitted by: Peter Sylvester
diff --git a/apps/s_client.c b/apps/s_client.c
index 5679b09..c24b6e4 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -222,9 +222,32 @@
 	BIO_printf(bio_err," -engine id    - Initialise and use the specified engine\n");
 #endif
 	BIO_printf(bio_err," -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR);
-
+#ifndef OPENSSL_NO_TLSEXT
+	BIO_printf(bio_err," -servername host  - Set TLS extension servername in ClientHello\n");
+#endif
 	}
 
+#ifndef OPENSSL_NO_TLSEXT
+
+/* This is a context that we pass to callbacks */
+typedef struct tlsextctx_st {
+   BIO * biodebug;
+   int ack;
+} tlsextctx;
+
+
+static int MS_CALLBACK ssl_servername_cb(SSL *s, int *ad, void *arg) {
+	tlsextctx * p = (tlsextctx *) arg;
+	const unsigned char * hn= SSL_get_servername(s, TLSEXT_TYPE_SERVER_host);
+	if (SSL_get_servername_type(s) != -1) 
+ 	        p->ack = !SSL_session_reused(s) && hn != NULL;
+	else 
+		BIO_printf(bio_err,"SSL_get_tlsext_hostname does not work\n");
+	
+	return SSL_ERROR_NONE;
+}
+#endif
+
 int MAIN(int, char **);
 
 int MAIN(int argc, char **argv)
@@ -254,10 +277,7 @@
 	int starttls_proto = 0;
 	int prexit = 0, vflags = 0;
 	const SSL_METHOD *meth=NULL;
-#ifdef sock_type
-#undef sock_type
-#endif
-	int sock_type=SOCK_STREAM;
+	int socketType=SOCK_STREAM;
 	BIO *sbio;
 	char *inrand=NULL;
 #ifndef OPENSSL_NO_ENGINE
@@ -268,6 +288,11 @@
 	struct timeval tv;
 #endif
 
+#ifndef OPENSSL_NO_TLSEXT
+	char *servername = NULL; 
+        tlsextctx tlsextcbp = 
+        {NULL,0};
+#endif
 	struct sockaddr peer;
 	int peerlen = sizeof(peer);
 	int enable_timeouts = 0 ;
@@ -394,7 +419,7 @@
 		else if	(strcmp(*argv,"-dtls1") == 0)
 			{
 			meth=DTLSv1_client_method();
-			sock_type=SOCK_DGRAM;
+			socketType=SOCK_DGRAM;
 			}
 		else if (strcmp(*argv,"-timeout") == 0)
 			enable_timeouts=1;
@@ -477,6 +502,14 @@
 			if (--argc < 1) goto bad;
 			inrand= *(++argv);
 			}
+#ifndef OPENSSL_NO_TLSEXT
+		else if (strcmp(*argv,"-servername") == 0)
+			{
+			if (--argc < 1) goto bad;
+			servername= *(++argv);
+			/* meth=TLSv1_client_method(); */
+			}
+#endif
 		else
 			{
 			BIO_printf(bio_err,"unknown option %s\n",*argv);
@@ -572,7 +605,7 @@
 	/* DTLS: partial reads end up discarding unread UDP bytes :-( 
 	 * Setting read ahead solves this problem.
 	 */
-	if (sock_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);
+	if (socketType == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);
 
 	if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
 	if (cipher != NULL)
@@ -600,8 +633,24 @@
 
 	store = SSL_CTX_get_cert_store(ctx);
 	X509_STORE_set_flags(store, vflags);
+#ifndef OPENSSL_NO_TLSEXT
+	if (servername != NULL) {
+		tlsextcbp.biodebug = bio_err;
+		SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
+		SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp);
+	}
+#endif
 
 	con=SSL_new(ctx);
+#ifndef OPENSSL_NO_TLSEXT
+	if (servername != NULL){
+		if (!SSL_set_tlsext_hostname(con,servername)){
+			BIO_printf(bio_err,"Unable to set TLS servername extension.\n");
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	}
+#endif
 #ifndef OPENSSL_NO_KRB5
 	if (con  &&  (con->kssl_ctx = kssl_ctx_new()) != NULL)
                 {
@@ -612,7 +661,7 @@
 
 re_start:
 
-	if (init_client(&s,host,port,sock_type) == 0)
+	if (init_client(&s,host,port,socketType) == 0)
 		{
 		BIO_printf(bio_err,"connect:errno=%d\n",get_last_socket_error());
 		SHUTDOWN(s);
@@ -741,6 +790,11 @@
 			if (in_init)
 				{
 				in_init=0;
+#ifndef OPENSSL_NO_TLSEXT
+	if (servername != NULL && !SSL_session_reused(con)) {
+		BIO_printf(bio_c_out,"Server did %sacknowledge servername extension.\n",tlsextcbp.ack?"":"not ");
+	}
+#endif
 				print_stuff(bio_c_out,con,full_log);
 				if (full_log > 0) full_log--;
 
diff --git a/apps/s_server.c b/apps/s_server.c
index 918f776..7dc864f 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -221,6 +221,9 @@
 static int accept_socket= -1;
 
 #define TEST_CERT	"server.pem"
+#ifndef OPENSSL_NO_TLSEXT
+#define TEST_CERT2	"server2.pem"
+#endif
 #undef PROG
 #define PROG		s_server_main
 
@@ -230,6 +233,9 @@
 static int s_server_verify=SSL_VERIFY_NONE;
 static int s_server_session_id_context = 1; /* anything will do */
 static const char *s_cert_file=TEST_CERT,*s_key_file=NULL;
+#ifndef OPENSSL_NO_TLSEXT
+static const char *s_cert_file2=TEST_CERT2,*s_key_file2=NULL;
+#endif
 static char *s_dcert_file=NULL,*s_dkey_file=NULL;
 #ifdef FIONBIO
 static int s_nbio=0;
@@ -237,6 +243,9 @@
 static int s_nbio_test=0;
 int s_crlf=0;
 static SSL_CTX *ctx=NULL;
+#ifndef OPENSSL_NO_TLSEXT
+static SSL_CTX *ctx2=NULL;
+#endif
 static int www=0;
 
 static BIO *bio_s_out=NULL;
@@ -251,10 +260,7 @@
 static const char *session_id_prefix=NULL;
 
 static int enable_timeouts = 0;
-#ifdef mtu
-#undef mtu
-#endif
-static long mtu;
+static long socketMtu;
 static int cert_chain = 0;
 
 
@@ -268,6 +274,11 @@
 	s_dkey_file=NULL;
 	s_cert_file=TEST_CERT;
 	s_key_file=NULL;
+#ifndef OPENSSL_NO_TLSEXT
+	s_cert_file2=TEST_CERT2;
+	s_key_file2=NULL;
+	ctx2=NULL;
+#endif
 #ifdef FIONBIO
 	s_nbio=0;
 #endif
@@ -354,6 +365,14 @@
 #endif
 	BIO_printf(bio_err," -id_prefix arg - Generate SSL/TLS session IDs prefixed by 'arg'\n");
 	BIO_printf(bio_err," -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR);
+#ifndef OPENSSL_NO_TLSEXT
+	BIO_printf(bio_err," -servername host - check TLS1 servername\n");
+	BIO_printf(bio_err," -cert2 arg    - certificate file to use for servername\n");
+	BIO_printf(bio_err,"                 (default is %s)\n",TEST_CERT2);
+	BIO_printf(bio_err," -key2 arg     - Private Key file to use for servername, in cert file if\n");
+	BIO_printf(bio_err,"                 not specified (default is %s)\n",TEST_CERT2);
+	BIO_printf(bio_err," -servername host - check TLS1 servername\n");
+#endif
 	}
 
 static int local_argc=0;
@@ -509,6 +528,37 @@
 }
 #endif
 
+#ifndef OPENSSL_NO_TLSEXT
+
+/* This is a context that we pass to callbacks */
+typedef struct tlsextctx_st {
+   char * servername;
+   BIO * biodebug;
+} tlsextctx;
+
+
+static int MS_CALLBACK ssl_servername_cb(SSL *s, int *ad, void *arg) {
+	tlsextctx * p = (tlsextctx *) arg;
+	const char * servername = SSL_get_servername(s, TLSEXT_TYPE_SERVER_host);
+        if (servername) 
+		BIO_printf(p->biodebug,"Hostname in TLS extension: \"%s\"\n",servername);
+        
+	if (!p->servername) {
+		SSL_set_tlsext_servername_done(s,2);
+		return SSL_ERROR_NONE;
+	}
+	
+	if (servername) {
+    		if (strcmp(servername,p->servername)) 
+			return TLS1_AD_UNRECOGNIZED_NAME;
+		if (ctx2) 
+			SSL_set_SSL_CTX(s,ctx2);
+		SSL_set_tlsext_servername_done(s,1);
+	}
+	return SSL_ERROR_NONE;
+}
+#endif
+
 int MAIN(int, char **);
 
 int MAIN(int argc, char *argv[])
@@ -528,10 +578,7 @@
 	int no_tmp_rsa=0,no_dhe=0,no_ecdhe=0,nocert=0;
 	int state=0;
 	const SSL_METHOD *meth=NULL;
-#ifdef sock_type
-#undef sock_type
-#endif
-    int sock_type=SOCK_STREAM;
+	int socketType=SOCK_STREAM;
 #ifndef OPENSSL_NO_ENGINE
 	ENGINE *e=NULL;
 #endif
@@ -542,7 +589,16 @@
 	int s_dcert_format = FORMAT_PEM, s_dkey_format = FORMAT_PEM;
 	X509 *s_cert = NULL, *s_dcert = NULL;
 	EVP_PKEY *s_key = NULL, *s_dkey = NULL;
+#ifndef OPENSSL_NO_TLSEXT
+	EVP_PKEY *s_key2 = NULL;
+	X509 *s_cert2 = NULL;
+#endif
 
+#ifndef OPENSSL_NO_TLSEXT
+        tlsextctx tlsextcbp = 
+        {NULL,NULL
+        };
+#endif
 #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3)
 	meth=SSLv23_server_method();
 #elif !defined(OPENSSL_NO_SSL3)
@@ -755,14 +811,14 @@
 		else if	(strcmp(*argv,"-dtls1") == 0)
 			{ 
 			meth=DTLSv1_server_method();
-			sock_type = SOCK_DGRAM;
+			socketType = SOCK_DGRAM;
 			}
 		else if (strcmp(*argv,"-timeout") == 0)
 			enable_timeouts = 1;
 		else if (strcmp(*argv,"-mtu") == 0)
 			{
 			if (--argc < 1) goto bad;
-			mtu = atol(*(++argv));
+			socketMtu = atol(*(++argv));
 			}
 		else if (strcmp(*argv, "-chain") == 0)
 			cert_chain = 1;
@@ -784,6 +840,24 @@
 			if (--argc < 1) goto bad;
 			inrand= *(++argv);
 			}
+#ifndef OPENSSL_NO_TLSEXT
+		else if (strcmp(*argv,"-servername") == 0)
+			{
+			if (--argc < 1) goto bad;
+			tlsextcbp.servername= *(++argv);
+			/* meth=TLSv1_server_method(); */
+			}
+		else if	(strcmp(*argv,"-cert2") == 0)
+			{
+			if (--argc < 1) goto bad;
+			s_cert_file2= *(++argv);
+			}
+		else if	(strcmp(*argv,"-key2") == 0)
+			{
+			if (--argc < 1) goto bad;
+			s_key_file2= *(++argv);
+			}
+#endif
 		else
 			{
 			BIO_printf(bio_err,"unknown option %s\n",*argv);
@@ -816,6 +890,10 @@
 
 	if (s_key_file == NULL)
 		s_key_file = s_cert_file;
+#ifndef OPENSSL_NO_TLSEXT
+	if (s_key_file2 == NULL)
+		s_key_file2 = s_cert_file2;
+#endif
 
 	if (nocert == 0)
 		{
@@ -835,8 +913,31 @@
 			ERR_print_errors(bio_err);
 			goto end;
 			}
+
+#ifndef OPENSSL_NO_TLSEXT
+			if (tlsextcbp.servername) 
+			{
+			s_key2 = load_key(bio_err, s_key_file2, s_key_format, 0, pass, e,
+		       	"second server certificate private key file");
+			if (!s_key2)
+				{
+				ERR_print_errors(bio_err);
+				goto end;
+				}
+
+			s_cert2 = load_cert(bio_err,s_cert_file2,s_cert_format,
+				NULL, e, "second server certificate file");
+
+			if (!s_cert2)
+				{
+				ERR_print_errors(bio_err);
+				goto end;
+				}
+			}
+#endif
 		}
 
+
 	if (s_dcert_file)
 		{
 
@@ -893,6 +994,10 @@
 		s_key_file=NULL;
 		s_dcert_file=NULL;
 		s_dkey_file=NULL;
+#ifndef OPENSSL_NO_TLSEXT
+		s_cert_file2=NULL;
+		s_key_file2=NULL;
+#endif
 		}
 
 	ctx=SSL_CTX_new(meth);
@@ -924,7 +1029,7 @@
 	/* DTLS: partial reads end up discarding unread UDP bytes :-( 
 	 * Setting read ahead solves this problem.
 	 */
-	if (sock_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);
+	if (socketType == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);
 
 	if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
 
@@ -952,6 +1057,57 @@
 	store = SSL_CTX_get_cert_store(ctx);
 	X509_STORE_set_flags(store, vflags);
 
+#ifndef OPENSSL_NO_TLSEXT
+	if (s_cert2) {
+	ctx2=SSL_CTX_new(meth);
+	if (ctx2 == NULL)
+		{
+		ERR_print_errors(bio_err);
+		goto end;
+		}
+	}
+	
+	if (ctx2) {
+			BIO_printf(bio_s_out,"Setting secondary ctx parameters\n");
+	if (session_id_prefix)
+		{
+		if(strlen(session_id_prefix) >= 32)
+			BIO_printf(bio_err,
+"warning: id_prefix is too long, only one new session will be possible\n");
+		else if(strlen(session_id_prefix) >= 16)
+			BIO_printf(bio_err,
+"warning: id_prefix is too long if you use SSLv2\n");
+		if(!SSL_CTX_set_generate_session_id(ctx2, generate_session_id))
+			{
+			BIO_printf(bio_err,"error setting 'id_prefix'\n");
+			ERR_print_errors(bio_err);
+			goto end;
+			}
+		BIO_printf(bio_err,"id_prefix '%s' set.\n", session_id_prefix);
+		}
+	SSL_CTX_set_quiet_shutdown(ctx2,1);
+	if (bugs) SSL_CTX_set_options(ctx2,SSL_OP_ALL);
+	if (hack) SSL_CTX_set_options(ctx2,SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
+	SSL_CTX_set_options(ctx2,off);
+	/* DTLS: partial reads end up discarding unread UDP bytes :-( 
+	 * Setting read ahead solves this problem.
+	 */
+	if (socketType == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx2, 1);
+
+	if (state) SSL_CTX_set_info_callback(ctx2,apps_ssl_info_callback);
+
+	SSL_CTX_sess_set_cache_size(ctx2,128);
+
+	if ((!SSL_CTX_load_verify_locations(ctx2,CAfile,CApath)) ||
+		(!SSL_CTX_set_default_verify_paths(ctx2)))
+		{
+			ERR_print_errors(bio_err);
+		}
+	store = SSL_CTX_get_cert_store(ctx2);
+	X509_STORE_set_flags(store, vflags);
+
+	}
+#endif 
 #ifndef OPENSSL_NO_DH
 	if (!no_dhe)
 		{
@@ -974,6 +1130,22 @@
 		(void)BIO_flush(bio_s_out);
 
 		SSL_CTX_set_tmp_dh(ctx,dh);
+#ifndef OPENSSL_NO_TLSEXT
+		if (ctx2) {
+			if (!dhfile) { 
+				DH *dh2=load_dh_param(s_cert_file2);
+				if (dh2 != NULL)
+				{
+					BIO_printf(bio_s_out,"Setting temp DH parameters\n");
+					(void)BIO_flush(bio_s_out);
+
+					DH_free(dh);
+					dh = dh2;
+				}
+			}
+			SSL_CTX_set_tmp_dh(ctx2,dh);
+		}
+#endif
 		DH_free(dh);
 		}
 #endif
@@ -1019,12 +1191,20 @@
 		(void)BIO_flush(bio_s_out);
 
 		SSL_CTX_set_tmp_ecdh(ctx,ecdh);
+#ifndef OPENSSL_NO_TLSEXT
+		if (ctx2) 
+			SSL_CTX_set_tmp_ecdh(ctx2,ecdh);
+#endif
 		EC_KEY_free(ecdh);
 		}
 #endif
 	
 	if (!set_cert_key_stuff(ctx,s_cert,s_key))
 		goto end;
+#ifndef OPENSSL_NO_TLSEXT
+	if (ctx2 && !set_cert_key_stuff(ctx2,s_cert2,s_key2))
+		goto end; 
+#endif
 	if (s_dcert != NULL)
 		{
 		if (!set_cert_key_stuff(ctx,s_dcert,s_dkey))
@@ -1033,8 +1213,13 @@
 
 #ifndef OPENSSL_NO_RSA
 #if 1
-	if (!no_tmp_rsa)
+	if (!no_tmp_rsa) {
 		SSL_CTX_set_tmp_rsa_callback(ctx,tmp_rsa_cb);
+#ifndef OPENSSL_NO_TLSEXT
+		if (ctx2) 
+			SSL_CTX_set_tmp_rsa_callback(ctx2,tmp_rsa_cb);
+#endif		
+	}
 #else
 	if (!no_tmp_rsa && SSL_CTX_need_tmp_RSA(ctx))
 		{
@@ -1050,30 +1235,65 @@
 			ERR_print_errors(bio_err);
 			goto end;
 			}
+#ifndef OPENSSL_NO_TLSEXT
+			if (ctx2) {
+				if (!SSL_CTX_set_tmp_rsa(ctx2,rsa))
+				{
+					ERR_print_errors(bio_err);
+					goto end;
+				}
+			}
+#endif
 		RSA_free(rsa);
 		BIO_printf(bio_s_out,"\n");
 		}
 #endif
 #endif
 
-	if (cipher != NULL)
+	if (cipher != NULL) {
 		if(!SSL_CTX_set_cipher_list(ctx,cipher)) {
-		BIO_printf(bio_err,"error setting cipher list\n");
-		ERR_print_errors(bio_err);
-		goto end;
+			BIO_printf(bio_err,"error setting cipher list\n");
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+#ifndef OPENSSL_NO_TLSEXT
+		if (ctx2 && !SSL_CTX_set_cipher_list(ctx2,cipher)) {
+			BIO_printf(bio_err,"error setting cipher list\n");
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+#endif
 	}
 	SSL_CTX_set_verify(ctx,s_server_verify,verify_callback);
 	SSL_CTX_set_session_id_context(ctx,(void*)&s_server_session_id_context,
 		sizeof s_server_session_id_context);
 
-	if (CAfile != NULL)
+#ifndef OPENSSL_NO_TLSEXT
+	if (ctx2) {
+		SSL_CTX_set_verify(ctx2,s_server_verify,verify_callback);
+		SSL_CTX_set_session_id_context(ctx2,(void*)&s_server_session_id_context,
+			sizeof s_server_session_id_context);
+
+	}
+	tlsextcbp.biodebug = bio_s_out;
+	SSL_CTX_set_tlsext_servername_callback(ctx2, ssl_servername_cb);
+	SSL_CTX_set_tlsext_servername_arg(ctx2, &tlsextcbp);
+	SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
+	SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp);
+#endif
+	if (CAfile != NULL) {
 	    SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAfile));
+#ifndef OPENSSL_NO_TLSEXT
+		if (ctx2) 
+	   		 SSL_CTX_set_client_CA_list(ctx2,SSL_load_client_CA_file(CAfile));
+#endif
+	}
 
 	BIO_printf(bio_s_out,"ACCEPT\n");
 	if (www)
-		do_server(port,sock_type,&accept_socket,www_body, context);
+		do_server(port,socketType,&accept_socket,www_body, context);
 	else
-		do_server(port,sock_type,&accept_socket,sv_body, context);
+		do_server(port,socketType,&accept_socket,sv_body, context);
 	print_stats(bio_s_out,ctx);
 	ret=0;
 end:
@@ -1090,6 +1310,13 @@
 		OPENSSL_free(pass);
 	if (dpass)
 		OPENSSL_free(dpass);
+#ifndef OPENSSL_NO_TLSEXT
+	if (ctx2 != NULL) SSL_CTX_free(ctx2);
+	if (s_cert2)
+		X509_free(s_cert2);
+	if (s_key2)
+		EVP_PKEY_free(s_key2);
+#endif
 	if (bio_s_out != NULL)
 		{
         BIO_free(bio_s_out);
@@ -1189,10 +1416,10 @@
 			}
 
 		
-		if ( mtu > 0)
+		if ( socketMtu > 0)
 			{
 			SSL_set_options(con, SSL_OP_NO_QUERY_MTU);
-			SSL_set_mtu(con, mtu);
+			SSL_set_mtu(con, socketMtu);
 			}
 		else
 			/* want to do MTU discovery */
diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c
index 1d1110b..5a07db1 100644
--- a/ssl/s23_clnt.c
+++ b/ssl/s23_clnt.c
@@ -349,6 +349,10 @@
 			p+=i;
 
 			/* COMPRESSION */
+#ifdef OPENSSL_NO_COMP
+			*(p++)=1;
+#else
+
 			if ((s->options & SSL_OP_NO_COMPRESSION)
 						|| !s->ctx->comp_methods)
 				j=0;
@@ -360,7 +364,15 @@
 				comp=sk_SSL_COMP_value(s->ctx->comp_methods,i);
 				*(p++)=comp->id;
 				}
+#endif
 			*(p++)=0; /* Add the NULL method */
+#ifndef OPENSSL_NO_TLSEXT
+			if ((p = ssl_add_ClientHello_TLS_extensions(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+			{
+				SSLerr(SSL_F_SSL3_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);
+				return -1;
+			}
+#endif
 			
 			l = p-d;
 			*p = 42;
diff --git a/ssl/s23_srvr.c b/ssl/s23_srvr.c
index b33b699..8bf044e 100644
--- a/ssl/s23_srvr.c
+++ b/ssl/s23_srvr.c
@@ -140,7 +140,7 @@
 int ssl23_accept(SSL *s)
 	{
 	BUF_MEM *buf;
-	unsigned long Time=(unsigned long)time(NULL);
+	unsigned long Time=time(NULL);
 	void (*cb)(const SSL *ssl,int type,int val)=NULL;
 	int ret= -1;
 	int new_state,state;
@@ -416,7 +416,7 @@
 		n2s(p,sil);
 		n2s(p,cl);
 		d=(unsigned char *)s->init_buf->data;
-		if ((csl+sil+cl+11) != s->packet_length)
+		if ((csl+sil+cl+11) > s->packet_length)
 			{
 			SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO,SSL_R_RECORD_LENGTH_MISMATCH);
 			goto err;
@@ -459,6 +459,12 @@
 		*(d++)=1;
 		*(d++)=0;
 		
+                /* copy any remaining data with may be extensions */
+	        p = p+csl+sil+cl ;
+		while (p <  s->packet+s->packet_length) {
+			*(d++)=*(p++);
+		}
+
 		i = (d-(unsigned char *)s->init_buf->data) - 4;
 		l2n3((long)i, d_len);
 
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 0098f56..7a4f256 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -255,6 +255,16 @@
 		case SSL3_ST_CR_SRVR_HELLO_B:
 			ret=ssl3_get_server_hello(s);
 			if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+			{
+				int extension_error = 0,al;
+				if ((al = ssl_check_Hello_TLS_extensions(s,&extension_error)) != SSL_ERROR_NONE){
+					ret = -1;
+					SSLerr(SSL_F_SSL3_CONNECT,SSL_R_SERVERHELLO_TLS_EXT);
+					goto end;
+				}
+			}
+#endif
 			if (s->hit)
 				s->state=SSL3_ST_CR_FINISHED_A;
 			else
@@ -602,6 +612,13 @@
 			}
 #endif
 		*(p++)=0; /* Add the NULL method */
+#ifndef OPENSSL_NO_TLSEXT
+		if ((p = ssl_add_ClientHello_TLS_extensions(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+		{
+			SSLerr(SSL_F_SSL3_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);
+			goto err;
+		}
+#endif
 		
 		l=(p-d);
 		d=buf;
@@ -786,6 +803,16 @@
 		s->s3->tmp.new_compression=comp;
 		}
 #endif
+#ifndef OPENSSL_NO_TLSEXT
+	/* TLS extensions*/
+	if (s->version > SSL3_VERSION)
+	{
+		if ((al = ssl_parse_ServerHello_TLS_extensions(s,&p,d,n)) != SSL_ERROR_NONE){
+			SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLS_EXT);
+			goto f_err; 
+		}
+	}
+#endif
 
 	if (p != (d+n))
 		{
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 791c5e9..845e5a1 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -1643,6 +1643,43 @@
 		}
 		break;
 #endif /* !OPENSSL_NO_ECDH */
+#ifndef OPENSSL_NO_TLSEXT
+	case SSL_CTRL_GET_TLSEXT_HOSTNAME:	
+		if (larg != TLSEXT_TYPE_SERVER_host)
+			{
+			SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE);
+			return(0);
+			}
+	   	*((char **) parg) = s->session&&s->session->tlsext_hostname?s->session->tlsext_hostname:s->tlsext_hostname;
+		ret = 1;
+                break;
+	case SSL_CTRL_SET_TLSEXT_HOSTNAME:
+ 		if (larg == TLSEXT_TYPE_SERVER_host) {
+			if (s->tlsext_hostname != NULL) 
+				OPENSSL_free(s->tlsext_hostname);
+			s->tlsext_hostname = NULL;
+
+			ret = 1;
+			if (parg == NULL) 
+				break;
+			if (strlen((char *)parg) > 255) {
+				SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME);
+				return 0;
+			}
+			if ((s->tlsext_hostname = BUF_strdup((char *)parg)) == NULL) {
+				SSLerr(SSL_F_SSL3_CTRL, ERR_R_INTERNAL_ERROR);
+				return 0;
+			}
+		} else {
+			SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE);
+			return 0;
+		}
+		s->options |= SSL_OP_NO_SSLv2;
+ 		break;
+	case SSL_CTRL_SET_TLSEXT_SERVERNAME_DONE:
+		s->servername_done = larg;
+		break;
+#endif /* !OPENSSL_NO_TLSEXT */
 	default:
 		break;
 		}
@@ -1827,6 +1864,11 @@
 		}
 		break;
 #endif /* !OPENSSL_NO_ECDH */
+#ifndef OPENSSL_NO_TLSEXT
+	case SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG:
+		ctx->tlsext_servername_arg=parg;
+		break;
+#endif /* !OPENSSL_NO_TLSEXT */
 	/* A Thawte special :-) */
 	case SSL_CTRL_EXTRA_CHAIN_CERT:
 		if (ctx->extra_certs == NULL)
@@ -1872,6 +1914,11 @@
 		}
 		break;
 #endif
+#ifndef OPENSSL_NO_TLSEXT
+	case SSL_CTRL_SET_TLSEXT_SERVERNAME_CB:
+		ctx->tlsext_servername_callback=(int (*)(SSL *,int *,void *))fp;
+		break;
+#endif
 	default:
 		return(0);
 		}
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 1803084..25b56fa 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -281,6 +281,17 @@
 			s->shutdown=0;
 			ret=ssl3_get_client_hello(s);
 			if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+			{
+				int extension_error = 0,al;
+				if ((al = ssl_check_Hello_TLS_extensions(s,&extension_error)) != SSL_ERROR_NONE){
+					ret = -1;
+					SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLS_EXT);
+					ssl3_send_alert(s,al,extension_error);
+					goto end;
+				}
+			}
+#endif
 			s->new_session = 2;
 			s->state=SSL3_ST_SW_SRVR_HELLO_A;
 			s->init_num=0;
@@ -942,6 +953,17 @@
 			}
 		}
 #endif
+#ifndef OPENSSL_NO_TLSEXT
+	/* TLS extensions*/
+	if (s->version > SSL3_VERSION)
+	{
+		if ((al = ssl_parse_ClientHello_TLS_extensions(s,&p,d,n)) != SSL_ERROR_NONE){
+			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLS_EXT);
+			ssl3_send_alert(s,SSL3_AL_WARNING,al);
+			return (ret = al);
+		}
+	}
+#endif
 
 	/* Given s->session->ciphers and SSL_get_ciphers, we must
 	 * pick a cipher */
@@ -1086,6 +1108,13 @@
 		else
 			*(p++)=s->s3->tmp.new_compression->id;
 #endif
+#ifndef OPENSSL_NO_TLSEXT
+		if ((p = ssl_add_ServerHello_TLS_extensions(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+		{
+			SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR);
+			return -1;
+		}
+#endif
 
 		/* do the header */
 		l=(p-d);
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 42e34b9..29f1e0b 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -172,6 +172,11 @@
 
 #include <openssl/e_os2.h>
 
+#ifdef OPENSSL_NO_TLS1
+#	ifndef OPENSSL_NO_TLSEXT 
+#		define OPENSSL_NO_TLSEXT
+#	endif
+#endif
 #ifndef OPENSSL_NO_COMP
 #include <openssl/comp.h>
 #endif
@@ -439,6 +444,9 @@
         unsigned int krb5_client_princ_len;
         unsigned char krb5_client_princ[SSL_MAX_KRB5_PRINCIPAL_LENGTH];
 #endif /* OPENSSL_NO_KRB5 */
+#ifndef OPENSSL_NO_TLSEXT
+	char *tlsext_hostname;
+#endif
 
 	int not_resumable;
 
@@ -755,6 +763,13 @@
 	 * padding and MAC overheads.
 	 */
 	unsigned int max_send_fragment;
+
+#ifndef OPENSSL_NO_TLSEXT
+    /* TLS extensions servername callback */
+	int (*tlsext_servername_callback)(SSL*, int *, void *);
+	void *tlsext_servername_arg;
+#endif
+
 	};
 
 #define SSL_SESS_CACHE_OFF			0x0000
@@ -977,6 +992,14 @@
 	int client_version;	/* what was passed, used for
 				 * SSLv3/TLS rollback check */
 	unsigned int max_send_fragment;
+#ifndef OPENSSL_NO_TLSEXT
+	char *tlsext_hostname;
+        int servername_done;   /* no further mod of servername 
+                                  0 : call the servername extension callback.
+                                  1 : prepare 2, allow last ack just after in server callback.
+                                  2 : don't call servername callback, no ack in server hello
+                               */
+#endif
 	};
 
 #ifdef __cplusplus
@@ -1122,6 +1145,9 @@
 #define SSL_AD_INTERNAL_ERROR		TLS1_AD_INTERNAL_ERROR	/* fatal */
 #define SSL_AD_USER_CANCELLED		TLS1_AD_USER_CANCELLED
 #define SSL_AD_NO_RENEGOTIATION		TLS1_AD_NO_RENEGOTIATION
+#ifndef OPENSSL_NO_TLSEXT
+#define SSL_AD_UNRECOGNIZED_NAME	TLS1_AD_UNRECOGNIZED_NAME
+#endif
 
 #define SSL_ERROR_NONE			0
 #define SSL_ERROR_SSL			1
@@ -1454,6 +1480,7 @@
 SSL_SESSION *SSL_get_session(const SSL *ssl);
 SSL_SESSION *SSL_get1_session(SSL *ssl); /* obtain a reference count */
 SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl);
+SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx);
 void SSL_set_info_callback(SSL *ssl,
 			   void (*cb)(const SSL *ssl,int type,int val));
 void (*SSL_get_info_callback(const SSL *ssl))(const SSL *ssl,int type,int val);
@@ -1777,6 +1804,7 @@
 #define SSL_R_CIPHER_CODE_WRONG_LENGTH			 137
 #define SSL_R_CIPHER_OR_HASH_UNAVAILABLE		 138
 #define SSL_R_CIPHER_TABLE_SRC_ERROR			 139
+#define SSL_R_CLIENTHELLO_TLS_EXT			 2003
 #define SSL_R_COMPRESSED_LENGTH_TOO_LONG		 140
 #define SSL_R_COMPRESSION_FAILURE			 141
 #define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE	 1120
@@ -1861,6 +1889,7 @@
 #define SSL_R_NULL_SSL_METHOD_PASSED			 196
 #define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED		 197
 #define SSL_R_PACKET_LENGTH_TOO_LONG			 198
+#define SSL_R_PARSE_TLS_EXT				 2004
 #define SSL_R_PATH_TOO_LONG				 270
 #define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE		 199
 #define SSL_R_PEER_ERROR				 200
@@ -1884,11 +1913,14 @@
 #define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO		 216
 #define SSL_R_REUSE_CERT_TYPE_NOT_ZERO			 217
 #define SSL_R_REUSE_CIPHER_LIST_NOT_ZERO		 218
+#define SSL_R_SERVERHELLO_TLS_EXT			 2005
 #define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED		 277
 #define SSL_R_SHORT_READ				 219
 #define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE	 220
 #define SSL_R_SSL23_DOING_SESSION_ID_REUSE		 221
 #define SSL_R_SSL2_CONNECTION_ID_TOO_LONG		 1114
+#define SSL_R_SSL3_EXT_INVALID_SERVERNAME		 2006
+#define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE		 2007
 #define SSL_R_SSL3_SESSION_ID_TOO_LONG			 1113
 #define SSL_R_SSL3_SESSION_ID_TOO_SHORT			 222
 #define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE		 1042
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index d129acc..e98a47f 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -78,12 +78,15 @@
 	ASN1_INTEGER time;
 	ASN1_INTEGER timeout;
 	ASN1_INTEGER verify_result;
+#ifndef OPENSSL_NO_TLSEXT
+	ASN1_OCTET_STRING tlsext_hostname;
+#endif /* OPENSSL_NO_TLSEXT */
 	} SSL_SESSION_ASN1;
 
 int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
 	{
 #define LSIZE2 (sizeof(long)*2)
-	int v1=0,v2=0,v3=0,v4=0,v5=0;
+	int v1=0,v2=0,v3=0,v4=0,v5=0,v6=0;
 	unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2];
 	unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2];
 	long l;
@@ -178,6 +181,14 @@
 		ASN1_INTEGER_set(&a.verify_result,in->verify_result);
 		}
 
+#ifndef OPENSSL_NO_TLSEXT
+	if (in->tlsext_hostname)
+                {
+                a.tlsext_hostname.length=strlen(in->tlsext_hostname);
+                a.tlsext_hostname.type=V_ASN1_OCTET_STRING;
+                a.tlsext_hostname.data=in->tlsext_hostname;
+                }                
+#endif /* OPENSSL_NO_TLSEXT */
 
 	M_ASN1_I2D_len(&(a.version),		i2d_ASN1_INTEGER);
 	M_ASN1_I2D_len(&(a.ssl_version),	i2d_ASN1_INTEGER);
@@ -200,6 +211,10 @@
 	if (in->verify_result != X509_V_OK)
 		M_ASN1_I2D_len_EXP_opt(&(a.verify_result),i2d_ASN1_INTEGER,5,v5);
 
+#ifndef OPENSSL_NO_TLSEXT
+	if (in->tlsext_hostname)
+        	M_ASN1_I2D_len_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
+#endif /* OPENSSL_NO_TLSEXT */
 	M_ASN1_I2D_seq_total();
 
 	M_ASN1_I2D_put(&(a.version),		i2d_ASN1_INTEGER);
@@ -223,6 +238,10 @@
 			       v4);
 	if (in->verify_result != X509_V_OK)
 		M_ASN1_I2D_put_EXP_opt(&a.verify_result,i2d_ASN1_INTEGER,5,v5);
+#ifndef OPENSSL_NO_TLSEXT
+	if (in->tlsext_hostname)
+        	M_ASN1_I2D_put_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
+#endif /* OPENSSL_NO_TLSEXT */
 	M_ASN1_I2D_finish();
 	}
 
@@ -394,5 +413,21 @@
 	else
 		ret->verify_result=X509_V_OK;
 
+#ifndef OPENSSL_NO_TLSEXT
+	os.length=0;
+	os.data=NULL;
+	M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,6);
+	if (os.data)
+		{
+		ret->tlsext_hostname = BUF_strndup(os.data, os.length);
+		OPENSSL_free(os.data);
+		os.data = NULL;
+		os.length = 0;
+		}
+	else
+		ret->tlsext_hostname=NULL;
+
+#endif /* OPENSSL_NO_TLSEXT */
+
 	M_ASN1_D2I_Finish(a,SSL_SESSION_free,SSL_F_D2I_SSL_SESSION);
 	}
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 282f1a6..133c4a7 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -292,6 +292,7 @@
 {ERR_REASON(SSL_R_CIPHER_CODE_WRONG_LENGTH),"cipher code wrong length"},
 {ERR_REASON(SSL_R_CIPHER_OR_HASH_UNAVAILABLE),"cipher or hash unavailable"},
 {ERR_REASON(SSL_R_CIPHER_TABLE_SRC_ERROR),"cipher table src error"},
+{ERR_REASON(SSL_R_CLIENTHELLO_TLS_EXT)   ,"clienthello tls ext"},
 {ERR_REASON(SSL_R_COMPRESSED_LENGTH_TOO_LONG),"compressed length too long"},
 {ERR_REASON(SSL_R_COMPRESSION_FAILURE)   ,"compression failure"},
 {ERR_REASON(SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE),"compression id not within private range"},
@@ -376,6 +377,7 @@
 {ERR_REASON(SSL_R_NULL_SSL_METHOD_PASSED),"null ssl method passed"},
 {ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),"old session cipher not returned"},
 {ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG),"packet length too long"},
+{ERR_REASON(SSL_R_PARSE_TLS_EXT)         ,"parse tls ext"},
 {ERR_REASON(SSL_R_PATH_TOO_LONG)         ,"path too long"},
 {ERR_REASON(SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE),"peer did not return a certificate"},
 {ERR_REASON(SSL_R_PEER_ERROR)            ,"peer error"},
@@ -399,11 +401,14 @@
 {ERR_REASON(SSL_R_REUSE_CERT_LENGTH_NOT_ZERO),"reuse cert length not zero"},
 {ERR_REASON(SSL_R_REUSE_CERT_TYPE_NOT_ZERO),"reuse cert type not zero"},
 {ERR_REASON(SSL_R_REUSE_CIPHER_LIST_NOT_ZERO),"reuse cipher list not zero"},
+{ERR_REASON(SSL_R_SERVERHELLO_TLS_EXT)   ,"serverhello tls ext"},
 {ERR_REASON(SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED),"session id context uninitialized"},
 {ERR_REASON(SSL_R_SHORT_READ)            ,"short read"},
 {ERR_REASON(SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE),"signature for non signing certificate"},
 {ERR_REASON(SSL_R_SSL23_DOING_SESSION_ID_REUSE),"ssl23 doing session id reuse"},
 {ERR_REASON(SSL_R_SSL2_CONNECTION_ID_TOO_LONG),"ssl2 connection id too long"},
+{ERR_REASON(SSL_R_SSL3_EXT_INVALID_SERVERNAME),"ssl3 ext invalid servername"},
+{ERR_REASON(SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE),"ssl3 ext invalid servername type"},
 {ERR_REASON(SSL_R_SSL3_SESSION_ID_TOO_LONG),"ssl3 session id too long"},
 {ERR_REASON(SSL_R_SSL3_SESSION_ID_TOO_SHORT),"ssl3 session id too short"},
 {ERR_REASON(SSL_R_SSLV3_ALERT_BAD_CERTIFICATE),"sslv3 alert bad certificate"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index b79ac1c..afe7162 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1315,6 +1315,27 @@
 	return(NULL);
 	}
 
+#ifndef OPENSSL_TLSEXT
+/** return a servername extension value if provided in CLIENT HELLO
+ * or NULL. 
+ * For the moment, only hostname types are supported. 
+ */
+
+const char *SSL_get_servername(const SSL *s, const int type) {
+
+	if (type != TLSEXT_TYPE_SERVER_host) 
+		return NULL;
+	return s->session /*&&s->session->tlsext_hostname*/?s->session->tlsext_hostname:s->tlsext_hostname;
+}
+
+int SSL_get_servername_type(const SSL *s) {
+
+	if (s->session &&s->session->tlsext_hostname ?s->session->tlsext_hostname:s->tlsext_hostname) 
+		return TLSEXT_TYPE_SERVER_host;
+	return -1;
+}
+
+#endif
 unsigned long SSL_SESSION_hash(const SSL_SESSION *a)
 	{
 	unsigned long l;
@@ -1466,6 +1487,10 @@
 
 	ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH;
 
+#ifndef OPENSSL_NO_TLSEXT
+	ret->tlsext_servername_callback = NULL;
+	ret->tlsext_servername_arg = NULL;
+#endif
 	return(ret);
 err:
 	SSLerr(SSL_F_SSL_CTX_NEW,ERR_R_MALLOC_FAILURE);
@@ -2415,6 +2440,19 @@
 	return(ssl->ctx);
 	}
 
+SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx)
+	{
+
+	if (ssl->cert != NULL)
+		ssl_cert_free(ssl->cert);
+	ssl->cert = ssl_cert_dup(ctx->cert);
+	CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
+	if (ssl->ctx != NULL)
+		SSL_CTX_free(ssl->ctx); /* decrement reference count */
+	ssl->ctx = ctx;
+	return(ssl->ctx);
+	}
+
 #ifndef OPENSSL_NO_STDIO
 int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)
 	{
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 6a56384..26a062f 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -940,5 +940,11 @@
 
 SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n);
 
-
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *ssl_add_ClientHello_TLS_extensions(SSL *s, unsigned char *p, unsigned char *limit); 
+unsigned char *ssl_add_ServerHello_TLS_extensions(SSL *s, unsigned char *p, unsigned char *limit); 
+int ssl_parse_ClientHello_TLS_extensions(SSL *s, unsigned char **data, unsigned char *d, int n);
+int ssl_parse_ServerHello_TLS_extensions(SSL *s, unsigned char **data, unsigned char *d, int n);
+int ssl_check_Hello_TLS_extensions(SSL *s,int *ad);
+#endif
 #endif
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index 7a4bb92..6c2c04b 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -122,6 +122,9 @@
 	ss->prev=NULL;
 	ss->next=NULL;
 	ss->compress_meth=0;
+#ifndef OPENSSL_NO_TLSEXT
+	ss->tlsext_hostname = NULL; 
+#endif
 	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data);
 	return(ss);
 	}
@@ -546,6 +549,10 @@
 	if (ss->sess_cert != NULL) ssl_sess_cert_free(ss->sess_cert);
 	if (ss->peer != NULL) X509_free(ss->peer);
 	if (ss->ciphers != NULL) sk_SSL_CIPHER_free(ss->ciphers);
+#ifndef OPENSSL_NO_TLSEXT
+	if (ss->tlsext_hostname != NULL)
+		OPENSSL_free(ss->tlsext_hostname);
+#endif
 	OPENSSL_cleanse(ss,sizeof(*ss));
 	OPENSSL_free(ss);
 	}
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index fd0d821..ff5bc58 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -101,14 +101,186 @@
 	s->version=TLS1_VERSION;
 	}
 
-#if 0
-long tls1_ctrl(SSL *s, int cmd, long larg, char *parg)
-	{
-	return(0);
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *ssl_add_ClientHello_TLS_extensions(SSL *s, unsigned char *p, unsigned char *limit) {
+	int extdatalen=0;
+	unsigned char *ret = p;
+
+	ret+=2;
+
+	if (ret>=limit) return NULL; /* this really never occurs, but ... */
+ 	if (s->servername_done == 0 && s->tlsext_hostname != NULL) { 
+		/* Add TLS extension servername to the Client Hello message */
+		unsigned long size_str;
+		long lenmax; 
+
+		if ((lenmax = limit - p - 7) < 0) return NULL; 
+		if ((size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) return NULL;
+
+		s2n(TLSEXT_TYPE_server_name,ret);
+		s2n(size_str+3,ret);
+		*(ret++) = (unsigned char) TLSEXT_TYPE_SERVER_host;
+		s2n(size_str,ret);
+	
+		memcpy(ret, s->tlsext_hostname, size_str);
+		ret+=size_str;
 	}
 
-long tls1_callback_ctrl(SSL *s, int cmd, void *(*fp)())
-	{
-	return(0);
+	
+	if ((extdatalen = ret-p-2)== 0) 
+		return p;
+
+	s2n(extdatalen,p);
+	return ret;
+
+}
+
+unsigned char *ssl_add_ServerHello_TLS_extensions(SSL *s, unsigned char *p, unsigned char *limit) {
+	int extdatalen=0;
+	unsigned char *ret = p;
+	if (s->hit || s->servername_done == 2)
+		return p;
+	ret+=2;
+	if (s->servername_done == 1)  
+		s->servername_done = 2;
+
+	if (ret>=limit) return NULL; /* this really never occurs, but ... */
+
+	if (s->session->tlsext_hostname != NULL) { 
+
+		if (limit - p - 4 < 0) return NULL; 
+
+		s2n(TLSEXT_TYPE_server_name,ret);
+		s2n(0,ret);
 	}
+
+	
+	if ((extdatalen = ret-p-2)== 0) 
+		return p;
+
+	s2n(extdatalen,p);
+	return ret;
+
+}
+
+int ssl_parse_ClientHello_TLS_extensions(SSL *s, unsigned char **p, unsigned char *d, int n) {
+	unsigned short type;
+	unsigned short size;
+	unsigned short len;
+	unsigned char * data = *p;
+
+	if (data >= (d+n-2))
+	   return SSL_ERROR_NONE;
+	n2s(data,len);
+
+        if (data > (d+n-len)) 
+	   return SSL_ERROR_NONE;
+
+	while(data <= (d+n-4)){
+		n2s(data,type);
+		n2s(data,size);
+
+		if (data+size > (d+n))
+	   		return SSL_ERROR_SSL;
+
+		if (type == TLSEXT_TYPE_server_name) {
+			unsigned char *sdata = data;
+			int servname_type;
+			int dsize = size-3 ;
+                        
+			if (dsize > 0 ) {
+ 				servname_type = *(sdata++); 
+				n2s(sdata,len);
+				if (len != dsize) 
+			   		return SSL_ERROR_SSL;
+
+				switch (servname_type) {
+				case TLSEXT_TYPE_SERVER_host:
+                                        if (s->session->tlsext_hostname == NULL) {
+						if (len > 255 || 
+							((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL))
+							return SSL_ERROR_SSL;
+						memcpy(s->session->tlsext_hostname, sdata, len);
+						s->session->tlsext_hostname[len]='\0'; 
+					}
+					break;
+				default:
+					break;
+				}
+                                 
+			}
+		}
+
+		data+=size;		
+	}
+	*p = data;
+
+	return SSL_ERROR_NONE;
+}
+int ssl_parse_ServerHello_TLS_extensions(SSL *s, unsigned char **p, unsigned char *d, int n) {
+	unsigned short type;
+	unsigned short size;
+	unsigned short len;  
+	unsigned char *data = *p;
+
+	int tlsext_servername = 0;
+
+	if (data >= (d+n-2))
+	   return SSL_ERROR_NONE;
+
+
+	n2s(data,len);
+
+	while(data <= (d+n-4)){
+		n2s(data,type);
+		n2s(data,size);
+
+		if (data+size > (d+n))
+	   		return SSL_ERROR_SSL;
+
+		if (type == TLSEXT_TYPE_server_name) {
+			if ( s->tlsext_hostname == NULL || size > 0 ) {
+				return SSL_ERROR_SSL;
+			}
+			tlsext_servername = 1;   
+		} 
+
+		data+=size;		
+	}
+
+	
+
+	if (data != d+n)
+	   	return SSL_ERROR_SSL;
+
+	if (!s->hit && tlsext_servername == 1) {
+ 		if (s->tlsext_hostname) {
+			if (s->session->tlsext_hostname == NULL) {
+				s->session->tlsext_hostname = BUF_strdup(s->tlsext_hostname);	
+				if (!s->session->tlsext_hostname)
+					return SSL_ERROR_SSL;
+			}
+		} else 
+			return SSL_ERROR_SSL;
+	}
+	*p = data;
+
+	return SSL_ERROR_NONE;
+}
+
+int ssl_check_Hello_TLS_extensions(SSL *s,int *ad)
+{
+	int ret = SSL_ERROR_NONE;
+
+	*ad = SSL_AD_UNRECOGNIZED_NAME;
+	if (s->servername_done == 0 && (s->ctx != NULL && s->ctx->tlsext_servername_callback != NULL) 
+		&& ((ret = s->ctx->tlsext_servername_callback(s, ad, s->ctx->tlsext_servername_arg))!= SSL_ERROR_NONE)) 
+  		return ret;
+
+	else if (s->servername_done == 1) 	
+		s->servername_done = 2;
+
+	return ret;
+}
 #endif
+
diff --git a/ssl/tls1.h b/ssl/tls1.h
index e7eaa83..4c8a5da 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -97,6 +97,53 @@
 #define TLS1_AD_USER_CANCELLED		90
 #define TLS1_AD_NO_RENEGOTIATION	100
 
+#ifndef OPENSSL_NO_TLSEXT
+#define TLS1_AD_UNRECOGNIZED_NAME 	122
+
+#define TLSEXT_TYPE_server_name			0
+#define TLSEXT_TYPE_max_fragment_length		1
+#define TLSEXT_TYPE_client_certificate_url	2
+#define TLSEXT_TYPE_trusted_ca_keys		3
+#define TLSEXT_TYPE_truncated_hmac		4
+#define TLSEXT_TYPE_status_request		5
+#define TLSEXT_TYPE_srp				6
+
+#define TLSEXT_TYPE_SERVER_host 0
+
+#define SSL_CTX_set_tlsext_hostname(ctx,name) \
+SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_TYPE_SERVER_host,(char *)name)
+#define SSL_set_tlsext_hostname(s,name) \
+SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_TYPE_SERVER_host,(char *)name)
+
+#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
+SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb)
+#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \
+SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
+
+
+const char *SSL_get_servername(const SSL *s, const int type) ;
+int SSL_get_servername_type(const SSL *s) ;
+
+#if 0
+	#define SSL_get_tlsext_hostname(s,psn) \
+	SSL_ctrl(s,SSL_CTRL_GET_TLSEXT_HOSTNAME,TLSEXT_TYPE_SERVER_host, (void *)psn)
+#else
+	#define SSL_get_tlsext_hostname(s,psn) \
+	(*psn = SSL_get_servername(s, TLSEXT_TYPE_SERVER_host),*psn != NULL)
+#endif
+	#define SSL_set_tlsext_servername_done(s,t) \
+	SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_SERVERNAME_DONE,t, NULL)
+
+void SSL_set_ctx(SSL *s, SSL_CTX *ctx) ;
+
+#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB	53
+#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG	54
+#define SSL_CTRL_SET_TLSEXT_HOSTNAME		55
+#define SSL_CTRL_GET_TLSEXT_HOSTNAME		56
+#define SSL_CTRL_SET_TLSEXT_SERVERNAME_DONE	57
+  
+#endif
+
 /* Additional TLS ciphersuites from expired Internet Draft
  * draft-ietf-tls-56-bit-ciphersuites-01.txt
  * (available if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES is defined, see