Remove extraneous white space, and add some braces
[openssl.git] / ssl / d1_both.c
index ee945cbd3a9d70dc71d9ac78ed92c01acb8324ab..a2a39baa60cdcaadbe5f85ecd3ca44641c6e8728 100644 (file)
@@ -156,9 +156,8 @@ static unsigned char bitmask_start_values[] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe
 static unsigned char bitmask_end_values[]   = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
 
 /* XDTLS:  figure out the right values */
-static unsigned int g_probable_mtu[] = {1500 - 28, 512 - 28, 256 - 28};
+static const unsigned int g_probable_mtu[] = {1500, 512, 256};
 
-static unsigned int dtls1_guess_mtu(unsigned int curr_mtu);
 static void dtls1_fix_message_header(SSL *s, unsigned long frag_off, 
        unsigned long frag_len);
 static unsigned char *dtls1_write_message_header(SSL *s,
@@ -211,82 +210,94 @@ dtls1_hm_fragment_new(unsigned long frag_len, int reassembly)
        return frag;
        }
 
-static void
-dtls1_hm_fragment_free(hm_fragment *frag)
+void dtls1_hm_fragment_free(hm_fragment *frag)
        {
+
+       if (frag->msg_header.is_ccs)
+               {
+               EVP_CIPHER_CTX_free(frag->msg_header.saved_retransmit_state.enc_write_ctx);
+               EVP_MD_CTX_destroy(frag->msg_header.saved_retransmit_state.write_hash);
+               }
        if (frag->fragment) OPENSSL_free(frag->fragment);
        if (frag->reassembly) OPENSSL_free(frag->reassembly);
        OPENSSL_free(frag);
        }
 
-/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
-int dtls1_do_write(SSL *s, int type)
-       {
-       int ret;
-       int curr_mtu;
-       unsigned int len, frag_off, mac_size, blocksize;
+static int dtls1_query_mtu(SSL *s)
+{
+       if(s->d1->link_mtu)
+               {
+               s->d1->mtu = s->d1->link_mtu-BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
+               s->d1->link_mtu = 0;
+               }
 
        /* AHA!  Figure out the MTU, and stick to the right size */
-       if (s->d1->mtu < dtls1_min_mtu() && !(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU))
+       if (s->d1->mtu < dtls1_min_mtu(s))
                {
-               s->d1->mtu = 
-                       BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
-
-               /* I've seen the kernel return bogus numbers when it doesn't know
-                * (initial write), so just make sure we have a reasonable number */
-               if (s->d1->mtu < dtls1_min_mtu())
+               if(!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU))
                        {
-                       s->d1->mtu = 0;
-                       s->d1->mtu = dtls1_guess_mtu(s->d1->mtu);
-                       BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU, 
-                               s->d1->mtu, NULL);
+                       s->d1->mtu =
+                               BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+
+                       /* I've seen the kernel return bogus numbers when it doesn't know
+                        * (initial write), so just make sure we have a reasonable number */
+                       if (s->d1->mtu < dtls1_min_mtu(s))
+                               {
+                               /* Set to min mtu */
+                               s->d1->mtu = dtls1_min_mtu(s);
+                               BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU,
+                                       s->d1->mtu, NULL);
+                               }
                        }
+               else
+                       return 0;
                }
-#if 0 
-       mtu = s->d1->mtu;
-
-       fprintf(stderr, "using MTU = %d\n", mtu);
-
-       mtu -= (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH);
-
-       curr_mtu = mtu - BIO_wpending(SSL_get_wbio(s));
+       return 1;
+}
 
-       if ( curr_mtu > 0)
-               mtu = curr_mtu;
-       else if ( ( ret = BIO_flush(SSL_get_wbio(s))) <= 0)
-               return ret;
+/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
+int dtls1_do_write(SSL *s, int type)
+       {
+       int ret;
+       unsigned int curr_mtu;
+       int retry = 1;
+       unsigned int len, frag_off, mac_size, blocksize, used_len;
 
-       if ( BIO_wpending(SSL_get_wbio(s)) + s->init_num >= mtu)
-               {
-               ret = BIO_flush(SSL_get_wbio(s));
-               if ( ret <= 0)
-                       return ret;
-               mtu = s->d1->mtu - (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH);
-               }
-#endif
+       if(!dtls1_query_mtu(s))
+               return -1;
 
-       OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu());  /* should have something reasonable now */
+       OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu(s));  /* should have something reasonable now */
 
        if ( s->init_off == 0  && type == SSL3_RT_HANDSHAKE)
                OPENSSL_assert(s->init_num == 
                        (int)s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH);
 
        if (s->write_hash)
-               mac_size = EVP_MD_CTX_size(s->write_hash);
+               {
+               if (s->enc_write_ctx && EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_GCM_MODE)
+                       mac_size = 0;
+               else
+                       mac_size = EVP_MD_CTX_size(s->write_hash);
+               }
        else
                mac_size = 0;
 
        if (s->enc_write_ctx && 
-               (EVP_CIPHER_mode( s->enc_write_ctx->cipher) & EVP_CIPH_CBC_MODE))
+               (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE))
                blocksize = 2 * EVP_CIPHER_block_size(s->enc_write_ctx->cipher);
        else
                blocksize = 0;
 
        frag_off = 0;
-       while( s->init_num)
+       /* s->init_num shouldn't ever be < 0...but just in case */
+       while(s->init_num > 0)
                {
-               curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) - 
-                       DTLS1_RT_HEADER_LENGTH - mac_size - blocksize;
+               used_len = BIO_wpending(SSL_get_wbio(s)) +  DTLS1_RT_HEADER_LENGTH
+                       + mac_size + blocksize;
+               if(s->d1->mtu > used_len)
+                       curr_mtu = s->d1->mtu - used_len;
+               else
+                       curr_mtu = 0;
 
                if ( curr_mtu <= DTLS1_HM_HEADER_LENGTH)
                        {
@@ -294,15 +305,27 @@ int dtls1_do_write(SSL *s, int type)
                        ret = BIO_flush(SSL_get_wbio(s));
                        if ( ret <= 0)
                                return ret;
-                       curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH -
-                               mac_size - blocksize;
+                       used_len = DTLS1_RT_HEADER_LENGTH + mac_size + blocksize;
+                       if(s->d1->mtu > used_len + DTLS1_HM_HEADER_LENGTH)
+                               {
+                               curr_mtu = s->d1->mtu - used_len;
+                               }
+                       else
+                               {
+                               /* Shouldn't happen */
+                               return -1;
+                               }
                        }
 
-               if ( s->init_num > curr_mtu)
+               /* We just checked that s->init_num > 0 so this cast should be safe */
+               if (((unsigned int)s->init_num) > curr_mtu)
                        len = curr_mtu;
                else
                        len = s->init_num;
 
+               /* Shouldn't ever happen */
+               if(len > INT_MAX)
+                       len = INT_MAX;
 
                /* XDTLS: this function is too long.  split out the CCS part */
                if ( type == SSL3_RT_HANDSHAKE)
@@ -313,18 +336,29 @@ int dtls1_do_write(SSL *s, int type)
                                s->init_off -= DTLS1_HM_HEADER_LENGTH;
                                s->init_num += DTLS1_HM_HEADER_LENGTH;
 
-                               if ( s->init_num > curr_mtu)
+                               /* We just checked that s->init_num > 0 so this cast should be safe */
+                               if (((unsigned int)s->init_num) > curr_mtu)
                                        len = curr_mtu;
                                else
                                        len = s->init_num;
                                }
 
+                       /* Shouldn't ever happen */
+                       if(len > INT_MAX)
+                               len = INT_MAX;
+
+                       if ( len < DTLS1_HM_HEADER_LENGTH )
+                               {
+                               /*
+                                * len is so small that we really can't do anything sensible
+                                * so fail
+                                */
+                               return -1;
+                               }
                        dtls1_fix_message_header(s, frag_off, 
                                len - DTLS1_HM_HEADER_LENGTH);
 
                        dtls1_write_message_header(s, (unsigned char *)&s->init_buf->data[s->init_off]);
-
-                       OPENSSL_assert(len >= DTLS1_HM_HEADER_LENGTH);
                        }
 
                ret=dtls1_write_bytes(s,type,&s->init_buf->data[s->init_off],
@@ -337,12 +371,23 @@ int dtls1_do_write(SSL *s, int type)
                         * is fine and wait for an alert to handle the
                         * retransmit 
                         */
-                       if ( BIO_ctrl(SSL_get_wbio(s),
+                       if ( retry && BIO_ctrl(SSL_get_wbio(s),
                                BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0 )
-                               s->d1->mtu = BIO_ctrl(SSL_get_wbio(s),
-                                       BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+                               {
+                               if(!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU))
+                                       {
+                                       if(!dtls1_query_mtu(s))
+                                               return -1;
+                                       /* Have one more go */
+                                       retry = 0;
+                                       }
+                               else
+                                       return -1;
+                               }
                        else
+                               {
                                return(-1);
+                               }
                        }
                else
                        {
@@ -581,29 +626,32 @@ dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
                return 0;
        }
 
+/* dtls1_max_handshake_message_len returns the maximum number of bytes
+ * permitted in a DTLS handshake message for |s|. The minimum is 16KB, but may
+ * be greater if the maximum certificate list size requires it. */
+static unsigned long dtls1_max_handshake_message_len(const SSL *s)
+       {
+       unsigned long max_len = DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
+       if (max_len < (unsigned long)s->max_cert_list)
+               return s->max_cert_list;
+       return max_len;
+       }
 
 static int
-dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
+dtls1_reassemble_fragment(SSL *s, const struct hm_header_st* msg_hdr, int *ok)
        {
        hm_fragment *frag = NULL;
        pitem *item = NULL;
        int i = -1, is_complete;
        unsigned char seq64be[8];
-       unsigned long frag_len = msg_hdr->frag_len, max_len;
+       unsigned long frag_len = msg_hdr->frag_len;
 
-       if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len)
+       if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len ||
+           msg_hdr->msg_len > dtls1_max_handshake_message_len(s))
                goto err;
 
-       /* Determine maximum allowed message size. Depends on (user set)
-        * maximum certificate length, but 16k is minimum.
-        */
-       if (DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH < s->max_cert_list)
-               max_len = s->max_cert_list;
-       else
-               max_len = DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
-
-       if ((msg_hdr->frag_off+frag_len) > max_len)
-               goto err;
+       if (frag_len == 0)
+               return DTLS1_HM_FRAGMENT_RETRY;
 
        /* Try to find item in queue */
        memset(seq64be,0,sizeof(seq64be));
@@ -621,10 +669,20 @@ dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
                frag->msg_header.frag_off = 0;
                }
        else
+               {
                frag = (hm_fragment*) item->data;
+               if (frag->msg_header.msg_len != msg_hdr->msg_len)
+                       {
+                       item = NULL;
+                       frag = NULL;
+                       goto err;
+                       }
+               }
+
 
        /* If message is already reassembled, this must be a
-        * retransmit and can be dropped.
+        * retransmit and can be dropped. In this case item != NULL and so frag
+        * does not need to be freed.
         */
        if (frag->reassembly == NULL)
                {
@@ -644,7 +702,9 @@ dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
        /* read the body of the fragment (header has already been read */
        i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
                frag->fragment + msg_hdr->frag_off,frag_len,0);
-       if (i<=0 || (unsigned long)i!=frag_len)
+       if ((unsigned long)i!=frag_len)
+               i=-1;
+       if (i<=0)
                goto err;
 
        RSMBLY_BITMASK_MARK(frag->reassembly, (long)msg_hdr->frag_off,
@@ -661,32 +721,32 @@ dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
 
        if (item == NULL)
                {
-               memset(seq64be,0,sizeof(seq64be));
-               seq64be[6] = (unsigned char)(msg_hdr->seq>>8);
-               seq64be[7] = (unsigned char)(msg_hdr->seq);
-
                item = pitem_new(seq64be, frag);
                if (item == NULL)
                        {
-                       goto err;
                        i = -1;
+                       goto err;
                        }
 
-               pqueue_insert(s->d1->buffered_messages, item);
+               item = pqueue_insert(s->d1->buffered_messages, item);
+               /* pqueue_insert fails iff a duplicate item is inserted.
+                * However, |item| cannot be a duplicate. If it were,
+                * |pqueue_find|, above, would have returned it and control
+                * would never have reached this branch. */
+               OPENSSL_assert(item != NULL);
                }
 
        return DTLS1_HM_FRAGMENT_RETRY;
 
 err:
-       if (frag != NULL) dtls1_hm_fragment_free(frag);
-       if (item != NULL) OPENSSL_free(item);
+       if (frag != NULL && item == NULL) dtls1_hm_fragment_free(frag);
        *ok = 0;
        return i;
        }
 
 
 static int
-dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
+dtls1_process_out_of_seq_message(SSL *s, const struct hm_header_st* msg_hdr, int *ok)
 {
        int i=-1;
        hm_fragment *frag = NULL;
@@ -706,7 +766,7 @@ dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
        /* If we already have an entry and this one is a fragment,
         * don't discard it and rather try to reassemble it.
         */
-       if (item != NULL && frag_len < msg_hdr->msg_len)
+       if (item != NULL && frag_len != msg_hdr->msg_len)
                item = NULL;
 
        /* Discard the message if sequence number was already there, is
@@ -731,9 +791,12 @@ dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
                }
        else
                {
-               if (frag_len && frag_len < msg_hdr->msg_len)
+               if (frag_len != msg_hdr->msg_len)
                        return dtls1_reassemble_fragment(s, msg_hdr, ok);
 
+               if (frag_len > dtls1_max_handshake_message_len(s))
+                       goto err;
+
                frag = dtls1_hm_fragment_new(frag_len, 0);
                if ( frag == NULL)
                        goto err;
@@ -745,26 +808,31 @@ dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
                        /* read the body of the fragment (header has already been read */
                        i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
                                frag->fragment,frag_len,0);
-                       if (i<=0 || (unsigned long)i!=frag_len)
+                       if ((unsigned long)i!=frag_len)
+                               i = -1;
+                       if (i<=0)
                                goto err;
                        }
 
-               memset(seq64be,0,sizeof(seq64be));
-               seq64be[6] = (unsigned char)(msg_hdr->seq>>8);
-               seq64be[7] = (unsigned char)(msg_hdr->seq);
-
                item = pitem_new(seq64be, frag);
                if ( item == NULL)
                        goto err;
 
-               pqueue_insert(s->d1->buffered_messages, item);
+               item = pqueue_insert(s->d1->buffered_messages, item);
+               /* pqueue_insert fails iff a duplicate item is inserted.
+                * However, |item| cannot be a duplicate. If it were,
+                * |pqueue_find|, above, would have returned it. Then, either
+                * |frag_len| != |msg_hdr->msg_len| in which case |item| is set
+                * to NULL and it will have been processed with
+                * |dtls1_reassemble_fragment|, above, or the record will have
+                * been discarded. */
+               OPENSSL_assert(item != NULL);
                }
 
        return DTLS1_HM_FRAGMENT_RETRY;
 
 err:
-       if ( frag != NULL) dtls1_hm_fragment_free(frag);
-       if ( item != NULL) OPENSSL_free(item);
+       if (frag != NULL && item == NULL) dtls1_hm_fragment_free(frag);
        *ok = 0;
        return i;
        }
@@ -778,6 +846,7 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok)
        int i,al;
        struct hm_header_st msg_hdr;
 
+       redo:
        /* see if we have the required fragment already */
        if ((frag_len = dtls1_retrieve_buffered_fragment(s,max,ok)) || *ok)
                {
@@ -836,8 +905,7 @@ dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok)
                                        s->msg_callback_arg);
                        
                        s->init_num = 0;
-                       return dtls1_get_message_fragment(s, st1, stn,
-                               max, ok);
+                       goto redo;
                        }
                else /* Incorrectly formated Hello request */
                        {
@@ -1031,13 +1099,15 @@ dtls1_buffer_message(SSL *s, int is_ccs)
        OPENSSL_assert(s->init_off == 0);
 
        frag = dtls1_hm_fragment_new(s->init_num, 0);
+       if (!frag)
+               return 0;
 
        memcpy(frag->fragment, s->init_buf->data, s->init_num);
 
        if ( is_ccs)
                {
                OPENSSL_assert(s->d1->w_msg_hdr.msg_len + 
-                              ((s->version==DTLS1_VERSION)?DTLS1_CCS_HEADER_LENGTH:3) == (unsigned int)s->init_num);
+                              DTLS1_CCS_HEADER_LENGTH == (unsigned int)s->init_num);
                }
        else
                {
@@ -1247,28 +1317,20 @@ dtls1_write_message_header(SSL *s, unsigned char *p)
        return p;
        }
 
-unsigned int 
-dtls1_min_mtu(void)
+unsigned int
+dtls1_link_min_mtu(void)
        {
        return (g_probable_mtu[(sizeof(g_probable_mtu) / 
                sizeof(g_probable_mtu[0])) - 1]);
        }
 
-static unsigned int 
-dtls1_guess_mtu(unsigned int curr_mtu)
+unsigned int
+dtls1_min_mtu(SSL *s)
        {
-       unsigned int i;
-
-       if ( curr_mtu == 0 )
-               return g_probable_mtu[0] ;
-
-       for ( i = 0; i < sizeof(g_probable_mtu)/sizeof(g_probable_mtu[0]); i++)
-               if ( curr_mtu > g_probable_mtu[i])
-                       return g_probable_mtu[i];
-
-       return curr_mtu;
+       return dtls1_link_min_mtu()-BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
        }
 
+
 void
 dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr)
        {
@@ -1319,26 +1381,39 @@ dtls1_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 */
+       if (s->s3->rrec.length > SSL3_RT_MAX_PLAIN_LENGTH)
+               return 0; /* silently discard per RFC 6520 sec. 4 */
+
+       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;
+               unsigned int write_length = 1 /* heartbeat type */ +
+                                           2 /* heartbeat length */ +
+                                           payload + padding;
                int r;
 
+               if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
+                       return 0;
+
                /* Allocate memory for the response, size is 1 byte
                 * message type, plus 2 bytes payload length, plus
                 * payload, plus padding
                 */
-               buffer = OPENSSL_malloc(1 + 2 + payload + padding);
+               buffer = OPENSSL_malloc(write_length);
                bp = buffer;
 
                /* Enter response type, length and copy payload */
@@ -1349,11 +1424,11 @@ dtls1_process_heartbeat(SSL *s)
                /* Random padding */
                RAND_pseudo_bytes(bp, padding);
 
-               r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
+               r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, write_length);
 
                if (r >= 0 && s->msg_callback)
                        s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
-                               buffer, 3 + payload + padding,
+                               buffer, write_length,
                                s, s->msg_callback_arg);
 
                OPENSSL_free(buffer);