]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
TLS testing: Allow hostapd to be used as a TLS testing tool
authorJouni Malinen <j@w1.fi>
Sat, 1 Mar 2014 22:43:59 +0000 (00:43 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 9 Mar 2014 16:47:09 +0000 (18:47 +0200)
The internal TLS server implementation and RADIUS server implementation
in hostapd can be configured to allow EAP clients to be tested to
perform TLS validation steps correctly. This functionality is not
included in the default build; CONFIG_TESTING_OPTIONS=y in
hostapd/.config can be used to enable this.

When enabled, the RADIUS server will configure special TLS test modes
based on the received User-Name attribute value in this format:
<user>@test-tls-<id>.<rest-of-realm>. For example,
anonymous@test-tls-1.example.com. When this special format is used, TLS
test modes are enabled. For other cases, the RADIUS server works
normally.

The following TLS test cases are enabled in this commit:
1 - break verify_data in the server Finished message
2 - break signed_params hash in ServerKeyExchange
3 - break Signature in ServerKeyExchange

Correctly behaving TLS client must abort connection if any of these
failures is detected and as such, shall not transmit continue the
session.

Signed-off-by: Jouni Malinen <j@w1.fi>
12 files changed:
src/crypto/tls.h
src/crypto/tls_internal.c
src/eap_server/eap.h
src/eap_server/eap_i.h
src/eap_server/eap_server.c
src/eap_server/eap_server_tls_common.c
src/radius/radius_server.c
src/tls/tlsv1_server.c
src/tls/tlsv1_server.h
src/tls/tlsv1_server_i.h
src/tls/tlsv1_server_read.c
src/tls/tlsv1_server_write.c

index df0c7153a17a1e6c6667da1eaf1fadee412fdcaf..81e588fb86e6b7b1aac2dc24e9a8ada5e30eed6f 100644 (file)
@@ -541,4 +541,10 @@ void tls_connection_set_log_cb(struct tls_connection *conn,
                               void (*log_cb)(void *ctx, const char *msg),
                               void *ctx);
 
+#define TLS_BREAK_VERIFY_DATA BIT(0)
+#define TLS_BREAK_SRV_KEY_X_HASH BIT(1)
+#define TLS_BREAK_SRV_KEY_X_SIGNATURE BIT(2)
+
+void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags);
+
 #endif /* TLS_H */
index 7327b4b53e0acbd353c51128e5a5c24ee5622bcf..6563ed21830f01b069bd654fcbed4f60838f9fff 100644 (file)
@@ -111,6 +111,17 @@ struct tls_connection * tls_connection_init(void *tls_ctx)
 }
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags)
+{
+       if (conn->server)
+               tlsv1_server_set_test_flags(conn->server, flags);
+}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
 void tls_connection_set_log_cb(struct tls_connection *conn,
                               void (*log_cb)(void *ctx, const char *msg),
                               void *ctx)
index f1eb46871a36fe209098483414c68a14da339512..698a5ac0b289a2ee3693243d9d9eaf4255cd558b 100644 (file)
@@ -110,6 +110,10 @@ struct eap_config {
 
        const u8 *server_id;
        size_t server_id_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+       u32 tls_test_flags;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 
 
index 0180aff4b49e849867c41bfb7b1436071eea57d9..3a6802b7a7cb1b3804a7c58192ded818f405df6e 100644 (file)
@@ -191,6 +191,10 @@ struct eap_sm {
 
        const u8 *server_id;
        size_t server_id_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+       u32 tls_test_flags;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 
 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
index 19997822f694c4c5230e9603c5f86a74c7b4a4f0..65d00ddaf8e22a50ebd70529e4752e24b220fb7a 100644 (file)
@@ -1327,6 +1327,10 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx,
        sm->server_id = conf->server_id;
        sm->server_id_len = conf->server_id_len;
 
+#ifdef CONFIG_TESTING_OPTIONS
+       sm->tls_test_flags = conf->tls_test_flags;
+#endif /* CONFIG_TESTING_OPTIONS */
+
        wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
 
        return sm;
index 0afb44b66ff76f8115c50c07c2a6e4cce1238c53..01853e689717209c1eafb3c847ed4a2bff87787c 100644 (file)
@@ -63,6 +63,9 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
 
 #ifdef CONFIG_TLS_INTERNAL
        tls_connection_set_log_cb(data->conn, eap_server_tls_log_cb, sm);
+#ifdef CONFIG_TESTING_OPTIONS
+       tls_connection_set_test_flags(data->conn, sm->tls_test_flags);
+#endif /* CONFIG_TESTING_OPTIONS */
 #endif /* CONFIG_TLS_INTERNAL */
 
        if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer)) {
index 958ddf97b1ce0133ee78e37b46e889f0a0f03030..c929fe1831ad98c055d1b3aa89c1183dae4e53ed 100644 (file)
@@ -17,6 +17,7 @@
 #include "eloop.h"
 #include "eap_server/eap.h"
 #include "ap/ap_config.h"
+#include "crypto/tls.h"
 #include "radius_server.h"
 
 /**
@@ -533,6 +534,51 @@ radius_server_new_session(struct radius_server_data *data,
 }
 
 
+#ifdef CONFIG_TESTING_OPTIONS
+static void radius_server_testing_options_tls(struct radius_session *sess,
+                                             const char *tls,
+                                             struct eap_config *eap_conf)
+{
+       int test = atoi(tls);
+
+       switch (test) {
+       case 1:
+               srv_log(sess, "TLS test - break VerifyData");
+               eap_conf->tls_test_flags = TLS_BREAK_VERIFY_DATA;
+               break;
+       case 2:
+               srv_log(sess, "TLS test - break ServerKeyExchange ServerParams hash");
+               eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_HASH;
+               break;
+       case 3:
+               srv_log(sess, "TLS test - break ServerKeyExchange ServerParams Signature");
+               eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_SIGNATURE;
+               break;
+       default:
+               srv_log(sess, "Unrecognized TLS test");
+               break;
+       }
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+static void radius_server_testing_options(struct radius_session *sess,
+                                         struct eap_config *eap_conf)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+       const char *pos;
+
+       pos = os_strstr(sess->username, "@test-");
+       if (pos == NULL)
+               return;
+       pos += 6;
+       if (os_strncmp(pos, "tls-", 4) == 0)
+               radius_server_testing_options_tls(sess, pos + 4, eap_conf);
+       else
+               srv_log(sess, "Unrecognized test: %s", pos);
+#endif /* CONFIG_TESTING_OPTIONS */
+}
+
+
 static struct radius_session *
 radius_server_get_new_session(struct radius_server_data *data,
                              struct radius_client *client,
@@ -605,6 +651,7 @@ radius_server_get_new_session(struct radius_server_data *data,
        eap_conf.pwd_group = data->pwd_group;
        eap_conf.server_id = (const u8 *) data->server_id;
        eap_conf.server_id_len = os_strlen(data->server_id);
+       radius_server_testing_options(sess, &eap_conf);
        sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
                                       &eap_conf);
        if (sess->eap == NULL) {
index 16e29cb0dc6303cb2b96aabe50b97eb9e1739b49..4aeccf6a97dcdbeeaca652e3afe5c03e0ccf1ef7 100644 (file)
@@ -315,6 +315,16 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn,
                        return -1;
                }
 
+#ifdef CONFIG_TESTING_OPTIONS
+               if ((conn->test_flags &&
+                    (TLS_BREAK_VERIFY_DATA | TLS_BREAK_SRV_KEY_X_HASH |
+                     TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+                   !conn->test_failure_reported) {
+                       tlsv1_server_log(conn, "TEST-FAILURE: Client ApplData received after invalid handshake");
+                       conn->test_failure_reported = 1;
+               }
+#endif /* CONFIG_TESTING_OPTIONS */
+
                out_pos += olen;
                if (out_pos > out_end) {
                        wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
@@ -656,3 +666,11 @@ void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
        conn->log_cb = cb;
        conn->log_cb_ctx = ctx;
 }
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags)
+{
+       conn->test_flags = flags;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
index b20ff1aacb5a41a85a4000bc769aa855b6d07981..b2b28d1e1215a00b434a5f75ad8d9a819ad7acf3 100644 (file)
@@ -48,4 +48,6 @@ void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
 void tlsv1_server_set_log_cb(struct tlsv1_server *conn,
                             void (*cb)(void *ctx, const char *msg), void *ctx);
 
+void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags);
+
 #endif /* TLSV1_SERVER_H */
index 12c57fd4b9a3da97690697f1f4f03c0bb0aa7614..9a36d8f0337e2b7a8f3cee340f406b3376adc7a1 100644 (file)
@@ -58,6 +58,11 @@ struct tlsv1_server {
 
        u8 *dh_secret;
        size_t dh_secret_len;
+
+#ifdef CONFIG_TESTING_OPTIONS
+       u32 test_flags;
+       int test_failure_reported;
+#endif /* CONFIG_TESTING_OPTIONS */
 };
 
 
index cef4a7c30f85e188e4b18cd9a0baf56104ad7e73..04622b5e7a5c52ca77bf3848aeb6a923ece2b523 100644 (file)
@@ -27,6 +27,23 @@ static int tls_process_change_cipher_spec(struct tlsv1_server *conn,
                                          size_t *in_len);
 
 
+static int testing_cipher_suite_filter(struct tlsv1_server *conn, u16 suite)
+{
+#ifdef CONFIG_TESTING_OPTIONS
+       if ((conn->test_flags &
+            (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+           suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 &&
+           suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA &&
+           suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 &&
+           suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA &&
+           suite != TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
+               return 1;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+       return 0;
+}
+
+
 static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
                                    const u8 *in_data, size_t *in_len)
 {
@@ -137,6 +154,8 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
 
        cipher_suite = 0;
        for (i = 0; !cipher_suite && i < conn->num_cipher_suites; i++) {
+               if (testing_cipher_suite_filter(conn, conn->cipher_suites[i]))
+                       continue;
                c = pos;
                for (j = 0; j < num_suites; j++) {
                        u16 tmp = WPA_GET_BE16(c);
@@ -968,6 +987,15 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct,
        u8 verify_data[TLS_VERIFY_DATA_LEN];
        u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
 
+#ifdef CONFIG_TESTING_OPTIONS
+       if ((conn->test_flags &
+            (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE)) &&
+           !conn->test_failure_reported) {
+               tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after invalid ServerKeyExchange");
+               conn->test_failure_reported = 1;
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+
        if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
                tlsv1_server_log(conn, "Expected Finished; received content type 0x%x",
                                 ct);
index e56cb0f327bf3dcd40ca2f18da0380dea16570b2..619b9ab8bc696b64da2232cab4a0c134675441fc 100644 (file)
@@ -502,6 +502,12 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
 
                wpa_hexdump(MSG_MSGDUMP, "TLS: ServerKeyExchange signed_params hash",
                            hash, hlen);
+#ifdef CONFIG_TESTING_OPTIONS
+               if (conn->test_flags & TLS_BREAK_SRV_KEY_X_HASH) {
+                       tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params hash");
+                       hash[hlen - 1] ^= 0x80;
+               }
+#endif /* CONFIG_TESTING_OPTIONS */
 
                /*
                 * RFC 2246, 4.7:
@@ -527,6 +533,12 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn,
                        return -1;
                }
                WPA_PUT_BE16(signed_start, clen);
+#ifdef CONFIG_TESTING_OPTIONS
+               if (conn->test_flags & TLS_BREAK_SRV_KEY_X_SIGNATURE) {
+                       tlsv1_server_log(conn, "TESTING: Break ServerKeyExchange signed params signature");
+                       pos[clen - 1] ^= 0x80;
+               }
+#endif /* CONFIG_TESTING_OPTIONS */
 
                pos += clen;
        }
@@ -754,6 +766,12 @@ static int tls_write_server_finished(struct tlsv1_server *conn,
        }
        wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
                        verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
+#ifdef CONFIG_TESTING_OPTIONS
+       if (conn->test_flags & TLS_BREAK_VERIFY_DATA) {
+               tlsv1_server_log(conn, "TESTING: Break verify_data (server)");
+               verify_data[1 + 3 + 1] ^= 0x80;
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
 
        /* Handshake */
        pos = hs_start = verify_data;