Add SRP.
[openssl.git] / ssl / t1_lib.c
index 4eb6d13840afa45247e1d4e24decaec9ba8761ee..ed6518166cfacdde6bbf86ea0b3f911ef777d60a 100644 (file)
@@ -166,7 +166,7 @@ void tls1_free(SSL *s)
 void tls1_clear(SSL *s)
        {
        ssl3_clear(s);
-       s->version=TLS1_VERSION;
+       s->version = s->method->version;
        }
 
 #ifndef OPENSSL_NO_EC
@@ -316,8 +316,9 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                ret+=size_str;
                }
 
-        /* Add the renegotiation option: TODOEKR switch */
-        {
+        /* Add RI if renegotiating */
+        if (s->renegotiate)
+          {
           int el;
           
           if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0))
@@ -340,6 +341,30 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
           ret += el;
         }
 
+#ifndef OPENSSL_NO_SRP
+#define MIN(x,y) (((x)<(y))?(x):(y))
+       /* we add SRP username the first time only if we have one! */
+       if (s->srp_ctx.login != NULL)
+               {/* Add TLS extension SRP username to the Client Hello message */
+               int login_len = MIN(strlen(s->srp_ctx.login) + 1, 255);
+               long lenmax; 
+
+               if ((lenmax = limit - ret - 5) < 0) return NULL; 
+               if (login_len > lenmax) return NULL;
+               if (login_len > 255)
+                       {
+                       SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                       return NULL;
+                       }
+               s2n(TLSEXT_TYPE_srp,ret);
+               s2n(login_len+1,ret);
+
+               (*ret++) = (unsigned char) MIN(strlen(s->srp_ctx.login), 254);
+               memcpy(ret, s->srp_ctx.login, MIN(strlen(s->srp_ctx.login), 254));
+               ret+=login_len;
+               }
+#endif
+
 #ifndef OPENSSL_NO_EC
        if (s->tlsext_ecpointformatlist != NULL &&
            s->version != DTLS1_VERSION)
@@ -713,14 +738,23 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                switch (servname_type)
                                        {
                                case TLSEXT_NAMETYPE_host_name:
-                                       if (s->session->tlsext_hostname == NULL)
+                                       if (!s->hit)
                                                {
-                                               if (len > TLSEXT_MAXLEN_host_name || 
-                                                       ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL))
+                                               if(s->session->tlsext_hostname)
+                                                       {
+                                                       *al = SSL_AD_DECODE_ERROR;
+                                                       return 0;
+                                                       }
+                                               if (len > TLSEXT_MAXLEN_host_name)
                                                        {
                                                        *al = TLS1_AD_UNRECOGNIZED_NAME;
                                                        return 0;
                                                        }
+                                               if ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL)
+                                                       {
+                                                       *al = TLS1_AD_INTERNAL_ERROR;
+                                                       return 0;
+                                                       }
                                                memcpy(s->session->tlsext_hostname, sdata, len);
                                                s->session->tlsext_hostname[len]='\0';
                                                if (strlen(s->session->tlsext_hostname) != len) {
@@ -733,7 +767,8 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 
                                                }
                                        else 
-                                               s->servername_done = strlen(s->session->tlsext_hostname) == len 
+                                               s->servername_done = s->session->tlsext_hostname
+                                                       && strlen(s->session->tlsext_hostname) == len 
                                                        && strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0;
                                        
                                        break;
@@ -751,6 +786,19 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                }
 
                        }
+#ifndef OPENSSL_NO_SRP
+               else if (type == TLSEXT_TYPE_srp)
+                       {
+                       if (size > 0)
+                               {
+                               len = data[0];
+                               if ((s->srp_ctx.login = OPENSSL_malloc(len+1)) == NULL)
+                                       return -1;
+                               memcpy(s->srp_ctx.login, &data[1], len);
+                               s->srp_ctx.login[len]='\0';  
+                               }
+                       }
+#endif
 
 #ifndef OPENSSL_NO_EC
                else if (type == TLSEXT_TYPE_ec_point_formats &&
@@ -764,15 +812,22 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                *al = TLS1_AD_DECODE_ERROR;
                                return 0;
                                }
-                       s->session->tlsext_ecpointformatlist_length = 0;
-                       if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist);
-                       if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+                       if (!s->hit)
                                {
-                               *al = TLS1_AD_INTERNAL_ERROR;
-                               return 0;
+                               if(s->session->tlsext_ecpointformatlist)
+                                       {
+                                       OPENSSL_free(s->session->tlsext_ecpointformatlist);
+                                       s->session->tlsext_ecpointformatlist = NULL;
+                                       }
+                               s->session->tlsext_ecpointformatlist_length = 0;
+                               if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
+                                       {
+                                       *al = TLS1_AD_INTERNAL_ERROR;
+                                       return 0;
+                                       }
+                               s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
+                               memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
                                }
-                       s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
-                       memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
 #if 0
                        fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ecpointformatlist (length=%i) ", s->session->tlsext_ecpointformatlist_length);
                        sdata = s->session->tlsext_ecpointformatlist;
@@ -793,15 +848,22 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                *al = TLS1_AD_DECODE_ERROR;
                                return 0;
                                }
-                       s->session->tlsext_ellipticcurvelist_length = 0;
-                       if (s->session->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->session->tlsext_ellipticcurvelist);
-                       if ((s->session->tlsext_ellipticcurvelist = OPENSSL_malloc(ellipticcurvelist_length)) == NULL)
+                       if (!s->hit)
                                {
-                               *al = TLS1_AD_INTERNAL_ERROR;
-                               return 0;
+                               if(s->session->tlsext_ellipticcurvelist)
+                                       {
+                                       *al = TLS1_AD_DECODE_ERROR;
+                                       return 0;
+                                       }
+                               s->session->tlsext_ellipticcurvelist_length = 0;
+                               if ((s->session->tlsext_ellipticcurvelist = OPENSSL_malloc(ellipticcurvelist_length)) == NULL)
+                                       {
+                                       *al = TLS1_AD_INTERNAL_ERROR;
+                                       return 0;
+                                       }
+                               s->session->tlsext_ellipticcurvelist_length = ellipticcurvelist_length;
+                               memcpy(s->session->tlsext_ellipticcurvelist, sdata, ellipticcurvelist_length);
                                }
-                       s->session->tlsext_ellipticcurvelist_length = ellipticcurvelist_length;
-                       memcpy(s->session->tlsext_ellipticcurvelist, sdata, ellipticcurvelist_length);
 #if 0
                        fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ellipticcurvelist (length=%i) ", s->session->tlsext_ellipticcurvelist_length);
                        sdata = s->session->tlsext_ellipticcurvelist;
@@ -892,6 +954,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                                }
                                        n2s(data, idsize);
                                        dsize -= 2 + idsize;
+                                       size -= 2 + idsize;
                                        if (dsize < 0)
                                                {
                                                *al = SSL_AD_DECODE_ERROR;
@@ -930,9 +993,14 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                        }
 
                                /* Read in request_extensions */
+                               if (size < 2)
+                                       {
+                                       *al = SSL_AD_DECODE_ERROR;
+                                       return 0;
+                                       }
                                n2s(data,dsize);
                                size -= 2;
-                               if (dsize > size) 
+                               if (dsize != size)
                                        {
                                        *al = SSL_AD_DECODE_ERROR;
                                        return 0;
@@ -968,7 +1036,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 
        /* Need RI if renegotiating */
 
-       if (!renegotiate_seen && s->new_session &&
+       if (!renegotiate_seen && s->renegotiate &&
                !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
                {
                *al = SSL_AD_HANDSHAKE_FAILURE;
@@ -982,9 +1050,9 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 
 int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
        {
+       unsigned short length;
        unsigned short type;
        unsigned short size;
-       unsigned short len;  
        unsigned char *data = *p;
        int tlsext_servername = 0;
        int renegotiate_seen = 0;
@@ -992,7 +1060,12 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
        if (data >= (d+n-2))
                goto ri_check;
 
-       n2s(data,len);
+       n2s(data,length);
+       if (data+length != d+n)
+               {
+               *al = SSL_AD_DECODE_ERROR;
+               return 0;
+               }
 
        while(data <= (d+n-4))
                {
@@ -1156,8 +1229,8 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
         * which doesn't support RI so for the immediate future tolerate RI
         * absence on initial connect only.
         */
-       if (!renegotiate_seen && 
-               (s->new_session || !(s->options & SSL_OP_LEGACY_SERVER_CONNECT))
+       if (!renegotiate_seen
+               && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT)
                && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
                {
                *al = SSL_AD_HANDSHAKE_FAILURE;
@@ -1194,7 +1267,7 @@ int ssl_prepare_clienthello_tlsext(SSL *s)
                        break;
                        }
                }
-       using_ecc = using_ecc && (s->version == TLS1_VERSION);
+       using_ecc = using_ecc && (s->version >= TLS1_VERSION);
        if (using_ecc)
                {
                if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist);
@@ -1422,23 +1495,20 @@ int ssl_check_serverhello_tlsext(SSL *s)
        int al = SSL_AD_UNRECOGNIZED_NAME;
 
 #ifndef OPENSSL_NO_EC
-       /* If we are client and using an elliptic curve cryptography cipher suite, then server
-        * must return a an EC point formats lists containing uncompressed.
+       /* If we are client and using an elliptic curve cryptography cipher
+        * suite, then if server returns an EC point formats lists extension
+        * it must contain uncompressed.
         */
        unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
        unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
        if ((s->tlsext_ecpointformatlist != NULL) && (s->tlsext_ecpointformatlist_length > 0) && 
+           (s->session->tlsext_ecpointformatlist != NULL) && (s->session->tlsext_ecpointformatlist_length > 0) && 
            ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA)))
                {
                /* we are using an ECC cipher */
                size_t i;
                unsigned char *list;
                int found_uncompressed = 0;
-               if ((s->session->tlsext_ecpointformatlist == NULL) || (s->session->tlsext_ecpointformatlist_length == 0))
-                       {
-                       SSLerr(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
-                       return -1;
-                       }
                list = s->session->tlsext_ecpointformatlist;
                for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
                        {