Fix for SRTP Memory Leak
[openssl.git] / ssl / t1_lib.c
index f93216d4540299356b78271d70484708b50cca82..12ee3c9a104d9bd925c8530c080e4195e6e02d78 100644 (file)
@@ -342,33 +342,26 @@ static unsigned char tls12_sigalgs[] = {
 #ifndef OPENSSL_NO_SHA
        tlsext_sigalg(TLSEXT_hash_sha1)
 #endif
-#ifndef OPENSSL_NO_MD5
-       tlsext_sigalg_rsa(TLSEXT_hash_md5)
-#endif
 };
 
 int tls12_get_req_sig_algs(SSL *s, unsigned char *p)
        {
        size_t slen = sizeof(tls12_sigalgs);
-#ifdef OPENSSL_FIPS
-       /* If FIPS mode don't include MD5 which is last */
-       if (FIPS_mode())
-               slen -= 2;
-#endif
        if (p)
                memcpy(p, tls12_sigalgs, slen);
        return (int)slen;
        }
 
-unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
+unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, unsigned char *limit)
        {
        int extdatalen=0;
-       unsigned char *ret = p;
+       unsigned char *orig = buf;
+       unsigned char *ret = buf;
 
        /* don't add extensions for SSLv3 unless doing secure renegotiation */
        if (s->client_version == SSL3_VERSION
                                        && !s->s3->send_connection_binding)
-               return p;
+               return orig;
 
        ret+=2;
 
@@ -417,7 +410,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
               return NULL;
               }
 
-          if((limit - p - 4 - el) < 0) return NULL;
+          if((limit - ret - 4 - el) < 0) return NULL;
           
           s2n(TLSEXT_TYPE_renegotiate,ret);
           s2n(el,ret);
@@ -460,8 +453,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
 #endif
 
 #ifndef OPENSSL_NO_EC
-       if (s->tlsext_ecpointformatlist != NULL &&
-           s->version != DTLS1_VERSION)
+       if (s->tlsext_ecpointformatlist != NULL)
                {
                /* Add TLS extension ECPointFormats to the ClientHello message */
                long lenmax; 
@@ -480,8 +472,7 @@ 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 &&
-           s->version != DTLS1_VERSION)
+       if (s->tlsext_ellipticcurvelist != NULL)
                {
                /* Add TLS extension EllipticCurves to the ClientHello message */
                long lenmax; 
@@ -625,6 +616,8 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
 
 #ifndef OPENSSL_NO_HEARTBEATS
        /* Add Heartbeat extension */
+       if ((limit - ret - 4 - 1) < 0)
+               return NULL;
        s2n(TLSEXT_TYPE_heartbeat,ret);
        s2n(1,ret);
        /* Set mode:
@@ -650,13 +643,13 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
 #endif
 
 #ifndef OPENSSL_NO_SRTP
-        if(SSL_get_srtp_profiles(s))
+       if(SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s))
                 {
                 int el;
 
                 ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0);
                 
-                if((limit - p - 4 - el) < 0) return NULL;
+                if((limit - ret - 4 - el) < 0) return NULL;
 
                 s2n(TLSEXT_TYPE_use_srtp,ret);
                 s2n(el,ret);
@@ -669,25 +662,55 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                 ret += el;
                 }
 #endif
+       /* Add padding to workaround bugs in F5 terminators.
+        * See https://tools.ietf.org/html/draft-agl-tls-padding-03
+        *
+        * NB: because this code works out the length of all existing
+        * extensions it MUST always appear last.
+        */
+       if (s->options & SSL_OP_TLSEXT_PADDING)
+               {
+               int hlen = ret - (unsigned char *)s->init_buf->data;
+               /* The code in s23_clnt.c to build ClientHello messages
+                * includes the 5-byte record header in the buffer, while
+                * the code in s3_clnt.c does not.
+                */
+               if (s->state == SSL23_ST_CW_CLNT_HELLO_A)
+                       hlen -= 5;
+               if (hlen > 0xff && hlen < 0x200)
+                       {
+                       hlen = 0x200 - hlen;
+                       if (hlen >= 4)
+                               hlen -= 4;
+                       else
+                               hlen = 0;
+
+                       s2n(TLSEXT_TYPE_padding, ret);
+                       s2n(hlen, ret);
+                       memset(ret, 0, hlen);
+                       ret += hlen;
+                       }
+               }
 
-       if ((extdatalen = ret-p-2)== 0) 
-               return p;
+       if ((extdatalen = ret-orig-2)== 0) 
+               return orig;
 
-       s2n(extdatalen,p);
+       s2n(extdatalen, orig);
        return ret;
        }
 
-unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
+unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, unsigned char *limit)
        {
        int extdatalen=0;
-       unsigned char *ret = p;
+       unsigned char *orig = buf;
+       unsigned char *ret = buf;
 #ifndef OPENSSL_NO_NEXTPROTONEG
        int next_proto_neg_seen;
 #endif
 
        /* don't add extensions for SSLv3, unless doing secure renegotiation */
        if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
-               return p;
+               return orig;
        
        ret+=2;
        if (ret>=limit) return NULL; /* this really never occurs, but ... */
@@ -710,7 +733,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
               return NULL;
               }
 
-          if((limit - p - 4 - el) < 0) return NULL;
+          if((limit - ret - 4 - el) < 0) return NULL;
           
           s2n(TLSEXT_TYPE_renegotiate,ret);
           s2n(el,ret);
@@ -725,8 +748,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
         }
 
 #ifndef OPENSSL_NO_EC
-       if (s->tlsext_ecpointformatlist != NULL &&
-           s->version != DTLS1_VERSION)
+       if (s->tlsext_ecpointformatlist != NULL)
                {
                /* Add TLS extension ECPointFormats to the ServerHello message */
                long lenmax; 
@@ -784,13 +806,13 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
 #endif
 
 #ifndef OPENSSL_NO_SRTP
-        if(s->srtp_profile)
+       if(SSL_IS_DTLS(s) && s->srtp_profile)
                 {
                 int el;
 
                 ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0);
                 
-                if((limit - p - 4 - el) < 0) return NULL;
+                if((limit - ret - 4 - el) < 0) return NULL;
 
                 s2n(TLSEXT_TYPE_use_srtp,ret);
                 s2n(el,ret);
@@ -823,6 +845,8 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
        /* Add Heartbeat extension if we've received one */
        if (s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED)
                {
+               if ((limit - ret - 4 - 1) < 0)
+                       return NULL;
                s2n(TLSEXT_TYPE_heartbeat,ret);
                s2n(1,ret);
                /* Set mode:
@@ -859,10 +883,10 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                }
 #endif
 
-       if ((extdatalen = ret-p-2)== 0) 
-               return p;
+       if ((extdatalen = ret-orig-2)== 0) 
+               return orig;
 
-       s2n(extdatalen,p);
+       s2n(extdatalen, orig);
        return ret;
        }
 
@@ -1127,8 +1151,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 #endif
 
 #ifndef OPENSSL_NO_EC
-               else if (type == TLSEXT_TYPE_ec_point_formats &&
-                    s->version != DTLS1_VERSION)
+               else if (type == TLSEXT_TYPE_ec_point_formats)
                        {
                        unsigned char *sdata = data;
                        int ecpointformatlist_length = *(sdata++);
@@ -1162,8 +1185,7 @@ 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 &&
-                    s->version != DTLS1_VERSION)
+               else if (type == TLSEXT_TYPE_elliptic_curves)
                        {
                        unsigned char *sdata = data;
                        int ellipticcurvelist_length = (*(sdata++) << 8);
@@ -1269,7 +1291,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                }
                        }
                else if (type == TLSEXT_TYPE_status_request &&
-                        s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
+                        s->version != DTLS1_VERSION)
                        {
                
                        if (size < 5) 
@@ -1422,7 +1444,8 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 
                /* session ticket processed earlier */
 #ifndef OPENSSL_NO_SRTP
-               else if (type == TLSEXT_TYPE_use_srtp)
+               else if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)
+                        && type == TLSEXT_TYPE_use_srtp)
                        {
                        if(ssl_parse_clienthello_use_srtp_ext(s, data, size,
                                                              al))
@@ -1522,8 +1545,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                        }
 
 #ifndef OPENSSL_NO_EC
-               else if (type == TLSEXT_TYPE_ec_point_formats &&
-                    s->version != DTLS1_VERSION)
+               else if (type == TLSEXT_TYPE_ec_point_formats)
                        {
                        unsigned char *sdata = data;
                        int ecpointformatlist_length = *(sdata++);
@@ -1534,15 +1556,18 @@ int ssl_parse_serverhello_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;
+                               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)
+                                       {
+                                       *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_serverhello_tlsext s->session->tlsext_ecpointformatlist ");
                        sdata = s->session->tlsext_ecpointformatlist;
@@ -1674,7 +1699,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                        }
 #endif
 #ifndef OPENSSL_NO_SRTP
-               else if (type == TLSEXT_TYPE_use_srtp)
+               else if (SSL_IS_DTLS(s) && type == TLSEXT_TYPE_use_srtp)
                        {
                         if(ssl_parse_serverhello_use_srtp_ext(s, data, size,
                                                              al))
@@ -2336,7 +2361,11 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
                }
        EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen);
        if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0)
+               {
+               EVP_CIPHER_CTX_cleanup(&ctx);
+               OPENSSL_free(sdec);
                return 2;
+               }
        slen += mlen;
        EVP_CIPHER_CTX_cleanup(&ctx);
        p = sdec;
@@ -2452,14 +2481,6 @@ const EVP_MD *tls12_get_hash(unsigned char hash_alg)
        {
        switch(hash_alg)
                {
-#ifndef OPENSSL_NO_MD5
-               case TLSEXT_hash_md5:
-#ifdef OPENSSL_FIPS
-               if (FIPS_mode())
-                       return NULL;
-#endif
-               return EVP_md5();
-#endif
 #ifndef OPENSSL_NO_SHA
                case TLSEXT_hash_sha1:
                return EVP_sha1();
@@ -2574,16 +2595,20 @@ tls1_process_heartbeat(SSL *s)
        unsigned int payload;
        unsigned int padding = 16; /* Use minimum padding */
 
-       /* Read type and payload length first */
-       hbtype = *p++;
-       n2s(p, payload);
-       pl = p;
-
        if (s->msg_callback)
                s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
                        &s->s3->rrec.data[0], s->s3->rrec.length,
                        s, s->msg_callback_arg);
 
+       /* Read type and payload length first */
+       if (1 + 2 + 16 > s->s3->rrec.length)
+               return 0; /* silently discard */
+       hbtype = *p++;
+       n2s(p, payload);
+       if (1 + 2 + payload + 16 > s->s3->rrec.length)
+               return 0; /* silently discard per RFC 6520 sec. 4 */
+       pl = p;
+
        if (hbtype == TLS1_HB_REQUEST)
                {
                unsigned char *buffer, *bp;