From 60239f60a613c0f7e65293f50258a640d2724217 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 22 Oct 2017 11:15:21 +0300 Subject: [PATCH] DPP: Protocol testing framework Add a generic mechanism for configuring the DPP implementation to behave in particular different (mostly incorrect) ways for protocol testing purposes. The new dpp_test parameter can be set to a non-zero integer to indicate a specific behavior. This is only available in CONFIG_TESTING_OPTIONS=y builds. This commit include cases for an extra attribute being added after the Wrapped Data attribute and Initiator/Responder capabilities having an unexpected zero capability. Signed-off-by: Jouni Malinen --- hostapd/ctrl_iface.c | 10 +++ src/common/dpp.c | 139 +++++++++++++++++++++++++++++++++--- src/common/dpp.h | 18 +++++ wpa_supplicant/ctrl_iface.c | 6 ++ 4 files changed, 164 insertions(+), 9 deletions(-) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index b3ef8d34a..af2a2821b 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -29,6 +29,7 @@ #include "common/version.h" #include "common/ieee802_11_defs.h" #include "common/ctrl_iface_common.h" +#include "common/dpp.h" #include "crypto/tls.h" #include "drivers/driver.h" #include "eapol_auth/eapol_auth_sm.h" @@ -1301,6 +1302,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) } else if (os_strcasecmp(cmd, "dpp_ignore_netaccesskey_mismatch") == 0) { hapd->dpp_ignore_netaccesskey_mismatch = atoi(value); + } else if (os_strcasecmp(cmd, "dpp_test") == 0) { + dpp_test = atoi(value); #endif /* CONFIG_DPP */ #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_MBO @@ -3508,6 +3511,13 @@ static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces) wps_testing_dummy_cred = 0; wps_corrupt_pkhash = 0; #endif /* CONFIG_WPS_TESTING */ + +#ifdef CONFIG_TESTING_OPTIONS +#ifdef CONFIG_DPP + dpp_test = DPP_TEST_DISABLED; +#endif /* CONFIG_DPP */ +#endif /* CONFIG_TESTING_OPTIONS */ + } diff --git a/src/common/dpp.c b/src/common/dpp.c index 51079506b..fa98db2f3 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -25,6 +25,10 @@ #include "dpp.h" +#ifdef CONFIG_TESTING_OPTIONS +enum dpp_test_behavior dpp_test = DPP_TEST_DISABLED; +#endif /* CONFIG_TESTING_OPTIONS */ + #if OPENSSL_VERSION_NUMBER < 0x10100000L /* Compatibility wrappers for older versions. */ @@ -1396,6 +1400,10 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx, /* Build DPP Authentication Request frame attributes */ attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + wpabuf_len(pi) + 4 + sizeof(wrapped_data); +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) + attr_len += 4; +#endif /* CONFIG_TESTING_OPTIONS */ msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len); if (!msg) goto fail; @@ -1440,6 +1448,12 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx, auth->i_capab = configurator ? DPP_CAPAB_CONFIGURATOR : DPP_CAPAB_ENROLLEE; *pos++ = auth->i_capab; +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_ZERO_I_CAPAB) { + wpa_printf(MSG_INFO, "DPP: TESTING - zero I-capabilities"); + pos[-1] = 0; + } +#endif /* CONFIG_TESTING_OPTIONS */ attr_end = wpabuf_put(msg, 0); @@ -1466,6 +1480,14 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx, wpabuf_put_le16(msg, siv_len); wpabuf_put_data(msg, wrapped_data, siv_len); +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ) { + wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); + wpabuf_put_le16(msg, DPP_ATTR_TESTING); + wpabuf_put_le16(msg, 0); + } +#endif /* CONFIG_TESTING_OPTIONS */ + wpa_hexdump_buf(MSG_DEBUG, "DPP: Authentication Request frame attributes", msg); @@ -1485,6 +1507,7 @@ struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth, size_t json_len, clear_len; struct wpabuf *clear = NULL, *msg = NULL; u8 *wrapped; + size_t attr_len; wpa_printf(MSG_DEBUG, "DPP: Build configuration request"); @@ -1500,7 +1523,12 @@ struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth, /* { E-nonce, configAttrib }ke */ clear_len = 4 + nonce_len + 4 + json_len; clear = wpabuf_alloc(clear_len); - msg = wpabuf_alloc(4 + clear_len + AES_BLOCK_SIZE); + attr_len = 4 + clear_len + AES_BLOCK_SIZE; +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) + attr_len += 4; +#endif /* CONFIG_TESTING_OPTIONS */ + msg = wpabuf_alloc(attr_len); if (!clear || !msg) goto fail; @@ -1527,6 +1555,14 @@ struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth, wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ) { + wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); + wpabuf_put_le16(msg, DPP_ATTR_TESTING); + wpabuf_put_le16(msg, 0); + } +#endif /* CONFIG_TESTING_OPTIONS */ + wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Request frame attributes", msg); wpabuf_free(clear); @@ -1940,6 +1976,10 @@ static int dpp_auth_build_resp(struct dpp_authentication *auth) /* Build DPP Authentication Response frame attributes */ attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) + 4 + wpabuf_len(pr) + 4 + sizeof(wrapped_data); +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) + attr_len += 4; +#endif /* CONFIG_TESTING_OPTIONS */ msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len); if (!msg) goto fail; @@ -2000,6 +2040,12 @@ static int dpp_auth_build_resp(struct dpp_authentication *auth) auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR : DPP_CAPAB_ENROLLEE; *pos++ = auth->r_capab; +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_ZERO_R_CAPAB) { + wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities"); + pos[-1] = 0; + } +#endif /* CONFIG_TESTING_OPTIONS */ /* {R-auth}ke */ WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA); pos += 2; @@ -2031,6 +2077,14 @@ static int dpp_auth_build_resp(struct dpp_authentication *auth) wpabuf_put_le16(msg, siv_len); wpabuf_put_data(msg, wrapped_data, siv_len); +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) { + wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); + wpabuf_put_le16(msg, DPP_ATTR_TESTING); + wpabuf_put_le16(msg, 0); + } +#endif /* CONFIG_TESTING_OPTIONS */ + wpa_hexdump_buf(MSG_DEBUG, "DPP: Authentication Response frame attributes", msg); @@ -2059,6 +2113,10 @@ static int dpp_auth_build_resp_status(struct dpp_authentication *auth, /* Build DPP Authentication Response frame attributes */ attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) + 4 + sizeof(wrapped_data); +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) + attr_len += 4; +#endif /* CONFIG_TESTING_OPTIONS */ msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len); if (!msg) goto fail; @@ -2106,6 +2164,12 @@ static int dpp_auth_build_resp_status(struct dpp_authentication *auth, auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR : DPP_CAPAB_ENROLLEE; *pos++ = auth->r_capab; +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_ZERO_R_CAPAB) { + wpa_printf(MSG_INFO, "DPP: TESTING - zero R-capabilities"); + pos[-1] = 0; + } +#endif /* CONFIG_TESTING_OPTIONS */ /* OUI, OUI type, Crypto Suite, DPP frame type */ addr[0] = wpabuf_head_u8(msg) + 2; @@ -2130,6 +2194,14 @@ static int dpp_auth_build_resp_status(struct dpp_authentication *auth, wpabuf_put_le16(msg, siv_len); wpabuf_put_data(msg, wrapped_data, siv_len); +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP) { + wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); + wpabuf_put_le16(msg, DPP_ATTR_TESTING); + wpabuf_put_le16(msg, 0); + } +#endif /* CONFIG_TESTING_OPTIONS */ + wpa_hexdump_buf(MSG_DEBUG, "DPP: Authentication Response frame attributes", msg); @@ -2378,6 +2450,10 @@ static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth) /* Build DPP Authentication Confirmation frame attributes */ attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) + 4 + i_auth_len + AES_BLOCK_SIZE; +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) + attr_len += 4; +#endif /* CONFIG_TESTING_OPTIONS */ msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len); if (!msg) goto fail; @@ -2428,6 +2504,14 @@ static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth) wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke", wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE); +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF) { + wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); + wpabuf_put_le16(msg, DPP_ATTR_TESTING); + wpabuf_put_le16(msg, 0); + } +#endif /* CONFIG_TESTING_OPTIONS */ + wpa_hexdump_buf(MSG_DEBUG, "DPP: Authentication Confirmation frame attributes", msg); @@ -3319,7 +3403,7 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, u16 e_nonce_len, int ap) { struct wpabuf *conf; - size_t clear_len; + size_t clear_len, attr_len; struct wpabuf *clear = NULL, *msg = NULL; u8 *wrapped; const u8 *addr[1]; @@ -3338,7 +3422,12 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, if (conf) clear_len += 4 + wpabuf_len(conf); clear = wpabuf_alloc(clear_len); - msg = wpabuf_alloc(4 + 1 + 4 + clear_len + AES_BLOCK_SIZE); + attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE; +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) + attr_len += 4; +#endif /* CONFIG_TESTING_OPTIONS */ + msg = wpabuf_alloc(attr_len); if (!clear || !msg) goto fail; @@ -3378,6 +3467,14 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, wpabuf_free(clear); clear = NULL; +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP) { + wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); + wpabuf_put_le16(msg, DPP_ATTR_TESTING); + wpabuf_put_le16(msg, 0); + } +#endif /* CONFIG_TESTING_OPTIONS */ + wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response attributes", msg); return msg; @@ -5406,7 +5503,7 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, u16 attr_status_len, attr_id_len, attr_key_len; const EC_GROUP *group; BN_CTX *bnctx = NULL; - size_t clear_len; + size_t clear_len, attr_len; struct wpabuf *clear = NULL; u8 *wrapped; struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL; @@ -5559,8 +5656,12 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, /* {A, u, [bootstrapping info]}z */ clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len; clear = wpabuf_alloc(clear_len); - msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, - 4 + clear_len + AES_BLOCK_SIZE); + attr_len = 4 + clear_len + AES_BLOCK_SIZE; +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) + attr_len += 4; +#endif /* CONFIG_TESTING_OPTIONS */ + msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len); if (!clear || !msg) goto fail; @@ -5594,6 +5695,14 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) { + wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); + wpabuf_put_le16(msg, DPP_ATTR_TESTING); + wpabuf_put_le16(msg, 0); + } +#endif /* CONFIG_TESTING_OPTIONS */ + out: wpabuf_free(clear); wpabuf_free(A_pub); @@ -5635,7 +5744,7 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex, struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL; struct wpabuf *B_pub = NULL; u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN]; - size_t clear_len; + size_t clear_len, attr_len; struct wpabuf *clear = NULL; u8 *wrapped; int res; @@ -5803,8 +5912,12 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex, /* {B, v [bootstrapping info]}z */ clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len; clear = wpabuf_alloc(clear_len); - msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, - 4 + clear_len + AES_BLOCK_SIZE); + attr_len = 4 + clear_len + AES_BLOCK_SIZE; +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) + attr_len += 4; +#endif /* CONFIG_TESTING_OPTIONS */ + msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len); if (!clear || !msg) goto fail; @@ -5837,6 +5950,14 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex, goto fail; wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); + +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) { + wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); + wpabuf_put_le16(msg, DPP_ATTR_TESTING); + wpabuf_put_le16(msg, 0); + } +#endif /* CONFIG_TESTING_OPTIONS */ out: EVP_PKEY_CTX_free(ctx); os_free(unwrapped); diff --git a/src/common/dpp.h b/src/common/dpp.h index dfee49918..f6bc5af01 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -52,6 +52,7 @@ enum dpp_attribute_id { DPP_ATTR_ENROLLEE_NONCE = 0x1014, DPP_ATTR_CODE_IDENTIFIER = 0x1015, DPP_ATTR_TRANSACTION_ID = 0x1016, + DPP_ATTR_TESTING = 0x10ff, /* not defined in the DPP tech spec */ }; enum dpp_status_error { @@ -203,6 +204,23 @@ struct dpp_introduction { size_t pmk_len; }; +#ifdef CONFIG_TESTING_OPTIONS +enum dpp_test_behavior { + DPP_TEST_DISABLED = 0, + DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ = 1, + DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP = 2, + DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF = 3, + DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ = 4, + DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP = 5, + DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ = 6, + DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP = 7, + DPP_TEST_ZERO_I_CAPAB = 8, + DPP_TEST_ZERO_R_CAPAB = 9, +}; + +extern enum dpp_test_behavior dpp_test; +#endif /* CONFIG_TESTING_OPTIONS */ + void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info); const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type); int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index c4d8dfe34..dbc654a2a 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -20,6 +20,7 @@ #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" +#include "common/dpp.h" #include "crypto/tls.h" #include "ap/hostapd.h" #include "eap_peer/eap.h" @@ -655,6 +656,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, } else if (os_strcasecmp(cmd, "dpp_ignore_netaccesskey_mismatch") == 0) { wpa_s->dpp_ignore_netaccesskey_mismatch = atoi(value); + } else if (os_strcasecmp(cmd, "dpp_test") == 0) { + dpp_test = atoi(value); #endif /* CONFIG_DPP */ #endif /* CONFIG_TESTING_OPTIONS */ #ifndef CONFIG_NO_CONFIG_BLOBS @@ -7778,6 +7781,9 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->get_pref_freq_list_override = NULL; wpabuf_free(wpa_s->sae_commit_override); wpa_s->sae_commit_override = NULL; +#ifdef CONFIG_DPP + dpp_test = DPP_TEST_DISABLED; +#endif /* CONFIG_DPP */ #endif /* CONFIG_TESTING_OPTIONS */ wpa_s->disconnected = 0;