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 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