Add heartbeat extension bounds check.
[openssl.git] / ssl / t1_lib.c
index 4734c37e0a02d90665a8ccd21f786b1a85d34b2e..bddffd92cc045ae920d63e6e140c78b4d96c3425 100644 (file)
@@ -342,19 +342,11 @@ 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;
@@ -432,25 +424,29 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
         }
 
 #ifndef OPENSSL_NO_SRP
-#define MIN(x,y) (((x)<(y))?(x):(y))
-       /* we add SRP username the first time only if we have one! */
+       /* Add SRP username if there is 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; 
+               { /* Add TLS extension SRP username to the Client Hello message */
 
-               if ((lenmax = limit - ret - 5) < 0) return NULL; 
-               if (login_len > lenmax) return NULL;
-               if (login_len > 255)
+               int login_len = strlen(s->srp_ctx.login);       
+               if (login_len > 255 || login_len == 0)
                        {
                        SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
                        return NULL;
-                       }
+                       } 
+
+               /* check for enough space.
+                  4 for the srp type type and entension length
+                  1 for the srp user identity
+                  + srp user identity length 
+               */
+               if ((limit - ret - 5 - login_len) < 0) return NULL; 
+
+               /* fill in the extension */
                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++) = (unsigned char) login_len;
+               memcpy(ret, s->srp_ctx.login, login_len);
                ret+=login_len;
                }
 #endif
@@ -540,7 +536,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                }
                skip_ext:
 
-       if (TLS1_get_version(s) >= TLS1_2_VERSION)
+       if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
                {
                if ((size_t)(limit - ret) < sizeof(tls12_sigalgs) + 6)
                        return NULL; 
@@ -645,6 +641,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                }
 #endif
 
+#ifndef OPENSSL_NO_SRTP
         if(SSL_get_srtp_profiles(s))
                 {
                 int el;
@@ -663,6 +660,37 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
                        }
                 ret += el;
                 }
+#endif
+
+#ifdef TLSEXT_TYPE_padding
+       /* 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.
+        */
+       {
+       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;
+               }
+       }
+#endif
 
        if ((extdatalen = ret-p-2)== 0) 
                return p;
@@ -777,6 +805,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                }
 #endif
 
+#ifndef OPENSSL_NO_SRTP
         if(s->srtp_profile)
                 {
                 int el;
@@ -795,6 +824,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                        }
                 ret+=el;
                 }
+#endif
 
        if (((s->s3->tmp.new_cipher->id & 0xFFFF)==0x80 || (s->s3->tmp.new_cipher->id & 0xFFFF)==0x81) 
                && (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG))
@@ -825,6 +855,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
                        *(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
                else
                        *(ret++) = SSL_TLSEXT_HB_ENABLED;
+
                }
 #endif
 
@@ -857,6 +888,89 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
        return ret;
        }
 
+#ifndef OPENSSL_NO_EC
+/* ssl_check_for_safari attempts to fingerprint Safari using OS X
+ * SecureTransport using the TLS extension block in |d|, of length |n|.
+ * Safari, since 10.6, sends exactly these extensions, in this order:
+ *   SNI,
+ *   elliptic_curves
+ *   ec_point_formats
+ *
+ * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8,
+ * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them.
+ * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from
+ * 10.8..10.8.3 (which don't work).
+ */
+static void ssl_check_for_safari(SSL *s, const unsigned char *data, const unsigned char *d, int n) {
+       unsigned short type, size;
+       static const unsigned char kSafariExtensionsBlock[] = {
+               0x00, 0x0a,  /* elliptic_curves extension */
+               0x00, 0x08,  /* 8 bytes */
+               0x00, 0x06,  /* 6 bytes of curve ids */
+               0x00, 0x17,  /* P-256 */
+               0x00, 0x18,  /* P-384 */
+               0x00, 0x19,  /* P-521 */
+
+               0x00, 0x0b,  /* ec_point_formats */
+               0x00, 0x02,  /* 2 bytes */
+               0x01,        /* 1 point format */
+               0x00,        /* uncompressed */
+       };
+
+       /* The following is only present in TLS 1.2 */
+       static const unsigned char kSafariTLS12ExtensionsBlock[] = {
+               0x00, 0x0d,  /* signature_algorithms */
+               0x00, 0x0c,  /* 12 bytes */
+               0x00, 0x0a,  /* 10 bytes */
+               0x05, 0x01,  /* SHA-384/RSA */
+               0x04, 0x01,  /* SHA-256/RSA */
+               0x02, 0x01,  /* SHA-1/RSA */
+               0x04, 0x03,  /* SHA-256/ECDSA */
+               0x02, 0x03,  /* SHA-1/ECDSA */
+       };
+
+       if (data >= (d+n-2))
+               return;
+       data += 2;
+
+       if (data > (d+n-4))
+               return;
+       n2s(data,type);
+       n2s(data,size);
+
+       if (type != TLSEXT_TYPE_server_name)
+               return;
+
+       if (data+size > d+n)
+               return;
+       data += size;
+
+       if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
+               {
+               const size_t len1 = sizeof(kSafariExtensionsBlock);
+               const size_t len2 = sizeof(kSafariTLS12ExtensionsBlock);
+
+               if (data + len1 + len2 != d+n)
+                       return;
+               if (memcmp(data, kSafariExtensionsBlock, len1) != 0)
+                       return;
+               if (memcmp(data + len1, kSafariTLS12ExtensionsBlock, len2) != 0)
+                       return;
+               }
+       else
+               {
+               const size_t len = sizeof(kSafariExtensionsBlock);
+
+               if (data + len != d+n)
+                       return;
+               if (memcmp(data, kSafariExtensionsBlock, len) != 0)
+                       return;
+               }
+
+       s->s3->is_probably_safari = 1;
+}
+#endif /* !OPENSSL_NO_EC */
+
 int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
        {
        unsigned short type;
@@ -877,6 +991,11 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                               SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
 #endif
 
+#ifndef OPENSSL_NO_EC
+       if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
+               ssl_check_for_safari(s, data, d, n);
+#endif /* !OPENSSL_NO_EC */
+
        if (data >= (d+n-2))
                goto ri_check;
        n2s(data,len);
@@ -1006,13 +1125,25 @@ 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)
+                       if (size <= 0 || ((len = data[0])) != (size -1))
                                {
-                               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';  
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
+                               }
+                       if (s->srp_ctx.login != NULL)
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 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';
+  
+                       if (strlen(s->srp_ctx.login) != len) 
+                               {
+                               *al = SSL_AD_DECODE_ERROR;
+                               return 0;
                                }
                        }
 #endif
@@ -1060,7 +1191,8 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                        int ellipticcurvelist_length = (*(sdata++) << 8);
                        ellipticcurvelist_length += (*(sdata++));
 
-                       if (ellipticcurvelist_length != size - 2)
+                       if (ellipticcurvelist_length != size - 2 ||
+                               ellipticcurvelist_length < 1)
                                {
                                *al = TLS1_AD_DECODE_ERROR;
                                return 0;
@@ -1159,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) 
@@ -1282,6 +1414,8 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                                        s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
                                                        s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
                                                        break;
+                               default:        *al = SSL_AD_ILLEGAL_PARAMETER;
+                                                       return 0;
                                }
                        }
 #endif
@@ -1309,12 +1443,14 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
 #endif
 
                /* session ticket processed earlier */
+#ifndef OPENSSL_NO_SRTP
                else if (type == TLSEXT_TYPE_use_srtp)
-                        {
+                       {
                        if(ssl_parse_clienthello_use_srtp_ext(s, data, size,
                                                              al))
                                return 0;
-                        }
+                       }
+#endif
 
                data+=size;
                }
@@ -1414,7 +1550,8 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                        unsigned char *sdata = data;
                        int ecpointformatlist_length = *(sdata++);
 
-                       if (ecpointformatlist_length != size - 1)
+                       if (ecpointformatlist_length != size - 1 || 
+                               ecpointformatlist_length < 1)
                                {
                                *al = TLS1_AD_DECODE_ERROR;
                                return 0;
@@ -1508,7 +1645,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                        unsigned char selected_len;
 
                        /* We must have requested it. */
-                       if ((s->ctx->next_proto_select_cb == NULL))
+                       if (s->ctx->next_proto_select_cb == NULL)
                                {
                                *al = TLS1_AD_UNSUPPORTED_EXTENSION;
                                return 0;
@@ -1553,15 +1690,19 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
                                                        s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
                                                        s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
                                                        break;
+                               default:        *al = SSL_AD_ILLEGAL_PARAMETER;
+                                                       return 0;
                                }
                        }
 #endif
+#ifndef OPENSSL_NO_SRTP
                else if (type == TLSEXT_TYPE_use_srtp)
-                        {
+                       {
                         if(ssl_parse_serverhello_use_srtp_ext(s, data, size,
                                                              al))
                                 return 0;
-                        }
+                       }
+#endif
 
                data+=size;             
                }
@@ -1742,7 +1883,7 @@ int ssl_prepare_serverhello_tlsext(SSL *s)
        return 1;
        }
 
-int ssl_check_clienthello_tlsext(SSL *s)
+int ssl_check_clienthello_tlsext_early(SSL *s)
        {
        int ret=SSL_TLSEXT_ERR_NOACK;
        int al = SSL_AD_UNRECOGNIZED_NAME;
@@ -1761,42 +1902,12 @@ int ssl_check_clienthello_tlsext(SSL *s)
        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 status request then ask callback what to do.
-        * Note: this must be called after servername callbacks in case 
-        * the certificate has changed.
-        */
-       if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
-               {
-               int r;
-               r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
-               switch (r)
-                       {
-                       /* We don't want to send a status request response */
-                       case SSL_TLSEXT_ERR_NOACK:
-                               s->tlsext_status_expected = 0;
-                               break;
-                       /* status request response should be sent */
-                       case SSL_TLSEXT_ERR_OK:
-                               if (s->tlsext_ocsp_resp)
-                                       s->tlsext_status_expected = 1;
-                               else
-                                       s->tlsext_status_expected = 0;
-                               break;
-                       /* something bad happened */
-                       case SSL_TLSEXT_ERR_ALERT_FATAL:
-                               ret = SSL_TLSEXT_ERR_ALERT_FATAL;
-                               al = SSL_AD_INTERNAL_ERROR;
-                               goto err;
-                       }
-               }
-       else
-               s->tlsext_status_expected = 0;
-
 #ifdef TLSEXT_TYPE_opaque_prf_input
        {
                /* This sort of belongs into ssl_prepare_serverhello_tlsext(),
                 * but we might be sending an alert in response to the client hello,
-                * so this has to happen here in ssl_check_clienthello_tlsext(). */
+                * so this has to happen here in
+                * ssl_check_clienthello_tlsext_early(). */
 
                int r = 1;
        
@@ -1848,8 +1959,8 @@ int ssl_check_clienthello_tlsext(SSL *s)
                        }
        }
 
-#endif
  err:
+#endif
        switch (ret)
                {
                case SSL_TLSEXT_ERR_ALERT_FATAL:
@@ -1867,6 +1978,71 @@ int ssl_check_clienthello_tlsext(SSL *s)
                }
        }
 
+int ssl_check_clienthello_tlsext_late(SSL *s)
+       {
+       int ret = SSL_TLSEXT_ERR_OK;
+       int al;
+
+       /* If status request then ask callback what to do.
+        * Note: this must be called after servername callbacks in case 
+        * the certificate has changed, and must be called after the cipher
+        * has been chosen because this may influence which certificate is sent
+        */
+       if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
+               {
+               int r;
+               CERT_PKEY *certpkey;
+               certpkey = ssl_get_server_send_pkey(s);
+               /* If no certificate can't return certificate status */
+               if (certpkey == NULL)
+                       {
+                       s->tlsext_status_expected = 0;
+                       return 1;
+                       }
+               /* Set current certificate to one we will use so
+                * SSL_get_certificate et al can pick it up.
+                */
+               s->cert->key = certpkey;
+               r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+               switch (r)
+                       {
+                       /* We don't want to send a status request response */
+                       case SSL_TLSEXT_ERR_NOACK:
+                               s->tlsext_status_expected = 0;
+                               break;
+                       /* status request response should be sent */
+                       case SSL_TLSEXT_ERR_OK:
+                               if (s->tlsext_ocsp_resp)
+                                       s->tlsext_status_expected = 1;
+                               else
+                                       s->tlsext_status_expected = 0;
+                               break;
+                       /* something bad happened */
+                       case SSL_TLSEXT_ERR_ALERT_FATAL:
+                               ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+                               al = SSL_AD_INTERNAL_ERROR;
+                               goto err;
+                       }
+               }
+       else
+               s->tlsext_status_expected = 0;
+
+ err:
+       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; 
+
+               default:
+                       return 1;
+               }
+       }
+
 int ssl_check_serverhello_tlsext(SSL *s)
        {
        int ret=SSL_TLSEXT_ERR_NOACK;
@@ -2168,7 +2344,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
        HMAC_Update(&hctx, etick, eticklen);
        HMAC_Final(&hctx, tick_hmac, NULL);
        HMAC_CTX_cleanup(&hctx);
-       if (memcmp(tick_hmac, etick + eticklen, mlen))
+       if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen))
                return 2;
        /* Attempt to decrypt session data */
        /* Move p after IV to start of encrypted ticket, update length */
@@ -2240,7 +2416,7 @@ static tls12_lookup tls12_sig[] = {
 #ifndef OPENSSL_NO_RSA
        {EVP_PKEY_RSA, TLSEXT_signature_rsa},
 #endif
-#ifndef OPENSSL_NO_RSA
+#ifndef OPENSSL_NO_DSA
        {EVP_PKEY_DSA, TLSEXT_signature_dsa},
 #endif
 #ifndef OPENSSL_NO_ECDSA
@@ -2274,6 +2450,8 @@ static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen)
 int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, const EVP_MD *md)
        {
        int sig_id, md_id;
+       if (!md)
+               return 0;
        md_id = tls12_find_id(EVP_MD_type(md), tls12_md,
                                sizeof(tls12_md)/sizeof(tls12_lookup));
        if (md_id == -1)
@@ -2296,14 +2474,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();
@@ -2391,7 +2561,7 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
         */
 #ifndef OPENSSL_NO_DSA
        if (!c->pkeys[SSL_PKEY_DSA_SIGN].digest)
-               c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_dss1();
+               c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1();
 #endif
 #ifndef OPENSSL_NO_RSA
        if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest)
@@ -2402,7 +2572,7 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
 #endif
 #ifndef OPENSSL_NO_ECDSA
        if (!c->pkeys[SSL_PKEY_ECC].digest)
-               c->pkeys[SSL_PKEY_ECC].digest = EVP_ecdsa();
+               c->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
 #endif
        return 1;
        }
@@ -2418,16 +2588,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;
@@ -2444,7 +2618,10 @@ tls1_process_heartbeat(SSL *s)
                *bp++ = TLS1_HB_RESPONSE;
                s2n(payload, bp);
                memcpy(bp, pl, payload);
-               
+               bp += payload;
+               /* Random padding */
+               RAND_pseudo_bytes(bp, padding);
+
                r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
 
                if (r >= 0 && s->msg_callback)