check length properly
[openssl.git] / ssl / t1_lib.c
index 330963ecabbbcd2838bc45898689934c53501f8f..69c0d42b1acd43d69c3d3a7b8a3bc8e3fc337a56 100644 (file)
@@ -164,22 +164,37 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
        ret+=2;
 
        if (ret>=limit) return NULL; /* this really never occurs, but ... */
-       if (s->servername_done == 0 && s->tlsext_hostname != NULL)
+       if (s->tlsext_hostname != NULL)
                { 
                /* Add TLS extension servername to the Client Hello message */
                unsigned long size_str;
                long lenmax; 
 
-               if ((lenmax = limit - p - 7) < 0) return NULL; 
-               if ((size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) return NULL;
+               /* 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);
                
-               s2n(TLSEXT_TYPE_server_name,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;
+
                }
 #ifndef OPENSSL_NO_EC
        if (s->tlsext_ecpointformatlist != NULL)
@@ -201,6 +216,25 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
                ret+=s->tlsext_ecpointformatlist_length;
                }
+       if (s->tlsext_ellipticcurvelist != NULL)
+               {
+               /* Add TLS extension EllipticCurves to the ClientHello message */
+               long lenmax; 
+
+               if ((lenmax = limit - p - 6) < 0) return NULL; 
+               if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL;
+               if (s->tlsext_ellipticcurvelist_length > 255)
+                       {
+                       SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+                       return NULL;
+                       }
+               
+               s2n(TLSEXT_TYPE_elliptic_curves,ret);
+               s2n(s->tlsext_ellipticcurvelist_length + 2, ret);
+               s2n(s->tlsext_ellipticcurvelist_length, ret);
+               memcpy(ret, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length);
+               ret+=s->tlsext_ellipticcurvelist_length;
+               }
 #endif /* OPENSSL_NO_EC */
 
        if ((extdatalen = ret-p-2)== 0) 
@@ -244,7 +278,9 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length;
                memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
                ret+=s->tlsext_ecpointformatlist_length;
+
                }
+       /* Currently the server should not respond with a SupportedCurves extension */
 #endif /* OPENSSL_NO_EC */
        
        if ((extdatalen = ret-p-2)== 0) 
@@ -260,9 +296,6 @@ 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))
@@ -305,20 +338,36 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 
                if (type == TLSEXT_TYPE_server_name)
                        {
-                       unsigned char *sdata = data;
+                       unsigned char *sdata;
                        int servname_type;
-                       int dsize = size-3 ;
-                        
-                       if (dsize > 0 )
+                       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++); 
+                               servname_type = *(sdata++); 
                                n2s(sdata,len);
-                               if (len != dsize) 
+                               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:
@@ -339,9 +388,6 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                                }
                                                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 
@@ -353,7 +399,14 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                        break;
                                        }
                                  
+                               dsize -= len;
+                               }
+                       if (dsize != 0) 
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
                                }
+
                        }
 
 #ifndef OPENSSL_NO_EC
@@ -384,9 +437,37 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                        fprintf(stderr,"\n");
 #endif
                        }
+               else if (type == TLSEXT_TYPE_elliptic_curves)
+                       {
+                       unsigned char *sdata = data;
+                       int ellipticcurvelist_length = (*(sdata++) << 8);
+                       ellipticcurvelist_length += (*(sdata++));
+
+                       if (ellipticcurvelist_length != size - 2)
+                               {
+                               *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)
+                               {
+                               *al = TLS1_AD_INTERNAL_ERROR;
+                               return 0;
+                               }
+                       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;
+                       for (i = 0; i < s->session->tlsext_ellipticcurvelist_length; i++)
+                               fprintf(stderr,"%i ",*(sdata++));
+                       fprintf(stderr,"\n");
+#endif
+                       }
+#endif /* OPENSSL_NO_EC */
                data+=size;             
                }
-#endif /* OPENSSL_NO_EC */
 
        *p = data;
        return 1;
@@ -400,9 +481,6 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
        unsigned char *data = *p;
 
        int tlsext_servername = 0;
-#ifndef OPENSSL_NO_EC
-       int tlsext_ecpointformats = 0;
-#endif /* OPENSSL_NO_EC */
 
        if (data >= (d+n-2))
                return 1;
@@ -455,10 +533,9 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                        fprintf(stderr,"\n");
 #endif
                        }
-
+#endif /* OPENSSL_NO_EC */
                data+=size;             
                }
-#endif /* OPENSSL_NO_EC */
 
        if (data != d+n)
                {
@@ -487,43 +564,117 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                        }
                }
 
+       *p = data;
+       return 1;
+}
+
 #ifndef OPENSSL_NO_EC
-       if (!s->hit && tlsext_ecpointformats == 1)
+static int nid_list[] =
+       {
+               NID_sect163k1, /* sect163k1 (1) */
+               NID_sect163r1, /* sect163r1 (2) */
+               NID_sect163r2, /* sect163r2 (3) */
+               NID_sect193r1, /* sect193r1 (4) */ 
+               NID_sect193r2, /* sect193r2 (5) */ 
+               NID_sect233k1, /* sect233k1 (6) */
+               NID_sect233r1, /* sect233r1 (7) */ 
+               NID_sect239k1, /* sect239k1 (8) */ 
+               NID_sect283k1, /* sect283k1 (9) */
+               NID_sect283r1, /* sect283r1 (10) */ 
+               NID_sect409k1, /* sect409k1 (11) */ 
+               NID_sect409r1, /* sect409r1 (12) */
+               NID_sect571k1, /* sect571k1 (13) */ 
+               NID_sect571r1, /* sect571r1 (14) */ 
+               NID_secp160k1, /* secp160k1 (15) */
+               NID_secp160r1, /* secp160r1 (16) */ 
+               NID_secp160r2, /* secp160r2 (17) */ 
+               NID_secp192k1, /* secp192k1 (18) */
+               NID_X9_62_prime192v1, /* secp192r1 (19) */ 
+               NID_secp224k1, /* secp224k1 (20) */ 
+               NID_secp224r1, /* secp224r1 (21) */
+               NID_secp256k1, /* secp256k1 (22) */ 
+               NID_X9_62_prime256v1, /* secp256r1 (23) */ 
+               NID_secp384r1, /* secp384r1 (24) */
+               NID_secp521r1  /* secp521r1 (25) */     
+       };
+       
+int tls1_ec_curve_id2nid(int curve_id)
+       {
+       /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
+       if ((curve_id < 1) || (curve_id > sizeof(nid_list)/sizeof(nid_list[0]))) return 0;
+       return nid_list[curve_id-1];
+       }
+
+int tls1_ec_nid2curve_id(int nid)
+       {
+       /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */
+       switch (nid)
                {
-               if (s->tlsext_ecpointformatlist)
-                       {
-                       if (s->session->tlsext_ecpointformatlist == NULL)
-                               {
-                               s->session->tlsext_ecpointformatlist_length = s->tlsext_ecpointformatlist_length;
-                               if (s->session->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->session->tlsext_ecpointformatlist);
-                               if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(s->tlsext_ecpointformatlist_length)) == NULL)
-                                       {
-                                       *al = TLS1_AD_INTERNAL_ERROR;
-                                       return 0;
-                                       }
-                               memcpy(s->session->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length);
-                               }
-                       else 
-                               {
-                               *al = SSL_AD_DECODE_ERROR;
-                               return 0;
-                               }
-                       }
+       case NID_sect163k1: /* sect163k1 (1) */
+               return 1;
+       case NID_sect163r1: /* sect163r1 (2) */
+               return 2;
+       case NID_sect163r2: /* sect163r2 (3) */
+               return 3;
+       case NID_sect193r1: /* sect193r1 (4) */ 
+               return 4;
+       case NID_sect193r2: /* sect193r2 (5) */ 
+               return 5;
+       case NID_sect233k1: /* sect233k1 (6) */
+               return 6;
+       case NID_sect233r1: /* sect233r1 (7) */ 
+               return 7;
+       case NID_sect239k1: /* sect239k1 (8) */ 
+               return 8;
+       case NID_sect283k1: /* sect283k1 (9) */
+               return 9;
+       case NID_sect283r1: /* sect283r1 (10) */ 
+               return 10;
+       case NID_sect409k1: /* sect409k1 (11) */ 
+               return 11;
+       case NID_sect409r1: /* sect409r1 (12) */
+               return 12;
+       case NID_sect571k1: /* sect571k1 (13) */ 
+               return 13;
+       case NID_sect571r1: /* sect571r1 (14) */ 
+               return 14;
+       case NID_secp160k1: /* secp160k1 (15) */
+               return 15;
+       case NID_secp160r1: /* secp160r1 (16) */ 
+               return 16;
+       case NID_secp160r2: /* secp160r2 (17) */ 
+               return 17;
+       case NID_secp192k1: /* secp192k1 (18) */
+               return 18;
+       case NID_X9_62_prime192v1: /* secp192r1 (19) */ 
+               return 19;
+       case NID_secp224k1: /* secp224k1 (20) */ 
+               return 20;
+       case NID_secp224r1: /* secp224r1 (21) */
+               return 21;
+       case NID_secp256k1: /* secp256k1 (22) */ 
+               return 22;
+       case NID_X9_62_prime256v1: /* secp256r1 (23) */ 
+               return 23;
+       case NID_secp384r1: /* secp384r1 (24) */
+               return 24;
+       case NID_secp521r1:  /* secp521r1 (25) */       
+               return 25;
+       default:
+               return 0;
                }
+       }
 #endif /* OPENSSL_NO_EC */
 
-       *p = data;
-       return 1;
-}
-
 int ssl_prepare_clienthello_tlsext(SSL *s)
        {
 #ifndef OPENSSL_NO_EC
-       /* If we are client and using an elliptic curve cryptography cipher suite, send the point formats we 
-        * support.
+       /* If we are client and using an elliptic curve cryptography cipher suite, send the point formats 
+        * and elliptic curves we support.
         */
        int using_ecc = 0;
        int i;
+       unsigned char *j;
        int algs;
        STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);
        for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++)
@@ -549,6 +700,18 @@ int ssl_prepare_clienthello_tlsext(SSL *s)
                s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed;
                s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime;
                s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2;
+
+               /* we support all named elliptic curves in draft-ietf-tls-ecc-12 */
+               if (s->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->tlsext_ellipticcurvelist);
+               s->tlsext_ellipticcurvelist_length = sizeof(nid_list)/sizeof(nid_list[0]) * 2;
+               if ((s->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL)
+                       {
+                       s->tlsext_ellipticcurvelist_length = 0;
+                       SSLerr(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+                       return -1;
+                       }
+               for (i = 1, j = s->tlsext_ellipticcurvelist; i <= sizeof(nid_list)/sizeof(nid_list[0]); i++)
+                       s2n(i,j);
                }
 #endif /* OPENSSL_NO_EC */
        return 1;
@@ -558,7 +721,8 @@ int ssl_prepare_serverhello_tlsext(SSL *s)
        {
 #ifndef OPENSSL_NO_EC
        /* If we are server and using an ECC cipher suite, send the point formats we support 
-        * if the client sent us an ECPointsFormat extension.
+        * if the client sent us an ECPointsFormat extension.  Note that the server is not
+        * supposed to send an EllipticCurves extension.
         */
        int algs = s->s3->tmp.new_cipher->algorithms;
        int using_ecc = (algs & SSL_kECDH) || (algs & SSL_kECDHE) || (algs & SSL_aECDSA);
@@ -587,10 +751,11 @@ int ssl_check_clienthello_tlsext(SSL *s)
        int al = SSL_AD_UNRECOGNIZED_NAME;
 
 #ifndef OPENSSL_NO_EC
-       /* If we are server and using an elliptic curve cyrptography cipher suite, then we don't
-        * need to check EC point formats since all clients must support uncompressed and it's the
-        * only thing we support; we just need to copy the data in.  We probably ought to check it
-        * for validity, but we never use it.
+       /* The handling of the ECPointFormats extension is done elsewhere, namely in 
+        * ssl3_choose_cipher in s3_lib.c.
+        */
+       /* The handling of the EllipticCurves extension is done elsewhere, namely in 
+        * ssl3_choose_cipher in s3_lib.c.
         */
 #endif
 
@@ -629,10 +794,10 @@ int ssl_check_serverhello_tlsext(SSL *s)
            ((algs & SSL_kECDH) || (algs & SSL_kECDHE) || (algs & SSL_aECDSA))) 
                {
                /* we are using an ECC cipher */
-               int i;
+               size_t i;
                unsigned char *list;
                int found_uncompressed = 0;
-               if ((s->session->tlsext_ecpointformatlist == NULL) || (s->session->tlsext_ecpointformatlist_length <= 0))
+               if ((s->session->tlsext_ecpointformatlist == NULL) || (s->session->tlsext_ecpointformatlist_length == 0))
                        {
                        SSLerr(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
                        return -1;
@@ -676,3 +841,4 @@ int ssl_check_serverhello_tlsext(SSL *s)
        }
 }
 #endif
+