]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP: PKEX counter t
authorJouni Malinen <jouni@qca.qualcomm.com>
Fri, 3 Nov 2017 15:49:45 +0000 (17:49 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 3 Nov 2017 17:59:46 +0000 (19:59 +0200)
Add limit on number of failed attempts that could have used PKEX code.
If the limit (5) is reached, drop the PKEX state (including the code)
and report this on the control interface to indicate that a new code
needs to be entered due to possible attack.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/ap/dpp_hostapd.c
src/common/dpp.c
src/common/dpp.h
src/common/wpa_ctrl.h
wpa_supplicant/dpp_supplicant.c

index f8fbc176b20019c6d347a5694cbf1552f68fc68e..45495f3b86e9c9a6a606e32d437b4a1f3d3ec616 100644 (file)
@@ -1069,6 +1069,8 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
        if (hapd->dpp_pkex->failed) {
                wpa_printf(MSG_DEBUG,
                           "DPP: Terminate PKEX exchange due to an earlier error");
+               if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
+                       hapd->dpp_pkex->own_bi->pkex_t = hapd->dpp_pkex->t;
                dpp_pkex_free(hapd->dpp_pkex);
                hapd->dpp_pkex = NULL;
        }
@@ -1134,6 +1136,9 @@ hostapd_dpp_rx_pkex_commit_reveal_req(struct hostapd_data *hapd, const u8 *src,
                wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
                if (hapd->dpp_pkex->failed) {
                        wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
+                       if (hapd->dpp_pkex->t > hapd->dpp_pkex->own_bi->pkex_t)
+                               hapd->dpp_pkex->own_bi->pkex_t =
+                                       hapd->dpp_pkex->t;
                        dpp_pkex_free(hapd->dpp_pkex);
                        hapd->dpp_pkex = NULL;
                }
@@ -1236,6 +1241,7 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
        u8 crypto_suite;
        enum dpp_public_action_frame_type type;
        const u8 *hdr;
+       unsigned int pkex_t;
 
        if (len < DPP_HDR_LEN)
                return;
@@ -1302,6 +1308,17 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
                           "DPP: Ignored unsupported frame subtype %d", type);
                break;
        }
+
+       if (hapd->dpp_pkex)
+               pkex_t = hapd->dpp_pkex->t;
+       else if (hapd->dpp_pkex_bi)
+               pkex_t = hapd->dpp_pkex_bi->pkex_t;
+       else
+               pkex_t = 0;
+       if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
+               wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
+               hostapd_dpp_pkex_remove(hapd, "*");
+       }
 }
 
 
@@ -1436,6 +1453,7 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
                return -1;
        }
        hapd->dpp_pkex_bi = own_bi;
+       own_bi->pkex_t = 0; /* clear pending errors on new code */
 
        os_free(hapd->dpp_pkex_identifier);
        hapd->dpp_pkex_identifier = NULL;
index 478ae53ff5d22389cc08d3d630b97aa83a0a1fff..566898b63583c68923bcb8d812741369c5ce9e35 100644 (file)
@@ -5769,6 +5769,12 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
        const EC_POINT *Y_point;
        BIGNUM *Nx = NULL, *Ny = NULL;
 
+       if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
+               wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
+                       "PKEX counter t limit reached - ignore message");
+               return NULL;
+       }
+
        attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER,
                               &attr_id_len);
        if (!attr_id && identifier) {
@@ -5841,12 +5847,14 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
            !EC_POINT_is_on_curve(group, X, bnctx)) {
                wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
                        "Invalid Encrypted Key value");
+               bi->pkex_t++;
                goto fail;
        }
 
        pkex = os_zalloc(sizeof(*pkex));
        if (!pkex)
                goto fail;
+       pkex->t = bi->pkex_t;
        pkex->msg_ctx = msg_ctx;
        pkex->own_bi = bi;
        os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
@@ -6103,7 +6111,7 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
        u8 u[DPP_MAX_HASH_LEN];
        int res;
 
-       if (pkex->failed)
+       if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT)
                return NULL;
 
        attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
@@ -6176,6 +6184,7 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
            EC_POINT_is_at_infinity(group, Y) ||
            !EC_POINT_is_on_curve(group, Y, bnctx)) {
                dpp_pkex_fail(pkex, "Invalid Encrypted Key value");
+               pkex->t++;
                goto fail;
        }
 
@@ -6396,7 +6405,8 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
        u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN];
        int res;
 
-       if (!pkex->exchange_done || pkex->failed)
+       if (!pkex->exchange_done || pkex->failed ||
+           pkex->t >= PKEX_COUNTER_T_LIMIT)
                goto fail;
 
        /* K = y * X' */
@@ -6455,6 +6465,7 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
                dpp_pkex_fail(pkex,
                              "AES-SIV decryption failed - possible PKEX code mismatch");
                pkex->failed = 1;
+               pkex->t++;
                goto fail;
        }
        wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
@@ -6523,6 +6534,7 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
                wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'",
                            u, curve->hash_len);
                wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len);
+               pkex->t++;
                goto fail;
        }
        wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received");
@@ -6598,7 +6610,8 @@ int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
        EVP_PKEY_CTX *ctx = NULL;
        struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL;
 
-       if (!pkex->exchange_done || pkex->failed)
+       if (!pkex->exchange_done || pkex->failed ||
+           pkex->t >= PKEX_COUNTER_T_LIMIT)
                goto fail;
 
        wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA,
@@ -6629,6 +6642,7 @@ int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
                            2, addr, len, unwrapped) < 0) {
                dpp_pkex_fail(pkex,
                              "AES-SIV decryption failed - possible PKEX code mismatch");
+               pkex->t++;
                goto fail;
        }
        wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
@@ -6696,6 +6710,7 @@ int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
                wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'",
                            v, curve->hash_len);
                wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len);
+               pkex->t++;
                goto fail;
        }
        wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received");
index d55c30e5d5936cd524145dbc0c5498466532c43f..c60d90f427c0d45fbcb604680fe5eb0779255b83 100644 (file)
@@ -107,8 +107,12 @@ struct dpp_bootstrap_info {
        EVP_PKEY *pubkey;
        u8 pubkey_hash[SHA256_MAC_LEN];
        const struct dpp_curve_params *curve;
+       unsigned int pkex_t; /* number of failures before dpp_pkex
+                             * instantiation */
 };
 
+#define PKEX_COUNTER_T_LIMIT 5
+
 struct dpp_pkex {
        void *msg_ctx;
        unsigned int initiator:1;
@@ -127,6 +131,7 @@ struct dpp_pkex {
        EVP_PKEY *peer_bootstrap_key;
        struct wpabuf *exchange_req;
        struct wpabuf *exchange_resp;
+       unsigned int t; /* number of failures on code use */
 };
 
 struct dpp_configuration {
index 6e9dcf14a615e956559dfc55faccdd3489265567..b3fd287b87cc24a6e96124e382b6cd5eb1e3a5ce 100644 (file)
@@ -171,6 +171,7 @@ extern "C" {
 #define DPP_EVENT_TX "DPP-TX "
 #define DPP_EVENT_TX_STATUS "DPP-TX-STATUS "
 #define DPP_EVENT_FAIL "DPP-FAIL "
+#define DPP_EVENT_PKEX_T_LIMIT "DPP-PKEX-T-LIMIT "
 #define DPP_EVENT_INTRO "DPP-INTRO "
 
 /* MESH events */
index 87131f5fdca11b96dbebba93a0e9b4a4087a7027..74dbb9311328ec7d2db4948cf945787482ede3bb 100644 (file)
@@ -1437,6 +1437,8 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
        if (wpa_s->dpp_pkex->failed) {
                wpa_printf(MSG_DEBUG,
                           "DPP: Terminate PKEX exchange due to an earlier error");
+               if (wpa_s->dpp_pkex->t > wpa_s->dpp_pkex->own_bi->pkex_t)
+                       wpa_s->dpp_pkex->own_bi->pkex_t = wpa_s->dpp_pkex->t;
                dpp_pkex_free(wpa_s->dpp_pkex);
                wpa_s->dpp_pkex = NULL;
        }
@@ -1558,6 +1560,8 @@ wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant *wpa_s, const u8 *src,
                wpa_printf(MSG_DEBUG, "DPP: Failed to process the request");
                if (pkex->failed) {
                        wpa_printf(MSG_DEBUG, "DPP: Terminate PKEX exchange");
+                       if (pkex->t > pkex->own_bi->pkex_t)
+                               pkex->own_bi->pkex_t = pkex->t;
                        dpp_pkex_free(wpa_s->dpp_pkex);
                        wpa_s->dpp_pkex = NULL;
                }
@@ -1664,6 +1668,7 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
        u8 crypto_suite;
        enum dpp_public_action_frame_type type;
        const u8 *hdr;
+       unsigned int pkex_t;
 
        if (len < DPP_HDR_LEN)
                return;
@@ -1730,6 +1735,17 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
                           "DPP: Ignored unsupported frame subtype %d", type);
                break;
        }
+
+       if (wpa_s->dpp_pkex)
+               pkex_t = wpa_s->dpp_pkex->t;
+       else if (wpa_s->dpp_pkex_bi)
+               pkex_t = wpa_s->dpp_pkex_bi->pkex_t;
+       else
+               pkex_t = 0;
+       if (pkex_t >= PKEX_COUNTER_T_LIMIT) {
+               wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PKEX_T_LIMIT "id=0");
+               wpas_dpp_pkex_remove(wpa_s, "*");
+       }
 }
 
 
@@ -2009,6 +2025,7 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
                return -1;
        }
        wpa_s->dpp_pkex_bi = own_bi;
+       own_bi->pkex_t = 0; /* clear pending errors on new code */
 
        os_free(wpa_s->dpp_pkex_identifier);
        wpa_s->dpp_pkex_identifier = NULL;