Commit 34653202 authored by Natanael Copa's avatar Natanael Copa

main/openssl: backport various secfixes

fixes #6176

- CVE-2016-2179
- CVE-2016-2181
- CVE-2016-2182
- CVE-2016-6302
- CVE-2016-6303
parent ce7b0119
# Maintainer: Timo Teras <timo.teras@iki.fi> # Maintainer: Timo Teras <timo.teras@iki.fi>
pkgname=openssl pkgname=openssl
pkgver=1.0.2h pkgver=1.0.2h
pkgrel=2 pkgrel=3
pkgdesc="Toolkit for SSL v2/v3 and TLS v1" pkgdesc="Toolkit for SSL v2/v3 and TLS v1"
url="http://openssl.org" url="http://openssl.org"
depends= depends=
...@@ -29,9 +29,33 @@ source="http://www.openssl.org/source/${pkgname}-${pkgver}.tar.gz ...@@ -29,9 +29,33 @@ source="http://www.openssl.org/source/${pkgname}-${pkgver}.tar.gz
1003-engines-e_padlock-implement-sha1-sha224-sha256-accel.patch 1003-engines-e_padlock-implement-sha1-sha224-sha256-accel.patch
CVE-2016-2177.patch CVE-2016-2177.patch
CVE-2016-2178.patch CVE-2016-2178.patch
CVE-2016-2179.patch
CVE-2016-2180.patch CVE-2016-2180.patch
CVE-2016-2181.patch
CVE-2016-2182.patch
CVE-2016-6302.patch
CVE-2016-6303.patch
" "
# secfixes:
# 1.0.2h-r0:
# - CVE-2016-2107
# - CVE-2016-2105
# - CVE-2016-2106
# - CVE-2016-2109
# - CVE-2016-2176
# 1.0.2h-r1:
# - CVE-2016-2177
# - CVE-2016-2178
# 1.0.2h-r2:
# - CVE-2016-2180
# 1.0.2h-r3:
# - CVE-2016-2179
# - CVE-2016-2181
# - CVE-2016-2182
# - CVE-2016-6302
# - CVE-2016-6303
_builddir="$srcdir"/$pkgname-$pkgver _builddir="$srcdir"/$pkgname-$pkgver
prepare() { prepare() {
...@@ -132,7 +156,12 @@ aa16c89b283faf0fe546e3f897279c44 1002-backport-changes-from-upstream-padlock-mo ...@@ -132,7 +156,12 @@ aa16c89b283faf0fe546e3f897279c44 1002-backport-changes-from-upstream-padlock-mo
57cca845e22c178c3b317010be56edf0 1003-engines-e_padlock-implement-sha1-sha224-sha256-accel.patch 57cca845e22c178c3b317010be56edf0 1003-engines-e_padlock-implement-sha1-sha224-sha256-accel.patch
1accc0880b6e95726ea9f668808cd8ba CVE-2016-2177.patch 1accc0880b6e95726ea9f668808cd8ba CVE-2016-2177.patch
5c8e962b3d7e0082c1af432f6d0ad221 CVE-2016-2178.patch 5c8e962b3d7e0082c1af432f6d0ad221 CVE-2016-2178.patch
6d2276c87a17ae8615b47a1dea306d41 CVE-2016-2180.patch" c00ded9884ee5dbe557e1ee4216bd99a CVE-2016-2179.patch
6d2276c87a17ae8615b47a1dea306d41 CVE-2016-2180.patch
8e287127e8a3f277d0722108051494de CVE-2016-2181.patch
43c75a464bb6c0110717decb76220778 CVE-2016-2182.patch
70159524406c4dc59e1c278d556696e8 CVE-2016-6302.patch
96af7035339f01cebfc26118a6f12795 CVE-2016-6303.patch"
sha256sums="1d4007e53aad94a5b2002fe045ee7bb0b3d98f1a47f8b2bc851dcd1c74332919 openssl-1.0.2h.tar.gz sha256sums="1d4007e53aad94a5b2002fe045ee7bb0b3d98f1a47f8b2bc851dcd1c74332919 openssl-1.0.2h.tar.gz
b449fb998b5f60a3a1779ac2f432b2c7f08ae52fc6dfa98bca37d735f863d400 0002-busybox-basename.patch b449fb998b5f60a3a1779ac2f432b2c7f08ae52fc6dfa98bca37d735f863d400 0002-busybox-basename.patch
c3e6a9710726dac72e3eeffd78961d3bae67a480f6bde7890e066547da25cdfd 0003-use-termios.patch c3e6a9710726dac72e3eeffd78961d3bae67a480f6bde7890e066547da25cdfd 0003-use-termios.patch
...@@ -148,7 +177,12 @@ aee88a24622ce9d71e38deeb874e58435dcf8ff5690f56194f0e4a00fb09b260 1002-backport- ...@@ -148,7 +177,12 @@ aee88a24622ce9d71e38deeb874e58435dcf8ff5690f56194f0e4a00fb09b260 1002-backport-
c10b8aaf56a4f4f79ca195fc587e0bb533f643e777d7a3e6fb0350399a6060ea 1003-engines-e_padlock-implement-sha1-sha224-sha256-accel.patch c10b8aaf56a4f4f79ca195fc587e0bb533f643e777d7a3e6fb0350399a6060ea 1003-engines-e_padlock-implement-sha1-sha224-sha256-accel.patch
e321860623758c8a98b15dfa0b4671244e2cff34b5c62a489c43437d1053ed06 CVE-2016-2177.patch e321860623758c8a98b15dfa0b4671244e2cff34b5c62a489c43437d1053ed06 CVE-2016-2177.patch
7abe837d39953d0c0f694013a54f444e6f9ca0db8b98ca8aaf1d58683086784e CVE-2016-2178.patch 7abe837d39953d0c0f694013a54f444e6f9ca0db8b98ca8aaf1d58683086784e CVE-2016-2178.patch
fa906541a97bf0dbb1faa600055e28a1515b073f8c2b607edbcbbb53bdd97c99 CVE-2016-2180.patch" 707bd694d828178ed6b5855a06ad70052f4c113c26f5ac2cb92133a82c0109e7 CVE-2016-2179.patch
fa906541a97bf0dbb1faa600055e28a1515b073f8c2b607edbcbbb53bdd97c99 CVE-2016-2180.patch
05de3d799c631f97b68a6cc33c85fd7015a36fa77a509c2bf0387629cd91a456 CVE-2016-2181.patch
9bf8bf766cd6784ca50fcd99f45ebf2c57e8a821fa05644ce3b70e673f83ed53 CVE-2016-2182.patch
5751fb95b74a4a6b6091ad034a4e5919ff5e5eb186321cac82a8ab590abe76bc CVE-2016-6302.patch
3fccf95efbd51dff85cd4a04d5c589c6c06dee5cfa8d428edf93c378d106fb1e CVE-2016-6303.patch"
sha512sums="780601f6f3f32f42b6d7bbc4c593db39a3575f9db80294a10a68b2b0bb79448d9bd529ca700b9977354cbdfc65887c76af0aa7b90d3ee421f74ab53e6f15c303 openssl-1.0.2h.tar.gz sha512sums="780601f6f3f32f42b6d7bbc4c593db39a3575f9db80294a10a68b2b0bb79448d9bd529ca700b9977354cbdfc65887c76af0aa7b90d3ee421f74ab53e6f15c303 openssl-1.0.2h.tar.gz
2244f46cb18e6b98f075051dd2446c47f7590abccd108fbab707f168a20cad8d32220d704635973f09e3b2879f523be5160f1ffbc12ab3900f8a8891dc855c5c 0002-busybox-basename.patch 2244f46cb18e6b98f075051dd2446c47f7590abccd108fbab707f168a20cad8d32220d704635973f09e3b2879f523be5160f1ffbc12ab3900f8a8891dc855c5c 0002-busybox-basename.patch
58e42058a0c8086c49d681b1e226da39a8cf8cb88c51cf739dec2ff12e1bb5d7208ac5033264b186d58e9bdfe992fe9ddb95701d01caf1824396b2cefe30c0a4 0003-use-termios.patch 58e42058a0c8086c49d681b1e226da39a8cf8cb88c51cf739dec2ff12e1bb5d7208ac5033264b186d58e9bdfe992fe9ddb95701d01caf1824396b2cefe30c0a4 0003-use-termios.patch
...@@ -164,4 +198,9 @@ a3555440b5f544bfd6b9ad97557d8f4c1d673f6a35219f65056a72035d186be5f354717ddf978489 ...@@ -164,4 +198,9 @@ a3555440b5f544bfd6b9ad97557d8f4c1d673f6a35219f65056a72035d186be5f354717ddf978489
6353c7a94016c20db5d683dde37775f6780952ecdb1a5f39f878d04ba37f6ad79ae10fb6d65d181d912505a5d1e22463004cd855d548b364c00b120da2b0fdbc 1003-engines-e_padlock-implement-sha1-sha224-sha256-accel.patch 6353c7a94016c20db5d683dde37775f6780952ecdb1a5f39f878d04ba37f6ad79ae10fb6d65d181d912505a5d1e22463004cd855d548b364c00b120da2b0fdbc 1003-engines-e_padlock-implement-sha1-sha224-sha256-accel.patch
6e149213d1c4cbab06e0aedeb04562f96c1430e6e8f9b9836ff4ddd79da361db2bcfbdf83f6615369e8feaaefecfc0dc5f9cee3b56c2eeeca57233a2daf25d2c CVE-2016-2177.patch 6e149213d1c4cbab06e0aedeb04562f96c1430e6e8f9b9836ff4ddd79da361db2bcfbdf83f6615369e8feaaefecfc0dc5f9cee3b56c2eeeca57233a2daf25d2c CVE-2016-2177.patch
9a90ee6b6329dea17a70c6cd62fbf349289b4beab74137adc2448c54652501c2ff47694b9154da6e610e8b947ff2070e0460fe2754b62301a6a439e16eb6fd1b CVE-2016-2178.patch 9a90ee6b6329dea17a70c6cd62fbf349289b4beab74137adc2448c54652501c2ff47694b9154da6e610e8b947ff2070e0460fe2754b62301a6a439e16eb6fd1b CVE-2016-2178.patch
6c330a4a204311b21c0319de4fae7ff99819d462313cb36b4486d3e322d1d7c6393392308ff6c9f7b5a7c070584be46de232a940626ff979db88656299c87d48 CVE-2016-2180.patch" 02e0f2dfcb13f22b42c3945af5a8c81d4dd12b4c73b1e30de1dd54b6af8d460b15a0d05011fce3168696f39f9a72b126cc7e8c9cd1e889a1f6c37bc5bc329820 CVE-2016-2179.patch
6c330a4a204311b21c0319de4fae7ff99819d462313cb36b4486d3e322d1d7c6393392308ff6c9f7b5a7c070584be46de232a940626ff979db88656299c87d48 CVE-2016-2180.patch
2677c29cd05c00516a6ca454814b3db17d3096767db177656249da20221eb42d86bdf4fee995c1895f97abffc44c028019fa96cf00d3f1ef53b913353bfb786e CVE-2016-2181.patch
f6a30bdbe6c2bf21b5dcd9a79fe25207c8c8df9e928935bbc84f65a2aa6719d316c5afca320df107cc5c46027859624fbad7a4f41d3d1447a9658e9949614152 CVE-2016-2182.patch
fe88218c57fa8382a565d921d54f6bc20c89b5a63ebf9c80b941095baa76f102152c584ee15aac7e284f71e2bd7d04c621af9ade7719f87b69cb19caf22f823c CVE-2016-6302.patch
9f3f6f9c2be8830f444c7045a7d54d35461a665b48a6227015bc7fff10f9220d2814a3a045461e57af5b753b90738113e43d916fca28dda6e47519a4564f1f63 CVE-2016-6303.patch"
From c175308407858afff3fc8c2e5e085d94d12edc7d Mon Sep 17 00:00:00 2001
From: Matt Caswell <matt@openssl.org>
Date: Mon, 22 Feb 2016 10:27:18 +0000
Subject: [PATCH] Fix BN_hex2bn/BN_dec2bn NULL ptr/heap corruption
In the BN_hex2bn function the number of hex digits is calculated using
an int value |i|. Later |bn_expand| is called with a value of |i * 4|.
For large values of |i| this can result in |bn_expand| not allocating any
memory because |i * 4| is negative. This leaves ret->d as NULL leading
to a subsequent NULL ptr deref. For very large values of |i|, the
calculation |i * 4| could be a positive value smaller than |i|. In this
case memory is allocated to ret->d, but it is insufficiently sized
leading to heap corruption. A similar issue exists in BN_dec2bn.
This could have security consequences if BN_hex2bn/BN_dec2bn is ever
called by user applications with very large untrusted hex/dec data. This is
anticipated to be a rare occurrence.
All OpenSSL internal usage of this function uses data that is not expected
to be untrusted, e.g. config file data or application command line
arguments. If user developed applications generate config file data based
on untrusted data then it is possible that this could also lead to security
consequences. This is also anticipated to be a rare.
Issue reported by Guido Vranken.
CVE-2016-0797
Reviewed-by: Andy Polyakov <appro@openssl.org>
---
crypto/bn/bn.h | 14 ++++++++++++--
crypto/bn/bn_print.c | 17 +++++++++++++----
2 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/crypto/bn/bn.h b/crypto/bn/bn.h
index 5696965..86264ae 100644
--- a/crypto/bn/bn.h
+++ b/crypto/bn/bn.h
@@ -125,6 +125,7 @@
#ifndef HEADER_BN_H
# define HEADER_BN_H
+# include <limits.h>
# include <openssl/e_os2.h>
# ifndef OPENSSL_NO_FP_API
# include <stdio.h> /* FILE */
@@ -721,8 +722,17 @@ const BIGNUM *BN_get0_nist_prime_521(void);
/* library internal functions */
-# define bn_expand(a,bits) ((((((bits+BN_BITS2-1))/BN_BITS2)) <= (a)->dmax)?\
- (a):bn_expand2((a),(bits+BN_BITS2-1)/BN_BITS2))
+# define bn_expand(a,bits) \
+ ( \
+ bits > (INT_MAX - BN_BITS2 + 1) ? \
+ NULL \
+ : \
+ (((bits+BN_BITS2-1)/BN_BITS2) <= (a)->dmax) ? \
+ (a) \
+ : \
+ bn_expand2((a),(bits+BN_BITS2-1)/BN_BITS2) \
+ )
+
# define bn_wexpand(a,words) (((words) <= (a)->dmax)?(a):bn_expand2((a),(words)))
BIGNUM *bn_expand2(BIGNUM *a, int words);
# ifndef OPENSSL_NO_DEPRECATED
diff --git a/crypto/bn/bn_print.c b/crypto/bn/bn_print.c
index ab10b95..bfa31ef 100644
--- a/crypto/bn/bn_print.c
+++ b/crypto/bn/bn_print.c
@@ -58,6 +58,7 @@
#include <stdio.h>
#include <ctype.h>
+#include <limits.h>
#include "cryptlib.h"
#include <openssl/buffer.h>
#include "bn_lcl.h"
@@ -189,7 +190,11 @@ int BN_hex2bn(BIGNUM **bn, const char *a)
a++;
}
- for (i = 0; isxdigit((unsigned char)a[i]); i++) ;
+ for (i = 0; i <= (INT_MAX/4) && isxdigit((unsigned char)a[i]); i++)
+ continue;
+
+ if (i > INT_MAX/4)
+ goto err;
num = i + neg;
if (bn == NULL)
@@ -204,7 +209,7 @@ int BN_hex2bn(BIGNUM **bn, const char *a)
BN_zero(ret);
}
- /* i is the number of hex digests; */
+ /* i is the number of hex digits */
if (bn_expand(ret, i * 4) == NULL)
goto err;
@@ -260,7 +265,11 @@ int BN_dec2bn(BIGNUM **bn, const char *a)
a++;
}
- for (i = 0; isdigit((unsigned char)a[i]); i++) ;
+ for (i = 0; i <= (INT_MAX/4) && isdigit((unsigned char)a[i]); i++)
+ continue;
+
+ if (i > INT_MAX/4)
+ goto err;
num = i + neg;
if (bn == NULL)
@@ -278,7 +287,7 @@ int BN_dec2bn(BIGNUM **bn, const char *a)
BN_zero(ret);
}
- /* i is the number of digests, a bit of an over expand; */
+ /* i is the number of digits, a bit of an over expand */
if (bn_expand(ret, i * 4) == NULL)
goto err;
--
1.9.1
From 26f2c5774f117aea588e8f31fad38bcf14e83bec Mon Sep 17 00:00:00 2001
From: Matt Caswell <matt@openssl.org>
Date: Thu, 30 Jun 2016 13:17:08 +0100
Subject: [PATCH] Fix DTLS buffered message DoS attack
DTLS can handle out of order record delivery. Additionally since
handshake messages can be bigger than will fit into a single packet, the
messages can be fragmented across multiple records (as with normal TLS).
That means that the messages can arrive mixed up, and we have to
reassemble them. We keep a queue of buffered messages that are "from the
future", i.e. messages we're not ready to deal with yet but have arrived
early. The messages held there may not be full yet - they could be one
or more fragments that are still in the process of being reassembled.
The code assumes that we will eventually complete the reassembly and
when that occurs the complete message is removed from the queue at the
point that we need to use it.
However, DTLS is also tolerant of packet loss. To get around that DTLS
messages can be retransmitted. If we receive a full (non-fragmented)
message from the peer after previously having received a fragment of
that message, then we ignore the message in the queue and just use the
non-fragmented version. At that point the queued message will never get
removed.
Additionally the peer could send "future" messages that we never get to
in order to complete the handshake. Each message has a sequence number
(starting from 0). We will accept a message fragment for the current
message sequence number, or for any sequence up to 10 into the future.
However if the Finished message has a sequence number of 2, anything
greater than that in the queue is just left there.
So, in those two ways we can end up with "orphaned" data in the queue
that will never get removed - except when the connection is closed. At
that point all the queues are flushed.
An attacker could seek to exploit this by filling up the queues with
lots of large messages that are never going to be used in order to
attempt a DoS by memory exhaustion.
I will assume that we are only concerned with servers here. It does not
seem reasonable to be concerned about a memory exhaustion attack on a
client. They are unlikely to process enough connections for this to be
an issue.
A "long" handshake with many messages might be 5 messages long (in the
incoming direction), e.g. ClientHello, Certificate, ClientKeyExchange,
CertificateVerify, Finished. So this would be message sequence numbers 0
to 4. Additionally we can buffer up to 10 messages in the future.
Therefore the maximum number of messages that an attacker could send
that could get orphaned would typically be 15.
The maximum size that a DTLS message is allowed to be is defined by
max_cert_list, which by default is 100k. Therefore the maximum amount of
"orphaned" memory per connection is 1500k.
Message sequence numbers get reset after the Finished message, so
renegotiation will not extend the maximum number of messages that can be
orphaned per connection.
As noted above, the queues do get cleared when the connection is closed.
Therefore in order to mount an effective attack, an attacker would have
to open many simultaneous connections.
Issue reported by Quan Luo.
CVE-2016-2179
Reviewed-by: Richard Levitte <levitte@openssl.org>
---
ssl/d1_both.c | 32 ++++++++++++++++----------------
ssl/d1_clnt.c | 1 +
ssl/d1_lib.c | 37 ++++++++++++++++++++++++++-----------
ssl/d1_srvr.c | 3 ++-
ssl/ssl_locl.h | 3 ++-
5 files changed, 47 insertions(+), 29 deletions(-)
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
index 5d2c209..46c70d8 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -618,11 +618,23 @@ static int dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
int al;
*ok = 0;
- item = pqueue_peek(s->d1->buffered_messages);
- if (item == NULL)
- return 0;
+ do {
+ item = pqueue_peek(s->d1->buffered_messages);
+ if (item == NULL)
+ return 0;
+
+ frag = (hm_fragment *)item->data;
+
+ if (frag->msg_header.seq < s->d1->handshake_read_seq) {
+ /* This is a stale message that has been buffered so clear it */
+ pqueue_pop(s->d1->buffered_messages);
+ dtls1_hm_fragment_free(frag);
+ pitem_free(item);
+ item = NULL;
+ frag = NULL;
+ }
+ } while (item == NULL);
- frag = (hm_fragment *)item->data;
/* Don't return if reassembly still in progress */
if (frag->reassembly != NULL)
@@ -1296,18 +1308,6 @@ dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off,
return ret;
}
-/* call this function when the buffered messages are no longer needed */
-void dtls1_clear_record_buffer(SSL *s)
-{
- pitem *item;
-
- for (item = pqueue_pop(s->d1->sent_messages);
- item != NULL; item = pqueue_pop(s->d1->sent_messages)) {
- dtls1_hm_fragment_free((hm_fragment *)item->data);
- pitem_free(item);
- }
-}
-
unsigned char *dtls1_set_message_header(SSL *s, unsigned char *p,
unsigned char mt, unsigned long len,
unsigned long frag_off,
diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c
index 3ddfa7b..7e2f5c2 100644
--- a/ssl/d1_clnt.c
+++ b/ssl/d1_clnt.c
@@ -769,6 +769,7 @@ int dtls1_connect(SSL *s)
/* done with handshaking */
s->d1->handshake_read_seq = 0;
s->d1->next_handshake_write_seq = 0;
+ dtls1_clear_received_buffer(s);
goto end;
/* break; */
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index ee78921..debd4fd 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -170,7 +170,6 @@ int dtls1_new(SSL *s)
static void dtls1_clear_queues(SSL *s)
{
pitem *item = NULL;
- hm_fragment *frag = NULL;
DTLS1_RECORD_DATA *rdata;
while ((item = pqueue_pop(s->d1->unprocessed_rcds.q)) != NULL) {
@@ -191,28 +190,44 @@ static void dtls1_clear_queues(SSL *s)
pitem_free(item);
}
+ while ((item = pqueue_pop(s->d1->buffered_app_data.q)) != NULL) {
+ rdata = (DTLS1_RECORD_DATA *)item->data;
+ if (rdata->rbuf.buf) {
+ OPENSSL_free(rdata->rbuf.buf);
+ }
+ OPENSSL_free(item->data);
+ pitem_free(item);
+ }
+
+ dtls1_clear_received_buffer(s);
+ dtls1_clear_sent_buffer(s);
+}
+
+void dtls1_clear_received_buffer(SSL *s)
+{
+ pitem *item = NULL;
+ hm_fragment *frag = NULL;
+
while ((item = pqueue_pop(s->d1->buffered_messages)) != NULL) {
frag = (hm_fragment *)item->data;
dtls1_hm_fragment_free(frag);
pitem_free(item);
}
+}
+
+void dtls1_clear_sent_buffer(SSL *s)
+{
+ pitem *item = NULL;
+ hm_fragment *frag = NULL;
while ((item = pqueue_pop(s->d1->sent_messages)) != NULL) {
frag = (hm_fragment *)item->data;
dtls1_hm_fragment_free(frag);
pitem_free(item);
}
-
- while ((item = pqueue_pop(s->d1->buffered_app_data.q)) != NULL) {
- rdata = (DTLS1_RECORD_DATA *)item->data;
- if (rdata->rbuf.buf) {
- OPENSSL_free(rdata->rbuf.buf);
- }
- OPENSSL_free(item->data);
- pitem_free(item);
- }
}
+
void dtls1_free(SSL *s)
{
ssl3_free(s);
@@ -456,7 +471,7 @@ void dtls1_stop_timer(SSL *s)
BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
&(s->d1->next_timeout));
/* Clear retransmission buffer */
- dtls1_clear_record_buffer(s);
+ dtls1_clear_sent_buffer(s);
}
int dtls1_check_timeout_num(SSL *s)
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
index e677d88..bc875b5 100644
--- a/ssl/d1_srvr.c
+++ b/ssl/d1_srvr.c
@@ -313,7 +313,7 @@ int dtls1_accept(SSL *s)
case SSL3_ST_SW_HELLO_REQ_B:
s->shutdown = 0;
- dtls1_clear_record_buffer(s);
+ dtls1_clear_sent_buffer(s);
dtls1_start_timer(s);
ret = ssl3_send_hello_request(s);
if (ret <= 0)
@@ -894,6 +894,7 @@ int dtls1_accept(SSL *s)
/* next message is server hello */
s->d1->handshake_write_seq = 0;
s->d1->next_handshake_write_seq = 0;
+ dtls1_clear_received_buffer(s);
goto end;
/* break; */
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 3dd2a54..e358031 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1248,7 +1248,8 @@ int dtls1_retransmit_message(SSL *s, unsigned short seq,
unsigned long frag_off, int *found);
int dtls1_get_queue_priority(unsigned short seq, int is_ccs);
int dtls1_retransmit_buffered_messages(SSL *s);
-void dtls1_clear_record_buffer(SSL *s);
+void dtls1_clear_received_buffer(SSL *s);
+void dtls1_clear_sent_buffer(SSL *s);
void dtls1_get_message_header(unsigned char *data,
struct hm_header_st *msg_hdr);
void dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr);
--
1.9.1
From 20744f6b40b5ded059a848f66d6ba922f2a62eb3 Mon Sep 17 00:00:00 2001
From: Matt Caswell <matt@openssl.org>
Date: Tue, 5 Jul 2016 11:46:26 +0100
Subject: [PATCH] Fix DTLS unprocessed records bug
During a DTLS handshake we may get records destined for the next epoch
arrive before we have processed the CCS. In that case we can't decrypt or
verify the record yet, so we buffer it for later use. When we do receive
the CCS we work through the queue of unprocessed records and process them.
Unfortunately the act of processing wipes out any existing packet data
that we were still working through. This includes any records from the new
epoch that were in the same packet as the CCS. We should only process the
buffered records if we've not got any data left.
Reviewed-by: Richard Levitte <levitte@openssl.org>
---
ssl/d1_pkt.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c
index fe30ec7..1fb119d 100644
--- a/ssl/d1_pkt.c
+++ b/ssl/d1_pkt.c
@@ -319,6 +319,7 @@ static int dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue)
static int dtls1_process_buffered_records(SSL *s)
{
pitem *item;
+ SSL3_BUFFER *rb;
item = pqueue_peek(s->d1->unprocessed_rcds.q);
if (item) {
@@ -326,6 +327,19 @@ static int dtls1_process_buffered_records(SSL *s)
if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch)
return (1); /* Nothing to do. */
+ rb = &s->s3->rbuf;
+
+ if (rb->left > 0) {
+ /*
+ * We've still got data from the current packet to read. There could
+ * be a record from the new epoch in it - so don't overwrite it
+ * with the unprocessed records yet (we'll do it when we've
+ * finished reading the current packet).
+ */
+ return 1;
+ }
+
+
/* Process all the records. */
while (pqueue_peek(s->d1->unprocessed_rcds.q)) {
dtls1_get_unprocessed_record(s);
@@ -581,6 +595,7 @@ int dtls1_get_record(SSL *s)
rr = &(s->s3->rrec);
+ again:
/*
* The epoch may have changed. If so, process all the pending records.
* This is a non-blocking operation.
@@ -593,7 +608,6 @@ int dtls1_get_record(SSL *s)
return 1;
/* get something from the wire */
- again:
/* check if we have the header */
if ((s->rstate != SSL_ST_READ_BODY) ||
(s->packet_length < DTLS1_RT_HEADER_LENGTH)) {
@@ -1830,8 +1844,13 @@ static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr,
if (rr->epoch == s->d1->r_epoch)
return &s->d1->bitmap;
- /* Only HM and ALERT messages can be from the next epoch */
+ /*
+ * Only HM and ALERT messages can be from the next epoch and only if we
+ * have already processed all of the unprocessed records from the last
+ * epoch
+ */
else if (rr->epoch == (unsigned long)(s->d1->r_epoch + 1) &&
+ s->d1->unprocessed_rcds.epoch != s->d1->r_epoch &&
(rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) {
*is_next_epoch = 1;
return &s->d1->next_bitmap;
--
1.9.1
From 3884b47b7c255c2e94d9b387ee83c7e8bb981258 Mon Sep 17 00:00:00 2001
From: Matt Caswell <matt@openssl.org>
Date: Tue, 5 Jul 2016 12:04:37 +0100
Subject: [PATCH] Fix DTLS replay protection
The DTLS implementation provides some protection against replay attacks
in accordance with RFC6347 section 4.1.2.6.
A sliding "window" of valid record sequence numbers is maintained with
the "right" hand edge of the window set to the highest sequence number we
have received so far. Records that arrive that are off the "left" hand
edge of the window are rejected. Records within the window are checked
against a list of records received so far. If we already received it then
we also reject the new record.
If we have not already received the record, or the sequence number is off
the right hand edge of the window then we verify the MAC of the record.
If MAC verification fails then we discard the record. Otherwise we mark
the record as received. If the sequence number was off the right hand edge
of the window, then we slide the window along so that the right hand edge
is in line with the newly received sequence number.
Records may arrive for future epochs, i.e. a record from after a CCS being
sent, can arrive before the CCS does if the packets get re-ordered. As we
have not yet received the CCS we are not yet in a position to decrypt or
validate the MAC of those records. OpenSSL places those records on an
unprocessed records queue. It additionally updates the window immediately,
even though we have not yet verified the MAC. This will only occur if
currently in a handshake/renegotiation.
This could be exploited by an attacker by sending a record for the next
epoch (which does not have to decrypt or have a valid MAC), with a very
large sequence number. This means the right hand edge of the window is
moved very far to the right, and all subsequent legitimate packets are
dropped causing a denial of service.
A similar effect can be achieved during the initial handshake. In this
case there is no MAC key negotiated yet. Therefore an attacker can send a
message for the current epoch with a very large sequence number. The code
will process the record as normal. If the hanshake message sequence number
(as opposed to the record sequence number that we have been talking about
so far) is in the future then the injected message is bufferred to be
handled later, but the window is still updated. Therefore all subsequent
legitimate handshake records are dropped. This aspect is not considered a
security issue because there are many ways for an attacker to disrupt the
initial handshake and prevent it from completing successfully (e.g.
injection of a handshake message will cause the Finished MAC to fail and
the handshake to be aborted). This issue comes about as a result of trying
to do replay protection, but having no integrity mechanism in place yet.
Does it even make sense to have replay protection in epoch 0? That
issue isn't addressed here though.
This addressed an OCAP Audit issue.
CVE-2016-2181
Reviewed-by: Richard Levitte <levitte@openssl.org>
---
ssl/d1_pkt.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++------------
ssl/ssl.h | 1 +
ssl/ssl_err.c | 4 +++-
3 files changed, 52 insertions(+), 13 deletions(-)
diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c
index 1fb119d..589bf9e 100644
--- a/ssl/d1_pkt.c
+++ b/ssl/d1_pkt.c
@@ -194,7 +194,7 @@ static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr,
#endif
static int dtls1_buffer_record(SSL *s, record_pqueue *q,
unsigned char *priority);
-static int dtls1_process_record(SSL *s);
+static int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap);
/* copy buffered record into SSL structure */
static int dtls1_copy_record(SSL *s, pitem *item)
@@ -320,13 +320,18 @@ static int dtls1_process_buffered_records(SSL *s)
{
pitem *item;
SSL3_BUFFER *rb;
+ SSL3_RECORD *rr;
+ DTLS1_BITMAP *bitmap;
+ unsigned int is_next_epoch;
+ int replayok = 1;
item = pqueue_peek(s->d1->unprocessed_rcds.q);
if (item) {
/* Check if epoch is current. */
if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch)
- return (1); /* Nothing to do. */
+ return 1; /* Nothing to do. */
+ rr = &s->s3->rrec;
rb = &s->s3->rbuf;
if (rb->left > 0) {
@@ -343,11 +348,41 @@ static int dtls1_process_buffered_records(SSL *s)
/* Process all the records. */
while (pqueue_peek(s->d1->unprocessed_rcds.q)) {
dtls1_get_unprocessed_record(s);
- if (!dtls1_process_record(s))
- return (0);
+ bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
+ if (bitmap == NULL) {
+ /*