Home | History | Annotate | Line # | Download | only in ap
      1 /*
      2  * hostapd / Comeback token mechanism for SAE
      3  * Copyright (c) 2002-2017, Jouni Malinen <j (at) 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 "hostapd.h"
     13 #include "crypto/sha256.h"
     14 #include "crypto/random.h"
     15 #include "common/ieee802_11_defs.h"
     16 #include "comeback_token.h"
     17 
     18 
     19 #if defined(CONFIG_SAE) || defined(CONFIG_PASN)
     20 
     21 static int comeback_token_hash(const u8 *comeback_key, const u8 *addr, u8 *idx)
     22 {
     23 	u8 hash[SHA256_MAC_LEN];
     24 
     25 	if (hmac_sha256(comeback_key, COMEBACK_KEY_SIZE,
     26 			addr, ETH_ALEN, hash) < 0)
     27 		return -1;
     28 	*idx = hash[0];
     29 	return 0;
     30 }
     31 
     32 
     33 int check_comeback_token(const u8 *comeback_key,
     34 			 u16 *comeback_pending_idx, const u8 *addr,
     35 			 const u8 *token, size_t token_len)
     36 {
     37 	u8 mac[SHA256_MAC_LEN];
     38 	const u8 *addrs[2];
     39 	size_t len[2];
     40 	u16 token_idx;
     41 	u8 idx;
     42 
     43 	if (token_len != SHA256_MAC_LEN ||
     44 	    comeback_token_hash(comeback_key, addr, &idx) < 0)
     45 		return -1;
     46 	token_idx = comeback_pending_idx[idx];
     47 	if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
     48 		wpa_printf(MSG_DEBUG,
     49 			   "Comeback: Invalid anti-clogging token from "
     50 			   MACSTR " - token_idx 0x%04x, expected 0x%04x",
     51 			   MAC2STR(addr), WPA_GET_BE16(token), token_idx);
     52 		return -1;
     53 	}
     54 
     55 	addrs[0] = addr;
     56 	len[0] = ETH_ALEN;
     57 	addrs[1] = token;
     58 	len[1] = 2;
     59 	if (hmac_sha256_vector(comeback_key, COMEBACK_KEY_SIZE,
     60 			       2, addrs, len, mac) < 0 ||
     61 	    os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
     62 		return -1;
     63 
     64 	comeback_pending_idx[idx] = 0; /* invalidate used token */
     65 
     66 	return 0;
     67 }
     68 
     69 
     70 struct wpabuf *
     71 auth_build_token_req(struct os_reltime *last_comeback_key_update,
     72 		     u8 *comeback_key, u16 comeback_idx,
     73 		     u16 *comeback_pending_idx, size_t idx_len,
     74 		     int group, const u8 *addr, int h2e)
     75 {
     76 	struct wpabuf *buf;
     77 	u8 *token;
     78 	struct os_reltime now;
     79 	u8 idx[2];
     80 	const u8 *addrs[2];
     81 	size_t len[2];
     82 	u8 p_idx;
     83 	u16 token_idx;
     84 
     85 	os_get_reltime(&now);
     86 	if (!os_reltime_initialized(last_comeback_key_update) ||
     87 	    os_reltime_expired(&now, last_comeback_key_update, 60) ||
     88 	    comeback_idx == 0xffff) {
     89 		if (random_get_bytes(comeback_key, COMEBACK_KEY_SIZE) < 0)
     90 			return NULL;
     91 		wpa_hexdump(MSG_DEBUG, "Comeback: Updated token key",
     92 			    comeback_key, COMEBACK_KEY_SIZE);
     93 		*last_comeback_key_update = now;
     94 		comeback_idx = 0;
     95 		os_memset(comeback_pending_idx, 0, idx_len);
     96 	}
     97 
     98 	buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
     99 	if (buf == NULL)
    100 		return NULL;
    101 
    102 	if (group)
    103 		wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
    104 
    105 	if (h2e) {
    106 		/* Encapsulate Anti-clogging Token field in a container IE */
    107 		wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
    108 		wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
    109 		wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
    110 	}
    111 
    112 	if (comeback_token_hash(comeback_key, addr, &p_idx) < 0) {
    113 		wpabuf_free(buf);
    114 		return NULL;
    115 	}
    116 
    117 	token_idx = comeback_pending_idx[p_idx];
    118 	if (!token_idx) {
    119 		comeback_idx++;
    120 		token_idx = comeback_idx;
    121 		comeback_pending_idx[p_idx] = token_idx;
    122 	}
    123 	WPA_PUT_BE16(idx, token_idx);
    124 	token = wpabuf_put(buf, SHA256_MAC_LEN);
    125 	addrs[0] = addr;
    126 	len[0] = ETH_ALEN;
    127 	addrs[1] = idx;
    128 	len[1] = sizeof(idx);
    129 	if (hmac_sha256_vector(comeback_key, COMEBACK_KEY_SIZE,
    130 			       2, addrs, len, token) < 0) {
    131 		wpabuf_free(buf);
    132 		return NULL;
    133 	}
    134 	WPA_PUT_BE16(token, token_idx);
    135 
    136 	return buf;
    137 }
    138 
    139 #endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */
    140