Further TLS extension updates
authorBodo Möller <bodo@openssl.org>
Mon, 9 Jan 2006 19:49:05 +0000 (19:49 +0000)
committerBodo Möller <bodo@openssl.org>
Mon, 9 Jan 2006 19:49:05 +0000 (19:49 +0000)
Submitted by: Peter Sylvester

CHANGES
apps/s_client.c
apps/s_server.c
crypto/ec/ec_err.c
ssl/s3_lib.c
ssl/s3_srvr.c
ssl/ssl.h
ssl/ssl_lib.c
ssl/ssl_sess.c
ssl/t1_lib.c
ssl/tls1.h

diff --git a/CHANGES b/CHANGES
index dda03549fcd02403253edfa40374b43b402722eb..f4014aeefc1b750bfeef6b89223289d863164b76 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -25,8 +25,6 @@
          SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG
                                       - SSL_CTX_set_tlsext_servername_arg()
          SSL_CTRL_SET_TLSEXT_HOSTNAME           - SSL_set_tlsext_hostname()
-         SSL_CTRL_SET_TLSEXT_SERVERNAME_DONE
-                                         - SSL_set_tlsext_servername_done()
 
      openssl s_client has a new '-servername' option.
 
@@ -34,6 +32,8 @@
      (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).
+     The option servername_warn allows to return a warning alert instead of
+     a fatal alert in case of servername mismatch. 
 
      [Peter Sylvester,  Remy Allais, Christophe Renou]
 
index 96cf511403b951637fdf4e2e8f8ef08428fd03ac..47cd9d93d57af5dd8bcf0119f71e2830011c1bbb 100644 (file)
@@ -647,7 +647,7 @@ bad:
 #ifndef OPENSSL_NO_TLSEXT
        if (servername != NULL)
                {
-               if (!SSL_set_tlsext_hostname(con,servername))
+               if (!SSL_set_tlsext_host_name(con,servername))
                        {
                        BIO_printf(bio_err,"Unable to set TLS servername extension.\n");
                        ERR_print_errors(bio_err);
index 24a25d815611eb42af7a0d7907f2e57ac499806b..e07f3dd20ed81bdd155c2d029a87e4a3716047e3 100644 (file)
@@ -367,6 +367,7 @@ static void sv_usage(void)
        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_warn - on mismatch send warning (default fatal 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");
@@ -533,6 +534,7 @@ static int ebcdic_puts(BIO *bp, const char *str)
 typedef struct tlsextctx_st {
    char * servername;
    BIO * biodebug;
+   int servername_warn;
 } tlsextctx;
 
 
@@ -544,18 +546,16 @@ static int MS_CALLBACK ssl_servername_cb(SSL *s, int *ad, void *arg)
                BIO_printf(p->biodebug,"Hostname in TLS extension: \"%s\"\n",servername);
         
        if (!p->servername)
-               {
-               SSL_set_tlsext_servername_done(s,2);
                return 1;
-               }
        
        if (servername)
                {
                if (strcmp(servername,p->servername)) 
-                       return 0;
-               if (ctx2) 
+                       return  p->servername_warn;
+               if (ctx2) {
+                       BIO_printf(p->biodebug,"Swiching server context.\n");
                        SSL_set_SSL_CTX(s,ctx2);
-               SSL_set_tlsext_servername_done(s,1);
+                       }     
                }
        return 1;
 }
@@ -597,7 +597,7 @@ int MAIN(int argc, char *argv[])
 #endif
 
 #ifndef OPENSSL_NO_TLSEXT
-        tlsextctx tlsextcbp = {NULL, NULL};
+        tlsextctx tlsextcbp = {NULL, NULL, -1};
 #endif
 #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3)
        meth=SSLv23_server_method();
@@ -846,6 +846,8 @@ int MAIN(int argc, char *argv[])
                        if (--argc < 1) goto bad;
                        tlsextcbp.servername= *(++argv);
                        }
+               else if (strcmp(*argv,"-servername_warn") == 0)
+                       { tlsextcbp.servername_warn = 0; }
                else if (strcmp(*argv,"-cert2") == 0)
                        {
                        if (--argc < 1) goto bad;
@@ -1553,6 +1555,7 @@ static int sv_body(char *hostname, int s, unsigned char *context)
                                        ret= -11;*/
                                        goto err;
                                        }
+
                                if ((buf[0] == 'r') && 
                                        ((buf[1] == '\n') || (buf[1] == '\r')))
                                        {
index 86b58271f4f2cc9a12d0122f9c48ea4a2a469ca5..18a300d7536f377c60872355c91fa688a75c4d6c 100644 (file)
@@ -131,7 +131,6 @@ static ERR_STRING_DATA EC_str_functs[]=
 {ERR_FUNC(EC_F_EC_GROUP_GET_ORDER),    "EC_GROUP_get_order"},
 {ERR_FUNC(EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS),        "EC_GROUP_get_pentanomial_basis"},
 {ERR_FUNC(EC_F_EC_GROUP_GET_TRINOMIAL_BASIS),  "EC_GROUP_get_trinomial_basis"},
-{ERR_FUNC(EC_F_EC_GROUP_GROUP2NID),    "EC_GROUP_GROUP2NID"},
 {ERR_FUNC(EC_F_EC_GROUP_NEW),  "EC_GROUP_new"},
 {ERR_FUNC(EC_F_EC_GROUP_NEW_BY_CURVE_NAME),    "EC_GROUP_new_by_curve_name"},
 {ERR_FUNC(EC_F_EC_GROUP_NEW_FROM_DATA),        "EC_GROUP_NEW_FROM_DATA"},
index 194b95d3f11bb8c1736b9400001089fff9d5b7b8..3b87222166d00e51934bc5206cb872cfa3a3ac79 100644 (file)
@@ -1654,7 +1654,7 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
                        ret = 1;
                        if (parg == NULL) 
                                break;
-                       if (strlen((char *)parg) > 255)
+                       if (strlen((char *)parg) > TLSEXT_MAXLEN_host_name)
                                {
                                SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME);
                                return 0;
@@ -1672,9 +1672,6 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
                        }
                s->options |= SSL_OP_NO_SSLv2; /* can't use extension w/ SSL 2.0 format */
                break;
-       case SSL_CTRL_SET_TLSEXT_SERVERNAME_DONE:
-               s->servername_done = larg;
-               break;
 #endif /* !OPENSSL_NO_TLSEXT */
        default:
                break;
index 954959404a6bc8cd0be112127f8da799f73237aa..c83505c0a50082e93fd188c319479eef45264470 100644 (file)
@@ -283,14 +283,16 @@ int ssl3_accept(SSL *s)
                        if (ret <= 0) goto end;
 #ifndef OPENSSL_NO_TLSEXT
                        {
-                               int al;
-                               if (ssl_check_tlsext(s,&al) <= 0)
-                                       {
-                                       ssl3_send_alert(s,SSL3_AL_FATAL,al); /* XXX does this *have* to be fatal? */
+                               int al,warn;
+                               warn = ssl_check_tlsext(s,&al);
+                               if (warn == 0)
+                                       ssl3_send_alert(s,SSL3_AL_WARNING,al); 
+                               else if (warn < 0) {
+                                       ssl3_send_alert(s,SSL3_AL_FATAL,al); 
                                        SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLS_EXT);
                                        ret = -1;
                                        goto end;
-                                       }
+                               }
                        }
 #endif
                        s->new_session = 2;
index 30c11d7bb65b0182b62b95edff84db1f0ab13b70..9370da16255f55a70091723c30104cefbde6a27a 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -994,6 +994,9 @@ struct ssl_st
                                  2 : don't call servername callback, no ack in server hello
                               */
        SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+#define session_ctx initial_ctx
+#else
+#define session_ctx ctx
 #endif
        };
 
@@ -1114,7 +1117,7 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
        PEM_ASN1_write_bio_of(SSL_SESSION,i2d_SSL_SESSION,PEM_STRING_SSL_SESSION,bp,x,NULL,NULL,0,NULL,NULL)
 #endif
 
-#define SSL_AD_REASON_OFFSET           1000 /* offset to get SSL_R_... value from SSL_AD_... /
+#define SSL_AD_REASON_OFFSET           1000 /* offset to get SSL_R_... value from SSL_AD_... */
 
 /* These alert types are for SSLv3 and TLSv1 */
 #define SSL_AD_CLOSE_NOTIFY            SSL3_AD_CLOSE_NOTIFY
@@ -1206,12 +1209,11 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
 
 #define SSL_CTRL_SET_MAX_SEND_FRAGMENT         52
 
-/* see tls.h for macros based on these */
+/* 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_SERVERNAME_DONE    56
 #endif
 
 #define SSL_session_reused(ssl) \
index 42aa8745420a400ae7ee93be33b1783cc9e4d145..7eec7f69d01894dd12acf8b70eca51a0bd4e1a61 100644 (file)
@@ -1332,15 +1332,15 @@ const char *SSL_get_servername(const SSL *s, const int type)
        {
        if (type != TLSEXT_NAMETYPE_host_name)
                return NULL;
-       /* XXX cf. SSL_CTRL_GET_TLSEXT_HOSTNAME case in ssl3_ctrl (s3_lib.c) */
-       return s->session /*&&s->session->tlsext_hostname*/ ?
+
+       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->session->tlsext_hostname ? s->session->tlsext_hostname : s->tlsext_hostname
+       if (s->session && (!s->tlsext_hostname ? s->session->tlsext_hostname : s->tlsext_hostname)
                return TLSEXT_NAMETYPE_host_name;
        return -1;
        }
@@ -1930,14 +1930,14 @@ void ssl_update_cache(SSL *s,int mode)
         * and it would be rather hard to do anyway :-) */
        if (s->session->session_id_length == 0) return;
 
-       i=s->ctx->session_cache_mode;
+       i=s->session_ctx->session_cache_mode;
        if ((i & mode) && (!s->hit)
                && ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE)
-                   || SSL_CTX_add_session(s->ctx,s->session))
-               && (s->ctx->new_session_cb != NULL))
+                   || SSL_CTX_add_session(s->session_ctx,s->session))
+               && (s->session_ctx->new_session_cb != NULL))
                {
                CRYPTO_add(&s->session->references,1,CRYPTO_LOCK_SSL_SESSION);
-               if (!s->ctx->new_session_cb(s,s->session))
+               if (!s->session_ctx->new_session_cb(s,s->session))
                        SSL_SESSION_free(s->session);
                }
 
@@ -1946,10 +1946,10 @@ void ssl_update_cache(SSL *s,int mode)
                ((i & mode) == mode))
                {
                if (  (((mode & SSL_SESS_CACHE_CLIENT)
-                       ?s->ctx->stats.sess_connect_good
-                       :s->ctx->stats.sess_accept_good) & 0xff) == 0xff)
+                       ?s->session_ctx->stats.sess_connect_good
+                       :s->session_ctx->stats.sess_accept_good) & 0xff) == 0xff)
                        {
-                       SSL_CTX_flush_sessions(s->ctx,(unsigned long)time(NULL));
+                       SSL_CTX_flush_sessions(s->session_ctx,(unsigned long)time(NULL));
                        }
                }
        }
@@ -2452,6 +2452,10 @@ SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl)
 
 SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx)
        {
+       if (ssl->ctx == ctx) 
+               return ssl->ctx;
+       if (ctx == NULL)
+               ctx = ssl->initial_ctx;
        if (ssl->cert != NULL)
                ssl_cert_free(ssl->cert);
        ssl->cert = ssl_cert_dup(ctx->cert);
index 5dfc4c81bc686de18bf3dffafa251f737215f835..ffacf94cc7491ea6bb7e1ce0f92f35ec9dbb5bb9 100644 (file)
 #include <openssl/rand.h>
 #include "ssl_locl.h"
 
-#ifndef OPENSSL_NO_TLSEXT
-#define session_ctx initial_ctx
-#else
-#define session_ctx ctx
-#endif
-
 static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s);
 static void SSL_SESSION_list_add(SSL_CTX *ctx,SSL_SESSION *s);
 static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck);
@@ -242,7 +236,7 @@ int ssl_get_new_session(SSL *s, int session)
        if (s->session_ctx->session_timeout == 0)
                ss->timeout=SSL_get_default_timeout(s);
        else
-               ss->timeout=s->ctx->session_timeout;
+               ss->timeout=s->session_ctx->session_timeout;
 
        if (s->session != NULL)
                {
@@ -319,6 +313,16 @@ int ssl_get_new_session(SSL *s, int session)
                        SSL_SESSION_free(ss);
                        return(0);
                        }
+#ifndef OPENSSL_NO_TLSEXT
+               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
                {
index b248dab36171d8e01303149d8dfe5541720fbf6b..cea8b8e8518a0e01120505d6577679620cc2c499 100644 (file)
@@ -193,15 +193,11 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
        {
        int extdatalen=0;
        unsigned char *ret = p;
-       if (s->hit || s->servername_done == 2)
-               return p;
-       ret+=2;
-       if (s->servername_done == 1)  
-               s->servername_done = 2;
 
+       ret+=2;
        if (ret>=limit) return NULL; /* this really never occurs, but ... */
 
-       if (s->session->tlsext_hostname != NULL)
+       if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL)
                { 
                if (limit - p - 4 < 0) return NULL; 
 
@@ -222,6 +218,10 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
        unsigned short size;
        unsigned short len;
        unsigned char *data = *p;
+#if 0
+       fprintf(stderr,"ssl_parse_clienthello_tlsext %s\n",s->session->tlsext_hostname?s->session->tlsext_hostname:"NULL");
+#endif
+       s->servername_done = 0;
 
        if (data >= (d+n-2))
                return 1;
@@ -238,6 +238,29 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                if (data+size > (d+n))
                        return 1;
                
+/* 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 = data;
@@ -259,16 +282,29 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                case TLSEXT_NAMETYPE_host_name:
                                         if (s->session->tlsext_hostname == NULL)
                                                {
-                                               if (len > 255 || 
+                                               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'; 
+                                               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; 
+
+#if 0
+                                               fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_hostname %s\n",s->session->tlsext_hostname);
+#endif
+                                               }
+                                       else 
+                                               s->servername_done = strlen(s->session->tlsext_hostname) == len 
+                                                       && strncmp(s->session->tlsext_hostname,sdata, len) == 0;
+                                       
                                        break;
 
                                default:
@@ -356,14 +392,18 @@ int ssl_check_tlsext(SSL *s,int *al)
        int ret;
 
        *al = SSL_AD_UNRECOGNIZED_NAME;
-       if (s->servername_done == 0 && (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0))
+       if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
                {
                ret = s->ctx->tlsext_servername_callback(s, al, s->ctx->tlsext_servername_arg);
                if (ret <= 0)
                        return ret;
                }
-       if (s->servername_done == 1)    
-               s->servername_done = 2;
+       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);
+               if (ret <= 0)
+                       return ret;
+               }
        
        return 1;
        }
index 26a7ae52d65fa0361485f90d241d1b98afb58b46..8e563799636a29be4fb2e25514b0a2d412c6a70e 100644 (file)
@@ -170,10 +170,12 @@ extern "C" {
 
 #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_hostname(s,name) \
+#define SSL_set_tlsext_host_name(s,name) \
 SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name)
 
 #define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \