PR: 1829
[oweals/openssl.git] / ssl / s3_pkt.c
index 3f88429e79a66ae5c189894332023b0b06b1c31a..9476dcddf6e958f6f3c566c3279f3f44bf74c4d7 100644 (file)
 
 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)
                {
@@ -275,11 +277,7 @@ again:
                n2s(p,rr->length);
 
                /* Lets check version */
-               if (s->first_packet)
-                       {
-                       s->first_packet=0;
-                       }
-               else
+               if (!s->first_packet)
                        {
                        if (version != s->version)
                                {
@@ -434,7 +432,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);
@@ -472,8 +470,9 @@ err:
        return(ret);
        }
 
-static int do_uncompress(SSL *ssl)
+int ssl3_do_uncompress(SSL *ssl)
        {
+#ifndef OPENSSL_NO_COMP
        int i;
        SSL3_RECORD *rr;
 
@@ -485,12 +484,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;
 
@@ -504,6 +504,7 @@ static int do_compress(SSL *ssl)
                wr->length=i;
 
        wr->input=wr->data;
+#endif
        return(1);
        }
 
@@ -580,7 +581,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 */
@@ -655,7 +656,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;
@@ -716,8 +717,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;
 
@@ -752,8 +753,15 @@ static int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
                        s->rwstate=SSL_NOTHING;
                        return(s->s3->wpend_ret);
                        }
-               else if (i <= 0)
+               else if (i <= 0) {
+                       if (s->version == DTLS1_VERSION ||
+                           s->version == DTLS1_BAD_VER) {
+                               /* For DTLS, just drop it. That's kind of the whole
+                                  point in using a datagram service */
+                               s->s3->wbuf.left = 0;
+                       }
                        return(i);
+               }
                s->s3->wbuf.offset+=i;
                s->s3->wbuf.left-=i;
                }
@@ -862,7 +870,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
@@ -969,7 +977,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)
@@ -1080,9 +1088,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;
@@ -1091,7 +1107,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;
@@ -1203,7 +1219,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;
@@ -1216,6 +1232,13 @@ static int do_change_cipher_spec(SSL *s)
 
        if (s->s3->tmp.key_block == NULL)
                {
+               if (s->session == NULL) 
+                       {
+                       /* might happen if dtls1_read_bytes() calls this */
+                       SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC,SSL_R_CCS_RECEIVED_EARLY);
+                       return (0);
+                       }
+
                s->session->cipher=s->s3->tmp.new_cipher;
                if (!s->method->ssl3_enc->setup_key_block(s)) return(0);
                }
@@ -1260,7 +1283,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 */
        }