You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
87 lines
3.0 KiB
87 lines
3.0 KiB
From fc7804ec392fcf8051abe6bc9da9108744d2ae35 Mon Sep 17 00:00:00 2001 |
|
From: Matt Caswell <matt@openssl.org> |
|
Date: Fri, 6 Jun 2014 14:25:52 -0700 |
|
Subject: [PATCH] Fix DTLS handshake message size checks. |
|
MIME-Version: 1.0 |
|
Content-Type: text/plain; charset=UTF-8 |
|
Content-Transfer-Encoding: 8bit |
|
|
|
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> |
|
--- |
|
ssl/d1_both.c | 29 ++++++++++++++++------------- |
|
1 file changed, 16 insertions(+), 13 deletions(-) |
|
|
|
diff --git a/ssl/d1_both.c b/ssl/d1_both.c |
|
index 6559dfc..b9e15df 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; |
|
-- |
|
1.8.3.1 |
|
|
|
|