1 /*
2 * hostapd / Comeback token mechanism for SAE
3 * Copyright (c) 2002-2017, 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 "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
comeback_token_hash(const u8 * comeback_key,const u8 * addr,u8 * idx)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
check_comeback_token(const u8 * comeback_key,u16 * comeback_pending_idx,const u8 * addr,const u8 * token,size_t token_len)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 *
auth_build_token_req(struct os_reltime * last_comeback_key_update,u8 * comeback_key,u16 comeback_idx,u16 * comeback_pending_idx,size_t idx_len,int group,const u8 * addr,int h2e)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