TLS: Add protection against record layer CBC attacks

Instead of using separate bad_record_mac and decryption_failed alerts,
use only bad_record_mac alert regardless of how the CBC decryption
failed. This provides less information to attackers that could modify
packets. In addition, instead of returning immediately on error, run
through the MAC check to make timing attacks more difficult.
This commit is contained in:
Jouni Malinen 2011-09-25 16:57:35 +03:00
parent 26296a8a7c
commit 85b7187ffc

View file

@ -250,6 +250,7 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
u8 padlen; u8 padlen;
struct crypto_hash *hmac; struct crypto_hash *hmac;
u8 len[2], hash[100]; u8 len[2], hash[100];
int force_mac_error = 0;
wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received", wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
in_data, in_len); in_data, in_len);
@ -326,11 +327,23 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
} }
plen = in_len; plen = in_len;
if (rl->iv_size) { if (rl->iv_size) {
/*
* TLS v1.0 defines different alert values for various
* failures. That may information to aid in attacks, so
* use the same bad_record_mac alert regardless of the
* issues.
*
* In addition, instead of returning immediately on
* error, run through the MAC check to make timing
* attacks more difficult.
*/
/* Verify and remove padding */
if (plen == 0) { if (plen == 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short record" wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
" (no pad)"); " (no pad)");
*alert = TLS_ALERT_DECODE_ERROR; force_mac_error = 1;
return -1; goto check_mac;
} }
padlen = out_data[plen - 1]; padlen = out_data[plen - 1];
if (padlen >= plen) { if (padlen >= plen) {
@ -338,8 +351,8 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
"length (%u, plen=%lu) in " "length (%u, plen=%lu) in "
"received record", "received record",
padlen, (unsigned long) plen); padlen, (unsigned long) plen);
*alert = TLS_ALERT_DECRYPTION_FAILED; force_mac_error = 1;
return -1; goto check_mac;
} }
for (i = plen - padlen; i < plen; i++) { for (i = plen - padlen; i < plen; i++) {
if (out_data[i] != padlen) { if (out_data[i] != padlen) {
@ -348,14 +361,15 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
"received record", "received record",
out_data + plen - padlen, out_data + plen - padlen,
padlen); padlen);
*alert = TLS_ALERT_DECRYPTION_FAILED; force_mac_error = 1;
return -1; goto check_mac;
} }
} }
plen -= padlen + 1; plen -= padlen + 1;
} }
check_mac:
wpa_hexdump(MSG_MSGDUMP, wpa_hexdump(MSG_MSGDUMP,
"TLSv1: Record Layer - Decrypted data", "TLSv1: Record Layer - Decrypted data",
out_data, plen); out_data, plen);
@ -363,7 +377,7 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
if (plen < rl->hash_size) { if (plen < rl->hash_size) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no " wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
"hash value"); "hash value");
*alert = TLS_ALERT_INTERNAL_ERROR; *alert = TLS_ALERT_BAD_RECORD_MAC;
return -1; return -1;
} }
@ -388,12 +402,15 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
if (crypto_hash_finish(hmac, hash, &hlen) < 0) { if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed " wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
"to calculate HMAC"); "to calculate HMAC");
*alert = TLS_ALERT_INTERNAL_ERROR;
return -1; return -1;
} }
if (hlen != rl->hash_size || if (hlen != rl->hash_size ||
os_memcmp(hash, out_data + plen, hlen) != 0) { os_memcmp(hash, out_data + plen, hlen) != 0 ||
force_mac_error) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in " wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
"received message"); "received message (force_mac_error=%d)",
force_mac_error);
*alert = TLS_ALERT_BAD_RECORD_MAC; *alert = TLS_ALERT_BAD_RECORD_MAC;
return -1; return -1;
} }