summaryrefslogtreecommitdiffstats
path: root/ssl/d1_both.c
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2014-06-06 14:25:52 -0700
committerMatt Caswell <matt@openssl.org>2014-08-06 20:27:51 +0100
commitfc7804ec392fcf8051abe6bc9da9108744d2ae35 (patch)
treeeba3e0ca0d97c3e5187a5c0721ced4a1176b82f9 /ssl/d1_both.c
parente7b9d9be48cdc598a46c8e1536035ed29a9af254 (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.c29
1 files changed, 16 insertions, 13 deletions
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
index 6559dfcd01..b9e15dfb38 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -587,6 +587,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)
@@ -595,20 +605,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 */
@@ -749,6 +749,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;