Sunil Ravi | 77d572f | 2023-01-17 23:58:31 +0000 | [diff] [blame^] | 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) */ |