TLS testing: Allow hostapd to be used as a TLS testing tool
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>
This commit is contained in:
parent
994afe3390
commit
390b92913a
12 changed files with 150 additions and 0 deletions
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue