TLS: Add support for TLS v1.1 (RFC 4346) with internal TLS

This is disabled by defautl and can be enabled with CONFIG_TLSV11=y
build configuration parameter.
This commit is contained in:
Jouni Malinen 2011-09-25 17:24:46 +03:00
parent 3bff59f857
commit 5c47af9a7a
13 changed files with 157 additions and 32 deletions

View file

@ -434,6 +434,10 @@ ifndef CONFIG_TLS
CONFIG_TLS=openssl
endif
ifdef CONFIG_TLSV11
CFLAGS += -DCONFIG_TLSV11
endif
ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
OBJS += ../src/crypto/tls_openssl.o

View file

@ -208,3 +208,39 @@ CONFIG_IPV6=y
# considered for builds that are known to be used on devices that meet the
# requirements described above.
#CONFIG_NO_RANDOM_POOL=y
# Select TLS implementation
# openssl = OpenSSL (default)
# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA)
# internal = Internal TLSv1 implementation (experimental)
# none = Empty template
#CONFIG_TLS=openssl
# Whether to enable TLS/IA support, which is required for EAP-TTLSv1.
# You need CONFIG_TLS=gnutls for this to have any effect. Please note that
# even though the core GnuTLS library is released under LGPL, this extra
# library uses GPL and as such, the terms of GPL apply to the combination
# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not
# apply for distribution of the resulting binary.
#CONFIG_GNUTLS_EXTRA=y
# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
# can be enabled to get a stronger construction of messages when block ciphers
# are used.
#CONFIG_TLSV11=y
# If CONFIG_TLS=internal is used, additional library and include paths are
# needed for LibTomMath. Alternatively, an integrated, minimal version of
# LibTomMath can be used. See beginning of libtommath.c for details on benefits
# and drawbacks of this option.
#CONFIG_INTERNAL_LIBTOMMATH=y
#ifndef CONFIG_INTERNAL_LIBTOMMATH
#LTM_PATH=/usr/src/libtommath-0.39
#CFLAGS += -I$(LTM_PATH)
#LIBS += -L$(LTM_PATH)
#LIBS_p += -L$(LTM_PATH)
#endif
# At the cost of about 4 kB of additional binary size, the internal LibTomMath
# can be configured to include faster routines for exptmod, sqr, and div to
# speed up DH and RSA calculation considerably
#CONFIG_INTERNAL_LIBTOMMATH_FAST=y

View file

@ -1,5 +1,5 @@
/*
* TLSv1 client (RFC 2246)
* TLS v1.0 (RFC 2246) and v1.1 (RFC 4346) client
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
@ -80,8 +80,9 @@ int tls_derive_keys(struct tlsv1_client *conn,
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
conn->rl.iv_size);
key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len);
if (conn->rl.tls_version == TLS_VERSION_1)
key_block_len += 2 * conn->rl.iv_size;
if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
"key expansion", seed, 2 * TLS_RANDOM_LEN,
key_block, key_block_len)) {
@ -107,12 +108,21 @@ int tls_derive_keys(struct tlsv1_client *conn,
os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
pos += conn->rl.key_material_len;
/* client_write_IV */
os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
pos += conn->rl.iv_size;
/* server_write_IV */
os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
pos += conn->rl.iv_size;
if (conn->rl.tls_version == TLS_VERSION_1) {
/* client_write_IV */
os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
pos += conn->rl.iv_size;
/* server_write_IV */
os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
pos += conn->rl.iv_size;
} else {
/*
* Use IV field to set the mask value for TLS v1.1. A fixed
* mask of zero is used per the RFC 4346, 6.2.3.2 CBC Block
* Cipher option 2a.
*/
os_memset(conn->rl.write_iv, 0, conn->rl.iv_size);
}
return 0;
}
@ -358,6 +368,8 @@ struct tlsv1_client * tlsv1_client_init(void)
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
conn->num_cipher_suites = count;
conn->rl.tls_version = TLS_VERSION;
return conn;
}

View file

@ -1,6 +1,6 @@
/*
* TLSv1 client - read handshake message
* Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
* TLS v1.0 (RFC 2246) and v1.1 (RFC 4346) client - read handshake message
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -38,6 +38,7 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
const u8 *pos, *end;
size_t left, len, i;
u16 cipher_suite;
u16 tls_version;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
@ -79,15 +80,22 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
/* ProtocolVersion server_version */
if (end - pos < 2)
goto decode_error;
if (WPA_GET_BE16(pos) != TLS_VERSION) {
tls_version = WPA_GET_BE16(pos);
if (tls_version != TLS_VERSION_1 &&
(tls_version != TLS_VERSION_1_1 ||
TLS_VERSION == TLS_VERSION_1)) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
"ServerHello");
"ServerHello %u.%u", pos[0], pos[1]);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_PROTOCOL_VERSION);
return -1;
}
pos += 2;
wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
tls_version == TLS_VERSION_1_1 ? "1.1" : "1.0");
conn->rl.tls_version = tls_version;
/* Random random */
if (end - pos < TLS_RANDOM_LEN)
goto decode_error;

View file

@ -1,5 +1,5 @@
/*
* TLSv1 client - write handshake message
* TLS v1.0 (RFC 2246) and v1.1 (RFC 4346) client - write handshake message
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
@ -774,7 +774,8 @@ u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
/* ContentType type */
*pos++ = TLS_CONTENT_TYPE_ALERT;
/* ProtocolVersion version */
WPA_PUT_BE16(pos, TLS_VERSION);
WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
TLS_VERSION);
pos += 2;
/* uint16 length (to be filled) */
length = pos;

View file

@ -1,6 +1,6 @@
/*
* TLSv1 common definitions
* Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
* TLS v1.0 (RFC 2246) and v1.1 (RFC 4346) common definitions
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -17,7 +17,13 @@
#include "crypto/crypto.h"
#define TLS_VERSION 0x0301 /* TLSv1 */
#define TLS_VERSION_1 0x0301 /* TLSv1 */
#define TLS_VERSION_1_1 0x0302 /* TLSv1.1 */
#ifdef CONFIG_TLSV11
#define TLS_VERSION TLS_VERSION_1_1
#else /* CONFIG_TLSV11 */
#define TLS_VERSION TLS_VERSION_1
#endif /* CONFIG_TLSV11 */
#define TLS_RANDOM_LEN 32
#define TLS_PRE_MASTER_SECRET_LEN 48
#define TLS_MASTER_SECRET_LEN 48

View file

@ -1,5 +1,5 @@
/*
* TLSv1 Record Protocol
* TLS v1.0 (RFC 2246) and v1.1 (RFC 4346) Record Protocol
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
@ -139,7 +139,7 @@ int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
* @rl: Pointer to TLS record layer data
* @content_type: Content type (TLS_CONTENT_TYPE_*)
* @buf: Buffer for the generated TLS message (needs to have extra space for
* header and HMAC)
* header, IV (TLS v1.1), and HMAC)
* @buf_size: Maximum buf size
* @payload: Payload to be sent
* @payload_len: Length of the payload
@ -156,6 +156,7 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
u8 *pos, *ct_start, *length, *cpayload;
struct crypto_hash *hmac;
size_t clen;
int explicit_iv;
pos = buf;
if (pos + TLS_RECORD_HEADER_LEN > buf + buf_size)
@ -165,7 +166,7 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
ct_start = pos;
*pos++ = content_type;
/* ProtocolVersion version */
WPA_PUT_BE16(pos, TLS_VERSION);
WPA_PUT_BE16(pos, rl->tls_version);
pos += 2;
/* uint16 length */
length = pos;
@ -173,6 +174,22 @@ int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
pos += 2;
cpayload = pos;
explicit_iv = rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL &&
rl->iv_size && rl->tls_version == TLS_VERSION_1_1;
if (explicit_iv) {
/* opaque IV[Cipherspec.block_length] */
if (pos + rl->iv_size > buf + buf_size)
return -1;
/*
* Use random number R per the RFC 4346, 6.2.3.2 CBC Block
* Cipher option 2a.
*/
if (os_get_random(pos, rl->iv_size))
return -1;
pos += rl->iv_size;
}
/*
* opaque fragment[TLSPlaintext.length]
@ -343,6 +360,9 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
return -1;
}
plen = in_len;
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
"data", out_data, plen);
if (rl->iv_size) {
/*
* TLS v1.0 defines different alert values for various
@ -355,6 +375,19 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
* attacks more difficult.
*/
if (rl->tls_version == TLS_VERSION_1_1) {
/* Remove opaque IV[Cipherspec.block_length] */
if (plen < rl->iv_size) {
wpa_printf(MSG_DEBUG, "TLSv1.1: Not "
"enough room for IV");
force_mac_error = 1;
goto check_mac;
}
os_memmove(out_data, out_data + rl->iv_size,
plen - rl->iv_size);
plen -= rl->iv_size;
}
/* Verify and remove padding */
if (plen == 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
@ -387,9 +420,9 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl,
}
check_mac:
wpa_hexdump(MSG_MSGDUMP,
"TLSv1: Record Layer - Decrypted data",
out_data, plen);
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 "

View file

@ -1,6 +1,6 @@
/*
* TLSv1 Record Protocol
* Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
* TLS v1.0 (RFC 2246) and v1.1 (RFC 4346) Record Protocol
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -35,6 +35,8 @@ enum {
};
struct tlsv1_record_layer {
u16 tls_version;
u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
u8 write_key[TLS_MAX_WRITE_KEY_LEN];

View file

@ -1,5 +1,5 @@
/*
* TLSv1 server (RFC 2246)
* TLS v1.0 (RFC 2246) and v1.1 (RFC 4346) server
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify

View file

@ -85,15 +85,26 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
conn->client_version = WPA_GET_BE16(pos);
wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
conn->client_version >> 8, conn->client_version & 0xff);
if (conn->client_version < TLS_VERSION) {
if (conn->client_version < TLS_VERSION_1) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
"ClientHello");
"ClientHello %u.%u",
conn->client_version >> 8,
conn->client_version & 0xff);
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_PROTOCOL_VERSION);
return -1;
}
pos += 2;
if (TLS_VERSION == TLS_VERSION_1)
conn->rl.tls_version = TLS_VERSION_1;
else if (conn->client_version > TLS_VERSION_1_1)
conn->rl.tls_version = TLS_VERSION_1_1;
else
conn->rl.tls_version = conn->client_version;
wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
conn->rl.tls_version == TLS_VERSION_1_1 ? "1.1" : "1.0");
/* Random random */
if (end - pos < TLS_RANDOM_LEN)
goto decode_error;

View file

@ -1,5 +1,5 @@
/*
* TLSv1 server - write handshake message
* TLS v1.0 (RFC 2246) and v1.1 (RFC 4346) server - write handshake message
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
@ -87,7 +87,7 @@ static int tls_write_server_hello(struct tlsv1_server *conn,
pos += 3;
/* body - ServerHello */
/* ProtocolVersion server_version */
WPA_PUT_BE16(pos, TLS_VERSION);
WPA_PUT_BE16(pos, conn->rl.tls_version);
pos += 2;
/* Random random: uint32 gmt_unix_time, opaque random_bytes */
os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
@ -764,7 +764,8 @@ u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
/* ContentType type */
*pos++ = TLS_CONTENT_TYPE_ALERT;
/* ProtocolVersion version */
WPA_PUT_BE16(pos, TLS_VERSION);
WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
TLS_VERSION);
pos += 2;
/* uint16 length (to be filled) */
length = pos;

View file

@ -806,6 +806,10 @@ ifndef CONFIG_TLS
CONFIG_TLS=openssl
endif
ifdef CONFIG_TLSV11
CFLAGS += -DCONFIG_TLSV11
endif
ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
CFLAGS += -DEAP_TLS_OPENSSL

View file

@ -335,6 +335,13 @@ CONFIG_PEERKEY=y
# apply for distribution of the resulting binary.
#CONFIG_GNUTLS_EXTRA=y
# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
# can be enabled to get a stronger construction of messages when block ciphers
# are used. It should be noted that some existing TLS v1.0 -based
# implementation may not be compatible with TLS v1.1 message (ClientHello is
# sent prior to negotiating which version will be used)
#CONFIG_TLSV11=y
# If CONFIG_TLS=internal is used, additional library and include paths are
# needed for LibTomMath. Alternatively, an integrated, minimal version of
# LibTomMath can be used. See beginning of libtommath.c for details on benefits