Backport of TLS extension code to OpenSSL 0.9.8.
authorDr. Stephen Henson <steve@openssl.org>
Sun, 12 Aug 2007 18:59:03 +0000 (18:59 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Sun, 12 Aug 2007 18:59:03 +0000 (18:59 +0000)
Include server name and RFC4507bis support.

This is not compiled in by default and must be explicitly enabled with
the Configure option enable-tlsext

21 files changed:
CHANGES
Configure
apps/s_apps.h
apps/s_cb.c
apps/s_client.c
apps/s_server.c
ssl/s23_clnt.c
ssl/s2_srvr.c
ssl/s3_clnt.c
ssl/s3_lib.c
ssl/s3_srvr.c
ssl/ssl.h
ssl/ssl3.h
ssl/ssl_asn1.c
ssl/ssl_err.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/ssl_sess.c
ssl/ssl_txt.c
ssl/t1_lib.c
ssl/tls1.h

diff --git a/CHANGES b/CHANGES
index 7b25bdc8118cca00c39084780919bdbfc307c7ba..78159bc62c3e75dbe4c8c2539170297af76d084c 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -3,6 +3,58 @@
  _______________
 
  Changes between 0.9.8e and 0.9.8f  [xx XXX xxxx]
+  
+  *) Add RFC4507 support to OpenSSL. This includes the corrections in
+     RFC4507bis. The encrypted ticket format is an encrypted encoded
+     SSL_SESSION structure, that way new session features are automatically
+     supported.
+
+     If a client application caches session in an SSL_SESSION support it
+     should automatically be supported because an extension includes the
+     ticket in the structure. The SSL_CTX structure automatically generates
+     keys for ticket protection in servers so again support should be possible
+     with no application modification.
+
+     If a client or server wishes to disable RFC4507 support then the option
+     SSL_OP_NO_TICKET can be set.
+
+     Add a TLS extension debugging callback to allow the contents of any client
+     or server extensions to be examined.
+     [Steve Henson]
+
+  *) Add initial support for TLS extensions, specifically for the server_name
+     extension so far.  The SSL_SESSION, SSL_CTX, and SSL data structures now
+     have new members for a host name.  The SSL data structure has an
+     additional member SSL_CTX *initial_ctx so that new sessions can be
+     stored in that context to allow for session resumption, even after the
+     SSL has been switched to a new SSL_CTX in reaction to a client's
+     server_name extension.
+
+     New functions (subject to change):
+
+         SSL_get_servername()
+         SSL_get_servername_type()
+         SSL_set_SSL_CTX()
+
+     New CTRL codes and macros (subject to change):
+
+         SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
+                                 - SSL_CTX_set_tlsext_servername_callback()
+         SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG
+                                      - SSL_CTX_set_tlsext_servername_arg()
+         SSL_CTRL_SET_TLSEXT_HOSTNAME           - SSL_set_tlsext_host_name()
+
+     openssl s_client has a new '-servername ...' option.
+
+     openssl s_server has new options '-servername_host ...', '-cert2 ...',
+     '-key2 ...', '-servername_fatal' (subject to change).  This allows
+     testing the HostName extension for a specific single host name ('-cert'
+     and '-key' remain fallbacks for handshakes without HostName
+     negotiation).  If the unrecogninzed_name alert has to be sent, this by
+     default is a warning; it becomes fatal with the '-servername_fatal'
+     option.
+
+     [Peter Sylvester,  Remy Allais, Christophe Renou, Steve Henson]
 
   *) Add AES and SSE2 assembly language support to VC++ build.
      [Steve Henson]
index f4b06967cad2aef9ebf91c2404752f6acd510413..a6575f9237bdd51f452310b3d85974ea6e4621be 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -607,6 +607,7 @@ my %disabled = ( # "what"         => "comment"
                  "rfc3779"        => "default",
                  "seed"           => "default",
                  "shared"         => "default",
+                 "tlsext"         => "default",
                  "zlib"           => "default",
                  "zlib-dynamic"   => "default"
                );
@@ -838,6 +839,10 @@ if (defined($disabled{"md5"}) || defined($disabled{"sha"})
        $disabled{"tls1"} = "forced";
        }
 
+if (defined($disabled{"tls1"}))
+       {
+       $disabled{"tlsext"} = "forced";
+       }
 
 if ($target eq "TABLE") {
        foreach $target (sort keys %table) {
index 886a95a2b8ceb061c365b3b751ab153da8d7a4e7..08fbbc2229640f3eb6d4e15af90f7e64926a4970 100644 (file)
@@ -167,4 +167,7 @@ long MS_CALLBACK bio_dump_callback(BIO *bio, int cmd, const char *argp,
 #ifdef HEADER_SSL_H
 void MS_CALLBACK apps_ssl_info_callback(const SSL *s, int where, int ret);
 void MS_CALLBACK msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
+void MS_CALLBACK tlsext_cb(SSL *s, int client_server, int type,
+                                       unsigned char *data, int len,
+                                       void *arg);
 #endif
index b4992aa623511445b951e7db28f79d521cb1c7c0..a512589e8c87d92b80fdc84751d02b7e9f91923c 100644 (file)
@@ -575,3 +575,62 @@ void MS_CALLBACK msg_cb(int write_p, int version, int content_type, const void *
                }
        (void)BIO_flush(bio);
        }
+
+void MS_CALLBACK tlsext_cb(SSL *s, int client_server, int type,
+                                       unsigned char *data, int len,
+                                       void *arg)
+       {
+       BIO *bio = arg;
+       char *extname;
+
+       switch(type)
+               {
+               case TLSEXT_TYPE_server_name:
+               extname = "server name";
+               break;
+
+               case TLSEXT_TYPE_max_fragment_length:
+               extname = "max fragment length";
+               break;
+
+               case TLSEXT_TYPE_client_certificate_url:
+               extname = "client certificate URL";
+               break;
+
+               case TLSEXT_TYPE_trusted_ca_keys:
+               extname = "trusted CA keys";
+               break;
+
+               case TLSEXT_TYPE_truncated_hmac:
+               extname = "truncated HMAC";
+               break;
+
+               case TLSEXT_TYPE_status_request:
+               extname = "status request";
+               break;
+
+               case TLSEXT_TYPE_elliptic_curves:
+               extname = "elliptic curves";
+               break;
+
+               case TLSEXT_TYPE_ec_point_formats:
+               extname = "EC point formats";
+               break;
+
+               case TLSEXT_TYPE_session_ticket:
+               extname = "server ticket";
+               break;
+
+
+               default:
+               extname = "unknown";
+               break;
+
+               }
+       
+       BIO_printf(bio, "TLS %s extension \"%s\" (id=%d), len=%d\n",
+                       client_server ? "server": "client",
+                       extname, type, len);
+       BIO_dump(bio, (char *)data, len);
+       (void)BIO_flush(bio);
+       }
index 6df534fa7ac428bf20ed5c341bfaa09aad77417a..602275ba095b4162256f80e749a49e718c86aa5b 100644 (file)
@@ -171,6 +171,9 @@ static int c_nbio=0;
 #endif
 static int c_Pause=0;
 static int c_debug=0;
+#ifndef OPENSSL_NO_TLSEXT
+static int c_tlsextdebug=0;
+#endif
 static int c_msg=0;
 static int c_showcerts=0;
 
@@ -231,9 +234,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 char * hn= SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
+       if (SSL_get_servername_type(s) != -1) 
+               p->ack = !SSL_session_reused(s) && hn != NULL;
+       else 
+               BIO_printf(bio_err,"Can't use SSL_get_servername\n");
+       
+       return SSL_TLSEXT_ERR_OK;
+       }
+#endif
 enum
 {
        PROTO_OFF       = 0,
@@ -287,6 +313,13 @@ int MAIN(int argc, char **argv)
        struct timeval tv;
 #endif
 
+#ifndef OPENSSL_NO_TLSEXT
+       char *servername = NULL; 
+        tlsextctx tlsextcbp = 
+        {NULL,0};
+#endif
+       char *sess_in = NULL;
+       char *sess_out = NULL;
        struct sockaddr peer;
        int peerlen = sizeof(peer);
        int enable_timeouts = 0 ;
@@ -361,6 +394,16 @@ int MAIN(int argc, char **argv)
                        if (--argc < 1) goto bad;
                        cert_file= *(++argv);
                        }
+               else if (strcmp(*argv,"-sess_out") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       sess_out = *(++argv);
+                       }
+               else if (strcmp(*argv,"-sess_in") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       sess_in = *(++argv);
+                       }
                else if (strcmp(*argv,"-certform") == 0)
                        {
                        if (--argc < 1) goto bad;
@@ -385,6 +428,10 @@ int MAIN(int argc, char **argv)
                        c_Pause=1;
                else if (strcmp(*argv,"-debug") == 0)
                        c_debug=1;
+#ifndef OPENSSL_NO_TLSEXT
+               else if (strcmp(*argv,"-tlsextdebug") == 0)
+                       c_tlsextdebug=1;
+#endif
 #ifdef WATT32
                else if (strcmp(*argv,"-wdebug") == 0)
                        dbug_init();
@@ -460,6 +507,10 @@ int MAIN(int argc, char **argv)
                        off|=SSL_OP_NO_SSLv3;
                else if (strcmp(*argv,"-no_ssl2") == 0)
                        off|=SSL_OP_NO_SSLv2;
+#ifndef OPENSSL_NO_TLSEXT
+               else if (strcmp(*argv,"-no_ticket") == 0)
+                       { off|=SSL_OP_NO_TICKET; }
+#endif
                else if (strcmp(*argv,"-serverpref") == 0)
                        off|=SSL_OP_CIPHER_SERVER_PREFERENCE;
                else if (strcmp(*argv,"-cipher") == 0)
@@ -498,6 +549,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);
@@ -621,8 +680,51 @@ 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);
+       if (sess_in)
+               {
+               SSL_SESSION *sess;
+               BIO *stmp = BIO_new_file(sess_in, "r");
+               if (!stmp)
+                       {
+                       BIO_printf(bio_err, "Can't open session file %s\n",
+                                               sess_in);
+                       ERR_print_errors(bio_err);
+                       goto end;
+                       }
+               sess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL);
+               BIO_free(stmp);
+               if (!sess)
+                       {
+                       BIO_printf(bio_err, "Can't open session file %s\n",
+                                               sess_in);
+                       ERR_print_errors(bio_err);
+                       goto end;
+                       }
+               SSL_set_session(con, sess);
+               SSL_SESSION_free(sess);
+               }
+#ifndef OPENSSL_NO_TLSEXT
+       if (servername != NULL)
+               {
+               if (!SSL_set_tlsext_host_name(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)
                 {
@@ -714,6 +816,13 @@ re_start:
                SSL_set_msg_callback(con, msg_cb);
                SSL_set_msg_callback_arg(con, bio_c_out);
                }
+#ifndef OPENSSL_NO_TLSEXT
+       if (c_tlsextdebug)
+               {
+               SSL_set_tlsext_debug_callback(con, tlsext_cb);
+               SSL_set_tlsext_debug_arg(con, bio_c_out);
+               }
+#endif
 
        SSL_set_bio(con,sbio,sbio);
        SSL_set_connect_state(con);
@@ -837,6 +946,17 @@ re_start:
                        if (in_init)
                                {
                                in_init=0;
+                               if (sess_out)
+                                       {
+                                       BIO *stmp = BIO_new_file(sess_out, "w");
+                                       if (stmp)
+                                               {
+                                               PEM_write_bio_SSL_SESSION(stmp, SSL_get_session(con));
+                                               BIO_free(stmp);
+                                               }
+                                       else 
+                                               BIO_printf(bio_err, "Error writing session file %s\n", sess_out);
+                                       }
                                print_stuff(bio_c_out,con,full_log);
                                if (full_log > 0) full_log--;
 
index 6c433e63fd647a4c2a457ed7dd47622b8c5fe6ab..343a05cefca8322255f35959890e8093937f48f7 100644 (file)
@@ -238,6 +238,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
 
@@ -247,6 +250,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;
@@ -254,10 +260,16 @@ 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;
 static int s_debug=0;
+#ifndef OPENSSL_NO_TLSEXT
+static int s_tlsextdebug=0;
+#endif
 static int s_msg=0;
 static int s_quiet=0;
 
@@ -285,6 +297,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
@@ -371,6 +388,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 - servername for HostName TLS extension\n");
+       BIO_printf(bio_err," -servername_fatal - on mismatch send fatal alert (default warning alert)\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);
+#endif
        }
 
 static int local_argc=0;
@@ -526,6 +551,39 @@ 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;
+   int extension_error;
+} 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_NAMETYPE_host_name);
+        if (servername && p->biodebug) 
+               BIO_printf(p->biodebug,"Hostname in TLS extension: \"%s\"\n",servername);
+        
+       if (!p->servername)
+               return SSL_TLSEXT_ERR_NOACK;
+       
+       if (servername)
+               {
+               if (strcmp(servername,p->servername)) 
+                       return p->extension_error;
+               if (ctx2)
+                       {
+                       BIO_printf(p->biodebug,"Swiching server context.\n");
+                       SSL_set_SSL_CTX(s,ctx2);
+                       }     
+               }
+       return SSL_TLSEXT_ERR_OK;
+}
+#endif
 int MAIN(int, char **);
 
 int MAIN(int argc, char *argv[])
@@ -545,10 +603,7 @@ int MAIN(int argc, char *argv[])
        int no_tmp_rsa=0,no_dhe=0,no_ecdhe=0,nocert=0;
        int state=0;
        SSL_METHOD *meth=NULL;
-#ifdef sock_type
-#undef sock_type
-#endif
-    int sock_type=SOCK_STREAM;
+        int socket_type=SOCK_STREAM;
 #ifndef OPENSSL_NO_ENGINE
        ENGINE *e=NULL;
 #endif
@@ -559,6 +614,14 @@ 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, SSL_TLSEXT_ERR_ALERT_WARNING};
+#endif
 
 #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3)
        meth=SSLv23_server_method();
@@ -724,6 +787,10 @@ int MAIN(int argc, char *argv[])
                        }
                else if (strcmp(*argv,"-debug") == 0)
                        { s_debug=1; }
+#ifndef OPENSSL_NO_TLSEXT
+               else if (strcmp(*argv,"-tlsextdebug") == 0)
+                       s_tlsextdebug=1;
+#endif
                else if (strcmp(*argv,"-msg") == 0)
                        { s_msg=1; }
                else if (strcmp(*argv,"-hack") == 0)
@@ -754,6 +821,10 @@ int MAIN(int argc, char *argv[])
                        { off|=SSL_OP_NO_SSLv3; }
                else if (strcmp(*argv,"-no_tls1") == 0)
                        { off|=SSL_OP_NO_TLSv1; }
+#ifndef OPENSSL_NO_TLSEXT
+               else if (strcmp(*argv,"-no_ticket") == 0)
+                       { off|=SSL_OP_NO_TICKET; }
+#endif
 #ifndef OPENSSL_NO_SSL2
                else if (strcmp(*argv,"-ssl2") == 0)
                        { meth=SSLv2_server_method(); }
@@ -770,7 +841,7 @@ int MAIN(int argc, char *argv[])
                else if (strcmp(*argv,"-dtls1") == 0)
                        { 
                        meth=DTLSv1_server_method();
-                       sock_type = SOCK_DGRAM;
+                       socket_type = SOCK_DGRAM;
                        }
                else if (strcmp(*argv,"-timeout") == 0)
                        enable_timeouts = 1;
@@ -799,6 +870,25 @@ 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);
+                       }
+               else if (strcmp(*argv,"-servername_fatal") == 0)
+                       { tlsextcbp.extension_error = SSL_TLSEXT_ERR_ALERT_FATAL; }
+               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);
@@ -831,6 +921,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)
                {
@@ -850,8 +944,29 @@ 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)
                {
 
@@ -908,6 +1023,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);
@@ -939,7 +1058,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 (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);
 
        if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
 
@@ -966,6 +1085,62 @@ 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 (socket_type == 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)
@@ -989,6 +1164,24 @@ 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
@@ -1034,12 +1227,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))
@@ -1049,7 +1250,13 @@ bad:
 #ifndef OPENSSL_NO_RSA
 #if 1
        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))
                {
@@ -1065,6 +1272,16 @@ 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");
                }
@@ -1076,19 +1293,46 @@ bad:
                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);
 
+#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));
-
+               {
+               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,socket_type,&accept_socket,www_body, context);
        else
-               do_server(port,sock_type,&accept_socket,sv_body, context);
+               do_server(port,socket_type,&accept_socket,sv_body, context);
        print_stats(bio_s_out,ctx);
        ret=0;
 end:
@@ -1105,6 +1349,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);
@@ -1171,6 +1422,13 @@ static int sv_body(char *hostname, int s, unsigned char *context)
 
        if (con == NULL) {
                con=SSL_new(ctx);
+#ifndef OPENSSL_NO_TLSEXT
+       if (s_tlsextdebug)
+               {
+               SSL_set_tlsext_debug_callback(con, tlsext_cb);
+               SSL_set_tlsext_debug_arg(con, bio_s_out);
+               }
+#endif
 #ifndef OPENSSL_NO_KRB5
                if ((con->kssl_ctx = kssl_ctx_new()) != NULL)
                         {
@@ -1241,6 +1499,13 @@ static int sv_body(char *hostname, int s, unsigned char *context)
                SSL_set_msg_callback(con, msg_cb);
                SSL_set_msg_callback_arg(con, bio_s_out);
                }
+#ifndef OPENSSL_NO_TLSEXT
+       if (s_tlsextdebug)
+               {
+               SSL_set_tlsext_debug_callback(con, tlsext_cb);
+               SSL_set_tlsext_debug_arg(con, bio_s_out);
+               }
+#endif
 
        width=s+1;
        for (;;)
@@ -1606,6 +1871,13 @@ static int www_body(char *hostname, int s, unsigned char *context)
        if (!BIO_set_write_buffer_size(io,bufsize)) goto err;
 
        if ((con=SSL_new(ctx)) == NULL) goto err;
+#ifndef OPENSSL_NO_TLSEXT
+               if (s_tlsextdebug)
+                       {
+                       SSL_set_tlsext_debug_callback(con, tlsext_cb);
+                       SSL_set_tlsext_debug_arg(con, bio_s_out);
+                       }
+#endif
 #ifndef OPENSSL_NO_KRB5
        if ((con->kssl_ctx = kssl_ctx_new()) != NULL)
                {
index 769dabdbb83cd34f9cd27a6c6f035e477d5ff717..146e1e17c18c546ea2a6d80fdc86371863f8ffe3 100644 (file)
@@ -360,6 +360,13 @@ static int ssl23_client_hello(SSL *s)
                                *(p++)=comp->id;
                                }
                        *(p++)=0; /* Add the NULL method */
+#ifndef OPENSSL_NO_TLSEXT
+                       if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+                               {
+                               SSLerr(SSL_F_SSL23_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);
+                               return -1;
+                               }
+#endif
                        
                        l = p-d;
                        *p = 42;
index 27d71a2e0952e5e3f15c3d487b534f74c5d9eec0..eeedc16a25166ec0f0ba3f1bdc1d1d96ca7f25ad 100644 (file)
@@ -607,7 +607,7 @@ static int get_client_hello(SSL *s)
        else
                {
                i=ssl_get_prev_session(s,&(p[s->s2->tmp.cipher_spec_length]),
-                       s->s2->tmp.session_id_length);
+                       s->s2->tmp.session_id_length, NULL);
                if (i == 1)
                        { /* previous session */
                        s->hit=1;
index d98c7f998f1459a16b19dbcdcf720803d1e17a5d..49f781225b2407a3b4514b30658c8d1d5f58ddc5 100644 (file)
 
 static SSL_METHOD *ssl3_get_client_method(int ver);
 static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b);
+#ifndef OPENSSL_NO_TLSEXT
+static int ssl3_check_finished(SSL *s);
+#endif
 
 #ifndef OPENSSL_NO_ECDH
 static int curve_id2nid(int curve_id);
@@ -264,6 +267,17 @@ int ssl3_connect(SSL *s)
 
                case SSL3_ST_CR_CERT_A:
                case SSL3_ST_CR_CERT_B:
+#ifndef OPENSSL_NO_TLSEXT
+                       ret=ssl3_check_finished(s);
+                       if (ret <= 0) goto end;
+                       if (ret == 2)
+                               {
+                               s->hit = 1;
+                               s->state=SSL3_ST_CR_FINISHED_A;
+                               s->init_num=0;
+                               break;
+                               }
+#endif
                        /* Check if it is anon DH/ECDH */
                        if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
                                {
@@ -416,11 +430,27 @@ int ssl3_connect(SSL *s)
                                }
                        else
                                {
+#ifndef OPENSSL_NO_TLSEXT
+                               /* Allow NewSessionTicket if ticket expected */
+                               if (s->tlsext_ticket_expected)
+                                       s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
+                               else
+#endif
+                               
                                s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
                                }
                        s->init_num=0;
                        break;
 
+#ifndef OPENSSL_NO_TLSEXT
+               case SSL3_ST_CR_SESSION_TICKET_A:
+               case SSL3_ST_CR_SESSION_TICKET_B:
+                       ret=ssl3_get_new_session_ticket(s);
+                       s->state=SSL3_ST_CR_FINISHED_A;
+                       s->init_num=0;
+               break;
+#endif
+
                case SSL3_ST_CR_FINISHED_A:
                case SSL3_ST_CR_FINISHED_B:
 
@@ -600,7 +630,13 @@ int ssl3_client_hello(SSL *s)
                        }
 #endif
                *(p++)=0; /* Add the NULL method */
-               
+#ifndef OPENSSL_NO_TLSEXT
+               if ((p = ssl_add_clienthello_tlsext(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;
                *(d++)=SSL3_MT_CLIENT_HELLO;
@@ -634,7 +670,7 @@ int ssl3_get_server_hello(SSL *s)
                SSL3_ST_CR_SRVR_HELLO_A,
                SSL3_ST_CR_SRVR_HELLO_B,
                -1,
-               300, /* ?? */
+               20000, /* ?? */
                &ok);
 
        if (!ok) return((int)n);
@@ -784,6 +820,24 @@ 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 (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al))
+                       {
+                       /* 'al' set by ssl_parse_serverhello_tlsext */
+                       SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLSEXT);
+                       goto f_err; 
+                       }
+               if (ssl_check_serverhello_tlsext(s) <= 0)
+                       {
+                       SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT);
+                               goto err;
+                       }
+               }
+#endif
+
 
        if (p != (d+n))
                {
@@ -1590,6 +1644,74 @@ static int ca_dn_cmp(const X509_NAME * const *a, const X509_NAME * const *b)
        {
        return(X509_NAME_cmp(*a,*b));
        }
+#ifndef OPENSSL_NO_TLSEXT
+int ssl3_get_new_session_ticket(SSL *s)
+       {
+       int ok,al,ret=0, ticklen;
+       long n;
+       const unsigned char *p;
+       unsigned char *d;
+
+       n=s->method->ssl_get_message(s,
+               SSL3_ST_CR_SESSION_TICKET_A,
+               SSL3_ST_CR_SESSION_TICKET_B,
+               -1,
+               16384,
+               &ok);
+
+       if (!ok)
+               return((int)n);
+
+       if (s->s3->tmp.message_type == SSL3_MT_FINISHED)
+               {
+               s->s3->tmp.reuse_message=1;
+               return(1);
+               }
+       if (s->s3->tmp.message_type != SSL3_MT_NEWSESSION_TICKET)
+               {
+               al=SSL_AD_UNEXPECTED_MESSAGE;
+               SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_BAD_MESSAGE_TYPE);
+               goto f_err;
+               }
+       if (n < 6)
+               {
+               /* need at least ticket_lifetime_hint + ticket length */
+               al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
+               SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
+               goto f_err;
+               }
+       p=d=(unsigned char *)s->init_msg;
+       n2l(p, s->session->tlsext_tick_lifetime_hint);
+       n2s(p, ticklen);
+       /* ticket_lifetime_hint + ticket_length + ticket */
+       if (ticklen + 6 != n)
+               {
+               al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
+               SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
+               goto f_err;
+               }
+       if (s->session->tlsext_tick)
+               {
+               OPENSSL_free(s->session->tlsext_tick);
+               s->session->tlsext_ticklen = 0;
+               }
+       s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+       if (!s->session->tlsext_tick)
+               {
+               SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
+               goto err;
+               }
+       memcpy(s->session->tlsext_tick, p, ticklen);
+       s->session->tlsext_ticklen = ticklen;
+       
+       ret=1;
+       return(ret);
+f_err:
+       ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+       return(-1);
+       }
+#endif
 
 int ssl3_get_server_done(SSL *s)
        {
@@ -2458,3 +2580,33 @@ static int curve_id2nid(int curve_id)
        return nid_list[curve_id];
 }
 #endif
+
+/* Check to see if handshake is full or resumed. Usually this is just a
+ * case of checking to see if a cache hit has occurred. In the case of
+ * session tickets we have to check the next message to be sure.
+ */
+
+#ifndef OPENSSL_NO_TLSEXT
+static int ssl3_check_finished(SSL *s)
+       {
+       int ok;
+       long n;
+       if (!s->session->tlsext_tick)
+               return 1;
+       /* this function is called when we really expect a Certificate
+        * message, so permit appropriate message length */
+       n=s->method->ssl_get_message(s,
+               SSL3_ST_CR_CERT_A,
+               SSL3_ST_CR_CERT_B,
+               -1,
+               s->max_cert_list,
+               &ok);
+       if (!ok) return((int)n);
+       s->s3->tmp.reuse_message = 1;
+       if ((s->s3->tmp.message_type == SSL3_MT_FINISHED)
+               || (s->s3->tmp.message_type == SSL3_MT_NEWSESSION_TICKET))
+               return 2;
+
+       return 1;
+       }
+#endif
index da7c2bef1ccda2508915fbfcc0d058dfcc55b791..7bd9860ea1c86521f01d713068078f9ccb692124 100644 (file)
@@ -1904,6 +1904,39 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
                }
                break;
 #endif /* !OPENSSL_NO_ECDH */
+#ifndef OPENSSL_NO_TLSEXT
+       case SSL_CTRL_SET_TLSEXT_HOSTNAME:
+               if (larg == TLSEXT_NAMETYPE_host_name)
+                       {
+                       if (s->tlsext_hostname != NULL) 
+                               OPENSSL_free(s->tlsext_hostname);
+                       s->tlsext_hostname = NULL;
+
+                       ret = 1;
+                       if (parg == NULL) 
+                               break;
+                       if (strlen((char *)parg) > TLSEXT_MAXLEN_host_name)
+                               {
+                               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; /* can't use extension w/ SSL 2.0 format */
+               break;
+       case SSL_CTRL_SET_TLSEXT_DEBUG_ARG:
+               s->tlsext_debug_arg=parg;
+               break;
+#endif /* !OPENSSL_NO_TLSEXT */
        default:
                break;
                }
@@ -1954,6 +1987,12 @@ long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp)(void))
                s->cert->ecdh_tmp_cb = (EC_KEY *(*)(SSL *, int, int))fp;
                }
                break;
+#endif
+#ifndef OPENSSL_NO_TLSEXT
+       case SSL_CTRL_SET_TLSEXT_DEBUG_CB:
+               s->tlsext_debug_cb=(void (*)(SSL *,int ,int,
+                                       unsigned char *, int, void *))fp;
+               break;
 #endif
        default:
                break;
@@ -2088,6 +2127,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)
@@ -2132,6 +2176,11 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void))
                cert->ecdh_tmp_cb = (EC_KEY *(*)(SSL *, int, int))fp;
                }
                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);
@@ -2178,6 +2227,7 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
        SSL_CIPHER *c,*ret=NULL;
        STACK_OF(SSL_CIPHER) *prio, *allow;
        int i,j,ok;
+
        CERT *cert;
        unsigned long alg,mask,emask;
 
index 39668f499ad6d0988d0eaa94a9395f34c0f46c73..99221a06905ed0428560ee426de9234ec601cd25 100644 (file)
 #include <openssl/rand.h>
 #include <openssl/objects.h>
 #include <openssl/evp.h>
+#include <openssl/hmac.h>
 #include <openssl/x509.h>
 #ifndef OPENSSL_NO_DH
 #include <openssl/dh.h>
 #include <openssl/md5.h>
 
 static SSL_METHOD *ssl3_get_server_method(int ver);
-
 #ifndef OPENSSL_NO_ECDH
 static int nid2curve_id(int nid);
 #endif
@@ -494,11 +494,26 @@ int ssl3_accept(SSL *s)
                        if (ret <= 0) goto end;
                        if (s->hit)
                                s->state=SSL_ST_OK;
+#ifndef OPENSSL_NO_TLSEXT
+                       else if (s->tlsext_ticket_expected)
+                               s->state=SSL3_ST_SW_SESSION_TICKET_A;
+#endif
                        else
                                s->state=SSL3_ST_SW_CHANGE_A;
                        s->init_num=0;
                        break;
 
+#ifndef OPENSSL_NO_TLSEXT
+               case SSL3_ST_SW_SESSION_TICKET_A:
+               case SSL3_ST_SW_SESSION_TICKET_B:
+                       ret=ssl3_send_newsession_ticket(s);
+                       if (ret <= 0) goto end;
+                       s->state=SSL3_ST_SW_CHANGE_A;
+                       s->init_num=0;
+                       break;
+
+#endif
+
                case SSL3_ST_SW_CHANGE_A:
                case SSL3_ST_SW_CHANGE_B:
 
@@ -727,14 +742,14 @@ int ssl3_get_client_hello(SSL *s)
         * might be written that become totally unsecure when compiled with
         * an earlier library version)
         */
-       if (j == 0 || (s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)))
+       if ((s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)))
                {
                if (!ssl_get_new_session(s,1))
                        goto err;
                }
        else
                {
-               i=ssl_get_prev_session(s,p,j);
+               i=ssl_get_prev_session(s, p, j, d + n);
                if (i == 1)
                        { /* previous session */
                        s->hit=1;
@@ -897,6 +912,22 @@ int ssl3_get_client_hello(SSL *s)
                goto f_err;
                }
 
+#ifndef OPENSSL_NO_TLSEXT
+       /* TLS extensions*/
+       if (s->version > SSL3_VERSION)
+               {
+               if (!ssl_parse_clienthello_tlsext(s,&p,d,n, &al))
+                       {
+                       /* 'al' set by ssl_parse_clienthello_tlsext */
+                       SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLSEXT);
+                       goto f_err;
+                       }
+               }
+               if (ssl_check_clienthello_tlsext(s) <= 0) {
+                       SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+                       goto err;
+               }
+#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
         * algorithms from the client, starting at q. */
@@ -1088,7 +1119,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_tlsext(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);
                d=buf;
@@ -2615,3 +2652,90 @@ static int nid2curve_id(int nid)
        }
 }
 #endif
+#ifndef OPENSSL_NO_TLSEXT
+int ssl3_send_newsession_ticket(SSL *s)
+       {
+       if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
+               {
+               unsigned char *p, *senc, *macstart;
+               int len, slen;
+               unsigned int hlen;
+               EVP_CIPHER_CTX ctx;
+               HMAC_CTX hctx;
+
+               /* get session encoding length */
+               slen = i2d_SSL_SESSION(s->session, NULL);
+               /* Some length values are 16 bits, so forget it if session is
+                * too long
+                */
+               if (slen > 0xFF00)
+                       return -1;
+               /* Grow buffer if need be: the length calculation is as
+                * follows 1 (size of message name) + 3 (message length
+                * bytes) + 4 (ticket lifetime hint) + 2 (ticket length) +
+                * 16 (key name) + max_iv_len (iv length) +
+                * session_length + max_enc_block_size (max encrypted session
+                * length) + max_md_size (HMAC).
+                */
+               if (!BUF_MEM_grow(s->init_buf,
+                       26 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH +
+                       EVP_MAX_MD_SIZE + slen))
+                       return -1;
+               senc = OPENSSL_malloc(slen);
+               if (!senc)
+                       return -1;
+               p = senc;
+               i2d_SSL_SESSION(s->session, &p);
+
+               p=(unsigned char *)s->init_buf->data;
+               /* do the header */
+               *(p++)=SSL3_MT_NEWSESSION_TICKET;
+               /* Skip message length for now */
+               p += 3;
+               l2n(s->session->tlsext_tick_lifetime_hint, p);
+               /* Skip ticket length for now */
+               p += 2;
+               /* Output key name */
+               macstart = p;
+               memcpy(p, s->ctx->tlsext_tick_key_name, 16);
+               p += 16;
+               /* Generate and output IV */
+               RAND_pseudo_bytes(p, 16);
+               EVP_CIPHER_CTX_init(&ctx);
+               /* Encrypt session data */
+               EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+                                       s->ctx->tlsext_tick_aes_key, p);
+               p += 16;
+               EVP_EncryptUpdate(&ctx, p, &len, senc, slen);
+               p += len;
+               EVP_EncryptFinal(&ctx, p, &len);
+               p += len;
+               EVP_CIPHER_CTX_cleanup(&ctx);
+
+               HMAC_CTX_init(&hctx);
+               HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
+                               EVP_sha1(), NULL);
+               HMAC_Update(&hctx, macstart, p - macstart);
+               HMAC_Final(&hctx, p, &hlen);
+               HMAC_CTX_cleanup(&hctx);
+
+               p += hlen;
+               /* Now write out lengths: p points to end of data written */
+               /* Total length */
+               len = p - (unsigned char *)s->init_buf->data;
+               p=(unsigned char *)s->init_buf->data + 1;
+               l2n3(len - 4, p); /* Message length */
+               p += 4;
+               s2n(len - 10, p);  /* Ticket length */
+
+               /* number of bytes to write */
+               s->init_num= len;
+               s->state=SSL3_ST_SW_SESSION_TICKET_B;
+               s->init_off=0;
+               OPENSSL_free(senc);
+               }
+
+       /* SSL3_ST_SW_SESSION_TICKET_B */
+       return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+       }
+#endif
index ff18cf5fd305880d57d968141b2fcc8c6a146386..07d109a235c77f114ae6dd1db4a58dfabd303fbb 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -474,6 +474,13 @@ typedef struct ssl_session_st
        /* These are used to make removal of session-ids more
         * efficient and to implement a maximum cache size. */
        struct ssl_session_st *prev,*next;
+#ifndef OPENSSL_NO_TLSEXT
+       char *tlsext_hostname;
+       /* RFC4507 info */
+       unsigned char *tlsext_tick;     /* Session ticket */
+       size_t  tlsext_ticklen;         /* Session ticket length */     
+       long tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */
+#endif
        } SSL_SESSION;
 
 
@@ -502,6 +509,8 @@ typedef struct ssl_session_st
 #define SSL_OP_NO_QUERY_MTU                 0x00001000L
 /* Turn on Cookie Exchange (on relevant for servers) */
 #define SSL_OP_COOKIE_EXCHANGE              0x00002000L
+/* Don't use RFC4507 ticket extension */
+#define SSL_OP_NO_TICKET                   0x00004000L
 
 /* As server, disallow session resumption on renegotiation */
 #define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION  0x00010000L
@@ -749,6 +758,17 @@ struct ssl_ctx_st
 #endif
 
        int quiet_shutdown;
+
+#ifndef OPENSSL_NO_TLSEXT
+       /* TLS extensions servername callback */
+       int (*tlsext_servername_callback)(SSL*, int *, void *);
+       void *tlsext_servername_arg;
+       /* RFC 4507 session ticket keys */
+       unsigned char tlsext_tick_key_name[16];
+       unsigned char tlsext_tick_hmac_key[16];
+       unsigned char tlsext_tick_aes_key[16];
+#endif
+
        };
 
 #define SSL_SESS_CACHE_OFF                     0x0000
@@ -970,6 +990,26 @@ struct ssl_st
        int first_packet;
        int client_version;     /* what was passed, used for
                                 * SSLv3/TLS rollback check */
+       unsigned int max_send_fragment;
+#ifndef OPENSSL_NO_TLSEXT
+       /* TLS extension debug callback */
+       void (*tlsext_debug_cb)(SSL *s, int client_server, int type,
+                                       unsigned char *data, int len,
+                                       void *arg);
+       void *tlsext_debug_arg;
+       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
+                              */
+       /* RFC4507 session ticket expected to be received or sent */
+       int tlsext_ticket_expected;
+       SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+#define session_ctx initial_ctx
+#else
+#define session_ctx ctx
+#endif
        };
 
 #ifdef __cplusplus
@@ -1115,6 +1155,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
+#define SSL_AD_UNSUPPORTED_EXTENSION   TLS1_AD_UNSUPPORTED_EXTENSION
+#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE
+#define SSL_AD_UNRECOGNIZED_NAME       TLS1_AD_UNRECOGNIZED_NAME
 
 #define SSL_ERROR_NONE                 0
 #define SSL_ERROR_SSL                  1
@@ -1173,6 +1216,15 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
 #define SSL_CTRL_GET_MAX_CERT_LIST             50
 #define SSL_CTRL_SET_MAX_CERT_LIST             51
 
+/* see tls1.h for macros based on these */
+#ifndef OPENSSL_NO_TLSEXT
+#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_SET_TLSEXT_DEBUG_CB           56
+#define SSL_CTRL_SET_TLSEXT_DEBUG_ARG          57
+#endif
+
 #define SSL_session_reused(ssl) \
        SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL)
 #define SSL_num_renegotiations(ssl) \
@@ -1445,6 +1497,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);
@@ -1621,10 +1674,12 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_SSL3_GET_FINISHED                                 140
 #define SSL_F_SSL3_GET_KEY_EXCHANGE                     141
 #define SSL_F_SSL3_GET_MESSAGE                          142
+#define SSL_F_SSL3_GET_NEW_SESSION_TICKET               283
 #define SSL_F_SSL3_GET_RECORD                           143
 #define SSL_F_SSL3_GET_SERVER_CERTIFICATE               144
 #define SSL_F_SSL3_GET_SERVER_DONE                      145
 #define SSL_F_SSL3_GET_SERVER_HELLO                     146
+#define SSL_F_SSL3_NEW_SESSION_TICKET                   284
 #define SSL_F_SSL3_OUTPUT_CERT_CHAIN                    147
 #define SSL_F_SSL3_PEEK                                         235
 #define SSL_F_SSL3_READ_BYTES                           148
@@ -1640,8 +1695,10 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_SSL3_SETUP_KEY_BLOCK                      157
 #define SSL_F_SSL3_WRITE_BYTES                          158
 #define SSL_F_SSL3_WRITE_PENDING                        159
+#define SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT                272
 #define SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK        215
 #define SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK       216
+#define SSL_F_SSL_ADD_SERVERHELLO_TLSEXT                273
 #define SSL_F_SSL_BAD_METHOD                            160
 #define SSL_F_SSL_BYTES_TO_CIPHER_LIST                  161
 #define SSL_F_SSL_CERT_DUP                              221
@@ -1649,6 +1706,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_SSL_CERT_INSTANTIATE                      214
 #define SSL_F_SSL_CERT_NEW                              162
 #define SSL_F_SSL_CHECK_PRIVATE_KEY                     163
+#define SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT              274
 #define SSL_F_SSL_CIPHER_PROCESS_RULESTR                230
 #define SSL_F_SSL_CIPHER_STRENGTH_SORT                  231
 #define SSL_F_SSL_CLEAR                                         164
@@ -1681,6 +1739,8 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_SSL_LOAD_CLIENT_CA_FILE                   185
 #define SSL_F_SSL_NEW                                   186
 #define SSL_F_SSL_PEEK                                  270
+#define SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT            275
+#define SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT            276
 #define SSL_F_SSL_READ                                  223
 #define SSL_F_SSL_RSA_PRIVATE_DECRYPT                   187
 #define SSL_F_SSL_RSA_PUBLIC_ENCRYPT                    188
@@ -1763,6 +1823,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_TLSEXT                        157
 #define SSL_R_COMPRESSED_LENGTH_TOO_LONG                140
 #define SSL_R_COMPRESSION_FAILURE                       141
 #define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE   307
@@ -1847,6 +1908,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED           197
 #define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE             297
 #define SSL_R_PACKET_LENGTH_TOO_LONG                    198
+#define SSL_R_PARSE_TLSEXT                              223
 #define SSL_R_PATH_TOO_LONG                             270
 #define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE                 199
 #define SSL_R_PEER_ERROR                                200
@@ -1870,11 +1932,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_TLSEXT                        224
 #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               299
+#define SSL_R_SSL3_EXT_INVALID_SERVERNAME               225
+#define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE          226
 #define SSL_R_SSL3_SESSION_ID_TOO_LONG                  300
 #define SSL_R_SSL3_SESSION_ID_TOO_SHORT                         222
 #define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE               1042
@@ -1909,6 +1974,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_TLSV1_ALERT_UNKNOWN_CA                    1048
 #define SSL_R_TLSV1_ALERT_USER_CANCELLED                1090
 #define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER      232
+#define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST            227
 #define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233
 #define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG   234
 #define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER           235
index bacaff157e5be0f295cc029a1175738ecbe0d485..01338e35241ea38e73a87a9dedc9fa75caf09e0c 100644 (file)
@@ -481,6 +481,8 @@ typedef struct ssl3_state_st
 #define SSL3_ST_CR_CHANGE_B            (0x1C1|SSL_ST_CONNECT)
 #define SSL3_ST_CR_FINISHED_A          (0x1D0|SSL_ST_CONNECT)
 #define SSL3_ST_CR_FINISHED_B          (0x1D1|SSL_ST_CONNECT)
+#define SSL3_ST_CR_SESSION_TICKET_A    (0x1E0|SSL_ST_CONNECT)
+#define SSL3_ST_CR_SESSION_TICKET_B    (0x1E1|SSL_ST_CONNECT)
 
 /* server */
 /* extra state */
@@ -522,10 +524,13 @@ typedef struct ssl3_state_st
 #define SSL3_ST_SW_CHANGE_B            (0x1D1|SSL_ST_ACCEPT)
 #define SSL3_ST_SW_FINISHED_A          (0x1E0|SSL_ST_ACCEPT)
 #define SSL3_ST_SW_FINISHED_B          (0x1E1|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SESSION_TICKET_A    (0x1F0|SSL_ST_CONNECT)
+#define SSL3_ST_SW_SESSION_TICKET_B    (0x1F1|SSL_ST_CONNECT)
 
 #define SSL3_MT_HELLO_REQUEST                  0
 #define SSL3_MT_CLIENT_HELLO                   1
 #define SSL3_MT_SERVER_HELLO                   2
+#define        SSL3_MT_NEWSESSION_TICKET               4
 #define SSL3_MT_CERTIFICATE                    11
 #define SSL3_MT_SERVER_KEY_EXCHANGE            12
 #define SSL3_MT_CERTIFICATE_REQUEST            13
index d129acc329110b90d1704be92dcca629ab1855c6..8d9fb6d7d33d9f1ee0069c3e362813e4f435047f 100644 (file)
@@ -78,6 +78,11 @@ 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;
+       ASN1_INTEGER tlsext_tick_lifetime;
+       ASN1_OCTET_STRING tlsext_tick;
+#endif /* OPENSSL_NO_TLSEXT */
        } SSL_SESSION_ASN1;
 
 int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
@@ -86,6 +91,10 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
        int v1=0,v2=0,v3=0,v4=0,v5=0;
        unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2];
        unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2];
+#ifndef OPENSSL_NO_TLSEXT
+       int v6=0,v9=0,v10=0;
+       unsigned char ibuf6[LSIZE2];
+#endif
        long l;
        SSL_SESSION_ASN1 a;
        M_ASN1_I2D_vars(in);
@@ -178,7 +187,32 @@ 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=(unsigned char *)in->tlsext_hostname;
+                }
+       if (in->tlsext_tick)
+                {
+                a.tlsext_tick.length= in->tlsext_ticklen;
+                a.tlsext_tick.type=V_ASN1_OCTET_STRING;
+                a.tlsext_tick.data=(unsigned char *)in->tlsext_tick;
+               /* If we have a ticket set session ID to empty because
+                * it will be bogus. 
+                */
+               if (in->tlsext_ticklen)
+                       a.session_id.length=0;
+                }
+       if (in->tlsext_tick_lifetime_hint != 0)
+               {
+               a.tlsext_tick_lifetime.length=LSIZE2;
+               a.tlsext_tick_lifetime.type=V_ASN1_INTEGER;
+               a.tlsext_tick_lifetime.data=ibuf6;
+               ASN1_INTEGER_set(&a.tlsext_tick_lifetime,in->tlsext_tick_lifetime_hint);
+               }
+#endif /* OPENSSL_NO_TLSEXT */
        M_ASN1_I2D_len(&(a.version),            i2d_ASN1_INTEGER);
        M_ASN1_I2D_len(&(a.ssl_version),        i2d_ASN1_INTEGER);
        M_ASN1_I2D_len(&(a.cipher),             i2d_ASN1_OCTET_STRING);
@@ -200,6 +234,14 @@ 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_tick_lifetime_hint)
+               M_ASN1_I2D_len_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
+       if (in->tlsext_tick)
+               M_ASN1_I2D_len_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
+       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 +265,14 @@ 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);
+       if (in->tlsext_tick_lifetime_hint)
+               M_ASN1_I2D_put_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9);
+       if (in->tlsext_tick)
+               M_ASN1_I2D_put_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
+#endif /* OPENSSL_NO_TLSEXT */
        M_ASN1_I2D_finish();
        }
 
@@ -394,5 +444,54 @@ 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;
+       M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,6);
+       if (os.data)
+               {
+               ret->tlsext_hostname = BUF_strndup((char *)os.data, os.length);
+               OPENSSL_free(os.data);
+               os.data = NULL;
+               os.length = 0;
+               }
+       else
+               ret->tlsext_hostname=NULL;
+       ai.length=0;
+       M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,9);
+       if (ai.data != NULL)
+               {
+               ret->tlsext_tick_lifetime_hint=ASN1_INTEGER_get(aip);
+               OPENSSL_free(ai.data); ai.data=NULL; ai.length=0;
+               }
+       else
+               ret->tlsext_tick_lifetime_hint=0;
+       os.length=0;
+       os.data=NULL;
+       M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,10);
+       if (os.data)
+               {
+               ret->tlsext_tick = os.data;
+               ret->tlsext_ticklen = os.length;
+               os.data = NULL;
+               os.length = 0;
+#if 0
+               /* There are two ways to detect a resumed ticket sesion.
+                * One is to set a random session ID and then the server
+                * must return a match in ServerHello. This allows the normal
+                * client session ID matching to work.
+                */ 
+               if (ret->session_id_length == 0)
+                       {
+                       ret->session_id_length=SSL3_MAX_SSL_SESSION_ID_LENGTH;
+                       RAND_pseudo_bytes(ret->session_id,
+                                               ret->session_id_length);
+                       }
+#endif
+               }
+       else
+               ret->tlsext_tick=NULL;
+#endif /* OPENSSL_NO_TLSEXT */
+
        M_ASN1_D2I_Finish(a,SSL_SESSION_free,SSL_F_D2I_SSL_SESSION);
        }
index e7f4d93c7dc4a1f3d40a25daf9aa24b67be6430e..70c08dbf0fa3e4eaf2fc76bb40fbf77455b9fc49 100644 (file)
@@ -147,10 +147,12 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL3_GET_FINISHED),    "SSL3_GET_FINISHED"},
 {ERR_FUNC(SSL_F_SSL3_GET_KEY_EXCHANGE),        "SSL3_GET_KEY_EXCHANGE"},
 {ERR_FUNC(SSL_F_SSL3_GET_MESSAGE),     "SSL3_GET_MESSAGE"},
+{ERR_FUNC(SSL_F_SSL3_GET_NEW_SESSION_TICKET),  "SSL3_GET_NEW_SESSION_TICKET"},
 {ERR_FUNC(SSL_F_SSL3_GET_RECORD),      "SSL3_GET_RECORD"},
 {ERR_FUNC(SSL_F_SSL3_GET_SERVER_CERTIFICATE),  "SSL3_GET_SERVER_CERTIFICATE"},
 {ERR_FUNC(SSL_F_SSL3_GET_SERVER_DONE), "SSL3_GET_SERVER_DONE"},
 {ERR_FUNC(SSL_F_SSL3_GET_SERVER_HELLO),        "SSL3_GET_SERVER_HELLO"},
+{ERR_FUNC(SSL_F_SSL3_NEW_SESSION_TICKET),      "SSL3_NEW_SESSION_TICKET"},
 {ERR_FUNC(SSL_F_SSL3_OUTPUT_CERT_CHAIN),       "SSL3_OUTPUT_CERT_CHAIN"},
 {ERR_FUNC(SSL_F_SSL3_PEEK),    "SSL3_PEEK"},
 {ERR_FUNC(SSL_F_SSL3_READ_BYTES),      "SSL3_READ_BYTES"},
@@ -166,8 +168,10 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL3_SETUP_KEY_BLOCK), "SSL3_SETUP_KEY_BLOCK"},
 {ERR_FUNC(SSL_F_SSL3_WRITE_BYTES),     "SSL3_WRITE_BYTES"},
 {ERR_FUNC(SSL_F_SSL3_WRITE_PENDING),   "SSL3_WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT),   "SSL_ADD_CLIENTHELLO_TLSEXT"},
 {ERR_FUNC(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK),   "SSL_add_dir_cert_subjects_to_stack"},
 {ERR_FUNC(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK),  "SSL_add_file_cert_subjects_to_stack"},
+{ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT),   "SSL_ADD_SERVERHELLO_TLSEXT"},
 {ERR_FUNC(SSL_F_SSL_BAD_METHOD),       "SSL_BAD_METHOD"},
 {ERR_FUNC(SSL_F_SSL_BYTES_TO_CIPHER_LIST),     "SSL_BYTES_TO_CIPHER_LIST"},
 {ERR_FUNC(SSL_F_SSL_CERT_DUP), "SSL_CERT_DUP"},
@@ -175,6 +179,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL_CERT_INSTANTIATE), "SSL_CERT_INSTANTIATE"},
 {ERR_FUNC(SSL_F_SSL_CERT_NEW), "SSL_CERT_NEW"},
 {ERR_FUNC(SSL_F_SSL_CHECK_PRIVATE_KEY),        "SSL_check_private_key"},
+{ERR_FUNC(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT), "SSL_CHECK_SERVERHELLO_TLSEXT"},
 {ERR_FUNC(SSL_F_SSL_CIPHER_PROCESS_RULESTR),   "SSL_CIPHER_PROCESS_RULESTR"},
 {ERR_FUNC(SSL_F_SSL_CIPHER_STRENGTH_SORT),     "SSL_CIPHER_STRENGTH_SORT"},
 {ERR_FUNC(SSL_F_SSL_CLEAR),    "SSL_clear"},
@@ -207,6 +212,8 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL_LOAD_CLIENT_CA_FILE),      "SSL_load_client_CA_file"},
 {ERR_FUNC(SSL_F_SSL_NEW),      "SSL_new"},
 {ERR_FUNC(SSL_F_SSL_PEEK),     "SSL_peek"},
+{ERR_FUNC(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT),       "SSL_PREPARE_CLIENTHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT),       "SSL_PREPARE_SERVERHELLO_TLSEXT"},
 {ERR_FUNC(SSL_F_SSL_READ),     "SSL_read"},
 {ERR_FUNC(SSL_F_SSL_RSA_PRIVATE_DECRYPT),      "SSL_RSA_PRIVATE_DECRYPT"},
 {ERR_FUNC(SSL_F_SSL_RSA_PUBLIC_ENCRYPT),       "SSL_RSA_PUBLIC_ENCRYPT"},
@@ -292,6 +299,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {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_TLSEXT)    ,"clienthello tlsext"},
 {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 +384,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),"old session cipher not returned"},
 {ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE),"only tls allowed in fips mode"},
 {ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG),"packet length too long"},
+{ERR_REASON(SSL_R_PARSE_TLSEXT)          ,"parse tlsext"},
 {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 +408,14 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {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_TLSEXT)    ,"serverhello tlsext"},
 {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"},
@@ -438,6 +450,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_TLSV1_ALERT_UNKNOWN_CA),"tlsv1 alert unknown ca"},
 {ERR_REASON(SSL_R_TLSV1_ALERT_USER_CANCELLED),"tlsv1 alert user cancelled"},
 {ERR_REASON(SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER),"tls client cert req with anon cipher"},
+{ERR_REASON(SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST),"tls invalid ecpointformat list"},
 {ERR_REASON(SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST),"tls peer did not respond with certificate list"},
 {ERR_REASON(SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG),"tls rsa encrypted value length is wrong"},
 {ERR_REASON(SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER),"tried to use unsupported cipher"},
index 4e81922d758811bd448db5f9da4e58cdc10b5458..31fd26d41bc8aaf4a93a98ef0a58fbdd7d620a24 100644 (file)
 #include <openssl/objects.h>
 #include <openssl/lhash.h>
 #include <openssl/x509v3.h>
+#include <openssl/rand.h>
 #ifndef OPENSSL_NO_DH
 #include <openssl/dh.h>
 #endif
@@ -306,7 +307,13 @@ SSL *SSL_new(SSL_CTX *ctx)
 
        CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
        s->ctx=ctx;
-
+#ifndef OPENSSL_NO_TLSEXT
+       s->tlsext_debug_cb = 0;
+       s->tlsext_debug_arg = NULL;
+       s->tlsext_ticket_expected = 0;
+       CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
+       s->initial_ctx=ctx;
+#endif
        s->verify_result=X509_V_OK;
 
        s->method=ctx->method;
@@ -492,7 +499,9 @@ void SSL_free(SSL *s)
        /* Free up if allocated */
 
        if (s->ctx) SSL_CTX_free(s->ctx);
-
+#ifndef OPENSSL_NO_TLSEXT
+       if (s->initial_ctx) SSL_CTX_free(s->initial_ctx);
+#endif
        if (s->client_CA != NULL)
                sk_X509_NAME_pop_free(s->client_CA,X509_NAME_free);
 
@@ -1304,6 +1313,29 @@ err:
        return(NULL);
        }
 
+#ifndef OPENSSL_NO_TLSEXT
+/** return a servername extension value if provided in Client Hello, or NULL.
+ * So far, only host_name types are defined (RFC 3546).
+ */
+
+const char *SSL_get_servername(const SSL *s, const int type)
+       {
+       if (type != TLSEXT_NAMETYPE_host_name)
+               return NULL;
+
+       return s->session && !s->tlsext_hostname ?
+               s->session->tlsext_hostname :
+               s->tlsext_hostname;
+       }
+
+int SSL_get_servername_type(const SSL *s)
+       {
+       if (s->session && (!s->tlsext_hostname ? s->session->tlsext_hostname : s->tlsext_hostname))
+               return TLSEXT_NAMETYPE_host_name;
+       return -1;
+       }
+#endif
+
 unsigned long SSL_SESSION_hash(const SSL_SESSION *a)
        {
        unsigned long l;
@@ -1453,6 +1485,17 @@ SSL_CTX *SSL_CTX_new(SSL_METHOD *meth)
        ret->extra_certs=NULL;
        ret->comp_methods=SSL_COMP_get_compression_methods();
 
+#ifndef OPENSSL_NO_TLSEXT
+       ret->tlsext_servername_callback = 0;
+       ret->tlsext_servername_arg = NULL;
+       /* Setup RFC4507 ticket keys */
+       if ((RAND_pseudo_bytes(ret->tlsext_tick_key_name, 16) <= 0)
+               || (RAND_bytes(ret->tlsext_tick_hmac_key, 16) <= 0)
+               || (RAND_bytes(ret->tlsext_tick_aes_key, 16) <= 0))
+               ret->options |= SSL_OP_NO_TICKET;
+
+#endif
+
        return(ret);
 err:
        SSLerr(SSL_F_SSL_CTX_NEW,ERR_R_MALLOC_FAILURE);
@@ -2402,6 +2445,24 @@ SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl)
        return(ssl->ctx);
        }
 
+SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx)
+       {
+       if (ssl->ctx == ctx)
+               return ssl->ctx;
+#ifndef OPENSSL_NO_TLSEXT
+       if (ctx == NULL)
+               ctx = ssl->initial_ctx;
+#endif
+       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)
        {
index bab1f953d71c569e89fcead014e93a123d7ab1de..e92dd66271030f3a3a57a65e2f81408486c1b514 100644 (file)
@@ -716,7 +716,7 @@ SESS_CERT *ssl_sess_cert_new(void);
 void ssl_sess_cert_free(SESS_CERT *sc);
 int ssl_set_peer_cert_type(SESS_CERT *c, int type);
 int ssl_get_new_session(SSL *s, int session);
-int ssl_get_prev_session(SSL *s, unsigned char *session,int len);
+int ssl_get_prev_session(SSL *s, unsigned char *session,int len, const unsigned char *limit);
 int ssl_cipher_id_cmp(const SSL_CIPHER *a,const SSL_CIPHER *b);
 int ssl_cipher_ptr_id_cmp(const SSL_CIPHER * const *ap,
                        const SSL_CIPHER * const *bp);
@@ -776,6 +776,7 @@ SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p);
 int ssl3_put_cipher_by_char(const SSL_CIPHER *c,unsigned char *p);
 void ssl3_init_finished_mac(SSL *s);
 int ssl3_send_server_certificate(SSL *s);
+int ssl3_send_newsession_ticket(SSL *s);
 int ssl3_get_finished(SSL *s,int state_a,int state_b);
 int ssl3_setup_key_block(SSL *s);
 int ssl3_send_change_cipher_spec(SSL *s,int state_a,int state_b);
@@ -866,6 +867,7 @@ long dtls1_default_timeout(void);
 int ssl3_client_hello(SSL *s);
 int ssl3_get_server_hello(SSL *s);
 int ssl3_get_certificate_request(SSL *s);
+int ssl3_get_new_session_ticket(SSL *s);
 int ssl3_get_server_done(SSL *s);
 int ssl3_send_client_verify(SSL *s);
 int ssl3_send_client_certificate(SSL *s);
@@ -947,5 +949,19 @@ int check_srvr_ecc_cert_and_alg(X509 *x, SSL_CIPHER *cs);
 
 SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n);
 
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); 
+unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); 
+int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n, int *al);
+int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n, int *al);
+int ssl_prepare_clienthello_tlsext(SSL *s);
+int ssl_prepare_serverhello_tlsext(SSL *s);
+int ssl_check_clienthello_tlsext(SSL *s);
+int ssl_check_serverhello_tlsext(SSL *s);
+int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
+                               const unsigned char *limit, SSL_SESSION **ret);
+EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ;
+void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
+#endif
 
 #endif
index 5bee2d5619ff403aa642b233b5318aea20407313..d30a24f2fe0caf8eabbb898416054584a90b5221 100644 (file)
@@ -122,6 +122,9 @@ SSL_SESSION *SSL_SESSION_new(void)
        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);
        }
@@ -216,6 +219,14 @@ int ssl_get_new_session(SSL *s, int session)
                        SSL_SESSION_free(ss);
                        return(0);
                        }
+#ifndef OPENSSL_NO_TLSEXT
+               /* If RFC4507 ticket use empty session ID */
+               if (s->tlsext_ticket_expected)
+                       {
+                       ss->session_id_length = 0;
+                       goto sess_id_done;
+                       }
+#endif
                /* Choose which callback will set the session ID */
                CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
                if(s->generate_session_id)
@@ -257,6 +268,17 @@ int ssl_get_new_session(SSL *s, int session)
                        SSL_SESSION_free(ss);
                        return(0);
                        }
+#ifndef OPENSSL_NO_TLSEXT
+               sess_id_done:
+               if (s->tlsext_hostname) {
+                       ss->tlsext_hostname = BUF_strdup(s->tlsext_hostname);
+                       if (ss->tlsext_hostname == NULL) {
+                               SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_INTERNAL_ERROR);
+                               SSL_SESSION_free(ss);
+                               return 0;
+                               }
+                       }
+#endif
                }
        else
                {
@@ -278,21 +300,39 @@ int ssl_get_new_session(SSL *s, int session)
        return(1);
        }
 
-int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len)
+int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
+                       const unsigned char *limit)
        {
        /* This is used only by servers. */
 
-       SSL_SESSION *ret=NULL,data;
+       SSL_SESSION *ret=NULL;
        int fatal = 0;
-
-       data.ssl_version=s->version;
-       data.session_id_length=len;
+#ifndef OPENSSL_NO_TLSEXT
+       int r;
+#endif
+  
        if (len > SSL_MAX_SSL_SESSION_ID_LENGTH)
                goto err;
-       memcpy(data.session_id,session_id,len);
-
+#ifndef OPENSSL_NO_TLSEXT
+       r = tls1_process_ticket(s, session_id, len, limit, &ret);
+       if (r == -1)
+               {
+               fatal = 1;
+               goto err;
+               }
+       else if (r == 0)
+               goto err;
+       else if (!ret && !(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
+#else
        if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP))
+#endif
                {
+               SSL_SESSION data;
+               data.ssl_version=s->version;
+               data.session_id_length=len;
+               if (len == 0)
+                       return 0;
+               memcpy(data.session_id,session_id,len);
                CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX);
                ret=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,&data);
                if (ret != NULL)
@@ -548,6 +588,10 @@ void SSL_SESSION_free(SSL_SESSION *ss)
        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);
+       if (ss->tlsext_tick != NULL) OPENSSL_free(ss->tlsext_tick);
+#endif
        OPENSSL_cleanse(ss,sizeof(*ss));
        OPENSSL_free(ss);
        }
index 4eb0867155e1633af6815b1aea0dba5225b54afb..06b86750fdb550b1929e91c665c46152bbcb53db 100644 (file)
@@ -151,6 +151,21 @@ int SSL_SESSION_print(BIO *bp, const SSL_SESSION *x)
                        if (BIO_printf(bp,"%02X",x->krb5_client_princ[i]) <= 0) goto err;
                        }
 #endif /* OPENSSL_NO_KRB5 */
+#ifndef OPENSSL_NO_TLSEXT
+       if (x->tlsext_tick_lifetime_hint)
+               {
+               if (BIO_printf(bp,
+                       "\n    TLS session ticket lifetime hint: %ld (seconds)",
+                       x->tlsext_tick_lifetime_hint) <=0)
+                       goto err;
+               }
+       if (x->tlsext_tick)
+               {
+               if (BIO_puts(bp, "\n    TLS session ticket:\n") <= 0) goto err;
+               if (BIO_dump_indent(bp, (char *)x->tlsext_tick, x->tlsext_ticklen, 4) <= 0)
+                       goto err;
+               }
+#endif
 #ifndef OPENSSL_NO_COMP
        if (x->compress_meth != 0)
                {
index 1ecbbcb8fb1fb5a4277261628eaf57096c1c4f71..cc5e80fefd3a2220eaa6f9667b8a6529b4a87d50 100644 (file)
 
 #include <stdio.h>
 #include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
 #include "ssl_locl.h"
 
 const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
 
+#ifndef OPENSSL_NO_TLSEXT
+static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen,
+                               const unsigned char *sess_id, int sesslen,
+                               SSL_SESSION **psess);
+#endif
+
 SSL3_ENC_METHOD TLSv1_enc_data={
        tls1_enc,
        tls1_mac,
@@ -117,3 +125,506 @@ long tls1_callback_ctrl(SSL *s, int cmd, void *(*fp)())
        return(0);
        }
 #endif
+
+#ifndef OPENSSL_NO_TLSEXT
+unsigned char *ssl_add_clienthello_tlsext(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->tlsext_hostname != NULL)
+               { 
+               /* Add TLS extension servername to the Client Hello message */
+               unsigned long size_str;
+               long lenmax; 
+
+               /* check for enough space.
+                  4 for the servername type and entension length
+                  2 for servernamelist length
+                  1 for the hostname type
+                  2 for hostname length
+                  + hostname length 
+               */
+                  
+               if ((lenmax = limit - p - 9) < 0 
+               || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) 
+                       return NULL;
+                       
+               /* extension type and length */
+               s2n(TLSEXT_TYPE_server_name,ret); 
+               s2n(size_str+5,ret);
+               
+               /* length of servername list */
+               s2n(size_str+3,ret);
+       
+               /* hostname type, length and hostname */
+               *(ret++) = (unsigned char) TLSEXT_NAMETYPE_host_name;
+               s2n(size_str,ret);
+               memcpy(ret, s->tlsext_hostname, size_str);
+               ret+=size_str;
+
+               }
+
+       if (!(SSL_get_options(s) & SSL_OP_NO_TICKET))
+               {
+               int ticklen;
+               if (s->session && s->session->tlsext_tick)
+                       ticklen = s->session->tlsext_ticklen;
+               else
+                       ticklen = 0;
+               /* Check for enough room 2 for extension type, 2 for len
+                * rest for ticket
+                */
+               if (limit - p - 4 - ticklen < 0)
+                       return NULL;
+               s2n(TLSEXT_TYPE_session_ticket,ret); 
+               s2n(ticklen,ret);
+               if (ticklen)
+                       {
+                       memcpy(ret, s->session->tlsext_tick, ticklen);
+                       ret += ticklen;
+                       }
+               }
+
+       if ((extdatalen = ret-p-2)== 0) 
+               return p;
+
+       s2n(extdatalen,p);
+       return ret;
+       }
+
+unsigned char *ssl_add_serverhello_tlsext(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->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL)
+               { 
+               if (limit - p - 4 < 0) return NULL; 
+
+               s2n(TLSEXT_TYPE_server_name,ret);
+               s2n(0,ret);
+               }
+       
+       if (s->tlsext_ticket_expected
+               && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) 
+               { 
+               if (limit - p - 4 < 0) return NULL; 
+               s2n(TLSEXT_TYPE_session_ticket,ret);
+               s2n(0,ret);
+               }
+               
+       if ((extdatalen = ret-p-2)== 0) 
+               return p;
+
+       s2n(extdatalen,p);
+       return ret;
+       }
+
+int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
+       {
+       unsigned short type;
+       unsigned short size;
+       unsigned short len;
+       unsigned char *data = *p;
+       s->servername_done = 0;
+
+       if (data >= (d+n-2))
+               return 1;
+       n2s(data,len);
+
+       if (data > (d+n-len)) 
+               return 1;
+
+       while (data <= (d+n-4))
+               {
+               n2s(data,type);
+               n2s(data,size);
+
+               if (data+size > (d+n))
+                       return 1;
+
+               if (s->tlsext_debug_cb)
+                       s->tlsext_debug_cb(s, 0, type, data, size,
+                                               s->tlsext_debug_arg);
+/* The servername extension is treated as follows:
+
+   - Only the hostname type is supported with a maximum length of 255.
+   - The servername is rejected if too long or if it contains zeros,
+     in which case an fatal alert is generated.
+   - The servername field is maintained together with the session cache.
+   - When a session is resumed, the servername call back invoked in order
+     to allow the application to position itself to the right context. 
+   - The servername is acknowledged if it is new for a session or when 
+     it is identical to a previously used for the same session. 
+     Applications can control the behaviour.  They can at any time
+     set a 'desirable' servername for a new SSL object. This can be the
+     case for example with HTTPS when a Host: header field is received and
+     a renegotiation is requested. In this case, a possible servername
+     presented in the new client hello is only acknowledged if it matches
+     the value of the Host: field. 
+   - Applications must  use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+     if they provide for changing an explicit servername context for the session,
+     i.e. when the session has been established with a servername extension. 
+   - On session reconnect, the servername extension may be absent. 
+
+*/      
+
+               if (type == TLSEXT_TYPE_server_name)
+                       {
+                       unsigned char *sdata;
+                       int servname_type;
+                       int dsize; 
+               
+                       if (size < 2) 
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       n2s(data,dsize);  
+                       size -= 2;
+                       if (dsize > size  ) 
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               } 
+
+                       sdata = data;
+                       while (dsize > 3) 
+                               {
+                               servname_type = *(sdata++); 
+                               n2s(sdata,len);
+                               dsize -= 3;
+
+                               if (len > dsize) 
+                                       {
+                                       *al = SSL_AD_DECODE_ERROR;
+                                       return 0;
+                                       }
+                               if (s->servername_done == 0)
+                               switch (servname_type)
+                                       {
+                               case TLSEXT_NAMETYPE_host_name:
+                                       if (s->session->tlsext_hostname == NULL)
+                                               {
+                                               if (len > TLSEXT_MAXLEN_host_name || 
+                                                       ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL))
+                                                       {
+                                                       *al = TLS1_AD_UNRECOGNIZED_NAME;
+                                                       return 0;
+                                                       }
+                                               memcpy(s->session->tlsext_hostname, sdata, len);
+                                               s->session->tlsext_hostname[len]='\0';
+                                               if (strlen(s->session->tlsext_hostname) != len) {
+                                                       OPENSSL_free(s->session->tlsext_hostname);
+                                                       *al = TLS1_AD_UNRECOGNIZED_NAME;
+                                                       return 0;
+                                               }
+                                               s->servername_done = 1; 
+
+                                               }
+                                       else 
+                                               s->servername_done = strlen(s->session->tlsext_hostname) == len 
+                                                       && strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0;
+                                       
+                                       break;
+
+                               default:
+                                       break;
+                                       }
+                                
+                               dsize -= len;
+                               }
+                       if (dsize != 0) 
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+
+                       }
+               /* session ticket processed earlier */
+
+               data+=size;             
+               }
+
+       *p = data;
+       return 1;
+       }
+
+int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
+       {
+       unsigned short type;
+       unsigned short size;
+       unsigned short len;  
+       unsigned char *data = *p;
+
+       int tlsext_servername = 0;
+
+       if (data >= (d+n-2))
+               return 1;
+
+       n2s(data,len);
+
+       while(data <= (d+n-4))
+               {
+               n2s(data,type);
+               n2s(data,size);
+
+               if (data+size > (d+n))
+                       return 1;
+
+               if (s->tlsext_debug_cb)
+                       s->tlsext_debug_cb(s, 1, type, data, size,
+                                               s->tlsext_debug_arg);
+
+               if (type == TLSEXT_TYPE_server_name)
+                       {
+                       if (s->tlsext_hostname == NULL || size > 0)
+                               {
+                               *al = TLS1_AD_UNRECOGNIZED_NAME;
+                               return 0;
+                               }
+                       tlsext_servername = 1;   
+                       }
+               else if (type == TLSEXT_TYPE_session_ticket)
+                       {
+                       if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
+                               || (size > 0))
+                               {
+                               *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+                               return 0;
+                               }
+                       s->tlsext_ticket_expected = 1;
+                       }
+
+               data+=size;             
+               }
+
+       if (data != d+n)
+               {
+               *al = SSL_AD_DECODE_ERROR;
+               return 0;
+               }
+
+       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)
+                                       {
+                                       *al = SSL_AD_UNRECOGNIZED_NAME;
+                                       return 0;
+                                       }
+                               }
+                       else 
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       }
+               }
+
+       *p = data;
+       return 1;
+       }
+
+int ssl_check_clienthello_tlsext(SSL *s)
+       {
+       int ret=SSL_TLSEXT_ERR_NOACK;
+       int al = SSL_AD_UNRECOGNIZED_NAME;
+
+       if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) 
+               ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
+       else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)             
+               ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
+
+       switch (ret)
+               {
+               case SSL_TLSEXT_ERR_ALERT_FATAL:
+                       ssl3_send_alert(s,SSL3_AL_FATAL,al); 
+                       return -1;
+
+               case SSL_TLSEXT_ERR_ALERT_WARNING:
+                       ssl3_send_alert(s,SSL3_AL_WARNING,al);
+                       return 1; 
+                                       
+               case SSL_TLSEXT_ERR_NOACK:
+                       s->servername_done=0;
+                       default:
+               return 1;
+               }
+       }
+
+int ssl_check_serverhello_tlsext(SSL *s)
+       {
+       int ret=SSL_TLSEXT_ERR_NOACK;
+       int al = SSL_AD_UNRECOGNIZED_NAME;
+
+       if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) 
+               ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
+       else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)             
+               ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
+
+       switch (ret)
+               {
+               case SSL_TLSEXT_ERR_ALERT_FATAL:
+                       ssl3_send_alert(s,SSL3_AL_FATAL,al); 
+                       return -1;
+
+               case SSL_TLSEXT_ERR_ALERT_WARNING:
+                       ssl3_send_alert(s,SSL3_AL_WARNING,al);
+                       return 1; 
+                                       
+               case SSL_TLSEXT_ERR_NOACK:
+                       s->servername_done=0;
+                       default:
+               return 1;
+               }
+       }
+
+/* Since the server cache lookup is done early on in the processing of client
+ * hello and other operations depend on the result we need to handle any TLS
+ * session ticket extension at the same time.
+ */
+
+int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
+                               const unsigned char *limit, SSL_SESSION **ret)
+       {
+       /* Point after session ID in client hello */
+       const unsigned char *p = session_id + len;
+       unsigned short i;
+       if ((s->version <= SSL3_VERSION) || !limit)
+               return 1;
+       if (p >= limit)
+               return -1;
+       /* Skip past cipher list */
+       n2s(p, i);
+       p+= i;
+       if (p >= limit)
+               return -1;
+       /* Skip past compression algorithm list */
+       i = *(p++);
+       p += i;
+       if (p > limit)
+               return -1;
+       /* Now at start of extensions */
+       if ((p + 2) >= limit)
+               return 1;
+       n2s(p, i);
+       while ((p + 4) <= limit)
+               {
+               unsigned short type, size;
+               n2s(p, type);
+               n2s(p, size);
+               if (p + size > limit)
+                       return 1;
+               if (type == TLSEXT_TYPE_session_ticket)
+                       {
+                       /* If tickets disabled indicate cache miss which will
+                        * trigger a full handshake
+                        */
+                       if (SSL_get_options(s) & SSL_OP_NO_TICKET)
+                               return 0;
+                       /* If zero length not client will accept a ticket
+                        * and indicate cache miss to trigger full handshake
+                        */
+                       if (size == 0)
+                               {
+                               s->tlsext_ticket_expected = 1;
+                               return 0;       /* Cache miss */
+                               }
+                       return tls_decrypt_ticket(s, p, size, session_id, len,
+                                                                       ret);
+                       }
+               p += size;
+               }
+       return 1;
+       }
+
+static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
+                               const unsigned char *sess_id, int sesslen,
+                               SSL_SESSION **psess)
+       {
+       SSL_SESSION *sess;
+       unsigned char *sdec;
+       const unsigned char *p;
+       int slen, mlen;
+       unsigned char tick_hmac[EVP_MAX_MD_SIZE];
+       HMAC_CTX hctx;
+       EVP_CIPHER_CTX ctx;
+       /* Attempt to process session ticket, first conduct sanity and
+        * integrity checks on ticket.
+        */
+       mlen = EVP_MD_size(EVP_sha1());
+       eticklen -= mlen;
+       /* Need at least keyname + iv + some encrypted data */
+       if (eticklen < 48)
+               goto tickerr;
+       /* Check key name matches */
+       if (memcmp(etick, s->ctx->tlsext_tick_key_name, 16))
+               goto tickerr;
+       /* Check HMAC of encrypted ticket */
+       HMAC_CTX_init(&hctx);
+       HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
+                               EVP_sha1(), NULL);
+       HMAC_Update(&hctx, etick, eticklen);
+       HMAC_Final(&hctx, tick_hmac, NULL);
+       HMAC_CTX_cleanup(&hctx);
+       if (memcmp(tick_hmac, etick + eticklen, mlen))
+               goto tickerr;
+       /* Set p to start of IV */
+       p = etick + 16;
+       EVP_CIPHER_CTX_init(&ctx);
+       /* Attempt to decrypt session data */
+       EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+                                       s->ctx->tlsext_tick_aes_key, p);
+       /* Move p after IV to start of encrypted ticket, update length */
+       p += 16;
+       eticklen -= 32;
+       sdec = OPENSSL_malloc(eticklen);
+       if (!sdec)
+               {
+               EVP_CIPHER_CTX_cleanup(&ctx);
+               return -1;
+               }
+       EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen);
+       if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0)
+               goto tickerr;
+       slen += mlen;
+       EVP_CIPHER_CTX_cleanup(&ctx);
+       p = sdec;
+               
+       sess = d2i_SSL_SESSION(NULL, &p, slen);
+       OPENSSL_free(sdec);
+       if (sess)
+               {
+               /* The session ID if non-empty is used by some clients to
+                * detect that the ticket has been accepted. So we copy it to
+                * the session structure. If it is empty set length to zero
+                * as required by standard.
+                */
+               if (sesslen)
+                       memcpy(sess->session_id, sess_id, sesslen);
+               sess->session_id_length = sesslen;
+               *psess = sess;
+               return 1;
+               }
+       /* If session decrypt failure indicate a cache miss and set state to
+        * send a new ticket
+        */
+       tickerr:        
+       s->tlsext_ticket_expected = 1;
+       return 0;
+       }
+
+#endif
index 2b04effeaecb8fdcfbacf88e6a7afe245a08db38..5a01cdd64e0f903a368f1d6448d4a0a146df3bee 100644 (file)
@@ -96,6 +96,55 @@ extern "C" {
 #define TLS1_AD_INTERNAL_ERROR         80      /* fatal */
 #define TLS1_AD_USER_CANCELLED         90
 #define TLS1_AD_NO_RENEGOTIATION       100
+/* codes 110-114 are from RFC3546 */
+#define TLS1_AD_UNSUPPORTED_EXTENSION  110
+#define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111
+#define TLS1_AD_UNRECOGNIZED_NAME      112
+#define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113
+#define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114
+#define TLS1_AD_UNKNOWN_PSK_IDENTITY   115     /* fatal */
+
+/* ExtensionType values from RFC 3546 */
+#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_elliptic_curves            10
+#define TLSEXT_TYPE_ec_point_formats           11
+#define TLSEXT_TYPE_session_ticket             35
+
+/* NameType value from RFC 3546 */
+#define TLSEXT_NAMETYPE_host_name 0
+
+#ifndef OPENSSL_NO_TLSEXT
+
+#define TLSEXT_MAXLEN_host_name 255
+
+const char *SSL_get_servername(const SSL *s, const int type) ;
+int SSL_get_servername_type(const SSL *s) ;
+
+#define SSL_set_tlsext_host_name(s,name) \
+SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name)
+
+#define SSL_set_tlsext_debug_callback(ssl, cb) \
+SSL_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_CB,(void (*)(void))cb)
+
+#define SSL_set_tlsext_debug_arg(ssl, arg) \
+SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_ARG,0, (void *)arg)
+
+#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_TLSEXT_ERR_OK 0    
+#define SSL_TLSEXT_ERR_ALERT_WARNING 1  
+#define SSL_TLSEXT_ERR_ALERT_FATAL 2 
+#define SSL_TLSEXT_ERR_NOACK 3
+
+#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \
+SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
+#endif
 
 /* Additional TLS ciphersuites from draft-ietf-tls-56-bit-ciphersuites-00.txt
  * (available if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES is defined, see