Coverage Report

Created: 2025-08-29 06:25

/src/hostap/src/ap/comeback_token.c
Line
Count
Source (jump to first uncovered line)
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
1
{
23
1
  u8 hash[SHA256_MAC_LEN];
24
25
1
  if (hmac_sha256(comeback_key, COMEBACK_KEY_SIZE,
26
1
      addr, ETH_ALEN, hash) < 0)
27
1
    return -1;
28
0
  *idx = hash[0];
29
0
  return 0;
30
1
}
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
11
{
37
11
  u8 mac[SHA256_MAC_LEN];
38
11
  const u8 *addrs[2];
39
11
  size_t len[2];
40
11
  u16 token_idx;
41
11
  u8 idx;
42
43
11
  if (token_len != SHA256_MAC_LEN ||
44
11
      comeback_token_hash(comeback_key, addr, &idx) < 0)
45
11
    return -1;
46
0
  token_idx = comeback_pending_idx[idx];
47
0
  if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) {
48
0
    wpa_printf(MSG_DEBUG,
49
0
         "Comeback: Invalid anti-clogging token from "
50
0
         MACSTR " - token_idx 0x%04x, expected 0x%04x",
51
0
         MAC2STR(addr), WPA_GET_BE16(token), token_idx);
52
0
    return -1;
53
0
  }
54
55
0
  addrs[0] = addr;
56
0
  len[0] = ETH_ALEN;
57
0
  addrs[1] = token;
58
0
  len[1] = 2;
59
0
  if (hmac_sha256_vector(comeback_key, COMEBACK_KEY_SIZE,
60
0
             2, addrs, len, mac) < 0 ||
61
0
      os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0)
62
0
    return -1;
63
64
0
  comeback_pending_idx[idx] = 0; /* invalidate used token */
65
66
0
  return 0;
67
0
}
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
0
{
76
0
  struct wpabuf *buf;
77
0
  u8 *token;
78
0
  struct os_reltime now;
79
0
  u8 idx[2];
80
0
  const u8 *addrs[2];
81
0
  size_t len[2];
82
0
  u8 p_idx;
83
0
  u16 token_idx;
84
85
0
  os_get_reltime(&now);
86
0
  if (!os_reltime_initialized(last_comeback_key_update) ||
87
0
      os_reltime_expired(&now, last_comeback_key_update, 60) ||
88
0
      comeback_idx == 0xffff) {
89
0
    if (random_get_bytes(comeback_key, COMEBACK_KEY_SIZE) < 0)
90
0
      return NULL;
91
0
    wpa_hexdump(MSG_DEBUG, "Comeback: Updated token key",
92
0
          comeback_key, COMEBACK_KEY_SIZE);
93
0
    *last_comeback_key_update = now;
94
0
    comeback_idx = 0;
95
0
    os_memset(comeback_pending_idx, 0, idx_len);
96
0
  }
97
98
0
  buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN);
99
0
  if (buf == NULL)
100
0
    return NULL;
101
102
0
  if (group)
103
0
    wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
104
105
0
  if (h2e) {
106
    /* Encapsulate Anti-clogging Token field in a container IE */
107
0
    wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
108
0
    wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN);
109
0
    wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN);
110
0
  }
111
112
0
  if (comeback_token_hash(comeback_key, addr, &p_idx) < 0) {
113
0
    wpabuf_free(buf);
114
0
    return NULL;
115
0
  }
116
117
0
  token_idx = comeback_pending_idx[p_idx];
118
0
  if (!token_idx) {
119
0
    comeback_idx++;
120
0
    token_idx = comeback_idx;
121
0
    comeback_pending_idx[p_idx] = token_idx;
122
0
  }
123
0
  WPA_PUT_BE16(idx, token_idx);
124
0
  token = wpabuf_put(buf, SHA256_MAC_LEN);
125
0
  addrs[0] = addr;
126
0
  len[0] = ETH_ALEN;
127
0
  addrs[1] = idx;
128
0
  len[1] = sizeof(idx);
129
0
  if (hmac_sha256_vector(comeback_key, COMEBACK_KEY_SIZE,
130
0
             2, addrs, len, token) < 0) {
131
0
    wpabuf_free(buf);
132
0
    return NULL;
133
0
  }
134
0
  WPA_PUT_BE16(token, token_idx);
135
136
0
  return buf;
137
0
}
138
139
#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */