fix Intel Mac configuration; patch supplied by JP Szikora <szikora@icp.ucl.ac.be>
[openssl.git] / ssl / s3_pkt.c
index 9ce82376e8cca19a379663fd4e9fd7e2b76cf092..d0f54e297bb7af5e53ff732363c5c6c85b530dd4 100644 (file)
 #include <stdio.h>
 #include <errno.h>
 #define USE_SOCKETS
+#include "ssl_locl.h"
 #include <openssl/evp.h>
 #include <openssl/buffer.h>
-#include "ssl_locl.h"
 
 static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
                         unsigned int len, int create_empty_fragment);
-static int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
-                             unsigned int len);
 static int ssl3_get_record(SSL *s);
-static int do_compress(SSL *ssl);
-static int do_uncompress(SSL *ssl);
-static int do_change_cipher_spec(SSL *ssl);
 
-/* used only by ssl3_get_record */
-static int ssl3_read_n(SSL *s, int n, int max, int extend)
+int ssl3_read_n(SSL *s, int n, int max, int extend)
        {
        /* If extend == 0, obtain new n-byte packet; if extend == 1, increase
         * packet by another n bytes.
@@ -147,6 +141,14 @@ static int ssl3_read_n(SSL *s, int n, int max, int extend)
                /* ... now we can act as if 'extend' was set */
                }
 
+       /* extend reads should not span multiple packets for DTLS */
+       if ( SSL_version(s) == DTLS1_VERSION &&
+               extend)
+               {
+               if ( s->s3->rbuf.left > 0 && n > s->s3->rbuf.left)
+                       n = s->s3->rbuf.left;
+               }
+
        /* if there is enough in the buffer from a previous read, take some */
        if (s->s3->rbuf.left >= (int)n)
                {
@@ -238,6 +240,8 @@ static int ssl3_get_record(SSL *s)
        unsigned int mac_size;
        int clear=0;
        size_t extra;
+       int decryption_failed_or_bad_record_mac = 0;
+       unsigned char *mac = NULL;
 
        rr= &(s->s3->rrec);
        sess=s->session;
@@ -353,8 +357,11 @@ again:
                        /* SSLerr() and ssl3_send_alert() have been called */
                        goto err;
 
-               /* otherwise enc_err == -1 */
-               goto decryption_failed_or_bad_record_mac;
+               /* Otherwise enc_err == -1, which indicates bad padding
+                * (rec->length has not been changed in this case).
+                * To minimize information leaked via timing, we will perform
+                * the MAC computation anyway. */
+               decryption_failed_or_bad_record_mac = 1;
                }
 
 #ifdef TLS_DEBUG
@@ -380,28 +387,46 @@ printf("\n");
                        SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG);
                        goto f_err;
 #else
-                       goto decryption_failed_or_bad_record_mac;
+                       decryption_failed_or_bad_record_mac = 1;
 #endif                 
                        }
                /* check the MAC for rr->input (it's in mac_size bytes at the tail) */
-               if (rr->length < mac_size)
+               if (rr->length >= mac_size)
+                       {
+                       rr->length -= mac_size;
+                       mac = &rr->data[rr->length];
+                       }
+               else
                        {
+                       /* record (minus padding) is too short to contain a MAC */
 #if 0 /* OK only for stream ciphers */
                        al=SSL_AD_DECODE_ERROR;
                        SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT);
                        goto f_err;
 #else
-                       goto decryption_failed_or_bad_record_mac;
+                       decryption_failed_or_bad_record_mac = 1;
+                       rr->length = 0;
 #endif
                        }
-               rr->length-=mac_size;
                i=s->method->ssl3_enc->mac(s,md,0);
-               if (memcmp(md,&(rr->data[rr->length]),mac_size) != 0)
+               if (mac == NULL || memcmp(md, mac, mac_size) != 0)
                        {
-                       goto decryption_failed_or_bad_record_mac;
+                       decryption_failed_or_bad_record_mac = 1;
                        }
                }
 
+       if (decryption_failed_or_bad_record_mac)
+               {
+               /* A separate 'decryption_failed' alert was introduced with TLS 1.0,
+                * SSL 3.0 only has 'bad_record_mac'.  But unless a decryption
+                * failure is directly visible from the ciphertext anyway,
+                * we should not reveal which kind of error occured -- this
+                * might become visible to an attacker (e.g. via a logfile) */
+               al=SSL_AD_BAD_RECORD_MAC;
+               SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+               goto f_err;
+               }
+
        /* r->length is now just compressed */
        if (s->expand != NULL)
                {
@@ -411,7 +436,7 @@ printf("\n");
                        SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG);
                        goto f_err;
                        }
-               if (!do_uncompress(s))
+               if (!ssl3_do_uncompress(s))
                        {
                        al=SSL_AD_DECOMPRESSION_FAILURE;
                        SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BAD_DECOMPRESSION);
@@ -443,22 +468,15 @@ printf("\n");
 
        return(1);
 
-decryption_failed_or_bad_record_mac:
-       /* Separate 'decryption_failed' alert was introduced with TLS 1.0,
-        * SSL 3.0 only has 'bad_record_mac'.  But unless a decryption
-        * failure is directly visible from the ciphertext anyway,
-        * we should not reveal which kind of error occured -- this
-        * might become visible to an attacker (e.g. via logfile) */
-       al=SSL_AD_BAD_RECORD_MAC;
-       SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
 f_err:
        ssl3_send_alert(s,SSL3_AL_FATAL,al);
 err:
        return(ret);
        }
 
-static int do_uncompress(SSL *ssl)
+int ssl3_do_uncompress(SSL *ssl)
        {
+#ifndef OPENSSL_NO_COMP
        int i;
        SSL3_RECORD *rr;
 
@@ -470,12 +488,13 @@ static int do_uncompress(SSL *ssl)
        else
                rr->length=i;
        rr->data=rr->comp;
-
+#endif
        return(1);
        }
 
-static int do_compress(SSL *ssl)
+int ssl3_do_compress(SSL *ssl)
        {
+#ifndef OPENSSL_NO_COMP
        int i;
        SSL3_RECORD *wr;
 
@@ -489,6 +508,7 @@ static int do_compress(SSL *ssl)
                wr->length=i;
 
        wr->input=wr->data;
+#endif
        return(1);
        }
 
@@ -565,7 +585,7 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
        /* If we have an alert to send, lets send it */
        if (s->s3->alert_dispatch)
                {
-               i=ssl3_dispatch_alert(s);
+               i=s->method->ssl_dispatch_alert(s);
                if (i <= 0)
                        return(i);
                /* if it went, fall through and send more stuff */
@@ -604,7 +624,7 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
                        if (prefix_len <= 0)
                                goto err;
 
-                       if (s->s3->wbuf.len < prefix_len + SSL3_RT_MAX_PACKET_SIZE)
+                       if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE)
                                {
                                /* insufficient space */
                                SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
@@ -640,7 +660,7 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
        /* first we compress */
        if (s->compress != NULL)
                {
-               if (!do_compress(s))
+               if (!ssl3_do_compress(s))
                        {
                        SSLerr(SSL_F_DO_SSL3_WRITE,SSL_R_COMPRESSION_FAILURE);
                        goto err;
@@ -701,8 +721,8 @@ err:
        }
 
 /* if s->s3->wbuf.left != 0, we need to call this */
-static int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
-                             unsigned int len)
+int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
+       unsigned int len)
        {
        int i;
 
@@ -847,7 +867,7 @@ start:
                {
                al=SSL_AD_UNEXPECTED_MESSAGE;
                SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
-               goto err;
+               goto f_err;
                }
 
        /* If the other end has shut down, throw anything we read away
@@ -954,7 +974,7 @@ start:
                        {
                        al=SSL_AD_DECODE_ERROR;
                        SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_BAD_HELLO_REQUEST);
-                       goto err;
+                       goto f_err;
                        }
 
                if (s->msg_callback)
@@ -1065,9 +1085,17 @@ start:
                if (    (rr->length != 1) || (rr->off != 0) ||
                        (rr->data[0] != SSL3_MT_CCS))
                        {
-                       i=SSL_AD_ILLEGAL_PARAMETER;
+                       al=SSL_AD_ILLEGAL_PARAMETER;
                        SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
-                       goto err;
+                       goto f_err;
+                       }
+
+               /* Check we have a cipher to change to */
+               if (s->s3->tmp.new_cipher == NULL)
+                       {
+                       al=SSL_AD_UNEXPECTED_MESSAGE;
+                       SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_CCS_RECEIVED_EARLY);
+                       goto f_err;
                        }
 
                rr->length=0;
@@ -1076,7 +1104,7 @@ start:
                        s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s, s->msg_callback_arg);
 
                s->s3->change_cipher_spec=1;
-               if (!do_change_cipher_spec(s))
+               if (!ssl3_do_change_cipher_spec(s))
                        goto err;
                else
                        goto start;
@@ -1188,7 +1216,7 @@ err:
        return(-1);
        }
 
-static int do_change_cipher_spec(SSL *s)
+int ssl3_do_change_cipher_spec(SSL *s)
        {
        int i;
        const char *sender;
@@ -1245,7 +1273,7 @@ void ssl3_send_alert(SSL *s, int level, int desc)
        s->s3->send_alert[0]=level;
        s->s3->send_alert[1]=desc;
        if (s->s3->wbuf.left == 0) /* data still being written out? */
-               ssl3_dispatch_alert(s);
+               s->method->ssl_dispatch_alert(s);
        /* else data is still being written out, we will get written
         * some time in the future */
        }