aboutsummaryrefslogtreecommitdiffstats
path: root/src/tls
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2011-11-05 13:04:02 +0200
committerJouni Malinen <j@w1.fi>2011-11-05 13:04:02 +0200
commitc4a34808262cc138ccc78b838e93e7a0e35f3c14 (patch)
treecf57ac6942518d8b152674a4e615728a2ff0cd89 /src/tls
parentedc95487aa41b584736e7d8ee10c3dc0d55cd0ea (diff)
downloadexternal_wpa_supplicant_8_ti-c4a34808262cc138ccc78b838e93e7a0e35f3c14.zip
external_wpa_supplicant_8_ti-c4a34808262cc138ccc78b838e93e7a0e35f3c14.tar.gz
external_wpa_supplicant_8_ti-c4a34808262cc138ccc78b838e93e7a0e35f3c14.tar.bz2
TLS: Clean up TLS record layer processing
Return number of user input bytes from tlsv1_record_receive() to move this detail into the proper record layer processing. In addition, ignore unknown content types at record layer and allow processing to continue after warning level TLS alerts to provide minimal workaround for closure alerts. Signed-hostap: Jouni Malinen <j@w1.fi>
Diffstat (limited to 'src/tls')
-rw-r--r--src/tls/tlsv1_client.c73
-rw-r--r--src/tls/tlsv1_record.c56
-rw-r--r--src/tls/tlsv1_server.c71
3 files changed, 140 insertions, 60 deletions
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 75b8612..a58c356 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -147,6 +147,7 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
size_t in_msg_len;
int no_appl_data;
+ int used;
if (conn->state == CLIENT_HELLO) {
if (in_len)
@@ -166,13 +167,21 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
/* Each received packet may include multiple records */
while (pos < end) {
in_msg_len = in_len;
- if (tlsv1_record_receive(&conn->rl, pos, end - pos,
- in_msg, &in_msg_len, &alert)) {
+ used = tlsv1_record_receive(&conn->rl, pos, end - pos,
+ in_msg, &in_msg_len, &alert);
+ if (used < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
"record failed");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
goto failed;
}
+ if (used == 0) {
+ /* need more data */
+ wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+ "yet supported");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ goto failed;
+ }
ct = pos[0];
in_pos = in_msg;
@@ -190,7 +199,7 @@ u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
in_pos += in_msg_len;
}
- pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+ pos += used;
}
os_free(in_msg);
@@ -266,8 +275,8 @@ int tlsv1_client_decrypt(struct tlsv1_client *conn,
u8 *out_data, size_t out_len)
{
const u8 *in_end, *pos;
- int res;
- u8 alert, *out_end, *out_pos;
+ int used;
+ u8 alert, *out_end, *out_pos, ct;
size_t olen;
pos = in_data;
@@ -276,23 +285,53 @@ int tlsv1_client_decrypt(struct tlsv1_client *conn,
out_end = out_data + out_len;
while (pos < in_end) {
- if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
- "0x%x", pos[0]);
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
- TLS_ALERT_UNEXPECTED_MESSAGE);
- return -1;
- }
-
+ ct = pos[0];
olen = out_end - out_pos;
- res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
- out_pos, &olen, &alert);
- if (res < 0) {
+ used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+ out_pos, &olen, &alert);
+ if (used < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
"failed");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
return -1;
}
+ if (used == 0) {
+ /* need more data */
+ wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+ "yet supported");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ return -1;
+ }
+
+ if (ct == TLS_CONTENT_TYPE_ALERT) {
+ if (olen < 2) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Alert "
+ "underflow");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+ out_pos[0], out_pos[1]);
+ if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
+ /* Continue processing */
+ pos += used;
+ continue;
+ }
+
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, out_pos[1]);
+ return -1;
+ }
+
+ if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
+ "0x%x when decrypting application data",
+ pos[0]);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
out_pos += olen;
if (out_pos > out_end) {
wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
@@ -302,7 +341,7 @@ int tlsv1_client_decrypt(struct tlsv1_client *conn,
return -1;
}
- pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+ pos += used;
}
return out_pos - out_data;
diff --git a/src/tls/tlsv1_record.c b/src/tls/tlsv1_record.c
index 332f8d4..1b1b466 100644
--- a/src/tls/tlsv1_record.c
+++ b/src/tls/tlsv1_record.c
@@ -271,7 +271,8 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
* @out_len: Set to maximum out_data length by caller; used to return the
* length of the used data
* @alert: Buffer for returning an alert value on failure
- * Returns: 0 on success, -1 on failure
+ * Returns: Number of bytes used from in_data on success, 0 if record was not
+ * complete (more data needed), or -1 on failure
*
* This function decrypts the received message, verifies HMAC and TLS record
* layer header.
@@ -285,30 +286,21 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
struct crypto_hash *hmac;
u8 len[2], hash[100];
int force_mac_error = 0;
-
- wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
- in_data, in_len);
+ u8 ct;
if (in_len < TLS_RECORD_HEADER_LEN) {
- wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu) - "
+ "need more data",
(unsigned long) in_len);
- *alert = TLS_ALERT_DECODE_ERROR;
- return -1;
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+ in_data, in_len);
+ return 0;
}
+ ct = in_data[0];
+ rlen = WPA_GET_BE16(in_data + 3);
wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
- "length %d", in_data[0], in_data[1], in_data[2],
- WPA_GET_BE16(in_data + 3));
-
- if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
- in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
- in_data[0] != TLS_CONTENT_TYPE_ALERT &&
- in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
- wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
- in_data[0]);
- *alert = TLS_ALERT_UNEXPECTED_MESSAGE;
- return -1;
- }
+ "length %d", ct, in_data[1], in_data[2], (int) rlen);
/*
* TLS v1.0 and v1.1 RFCs were not exactly clear on the use of the
@@ -322,8 +314,6 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
return -1;
}
- rlen = WPA_GET_BE16(in_data + 3);
-
/* TLSCiphertext must not be more than 2^14+2048 bytes */
if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
@@ -339,7 +329,19 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
"(rlen=%lu > in_len=%lu)",
(unsigned long) rlen, (unsigned long) in_len);
- *alert = TLS_ALERT_DECODE_ERROR;
+ return 0;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+ in_data, rlen);
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE &&
+ ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
+ ct != TLS_CONTENT_TYPE_ALERT &&
+ ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Ignore record with unknown "
+ "content type 0x%x", ct);
+ *alert = TLS_ALERT_UNEXPECTED_MESSAGE;
return -1;
}
@@ -417,13 +419,13 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
}
plen -= padlen + 1;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - "
+ "Decrypted data with IV and padding "
+ "removed", out_data, plen);
}
check_mac:
- wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
- "data with IV and padding removed",
- out_data, plen);
-
if (plen < rl->hash_size) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
"hash value");
@@ -481,5 +483,5 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
- return 0;
+ return TLS_RECORD_HEADER_LEN + rlen;
}
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index 1f48aa5..3661c16 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -115,6 +115,7 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
const u8 *pos, *end;
u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
size_t in_msg_len;
+ int used;
if (in_data == NULL || in_len == 0) {
wpa_printf(MSG_DEBUG, "TLSv1: No input data to server");
@@ -130,13 +131,21 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
/* Each received packet may include multiple records */
while (pos < end) {
in_msg_len = in_len;
- if (tlsv1_record_receive(&conn->rl, pos, end - pos,
- in_msg, &in_msg_len, &alert)) {
+ used = tlsv1_record_receive(&conn->rl, pos, end - pos,
+ in_msg, &in_msg_len, &alert);
+ if (used < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
"record failed");
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
goto failed;
}
+ if (used == 0) {
+ /* need more data */
+ wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+ "yet supported");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ goto failed;
+ }
ct = pos[0];
in_pos = in_msg;
@@ -152,7 +161,7 @@ u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
in_pos += in_msg_len;
}
- pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+ pos += used;
}
os_free(in_msg);
@@ -230,8 +239,8 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
u8 *out_data, size_t out_len)
{
const u8 *in_end, *pos;
- int res;
- u8 alert, *out_end, *out_pos;
+ int used;
+ u8 alert, *out_end, *out_pos, ct;
size_t olen;
pos = in_data;
@@ -240,7 +249,46 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
out_end = out_data + out_len;
while (pos < in_end) {
- if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+ ct = pos[0];
+ olen = out_end - out_pos;
+ used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+ out_pos, &olen, &alert);
+ if (used < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
+ "failed");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ return -1;
+ }
+ if (used == 0) {
+ /* need more data */
+ wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+ "yet supported");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ return -1;
+ }
+
+ if (ct == TLS_CONTENT_TYPE_ALERT) {
+ if (olen < 2) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Alert "
+ "underflow");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+ out_pos[0], out_pos[1]);
+ if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
+ /* Continue processing */
+ pos += used;
+ continue;
+ }
+
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ out_pos[1]);
+ return -1;
+ }
+
+ if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
"0x%x", pos[0]);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -248,15 +296,6 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
return -1;
}
- olen = out_end - out_pos;
- res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
- out_pos, &olen, &alert);
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
- "failed");
- tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
- return -1;
- }
out_pos += olen;
if (out_pos > out_end) {
wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
@@ -266,7 +305,7 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
return -1;
}
- pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+ pos += used;
}
return out_pos - out_data;