Merge branch 'mbedtls-2.1' into mbedtls-2.1-restricted
diff --git a/ChangeLog b/ChangeLog
index 6e82bdf..8ea7791 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,6 +10,14 @@
data is all zeros.
* Fix unsafe bounds check in ssl_parse_client_psk_identity() when adding
64kB to the address of the SSL buffer wraps around.
+ * Fix a potential heap buffer overflow in mbedtls_ssl_write. When the (by
+ default enabled) maximum fragment length extension is disabled in the
+ config and the application data buffer passed to mbedtls_ssl_write
+ is larger than the internal message buffer (16384 bytes by default), the
+ latter overflows. The exploitability of this issue depends on whether the
+ application layer can be forced into sending such large packets. The issue
+ was independently reported by Tim Nordell via e-mail and by Florin Petriuc
+ and sjorsdewit on GitHub. Fix proposed by Florin Petriuc in #1022. Fixes #707.
Bugfix
* Fix some invalid RSA-PSS signatures with keys of size 8N+1 that were
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 8088e88..79fb9a7 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -6823,7 +6823,9 @@
int ret;
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
size_t max_len = mbedtls_ssl_get_max_frag_len( ssl );
-
+#else
+ size_t max_len = MBEDTLS_SSL_MAX_CONTENT_LEN;
+#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
if( len > max_len )
{
#if defined(MBEDTLS_SSL_PROTO_DTLS)
@@ -6838,7 +6840,6 @@
#endif
len = max_len;
}
-#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
if( ssl->out_left != 0 )
{
@@ -6869,7 +6870,7 @@
*
* With non-blocking I/O, ssl_write_real() may return WANT_WRITE,
* then the caller will call us again with the same arguments, so
- * remember wether we already did the split or not.
+ * remember whether we already did the split or not.
*/
#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING)
static int ssl_write_split( mbedtls_ssl_context *ssl,
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 186e2a0..390ebae 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -60,6 +60,9 @@
#include <stdlib.h>
#include <string.h>
+#define MAX_REQUEST_SIZE 20000
+#define MAX_REQUEST_SIZE_STR "20000"
+
#define DFL_SERVER_NAME "localhost"
#define DFL_SERVER_ADDR NULL
#define DFL_SERVER_PORT "4433"
@@ -231,8 +234,8 @@
" server_addr=%%s default: given by name\n" \
" server_port=%%d default: 4433\n" \
" request_page=%%s default: \".\"\n" \
- " request_size=%%d default: about 34 (basic request)\n" \
- " (minimum: 0, max: 16384)\n" \
+ " request_size=%%d default: about 34 (basic request)\n" \
+ " (minimum: 0, max: " MAX_REQUEST_SIZE_STR " )\n" \
" debug_level=%%d default: 0 (disabled)\n" \
" nbio=%%d default: 0 (blocking I/O)\n" \
" options: 1 (non-blocking), 2 (added delays)\n" \
@@ -424,7 +427,9 @@
{
int ret = 0, len, tail_len, i, written, frags, retry_left;
mbedtls_net_context server_fd;
- unsigned char buf[MBEDTLS_SSL_MAX_CONTENT_LEN + 1];
+
+ unsigned char buf[MAX_REQUEST_SIZE + 1];
+
#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
unsigned char psk[MBEDTLS_PSK_MAX_LEN];
size_t psk_len = 0;
@@ -588,7 +593,8 @@
else if( strcmp( p, "request_size" ) == 0 )
{
opt.request_size = atoi( q );
- if( opt.request_size < 0 || opt.request_size > MBEDTLS_SSL_MAX_CONTENT_LEN )
+ if( opt.request_size < 0 ||
+ opt.request_size > MAX_REQUEST_SIZE )
goto usage;
}
else if( strcmp( p, "ca_file" ) == 0 )
@@ -1465,8 +1471,8 @@
mbedtls_printf( " > Write to server:" );
fflush( stdout );
- len = mbedtls_snprintf( (char *) buf, sizeof(buf) - 1, GET_REQUEST,
- opt.request_page );
+ len = mbedtls_snprintf( (char *) buf, sizeof( buf ) - 1, GET_REQUEST,
+ opt.request_page );
tail_len = (int) strlen( GET_REQUEST_END );
/* Add padding to GET request to reach opt.request_size in length */
@@ -1477,7 +1483,7 @@
len += opt.request_size - len - tail_len;
}
- strncpy( (char *) buf + len, GET_REQUEST_END, sizeof(buf) - len - 1 );
+ strncpy( (char *) buf + len, GET_REQUEST_END, sizeof( buf ) - len - 1 );
len += tail_len;
/* Truncate if request size is smaller than the "natural" size */
@@ -1521,6 +1527,12 @@
frags = 1;
written = ret;
+
+ if( written < len )
+ {
+ mbedtls_printf( " warning\n ! request didn't fit into single datagram and "
+ "was truncated to size %u", (unsigned) written );
+ }
}
buf[written] = '\0';
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 6defcdc..f0594a2 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -261,6 +261,16 @@
msg "test: compat.sh (ASan build)" # ~ 6 min
tests/compat.sh
+msg "build: default config except MFL extension (ASan build)" # ~ 30s
+cleanup
+cp "$CONFIG_H" "$CONFIG_BAK"
+scripts/config.pl unset MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+make
+
+msg "test: ssl-opt.sh, MFL-related tests"
+tests/ssl-opt.sh -f "Max fragment length"
+
msg "build: Default + SSLv3 (ASan build)" # ~ 6 min
cleanup
cp "$CONFIG_H" "$CONFIG_BAK"
@@ -485,4 +495,3 @@
msg "Done, cleaning up"
cleanup
-
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index d8f0fd7..5f47bb5 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -1218,7 +1218,23 @@
# Tests for Max Fragment Length extension
-run_test "Max fragment length: not used, reference" \
+MAX_CONTENT_LEN_EXPECT='16384'
+MAX_CONTENT_LEN_CONFIG=$( ../scripts/config.pl get MBEDTLS_SSL_MAX_CONTENT_LEN)
+
+if [ -n "$MAX_CONTENT_LEN_CONFIG" ] && [ "$MAX_CONTENT_LEN_CONFIG" -ne "$MAX_CONTENT_LEN_EXPECT" ]; then
+ printf "The ${CONFIG_H} file contains a value for the configuration of\n"
+ printf "MBEDTLS_SSL_MAX_CONTENT_LEN that is different from the script’s\n"
+ printf "test value of ${MAX_CONTENT_LEN_EXPECT}. \n"
+ printf "\n"
+ printf "The tests assume this value and if it changes, the tests in this\n"
+ printf "script should also be adjusted.\n"
+ printf "\n"
+
+ exit 1
+fi
+
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test "Max fragment length: enabled, default" \
"$P_SRV debug_level=3" \
"$P_CLI debug_level=3" \
0 \
@@ -1229,6 +1245,55 @@
-S "server hello, max_fragment_length extension" \
-C "found max_fragment_length extension"
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test "Max fragment length: enabled, default, larger message" \
+ "$P_SRV debug_level=3" \
+ "$P_CLI debug_level=3 request_size=16385" \
+ 0 \
+ -c "Maximum fragment length is 16384" \
+ -s "Maximum fragment length is 16384" \
+ -C "client hello, adding max_fragment_length extension" \
+ -S "found max fragment length extension" \
+ -S "server hello, max_fragment_length extension" \
+ -C "found max_fragment_length extension" \
+ -c "16385 bytes written in 2 fragments" \
+ -s "16384 bytes read" \
+ -s "1 bytes read"
+
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test "Max fragment length, DTLS: enabled, default, larger message" \
+ "$P_SRV debug_level=3 dtls=1" \
+ "$P_CLI debug_level=3 dtls=1 request_size=16385" \
+ 1 \
+ -c "Maximum fragment length is 16384" \
+ -s "Maximum fragment length is 16384" \
+ -C "client hello, adding max_fragment_length extension" \
+ -S "found max fragment length extension" \
+ -S "server hello, max_fragment_length extension" \
+ -C "found max_fragment_length extension" \
+ -c "fragment larger than.*maximum "
+
+requires_config_disabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test "Max fragment length: disabled, larger message" \
+ "$P_SRV debug_level=3" \
+ "$P_CLI debug_level=3 request_size=16385" \
+ 0 \
+ -C "Maximum fragment length is 16384" \
+ -S "Maximum fragment length is 16384" \
+ -c "16385 bytes written in 2 fragments" \
+ -s "16384 bytes read" \
+ -s "1 bytes read"
+
+requires_config_disabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test "Max fragment length DTLS: disabled, larger message" \
+ "$P_SRV debug_level=3 dtls=1" \
+ "$P_CLI debug_level=3 dtls=1 request_size=16385" \
+ 1 \
+ -C "Maximum fragment length is 16384" \
+ -S "Maximum fragment length is 16384" \
+ -c "fragment larger than.*maximum "
+
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
run_test "Max fragment length: used by client" \
"$P_SRV debug_level=3" \
"$P_CLI debug_level=3 max_frag_len=4096" \
@@ -1240,6 +1305,7 @@
-s "server hello, max_fragment_length extension" \
-c "found max_fragment_length extension"
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
run_test "Max fragment length: used by server" \
"$P_SRV debug_level=3 max_frag_len=4096" \
"$P_CLI debug_level=3" \
@@ -1251,6 +1317,7 @@
-S "server hello, max_fragment_length extension" \
-C "found max_fragment_length extension"
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
requires_gnutls
run_test "Max fragment length: gnutls server" \
"$G_SRV" \
@@ -1260,6 +1327,7 @@
-c "client hello, adding max_fragment_length extension" \
-c "found max_fragment_length extension"
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
run_test "Max fragment length: client, message just fits" \
"$P_SRV debug_level=3" \
"$P_CLI debug_level=3 max_frag_len=2048 request_size=2048" \
@@ -1273,6 +1341,7 @@
-c "2048 bytes written in 1 fragments" \
-s "2048 bytes read"
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
run_test "Max fragment length: client, larger message" \
"$P_SRV debug_level=3" \
"$P_CLI debug_level=3 max_frag_len=2048 request_size=2345" \
@@ -1287,6 +1356,7 @@
-s "2048 bytes read" \
-s "297 bytes read"
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
run_test "Max fragment length: DTLS client, larger message" \
"$P_SRV debug_level=3 dtls=1" \
"$P_CLI debug_level=3 dtls=1 max_frag_len=2048 request_size=2345" \
@@ -3066,6 +3136,7 @@
"$P_CLI request_size=16384 force_version=ssl3 recsplit=0 \
force_ciphersuite=TLS-RSA-WITH-AES-256-CBC-SHA" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
requires_config_enabled MBEDTLS_SSL_PROTO_SSL3
@@ -3074,6 +3145,7 @@
"$P_CLI request_size=16384 force_version=ssl3 \
force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.0 BlockCipher" \
@@ -3081,6 +3153,7 @@
"$P_CLI request_size=16384 force_version=tls1 recsplit=0 \
force_ciphersuite=TLS-RSA-WITH-AES-256-CBC-SHA" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.0 BlockCipher truncated MAC" \
@@ -3089,6 +3162,7 @@
force_ciphersuite=TLS-RSA-WITH-AES-256-CBC-SHA \
trunc_hmac=1" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.0 StreamCipher truncated MAC" \
@@ -3097,6 +3171,7 @@
force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA \
trunc_hmac=1" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.1 BlockCipher" \
@@ -3104,6 +3179,7 @@
"$P_CLI request_size=16384 force_version=tls1_1 \
force_ciphersuite=TLS-RSA-WITH-AES-256-CBC-SHA" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.1 StreamCipher" \
@@ -3111,6 +3187,7 @@
"$P_CLI request_size=16384 force_version=tls1_1 \
force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.1 BlockCipher truncated MAC" \
@@ -3119,6 +3196,7 @@
force_ciphersuite=TLS-RSA-WITH-AES-256-CBC-SHA \
trunc_hmac=1" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.1 StreamCipher truncated MAC" \
@@ -3127,6 +3205,7 @@
force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA \
trunc_hmac=1" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.2 BlockCipher" \
@@ -3134,6 +3213,7 @@
"$P_CLI request_size=16384 force_version=tls1_2 \
force_ciphersuite=TLS-RSA-WITH-AES-256-CBC-SHA" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.2 BlockCipher larger MAC" \
@@ -3141,6 +3221,7 @@
"$P_CLI request_size=16384 force_version=tls1_2 \
force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.2 BlockCipher truncated MAC" \
@@ -3149,6 +3230,7 @@
force_ciphersuite=TLS-RSA-WITH-AES-256-CBC-SHA \
trunc_hmac=1" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.2 StreamCipher" \
@@ -3156,6 +3238,7 @@
"$P_CLI request_size=16384 force_version=tls1_2 \
force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.2 StreamCipher truncated MAC" \
@@ -3164,6 +3247,7 @@
force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA \
trunc_hmac=1" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.2 AEAD" \
@@ -3171,6 +3255,7 @@
"$P_CLI request_size=16384 force_version=tls1_2 \
force_ciphersuite=TLS-RSA-WITH-AES-256-CCM" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
run_test "Large packet TLS 1.2 AEAD shorter tag" \
@@ -3178,6 +3263,7 @@
"$P_CLI request_size=16384 force_version=tls1_2 \
force_ciphersuite=TLS-RSA-WITH-AES-256-CCM-8" \
0 \
+ -c "16384 bytes written in 1 fragments" \
-s "Read from client: 16384 bytes read"
# Tests for DTLS HelloVerifyRequest