summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/s_client.c70
-rw-r--r--apps/s_server.c269
-rw-r--r--ssl/s23_clnt.c12
-rw-r--r--ssl/s23_srvr.c10
-rw-r--r--ssl/s3_clnt.c27
-rw-r--r--ssl/s3_lib.c47
-rw-r--r--ssl/s3_srvr.c29
-rw-r--r--ssl/ssl.h32
-rw-r--r--ssl/ssl_asn1.c37
-rw-r--r--ssl/ssl_err.c5
-rw-r--r--ssl/ssl_lib.c38
-rw-r--r--ssl/ssl_locl.h8
-rw-r--r--ssl/ssl_sess.c7
-rw-r--r--ssl/t1_lib.c186
-rw-r--r--ssl/tls1.h47
15 files changed, 784 insertions, 40 deletions
diff --git a/apps/s_client.c b/apps/s_client.c
index 5679b09cf1..c24b6e4a26 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -222,9 +222,32 @@ static void sc_usage(void)
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 MAIN(int argc, char **argv)
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 @@ int MAIN(int argc, char **argv)
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 @@ int MAIN(int argc, char **argv)
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 @@ int MAIN(int argc, char **argv)
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 @@ bad:
/* 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 @@ bad:
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 @@ bad:
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 @@ re_start:
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 918f776ee5..7dc864fab9 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -221,6 +221,9 @@ static int bufsize=BUFSIZZ;
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 char *cipher=NULL;
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=0;
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 char *engine_id=NULL;
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 @@ static void s_server_init(void)
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 @@ static void sv_usage(void)
#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 @@ static int ebcdic_puts(BIO *bp, const char *str)
}
#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 MAIN(int argc, char *argv[])
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 MAIN(int argc, char *argv[])
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 @@ int MAIN(int argc, char *argv[])
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 @@ int MAIN(int argc, char *argv[])
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 @@ bad:
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 @@ bad:
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 @@ bad:
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 @@ bad:
/* 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 @@ bad:
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 @@ bad:
(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 @@ bad:
(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 @@ bad:
#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 @@ bad:
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 @@ end:
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 @@ static int sv_body(char *hostname, int s, unsigned char *context)
}
- 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 1d1110b6f0..5a07db158f 100644
--- a/ssl/s23_clnt.c
+++ b/ssl/s23_clnt.c
@@ -349,6 +349,10 @@ static int ssl23_client_hello(SSL *s)
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 @@ static int ssl23_client_hello(SSL *s)
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 b33b699a1c..8bf044e15f 100644
--- a/ssl/s23_srvr.c
+++ b/ssl/s23_srvr.c
@@ -140,7 +140,7 @@ IMPLEMENT_ssl23_meth_func(SSLv23_server_method,
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 @@ int ssl23_get_client_hello(SSL *s)
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 @@ int ssl23_get_client_hello(SSL *s)
*(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 0098f56178..7a4f256642 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -255,6 +255,16 @@ int ssl3_connect(SSL *s)
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 @@ int ssl3_client_hello(SSL *s)
}
#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 @@ int ssl3_get_server_hello(SSL *s)
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 791c5e987c..845e5a16c5 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -1643,6 +1643,43 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
}
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 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
}
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 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
}
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 18030842b8..25b56fa6fa 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -281,6 +281,17 @@ int ssl3_accept(SSL *s)
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 @@ int ssl3_get_client_hello(SSL *s)
}
}
#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 @@ int ssl3_send_server_hello(SSL *s)
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 42e34b912b..29f1e0beec 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 @@ typedef struct ssl_session_st
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 @@ struct ssl_ctx_st
* 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 @@ struct ssl_st
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 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
#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 @@ int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
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 @@ void ERR_load_SSL_strings(void);
#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 @@ void ERR_load_SSL_strings(void);
#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 @@ void ERR_load_SSL_strings(void);
#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 d129acc329..e98a47fc9d 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -78,12 +78,15 @@ typedef struct ssl_session_asn1_st
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 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
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 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
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 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
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 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
else
ret->verify_result=X509_V_OK;
+#ifndef OPENSSL_NO_TLSEXT
+ os.length=0;
+ os.data=NULL;
+