Fix DTLS handshake message size checks.
In |dtls1_reassemble_fragment|, the value of |msg_hdr->frag_off+frag_len| was being checked against the maximum handshake message size, but then |msg_len| bytes were allocated for the fragment buffer. This means that so long as the fragment was within the allowed size, the pending handshake message could consume 16MB + 2MB (for the reassembly bitmap). Approx 10 outstanding handshake messages are allowed, meaning that an attacker could consume ~180MB per DTLS connection. In the non-fragmented path (in |dtls1_process_out_of_seq_message|), no check was applied. Fixes CVE-2014-3506 Wholly based on patch by Adam Langley with one minor amendment. Reviewed-by: Emilia Käsper <emilia@openssl.org> (Imported from upstream's 0598468fc04fb0cf2438c4ee635b587aac1bcce6) Change-Id: I4849498eabb45ec973fcb988d639b23145891e25 Reviewed-on: https://boringssl-review.googlesource.com/1434 Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
parent
3873f6f33d
commit
2306fe5ff5
@ -595,6 +595,16 @@ dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
|
|||||||
return 0;
|
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
|
static int
|
||||||
dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
|
dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
|
||||||
@ -603,20 +613,10 @@ dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok)
|
|||||||
pitem *item = NULL;
|
pitem *item = NULL;
|
||||||
int i = -1, is_complete;
|
int i = -1, is_complete;
|
||||||
unsigned char seq64be[8];
|
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 ||
|
||||||
goto err;
|
msg_hdr->msg_len > dtls1_max_handshake_message_len(s))
|
||||||
|
|
||||||
/* 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;
|
goto err;
|
||||||
|
|
||||||
/* Try to find item in queue */
|
/* Try to find item in queue */
|
||||||
@ -756,6 +756,9 @@ dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
|
|||||||
if (frag_len && frag_len < msg_hdr->msg_len)
|
if (frag_len && frag_len < msg_hdr->msg_len)
|
||||||
return dtls1_reassemble_fragment(s, msg_hdr, ok);
|
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);
|
frag = dtls1_hm_fragment_new(frag_len, 0);
|
||||||
if ( frag == NULL)
|
if ( frag == NULL)
|
||||||
goto err;
|
goto err;
|
||||||
|
Loading…
Reference in New Issue
Block a user