LCOV - code coverage report
Current view: top level - src/ap - peerkey_auth.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1401264779 Lines: 109 149 73.2 %
Date: 2014-05-28 Functions: 7 9 77.8 %

          Line data    Source code
       1             : /*
       2             :  * hostapd - PeerKey for Direct Link Setup (DLS)
       3             :  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "utils/includes.h"
      10             : 
      11             : #include "utils/common.h"
      12             : #include "utils/eloop.h"
      13             : #include "crypto/sha1.h"
      14             : #include "crypto/sha256.h"
      15             : #include "crypto/random.h"
      16             : #include "wpa_auth.h"
      17             : #include "wpa_auth_i.h"
      18             : #include "wpa_auth_ie.h"
      19             : 
      20             : #ifdef CONFIG_PEERKEY
      21             : 
      22           0 : static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
      23             : {
      24             : #if 0
      25             :         struct wpa_authenticator *wpa_auth = eloop_ctx;
      26             :         struct wpa_stsl_negotiation *neg = timeout_ctx;
      27             : #endif
      28             : 
      29             :         /* TODO: ? */
      30           0 : }
      31             : 
      32             : 
      33             : struct wpa_stsl_search {
      34             :         const u8 *addr;
      35             :         struct wpa_state_machine *sm;
      36             : };
      37             : 
      38             : 
      39          11 : static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
      40             : {
      41          11 :         struct wpa_stsl_search *search = ctx;
      42          11 :         if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
      43           6 :                 search->sm = sm;
      44           6 :                 return 1;
      45             :         }
      46           5 :         return 0;
      47             : }
      48             : 
      49             : 
      50           3 : static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
      51             :                                struct wpa_state_machine *sm, const u8 *peer,
      52             :                                u16 mui, u16 error_type)
      53             : {
      54             :         u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
      55             :                2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
      56             :         u8 *pos;
      57             :         struct rsn_error_kde error;
      58             : 
      59           3 :         wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
      60             :                         "Sending SMK Error");
      61             : 
      62           3 :         pos = kde;
      63             : 
      64           3 :         if (peer) {
      65           3 :                 pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
      66             :                                   NULL, 0);
      67             :         }
      68             : 
      69           3 :         error.mui = host_to_be16(mui);
      70           3 :         error.error_type = host_to_be16(error_type);
      71           3 :         pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
      72             :                           (u8 *) &error, sizeof(error), NULL, 0);
      73             : 
      74           3 :         __wpa_send_eapol(wpa_auth, sm,
      75             :                          WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
      76             :                          WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
      77           3 :                          NULL, NULL, kde, pos - kde, 0, 0, 0);
      78           3 : }
      79             : 
      80             : 
      81           4 : void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
      82             :                 struct wpa_state_machine *sm, struct wpa_eapol_key *key)
      83             : {
      84             :         struct wpa_eapol_ie_parse kde;
      85             :         struct wpa_stsl_search search;
      86             :         u8 *buf, *pos;
      87             :         size_t buf_len;
      88             : 
      89           4 :         if (wpa_parse_kde_ies((const u8 *) (key + 1),
      90           4 :                               WPA_GET_BE16(key->key_data_length), &kde) < 0) {
      91           0 :                 wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
      92           0 :                 return;
      93             :         }
      94             : 
      95           8 :         if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
      96           4 :             kde.mac_addr_len < ETH_ALEN) {
      97           0 :                 wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
      98             :                            "SMK M1");
      99           0 :                 return;
     100             :         }
     101             : 
     102             :         /* Initiator = sm->addr; Peer = kde.mac_addr */
     103             : 
     104           4 :         search.addr = kde.mac_addr;
     105           4 :         search.sm = NULL;
     106           4 :         if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
     107           3 :             0 || search.sm == NULL) {
     108           6 :                 wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
     109             :                            " aborted - STA not associated anymore",
     110           6 :                            MAC2STR(kde.mac_addr));
     111           1 :                 wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
     112             :                                    STK_ERR_STA_NR);
     113             :                 /* FIX: wpa_stsl_remove(wpa_auth, neg); */
     114           1 :                 return;
     115             :         }
     116             : 
     117           3 :         buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
     118           3 :         buf = os_malloc(buf_len);
     119           3 :         if (buf == NULL)
     120           0 :                 return;
     121             :         /* Initiator RSN IE */
     122           3 :         os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
     123           3 :         pos = buf + kde.rsn_ie_len;
     124             :         /* Initiator MAC Address */
     125           3 :         pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
     126             :                           NULL, 0);
     127             : 
     128             :         /* SMK M2:
     129             :          * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
     130             :          *           MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
     131             :          */
     132             : 
     133           3 :         wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
     134             :                         "Sending SMK M2");
     135             : 
     136           6 :         __wpa_send_eapol(wpa_auth, search.sm,
     137             :                          WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
     138             :                          WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
     139           6 :                          NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
     140             : 
     141           3 :         os_free(buf);
     142             : }
     143             : 
     144             : 
     145           1 : static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
     146             :                             struct wpa_state_machine *sm,
     147             :                             struct wpa_eapol_key *key,
     148             :                             struct wpa_eapol_ie_parse *kde,
     149             :                             const u8 *smk)
     150             : {
     151             :         u8 *buf, *pos;
     152             :         size_t buf_len;
     153             :         u32 lifetime;
     154             : 
     155             :         /* SMK M4:
     156             :          * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
     157             :          *           MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
     158             :          *           Lifetime KDE)
     159             :          */
     160             : 
     161           1 :         buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
     162             :                 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
     163             :                 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
     164             :                 2 + RSN_SELECTOR_LEN + sizeof(lifetime);
     165           1 :         pos = buf = os_malloc(buf_len);
     166           1 :         if (buf == NULL)
     167           1 :                 return;
     168             : 
     169             :         /* Initiator MAC Address */
     170           1 :         pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
     171             :                           NULL, 0);
     172             : 
     173             :         /* Initiator Nonce */
     174           1 :         pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
     175             :                           NULL, 0);
     176             : 
     177             :         /* SMK with PNonce */
     178           1 :         pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
     179           1 :                           key->key_nonce, WPA_NONCE_LEN);
     180             : 
     181             :         /* Lifetime */
     182           1 :         lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
     183           1 :         pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
     184             :                           (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
     185             : 
     186           1 :         wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
     187             :                         "Sending SMK M4");
     188             : 
     189           2 :         __wpa_send_eapol(wpa_auth, sm,
     190             :                          WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
     191             :                          WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
     192           2 :                          NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
     193             : 
     194           1 :         os_free(buf);
     195             : }
     196             : 
     197             : 
     198           1 : static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
     199             :                             struct wpa_state_machine *sm,
     200             :                             struct wpa_eapol_key *key,
     201             :                             struct wpa_eapol_ie_parse *kde,
     202             :                             const u8 *smk, const u8 *peer)
     203             : {
     204             :         u8 *buf, *pos;
     205             :         size_t buf_len;
     206             :         u32 lifetime;
     207             : 
     208             :         /* SMK M5:
     209             :          * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
     210             :          *           MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
     211             :          *                             Lifetime KDE))
     212             :          */
     213             : 
     214           1 :         buf_len = kde->rsn_ie_len +
     215             :                 2 + RSN_SELECTOR_LEN + ETH_ALEN +
     216             :                 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
     217             :                 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
     218             :                 2 + RSN_SELECTOR_LEN + sizeof(lifetime);
     219           1 :         pos = buf = os_malloc(buf_len);
     220           1 :         if (buf == NULL)
     221           1 :                 return;
     222             : 
     223             :         /* Peer RSN IE */
     224           1 :         os_memcpy(pos, kde->rsn_ie, kde->rsn_ie_len);
     225           1 :         pos += kde->rsn_ie_len;
     226             : 
     227             :         /* Peer MAC Address */
     228           1 :         pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
     229             : 
     230             :         /* PNonce */
     231           1 :         pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
     232             :                           WPA_NONCE_LEN, NULL, 0);
     233             : 
     234             :         /* SMK and INonce */
     235           1 :         pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
     236             :                           kde->nonce, WPA_NONCE_LEN);
     237             : 
     238             :         /* Lifetime */
     239           1 :         lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
     240           1 :         pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
     241             :                           (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
     242             : 
     243           1 :         wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
     244             :                         "Sending SMK M5");
     245             : 
     246           1 :         __wpa_send_eapol(wpa_auth, sm,
     247             :                          WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
     248             :                          WPA_KEY_INFO_SMK_MESSAGE,
     249           1 :                          NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
     250             : 
     251           1 :         os_free(buf);
     252             : }
     253             : 
     254             : 
     255           1 : void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
     256             :                 struct wpa_state_machine *sm, struct wpa_eapol_key *key)
     257             : {
     258             :         struct wpa_eapol_ie_parse kde;
     259             :         struct wpa_stsl_search search;
     260             :         u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
     261             : 
     262           1 :         if (wpa_parse_kde_ies((const u8 *) (key + 1),
     263           1 :                               WPA_GET_BE16(key->key_data_length), &kde) < 0) {
     264           0 :                 wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
     265           0 :                 return;
     266             :         }
     267             : 
     268           2 :         if (kde.rsn_ie == NULL ||
     269           3 :             kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
     270           2 :             kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
     271           0 :                 wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
     272             :                            "Nonce KDE in SMK M3");
     273           0 :                 return;
     274             :         }
     275             : 
     276             :         /* Peer = sm->addr; Initiator = kde.mac_addr;
     277             :          * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
     278             : 
     279           1 :         search.addr = kde.mac_addr;
     280           1 :         search.sm = NULL;
     281           1 :         if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
     282           1 :             0 || search.sm == NULL) {
     283           0 :                 wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
     284             :                            " aborted - STA not associated anymore",
     285           0 :                            MAC2STR(kde.mac_addr));
     286           0 :                 wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
     287             :                                    STK_ERR_STA_NR);
     288             :                 /* FIX: wpa_stsl_remove(wpa_auth, neg); */
     289           0 :                 return;
     290             :         }
     291             : 
     292           1 :         if (random_get_bytes(smk, PMK_LEN)) {
     293           0 :                 wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
     294           0 :                 return;
     295             :         }
     296             : 
     297             :         /* SMK = PRF-256(Random number, "SMK Derivation",
     298             :          *               AA || Time || INonce || PNonce)
     299             :          */
     300           1 :         os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
     301           1 :         pos = buf + ETH_ALEN;
     302           1 :         wpa_get_ntp_timestamp(pos);
     303           1 :         pos += 8;
     304           1 :         os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
     305           1 :         pos += WPA_NONCE_LEN;
     306           1 :         os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
     307             : #ifdef CONFIG_IEEE80211W
     308           1 :         sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
     309             :                    smk, PMK_LEN);
     310             : #else /* CONFIG_IEEE80211W */
     311             :         sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
     312             :                  smk, PMK_LEN);
     313             : #endif /* CONFIG_IEEE80211W */
     314             : 
     315           1 :         wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
     316             : 
     317           1 :         wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
     318           1 :         wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
     319             : 
     320             :         /* Authenticator does not need SMK anymore and it is required to forget
     321             :          * it. */
     322           1 :         os_memset(smk, 0, sizeof(*smk));
     323             : }
     324             : 
     325             : 
     326           2 : void wpa_smk_error(struct wpa_authenticator *wpa_auth,
     327             :                    struct wpa_state_machine *sm, struct wpa_eapol_key *key)
     328             : {
     329             :         struct wpa_eapol_ie_parse kde;
     330             :         struct wpa_stsl_search search;
     331             :         struct rsn_error_kde error;
     332             :         u16 mui, error_type;
     333             : 
     334           2 :         if (wpa_parse_kde_ies((const u8 *) (key + 1),
     335           2 :                               WPA_GET_BE16(key->key_data_length), &kde) < 0) {
     336           0 :                 wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
     337           0 :                 return;
     338             :         }
     339             : 
     340           4 :         if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
     341           4 :             kde.error == NULL || kde.error_len < sizeof(error)) {
     342           0 :                 wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
     343             :                            "SMK Error");
     344           0 :                 return;
     345             :         }
     346             : 
     347           2 :         search.addr = kde.mac_addr;
     348           2 :         search.sm = NULL;
     349           2 :         if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
     350           2 :             0 || search.sm == NULL) {
     351           0 :                 wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
     352             :                            "associated for SMK Error message from " MACSTR,
     353           0 :                            MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
     354           0 :                 return;
     355             :         }
     356             : 
     357           2 :         os_memcpy(&error, kde.error, sizeof(error));
     358           2 :         mui = be_to_host16(error.mui);
     359           2 :         error_type = be_to_host16(error.error_type);
     360          14 :         wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
     361             :                          "STA reported SMK Error: Peer " MACSTR
     362             :                          " MUI %d Error Type %d",
     363          12 :                          MAC2STR(kde.mac_addr), mui, error_type);
     364             : 
     365           2 :         wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
     366             : }
     367             : 
     368             : 
     369           0 : int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
     370             :                     struct wpa_stsl_negotiation *neg)
     371             : {
     372             :         struct wpa_stsl_negotiation *pos, *prev;
     373             : 
     374           0 :         if (wpa_auth == NULL)
     375           0 :                 return -1;
     376           0 :         pos = wpa_auth->stsl_negotiations;
     377           0 :         prev = NULL;
     378           0 :         while (pos) {
     379           0 :                 if (pos == neg) {
     380           0 :                         if (prev)
     381           0 :                                 prev->next = pos->next;
     382             :                         else
     383           0 :                                 wpa_auth->stsl_negotiations = pos->next;
     384             : 
     385           0 :                         eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
     386           0 :                         os_free(pos);
     387           0 :                         return 0;
     388             :                 }
     389           0 :                 prev = pos;
     390           0 :                 pos = pos->next;
     391             :         }
     392             : 
     393           0 :         return -1;
     394             : }
     395             : 
     396             : #endif /* CONFIG_PEERKEY */

Generated by: LCOV version 1.10