1 // Copyright 2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifdef CONFIG_WPA3_SAE
16 
17 #include "common/sae.h"
18 #include "common/ieee802_11_defs.h"
19 #include "esp_wifi_driver.h"
20 #include "rsn_supp/wpa.h"
21 
22 static struct sae_data g_sae_data;
23 static struct wpabuf *g_sae_token = NULL;
24 static struct wpabuf *g_sae_commit = NULL;
25 static struct wpabuf *g_sae_confirm = NULL;
26 int g_allowed_groups[] = { IANA_SECP256R1, 0 };
27 
wpa3_build_sae_commit(u8 * bssid)28 static esp_err_t wpa3_build_sae_commit(u8 *bssid)
29 {
30     int default_group = IANA_SECP256R1;
31     u32 len = 0;
32     u8 own_addr[ETH_ALEN];
33     const u8 *pw;
34 
35     if (wpa_sta_cur_pmksa_matches_akm()) {
36         wpa_printf(MSG_INFO, "wpa3: Skip SAE and use cached PMK instead");
37         return ESP_FAIL;
38     }
39 
40     if (g_sae_commit) {
41         wpabuf_free(g_sae_commit);
42         g_sae_commit = NULL;
43     }
44 
45     if (g_sae_token) {
46         len = wpabuf_len(g_sae_token);
47         goto reuse_data;
48     }
49 
50     memset(&g_sae_data, 0, sizeof(g_sae_data));
51     if (sae_set_group(&g_sae_data, default_group)) {
52         wpa_printf(MSG_ERROR, "wpa3: could not set SAE group %d", default_group);
53         return ESP_FAIL;
54     }
55 
56     esp_wifi_get_macaddr_internal(WIFI_IF_STA, own_addr);
57     if (!bssid) {
58         wpa_printf(MSG_ERROR, "wpa3: cannot prepare SAE commit with no BSSID!");
59         return ESP_FAIL;
60     }
61 
62     pw = (const u8 *)esp_wifi_sta_get_prof_password_internal();
63     if (sae_prepare_commit(own_addr, bssid, pw, strlen((const char *)pw), NULL, &g_sae_data) < 0) {
64         wpa_printf(MSG_ERROR, "wpa3: failed to prepare SAE commit!");
65         return ESP_FAIL;
66     }
67 
68 reuse_data:
69     len += SAE_COMMIT_MAX_LEN;
70     g_sae_commit = wpabuf_alloc(len);
71     if (!g_sae_commit) {
72         wpa_printf(MSG_ERROR, "wpa3: failed to allocate buffer for commit msg");
73         return ESP_FAIL;
74     }
75 
76     if (sae_write_commit(&g_sae_data, g_sae_commit, g_sae_token, NULL) != ESP_OK) {
77         wpa_printf(MSG_ERROR, "wpa3: failed to write SAE commit msg");
78         wpabuf_free(g_sae_commit);
79         g_sae_commit = NULL;
80         return ESP_FAIL;
81     }
82 
83     if (g_sae_token) {
84         wpabuf_free(g_sae_token);
85         g_sae_token = NULL;
86     }
87     g_sae_data.state = SAE_COMMITTED;
88 
89     return ESP_OK;
90 }
91 
wpa3_build_sae_confirm(void)92 static esp_err_t wpa3_build_sae_confirm(void)
93 {
94     if (g_sae_data.state != SAE_COMMITTED)
95         return ESP_FAIL;
96 
97     if (g_sae_confirm) {
98         wpabuf_free(g_sae_confirm);
99         g_sae_confirm = NULL;
100     }
101 
102     g_sae_confirm = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
103     if (!g_sae_confirm) {
104         wpa_printf(MSG_ERROR, "wpa3: failed to allocate buffer for confirm msg");
105         return ESP_FAIL;
106     }
107 
108     if (sae_write_confirm(&g_sae_data, g_sae_confirm) != ESP_OK) {
109         wpa_printf(MSG_ERROR, "wpa3: failed to write SAE confirm msg");
110         wpabuf_free(g_sae_confirm);
111         g_sae_confirm = NULL;
112         return ESP_FAIL;
113     }
114     g_sae_data.state = SAE_CONFIRMED;
115 
116     return ESP_OK;
117 }
118 
esp_wpa3_free_sae_data(void)119 void esp_wpa3_free_sae_data(void)
120 {
121     if (g_sae_commit) {
122         wpabuf_free(g_sae_commit);
123         g_sae_commit = NULL;
124     }
125 
126     if (g_sae_confirm) {
127         wpabuf_free(g_sae_confirm);
128         g_sae_confirm = NULL;
129     }
130     sae_clear_data(&g_sae_data);
131 }
132 
wpa3_build_sae_msg(u8 * bssid,u32 sae_msg_type,size_t * sae_msg_len)133 static u8 *wpa3_build_sae_msg(u8 *bssid, u32 sae_msg_type, size_t *sae_msg_len)
134 {
135     u8 *buf = NULL;
136 
137     switch (sae_msg_type) {
138         case SAE_MSG_COMMIT:
139             if (ESP_OK != wpa3_build_sae_commit(bssid))
140                 return NULL;
141             *sae_msg_len = wpabuf_len(g_sae_commit);
142             buf = wpabuf_mhead_u8(g_sae_commit);
143             break;
144         case SAE_MSG_CONFIRM:
145             if (ESP_OK != wpa3_build_sae_confirm())
146                 return NULL;
147             *sae_msg_len = wpabuf_len(g_sae_confirm);
148             buf = wpabuf_mhead_u8(g_sae_confirm);
149             break;
150         default:
151             break;
152     }
153 
154     return buf;
155 }
156 
wpa3_parse_sae_commit(u8 * buf,u32 len,u16 status)157 static int wpa3_parse_sae_commit(u8 *buf, u32 len, u16 status)
158 {
159     int ret;
160 
161     if (g_sae_data.state != SAE_COMMITTED) {
162         wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!",
163                    g_sae_data.state);
164         return ESP_FAIL;
165     }
166 
167     if (status == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ) {
168         if (g_sae_token)
169             wpabuf_free(g_sae_token);
170         g_sae_token = wpabuf_alloc_copy(buf + 2, len - 2);
171         return ESP_OK;
172     }
173 
174     ret = sae_parse_commit(&g_sae_data, buf, len, NULL, 0, g_allowed_groups);
175     if (ret) {
176         wpa_printf(MSG_ERROR, "wpa3: could not parse commit(%d)", ret);
177         return ret;
178     }
179 
180     ret = sae_process_commit(&g_sae_data);
181     if (ret) {
182         wpa_printf(MSG_ERROR, "wpa3: could not process commit(%d)", ret);
183         return ret;
184     }
185 
186     return ESP_OK;
187 }
188 
wpa3_parse_sae_confirm(u8 * buf,u32 len)189 static int wpa3_parse_sae_confirm(u8 *buf, u32 len)
190 {
191     if (g_sae_data.state != SAE_CONFIRMED) {
192         wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE commit in state(%d)!",
193                    g_sae_data.state);
194         return ESP_FAIL;
195     }
196 
197     if (sae_check_confirm(&g_sae_data, buf, len) != ESP_OK) {
198         wpa_printf(MSG_ERROR, "wpa3: failed to parse SAE confirm");
199         return ESP_FAIL;
200     }
201     g_sae_data.state = SAE_ACCEPTED;
202 
203     wpa_set_pmk(g_sae_data.pmk, g_sae_data.pmkid, true);
204 
205     return ESP_OK;
206 }
207 
wpa3_parse_sae_msg(u8 * buf,size_t len,u32 sae_msg_type,u16 status)208 static int wpa3_parse_sae_msg(u8 *buf, size_t len, u32 sae_msg_type, u16 status)
209 {
210     int ret = ESP_OK;
211 
212     switch (sae_msg_type) {
213         case SAE_MSG_COMMIT:
214             ret = wpa3_parse_sae_commit(buf, len, status);
215             break;
216         case SAE_MSG_CONFIRM:
217             ret = wpa3_parse_sae_confirm(buf, len);
218             esp_wpa3_free_sae_data();
219             break;
220         default:
221             wpa_printf(MSG_ERROR, "wpa3: Invalid SAE msg type(%d)!", sae_msg_type);
222             ret = ESP_FAIL;
223             break;
224     }
225 
226     return ret;
227 }
228 
esp_wifi_register_wpa3_cb(struct wpa_funcs * wpa_cb)229 void esp_wifi_register_wpa3_cb(struct wpa_funcs *wpa_cb)
230 {
231     wpa_cb->wpa3_build_sae_msg = wpa3_build_sae_msg;
232     wpa_cb->wpa3_parse_sae_msg = wpa3_parse_sae_msg;
233 }
234 
235 #endif /* CONFIG_WPA3_SAE */
236