diff options
author | Matt Caswell <matt@openssl.org> | 2014-06-06 14:25:52 -0700 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2014-08-06 20:36:40 +0100 |
commit | 1250f12613b61758675848f6600ebd914ccd7636 (patch) | |
tree | 619cd2a262f19308dcb353f796c25275c0ae5c46 /ssl/d1_both.c | |
parent | 11e7982a7cc6cbbcbb13046ceed37639c26a0bc1 (diff) |
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>
Diffstat (limited to 'ssl/d1_both.c')
-rw-r--r-- | ssl/d1_both.c | 29 |
1 files changed, 16 insertions, 13 deletions
diff --git a/ssl/d1_both.c b/ssl/d1_both.c index d98ae9392f..c5beea8824 100644 --- a/ssl/d1_both.c +++ b/ssl/d1_both.c @@ -592,6 +592,16 @@ 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) @@ -600,20 +610,10 @@ dtls1_reassemble_fragment(SSL *s, struct hm_header_st* msg_hdr, int *ok) pitem *item = NULL; int i = -1, is_complete; unsigned char seq64be[8]; - unsigned long frag_len = msg_hdr->frag_len, max_len; - - if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len) - 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; + unsigned long frag_len = msg_hdr->frag_len; - if ((msg_hdr->frag_off+frag_len) > max_len) + if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len || + msg_hdr->msg_len > dtls1_max_handshake_message_len(s)) goto err; /* Try to find item in queue */ @@ -754,6 +754,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) 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; |