1 /* 2 * PASN common processing 3 * 4 * Copyright (C) 2024, Qualcomm Innovation Center, Inc. 5 * 6 * This software may be distributed under the terms of the BSD license. 7 * See README for more details. 8 */ 9 10 #include "utils/includes.h" 11 12 #include "utils/common.h" 13 #include "common/wpa_common.h" 14 #include "common/sae.h" 15 #include "crypto/sha384.h" 16 #include "crypto/crypto.h" 17 #include "common/ieee802_11_defs.h" 18 #include "common/ieee802_11_common.h" 19 #include "crypto/aes_wrap.h" 20 #include "pasn_common.h" 21 22 pasn_data_init(void)23 struct pasn_data * pasn_data_init(void) 24 { 25 struct pasn_data *pasn = os_zalloc(sizeof(struct pasn_data)); 26 27 return pasn; 28 } 29 30 pasn_data_deinit(struct pasn_data * pasn)31 void pasn_data_deinit(struct pasn_data *pasn) 32 { 33 if (!pasn) 34 return; 35 os_free(pasn->rsnxe_ie); 36 wpabuf_free(pasn->frame); 37 bin_clear_free(pasn, sizeof(struct pasn_data)); 38 } 39 40 pasn_register_callbacks(struct pasn_data * pasn,void * cb_ctx,int (* send_mgmt)(void * ctx,const u8 * data,size_t data_len,int noack,unsigned int freq,unsigned int wait),int (* validate_custom_pmkid)(void * ctx,const u8 * addr,const u8 * pmkid))41 void pasn_register_callbacks(struct pasn_data *pasn, void *cb_ctx, 42 int (*send_mgmt)(void *ctx, const u8 *data, 43 size_t data_len, int noack, 44 unsigned int freq, 45 unsigned int wait), 46 int (*validate_custom_pmkid)(void *ctx, 47 const u8 *addr, 48 const u8 *pmkid)) 49 { 50 if (!pasn) 51 return; 52 53 pasn->cb_ctx = cb_ctx; 54 pasn->send_mgmt = send_mgmt; 55 pasn->validate_custom_pmkid = validate_custom_pmkid; 56 } 57 58 pasn_enable_kdk_derivation(struct pasn_data * pasn)59 void pasn_enable_kdk_derivation(struct pasn_data *pasn) 60 { 61 if (!pasn) 62 return; 63 pasn->derive_kdk = true; 64 pasn->kdk_len = WPA_KDK_MAX_LEN; 65 } 66 67 pasn_disable_kdk_derivation(struct pasn_data * pasn)68 void pasn_disable_kdk_derivation(struct pasn_data *pasn) 69 { 70 if (!pasn) 71 return; 72 pasn->derive_kdk = false; 73 pasn->kdk_len = 0; 74 } 75 76 pasn_set_akmp(struct pasn_data * pasn,int akmp)77 void pasn_set_akmp(struct pasn_data *pasn, int akmp) 78 { 79 if (!pasn) 80 return; 81 pasn->akmp = akmp; 82 } 83 84 pasn_set_cipher(struct pasn_data * pasn,int cipher)85 void pasn_set_cipher(struct pasn_data *pasn, int cipher) 86 { 87 if (!pasn) 88 return; 89 pasn->cipher = cipher; 90 } 91 92 pasn_set_own_addr(struct pasn_data * pasn,const u8 * addr)93 void pasn_set_own_addr(struct pasn_data *pasn, const u8 *addr) 94 { 95 if (!pasn || !addr) 96 return; 97 os_memcpy(pasn->own_addr, addr, ETH_ALEN); 98 } 99 100 pasn_set_peer_addr(struct pasn_data * pasn,const u8 * addr)101 void pasn_set_peer_addr(struct pasn_data *pasn, const u8 *addr) 102 { 103 if (!pasn || !addr) 104 return; 105 os_memcpy(pasn->peer_addr, addr, ETH_ALEN); 106 } 107 108 pasn_set_bssid(struct pasn_data * pasn,const u8 * addr)109 void pasn_set_bssid(struct pasn_data *pasn, const u8 *addr) 110 { 111 if (!pasn || !addr) 112 return; 113 os_memcpy(pasn->bssid, addr, ETH_ALEN); 114 } 115 116 pasn_set_pt(struct pasn_data * pasn,struct sae_pt * pt)117 int pasn_set_pt(struct pasn_data *pasn, struct sae_pt *pt) 118 { 119 if (!pasn) 120 return -1; 121 #ifdef CONFIG_SAE 122 pasn->pt = pt; 123 return 0; 124 #else /* CONFIG_SAE */ 125 return -1; 126 #endif /* CONFIG_SAE */ 127 } 128 129 pasn_set_password(struct pasn_data * pasn,const char * password)130 void pasn_set_password(struct pasn_data *pasn, const char *password) 131 { 132 if (!pasn) 133 return; 134 pasn->password = password; 135 } 136 137 pasn_set_wpa_key_mgmt(struct pasn_data * pasn,int key_mgmt)138 void pasn_set_wpa_key_mgmt(struct pasn_data *pasn, int key_mgmt) 139 { 140 if (!pasn) 141 return; 142 pasn->wpa_key_mgmt = key_mgmt; 143 } 144 145 pasn_set_rsn_pairwise(struct pasn_data * pasn,int rsn_pairwise)146 void pasn_set_rsn_pairwise(struct pasn_data *pasn, int rsn_pairwise) 147 { 148 if (!pasn) 149 return; 150 pasn->rsn_pairwise = rsn_pairwise; 151 } 152 153 pasn_set_rsnxe_caps(struct pasn_data * pasn,u16 rsnxe_capab)154 void pasn_set_rsnxe_caps(struct pasn_data *pasn, u16 rsnxe_capab) 155 { 156 if (!pasn) 157 return; 158 pasn->rsnxe_capab = rsnxe_capab; 159 } 160 161 pasn_set_rsnxe_ie(struct pasn_data * pasn,const u8 * rsnxe_ie)162 void pasn_set_rsnxe_ie(struct pasn_data *pasn, const u8 *rsnxe_ie) 163 { 164 if (!pasn || !rsnxe_ie) 165 return; 166 pasn->rsnxe_ie = os_memdup(rsnxe_ie, 2 + rsnxe_ie[1]); 167 } 168 169 pasn_set_custom_pmkid(struct pasn_data * pasn,const u8 * pmkid)170 void pasn_set_custom_pmkid(struct pasn_data *pasn, const u8 *pmkid) 171 { 172 if (!pasn || !pmkid) 173 return; 174 os_memcpy(pasn->custom_pmkid, pmkid, PMKID_LEN); 175 pasn->custom_pmkid_valid = true; 176 } 177 178 pasn_set_extra_ies(struct pasn_data * pasn,const u8 * extra_ies,size_t extra_ies_len)179 int pasn_set_extra_ies(struct pasn_data *pasn, const u8 *extra_ies, 180 size_t extra_ies_len) 181 { 182 if (!pasn || !extra_ies_len || !extra_ies) 183 return -1; 184 185 if (pasn->extra_ies) { 186 os_free((u8 *) pasn->extra_ies); 187 pasn->extra_ies_len = extra_ies_len; 188 } 189 190 pasn->extra_ies = os_memdup(extra_ies, extra_ies_len); 191 if (!pasn->extra_ies) { 192 wpa_printf(MSG_ERROR, 193 "PASN: Extra IEs memory allocation failed"); 194 return -1; 195 } 196 pasn->extra_ies_len = extra_ies_len; 197 return 0; 198 } 199 200 pasn_set_noauth(struct pasn_data * pasn,bool noauth)201 void pasn_set_noauth(struct pasn_data *pasn, bool noauth) 202 { 203 if (!pasn) 204 return; 205 pasn->noauth = noauth; 206 } 207 208 pasn_get_akmp(struct pasn_data * pasn)209 int pasn_get_akmp(struct pasn_data *pasn) 210 { 211 if (!pasn) 212 return 0; 213 return pasn->akmp; 214 } 215 216 pasn_get_cipher(struct pasn_data * pasn)217 int pasn_get_cipher(struct pasn_data *pasn) 218 { 219 if (!pasn) 220 return 0; 221 return pasn->cipher; 222 } 223 224 pasn_get_pmk_len(struct pasn_data * pasn)225 size_t pasn_get_pmk_len(struct pasn_data *pasn) 226 { 227 if (!pasn) 228 return 0; 229 return pasn->pmk_len; 230 } 231 232 pasn_get_pmk(struct pasn_data * pasn)233 u8 * pasn_get_pmk(struct pasn_data *pasn) 234 { 235 if (!pasn) 236 return NULL; 237 return pasn->pmk; 238 } 239 240 pasn_get_ptk(struct pasn_data * pasn)241 struct wpa_ptk * pasn_get_ptk(struct pasn_data *pasn) 242 { 243 if (!pasn) 244 return NULL; 245 return &pasn->ptk; 246 } 247 248 pasn_add_encrypted_data(struct pasn_data * pasn,struct wpabuf * buf,const u8 * data,size_t data_len)249 int pasn_add_encrypted_data(struct pasn_data *pasn, struct wpabuf *buf, 250 const u8 *data, size_t data_len) 251 { 252 int ret; 253 u8 *encrypted_data, *padded_data = NULL; 254 u8 *len; 255 size_t pad_len = 0; 256 257 if (!pasn->ptk.kek_len) { 258 wpa_printf(MSG_DEBUG, "PASN: KEK not available"); 259 return -2; 260 } 261 262 pad_len = data_len % 8; 263 if (pad_len) { 264 pad_len = 8 - pad_len; 265 padded_data = os_zalloc(data_len + pad_len); 266 if (!padded_data) 267 return -1; 268 os_memcpy(padded_data, data, data_len); 269 data = padded_data; 270 padded_data[data_len] = 0xdd; 271 } 272 data_len += pad_len + 8; 273 274 encrypted_data = os_malloc(data_len); 275 if (!encrypted_data) { 276 os_free(padded_data); 277 return -1; 278 } 279 280 ret = aes_wrap(pasn->ptk.kek, pasn->ptk.kek_len, 281 (data_len - 8) / 8, data, encrypted_data); 282 if (ret) { 283 wpa_printf(MSG_DEBUG, "PASN: AES wrap failed, ret=%d", ret); 284 goto out; 285 } 286 287 if (wpabuf_tailroom(buf) < 1 + 1 + 1 + data_len) { 288 wpa_printf(MSG_DEBUG, 289 "PASN: Not enough room in the buffer for PASN Encrypred Data element"); 290 ret = -1; 291 goto out; 292 } 293 294 wpabuf_put_u8(buf, WLAN_EID_EXTENSION); 295 len = wpabuf_put(buf, 1); 296 297 wpabuf_put_u8(buf, WLAN_EID_EXT_PASN_ENCRYPTED_DATA); 298 299 wpabuf_put_data(buf, encrypted_data, data_len); 300 *len = (u8 *) wpabuf_put(buf, 0) - len - 1; 301 302 out: 303 os_free(padded_data); 304 os_free(encrypted_data); 305 return ret; 306 } 307 308 pasn_parse_encrypted_data(struct pasn_data * pasn,const u8 * data,size_t len)309 int pasn_parse_encrypted_data(struct pasn_data *pasn, const u8 *data, 310 size_t len) 311 { 312 int ret = -1; 313 u8 *buf; 314 u16 buf_len; 315 struct ieee802_11_elems elems; 316 const struct ieee80211_mgmt *mgmt = 317 (const struct ieee80211_mgmt *) data; 318 319 if (len < 24 + 6 || 320 ieee802_11_parse_elems(mgmt->u.auth.variable, 321 len - offsetof(struct ieee80211_mgmt, 322 u.auth.variable), 323 &elems, 0) == ParseFailed) { 324 wpa_printf(MSG_DEBUG, 325 "PASN: Failed parsing Authentication frame"); 326 return -1; 327 } 328 329 if (!elems.pasn_encrypted_data || elems.pasn_encrypted_data_len < 8 || 330 elems.pasn_encrypted_data_len % 8) { 331 wpa_printf(MSG_DEBUG, "PASN: No encrypted elements"); 332 return 0; 333 } 334 335 buf_len = elems.pasn_encrypted_data_len - 8; 336 337 buf = os_malloc(buf_len); 338 if (!buf) 339 return -1; 340 341 ret = aes_unwrap(pasn->ptk.kek, pasn->ptk.kek_len, buf_len / 8, 342 elems.pasn_encrypted_data, buf); 343 if (ret) 344 wpa_printf(MSG_DEBUG, "PASN: AES unwrap failed, ret=%d", ret); 345 else if (pasn->parse_data_element && pasn->cb_ctx) 346 ret = pasn->parse_data_element(pasn->cb_ctx, buf, buf_len); 347 348 os_free(buf); 349 return ret; 350 } 351