Fix for TLS record tampering bug CVE-2013-4353
[openssl.git] / ssl / s3_both.c
index d757c4dd58e0cc1af2cc9951a64bfddcdcc05436..53b9390fdd3af30d0576825d0b0e19bc5d290ac6 100644 (file)
@@ -161,11 +161,30 @@ int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen)
 
                i=s->method->ssl3_enc->final_finish_mac(s,
                        sender,slen,s->s3->tmp.finish_md);
+               if (i == 0)
+                       return 0;
                s->s3->tmp.finish_md_len = i;
                memcpy(p, s->s3->tmp.finish_md, i);
                p+=i;
                l=i;
 
+                /* Copy the finished so we can use it for
+                   renegotiation checks */
+                if(s->type == SSL_ST_CONNECT)
+                        {
+                         OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+                         memcpy(s->s3->previous_client_finished, 
+                             s->s3->tmp.finish_md, i);
+                         s->s3->previous_client_finished_len=i;
+                        }
+                else
+                        {
+                        OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+                        memcpy(s->s3->previous_server_finished, 
+                            s->s3->tmp.finish_md, i);
+                        s->s3->previous_server_finished_len=i;
+                        }
+
 #ifdef OPENSSL_SYS_WIN16
                /* MSVC 1.5 does not clear the top bytes of the word unless
                 * I do this.
@@ -185,15 +204,44 @@ int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen)
        return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
        }
 
+#ifndef OPENSSL_NO_NEXTPROTONEG
+/* ssl3_take_mac calculates the Finished MAC for the handshakes messages seen to far. */
+static void ssl3_take_mac(SSL *s)
+       {
+       const char *sender;
+       int slen;
+       /* If no new cipher setup return immediately: other functions will
+        * set the appropriate error.
+        */
+       if (s->s3->tmp.new_cipher == NULL)
+               return;
+       if (s->state & SSL_ST_CONNECT)
+               {
+               sender=s->method->ssl3_enc->server_finished_label;
+               slen=s->method->ssl3_enc->server_finished_label_len;
+               }
+       else
+               {
+               sender=s->method->ssl3_enc->client_finished_label;
+               slen=s->method->ssl3_enc->client_finished_label_len;
+               }
+
+       s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s,
+               sender,slen,s->s3->tmp.peer_finish_md);
+       }
+#endif
+
 int ssl3_get_finished(SSL *s, int a, int b)
        {
        int al,i,ok;
        long n;
        unsigned char *p;
 
+#ifdef OPENSSL_NO_NEXTPROTONEG
        /* the mac has already been generated when we received the
-        * change cipher spec message and is in s->s3->tmp.peer_finish_md
+        * change cipher spec message and is in s->s3->tmp.peer_finish_md.
         */ 
+#endif
 
        n=s->method->ssl_get_message(s,
                a,
@@ -223,13 +271,30 @@ int ssl3_get_finished(SSL *s, int a, int b)
                goto f_err;
                }
 
-       if (memcmp(p, s->s3->tmp.peer_finish_md, i) != 0)
+       if (CRYPTO_memcmp(p, s->s3->tmp.peer_finish_md, i) != 0)
                {
                al=SSL_AD_DECRYPT_ERROR;
                SSLerr(SSL_F_SSL3_GET_FINISHED,SSL_R_DIGEST_CHECK_FAILED);
                goto f_err;
                }
 
+        /* Copy the finished so we can use it for
+           renegotiation checks */
+        if(s->type == SSL_ST_ACCEPT)
+                {
+                OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+                memcpy(s->s3->previous_client_finished, 
+                    s->s3->tmp.peer_finish_md, i);
+                s->s3->previous_client_finished_len=i;
+                }
+        else
+                {
+                OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+                memcpy(s->s3->previous_server_finished, 
+                    s->s3->tmp.peer_finish_md, i);
+                s->s3->previous_server_finished_len=i;
+                }
+
        return(1);
 f_err:
        ssl3_send_alert(s,SSL3_AL_FATAL,al);
@@ -318,6 +383,8 @@ unsigned long ssl3_output_cert_chain(SSL *s, X509 *x)
                                return(0);
                                }
                        X509_verify_cert(&xs_ctx);
+                       /* Don't leave errors in the queue */
+                       ERR_clear_error();
                        for (i=0; i < sk_X509_num(xs_ctx.chain); i++)
                                {
                                x = sk_X509_value(xs_ctx.chain, i);
@@ -478,6 +545,15 @@ long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
                s->init_num += i;
                n -= i;
                }
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+       /* If receiving Finished, record MAC of prior handshake messages for
+        * Finished verification. */
+       if (*s->init_buf->data == SSL3_MT_FINISHED)
+               ssl3_take_mac(s);
+#endif
+
+       /* Feed this message into MAC computation. */
        ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, s->init_num + 4);
        if (s->msg_callback)
                s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, (size_t)s->init_num + 4, s, s->msg_callback_arg);