If we're going to return errors (no matter how stupid), then we should
[openssl.git] / ssl / s3_pkt.c
index 6754e993c5c8d151bc3d8b19404ba1916fbd0ce5..e6c68b339b7b2736a8b49243277107e9876c4ee9 100644 (file)
@@ -129,16 +129,21 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
         * (If s->read_ahead is set, 'max' bytes may be stored in rbuf
         * [plus s->packet_length bytes if extend == 1].)
         */
-       int i,len,left,align=0;
+       int i,len,left;
+       long align=0;
        unsigned char *pkt;
        SSL3_BUFFER *rb;
 
        if (n <= 0) return n;
 
        rb    = &(s->s3->rbuf);
+       if (rb->buf == NULL)
+               if (!ssl3_setup_read_buffer(s))
+                       return -1;
+
        left  = rb->left;
 #if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
-       align = (int)rb->buf + SSL3_RT_HEADER_LENGTH;
+       align = (long)rb->buf + SSL3_RT_HEADER_LENGTH;
        align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
 #endif
 
@@ -233,6 +238,9 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
                if (i <= 0)
                        {
                        rb->left = left;
+                       if (s->mode & SSL_MODE_RELEASE_BUFFERS)
+                               if (len+left == 0)
+                                       ssl3_release_read_buffer(s);
                        return(i);
                        }
                left+=i;
@@ -399,12 +407,14 @@ printf("\n");
        /* r->length is now the compressed data plus mac */
        if (    (sess == NULL) ||
                (s->enc_read_ctx == NULL) ||
-               (s->read_hash == NULL))
+               (EVP_MD_CTX_md(s->read_hash) == NULL))
                clear=1;
 
        if (!clear)
                {
-               mac_size=EVP_MD_size(s->read_hash);
+               /* !clear => s->read_hash != NULL => mac_size != -1 */
+               mac_size=EVP_MD_CTX_size(s->read_hash);
+               OPENSSL_assert(mac_size >= 0);
 
                if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size)
                        {
@@ -435,7 +445,7 @@ printf("\n");
 #endif
                        }
                i=s->method->ssl3_enc->mac(s,md,0);
-               if (mac == NULL || memcmp(md, mac, mac_size) != 0)
+               if (i < 0 || mac == NULL || memcmp(md, mac, mac_size) != 0)
                        {
                        decryption_failed_or_bad_record_mac = 1;
                        }
@@ -602,11 +612,16 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
        {
        unsigned char *p,*plen;
        int i,mac_size,clear=0;
-       int prefix_len=0,align=0;
+       int prefix_len=0;
+       long align=0;
        SSL3_RECORD *wr;
        SSL3_BUFFER *wb=&(s->s3->wbuf);
        SSL_SESSION *sess;
 
+       if (wb->buf == NULL)
+               if (!ssl3_setup_write_buffer(s))
+                       return -1;
+
        /* first check if there is a SSL3_BUFFER still being written
         * out.  This will happen with non blocking IO */
        if (wb->left != 0)
@@ -629,13 +644,17 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
 
        if (    (sess == NULL) ||
                (s->enc_write_ctx == NULL) ||
-               (s->write_hash == NULL))
+               (EVP_MD_CTX_md(s->write_hash) == NULL))
                clear=1;
 
        if (clear)
                mac_size=0;
        else
-               mac_size=EVP_MD_size(s->write_hash);
+               {
+               mac_size=EVP_MD_CTX_size(s->write_hash);
+               if (mac_size < 0)
+                       goto err;
+               }
 
        /* 'create_empty_fragment' is true only when this function calls itself */
        if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done)
@@ -672,7 +691,7 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
                 * which would be multiple of SSL3_ALIGN_PAYLOAD, so
                 * if we want to align the real payload, then we can
                 * just pretent we simply have two headers. */
-               align = (int)wb->buf + 2*SSL3_RT_HEADER_LENGTH;
+               align = (long)wb->buf + 2*SSL3_RT_HEADER_LENGTH;
                align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
 #endif
                p = wb->buf + align;
@@ -685,7 +704,7 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
        else
                {
 #if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
-               align = (int)wb->buf + SSL3_RT_HEADER_LENGTH;
+               align = (long)wb->buf + SSL3_RT_HEADER_LENGTH;
                align = (-align)&(SSL3_ALIGN_PAYLOAD-1);
 #endif
                p = wb->buf + align;
@@ -733,7 +752,8 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
 
        if (mac_size != 0)
                {
-               s->method->ssl3_enc->mac(s,&(p[wr->length]),1);
+               if (s->method->ssl3_enc->mac(s,&(p[wr->length]),1) < 0)
+                       goto err;
                wr->length+=mac_size;
                wr->input=p;
                wr->data=p;
@@ -810,11 +830,20 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
                        {
                        wb->left=0;
                        wb->offset+=i;
+                       if (s->mode & SSL_MODE_RELEASE_BUFFERS)
+                               ssl3_release_write_buffer(s);
                        s->rwstate=SSL_NOTHING;
                        return(s->s3->wpend_ret);
                        }
-               else if (i <= 0)
+               else if (i <= 0) {
+                       if (s->version == DTLS1_VERSION) {
+                               /* For DTLS, just drop it. That's kind of the wh
+ole
+                                  point in using a datagram service */
+                               wb->left = 0;
+                       }
                        return(i);
+               }
                wb->offset+=i;
                wb->left-=i;
                }
@@ -855,7 +884,7 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
        void (*cb)(const SSL *ssl,int type2,int val)=NULL;
 
        if (s->s3->rbuf.buf == NULL) /* Not initialized yet */
-               if (!ssl3_setup_buffers(s))
+               if (!ssl3_setup_read_buffer(s))
                        return(-1);
 
        if ((type && (type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE) && type) ||
@@ -964,6 +993,8 @@ start:
                                {
                                s->rstate=SSL_ST_READ_HEADER;
                                rr->off=0;
+                               if (s->mode & SSL_MODE_RELEASE_BUFFERS)
+                                       ssl3_release_read_buffer(s);
                                }
                        }
                return(n);
@@ -1285,6 +1316,13 @@ int ssl3_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);
                }
@@ -1307,8 +1345,6 @@ int ssl3_do_change_cipher_spec(SSL *s)
                }
 
        s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s,
-               &(s->s3->finish_dgst1),
-               &(s->s3->finish_dgst2),
                sender,slen,s->s3->tmp.peer_finish_md);
 
        return(1);