]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
TLS: Add support for TLS v1.1 (RFC 4346) with internal TLS
authorJouni Malinen <j@w1.fi>
Sun, 25 Sep 2011 14:24:46 +0000 (17:24 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 25 Sep 2011 14:24:46 +0000 (17:24 +0300)
This is disabled by defautl and can be enabled with CONFIG_TLSV11=y
build configuration parameter.

13 files changed:
hostapd/Makefile
hostapd/defconfig
src/tls/tlsv1_client.c
src/tls/tlsv1_client_read.c
src/tls/tlsv1_client_write.c
src/tls/tlsv1_common.h
src/tls/tlsv1_record.c
src/tls/tlsv1_record.h
src/tls/tlsv1_server.c
src/tls/tlsv1_server_read.c
src/tls/tlsv1_server_write.c
wpa_supplicant/Makefile
wpa_supplicant/defconfig

index d2b85af859c0e46293bbf3bf2b0dacedd47c2661..047961e863b8149f67919d3be6f5eb8d05ceab91 100644 (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
index 26be2a83b6e5c33accd77be2f82ddc1f0d096ffb..d9b4b6d13bbc4b3335198365a00a2462477a0592 100644 (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
index d87ea4f81432abb62fd96b7540a150fee95ce212..75b8612b6210b5d610cf9caff04d2983fff7f683 100644 (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;
 }
 
index faa891aaf2dbdf317cd0506b990da20769d99650..457c3b00f831e81ac50613d57023b0a6f5412740 100644 (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;
index 91ac5af4a948f3961155f1e96b2b21668882041f..9d53dd137e23c75b7af469ccbcbe5727e752acf5 100644 (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;
index 763a4af3d5611ff43af307f4205ce05de1d721fa..712d2764b03446bc3c0216c4ee8a69c13d4249d5 100644 (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
 
 #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
index 8efdae67d7ab38e6f5cf588119bdccd2c7723a43..332f8d4b23c47bd5e1980234e7047a2f577b0fbe 100644 (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 "
index acbdccaee97b640d4b91e15f162bc9b3dd11ade8..0d62816225e0df153da3dc1441365cd44945e1e4 100644 (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];
index 06eab61ca86a9c84c82e42c2488d8e4f0486a1d2..1f48aa5f4dc39fe9330545666000797c930b3f2c 100644 (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
index fd7443656a26e8dcf6b9ea02589c15dad2152ec8..5b7ccc39b0f5738bba85e9bd8d443c63dc3f2b29 100644 (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;
index a3d32b0ab653dc685262aa61942d1165342c002d..63d70a2df4ac07e031710e3999ab5b956b97c213 100644 (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;
index de4d6adf34a7afda1ae4104816784f9de5a14119..41fd1fd39524fca56e2ccaac1c7ff6c670f21d9a 100644 (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
index dfdc2d30cc871b4c1736f102815c66f7a71936a0..e1ede9ffe4c6cdcb5a7718816081d3f8e366f722 100644 (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