/** * wpa_eapol_key_mic - Calculate EAPOL-Key MIC * @key: EAPOL-Key Key Confirmation Key (KCK) * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) * @buf: Pointer to the beginning of the EAPOL header (version field) * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written * Returns: 0 on success, -1 on failure * * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has * to be cleared (all zeroes) when calling this function. * * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the * description of the Key MIC calculation. It includes packet data from the * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change * happened during final editing of the standard and the correct behavior is * defined in the last draft (IEEE 802.11i/D10). */ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, u8 *mic) { u8 hash[SHA1_MAC_LEN]; switch (ver) { #ifndef CONFIG_FIPS case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: return hmac_md5(key, 16, buf, len, mic); #endif /* CONFIG_FIPS */ case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: if (hmac_sha1(key, 16, buf, len, hash)) return -1; os_memcpy(mic, hash, MD5_MAC_LEN); break; #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) case WPA_KEY_INFO_TYPE_AES_128_CMAC: return omac1_aes_128(key, buf, len, mic); #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ #ifdef CONFIG_HS20 case WPA_KEY_INFO_TYPE_AKM_DEFINED: /* FIX: This should be based on negotiated AKM */ return omac1_aes_128(key, buf, len, mic); #endif /* CONFIG_HS20 */ default: return -1; } return 0; }
/** * aes_128_eax_decrypt - AES-128 EAX mode decryption * @key: Key for decryption (16 bytes) * @nonce: Nonce for counter mode * @nonce_len: Nonce length in bytes * @hdr: Header data to be authenticity protected * @hdr_len: Length of the header data bytes * @data: Data to encrypt in-place * @data_len: Length of data in bytes * @tag: 16-byte tag value * Returns: 0 on success, -1 on failure, -2 if tag does not match */ int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len, const u8 *hdr, size_t hdr_len, u8 *data, size_t data_len, const u8 *tag) { u8 *buf; size_t buf_len; u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE], data_mac[AES_BLOCK_SIZE]; int i; if (nonce_len > data_len) buf_len = nonce_len; else buf_len = data_len; if (hdr_len > buf_len) buf_len = hdr_len; buf_len += 16; buf = os_malloc(buf_len); if (buf == NULL) return -1; os_memset(buf, 0, 15); buf[15] = 0; os_memcpy(buf + 16, nonce, nonce_len); if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) { os_free(buf); return -1; } buf[15] = 1; os_memcpy(buf + 16, hdr, hdr_len); if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) { os_free(buf); return -1; } buf[15] = 2; os_memcpy(buf + 16, data, data_len); if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) { os_free(buf); return -1; } os_free(buf); for (i = 0; i < AES_BLOCK_SIZE; i++) { if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i])) return -2; } return aes_128_ctr_encrypt(key, nonce_mac, data, data_len); }
/** * aes_128_eax_encrypt - AES-128 EAX mode encryption * @key: Key for encryption (16 bytes) * @nonce: Nonce for counter mode * @nonce_len: Nonce length in bytes * @hdr: Header data to be authenticity protected * @hdr_len: Length of the header data bytes * @data: Data to encrypt in-place * @data_len: Length of data in bytes * @tag: 16-byte tag value * Returns: 0 on success, -1 on failure */ int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len, const u8 *hdr, size_t hdr_len, u8 *data, size_t data_len, u8 *tag) { u8 *buf; size_t buf_len; u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE], data_mac[AES_BLOCK_SIZE]; int i, ret = -1; if (nonce_len > data_len) buf_len = nonce_len; else buf_len = data_len; if (hdr_len > buf_len) buf_len = hdr_len; buf_len += 16; buf = os_malloc(buf_len); if (buf == NULL) return -1; os_memset(buf, 0, 15); buf[15] = 0; os_memcpy(buf + 16, nonce, nonce_len); if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) goto fail; buf[15] = 1; os_memcpy(buf + 16, hdr, hdr_len); if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) goto fail; if (aes_128_ctr_encrypt(key, nonce_mac, data, data_len)) goto fail; buf[15] = 2; os_memcpy(buf + 16, data, data_len); if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) goto fail; for (i = 0; i < AES_BLOCK_SIZE; i++) tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]; ret = 0; fail: bin_clear_free(buf, buf_len); return ret; }
/** * wpa_eapol_key_mic - Calculate EAPOL-Key MIC * @key: EAPOL-Key Key Confirmation Key (KCK) * @key_len: KCK length in octets * @akmp: WPA_KEY_MGMT_* used in key derivation * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) * @buf: Pointer to the beginning of the EAPOL header (version field) * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written * Returns: 0 on success, -1 on failure * * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has * to be cleared (all zeroes) when calling this function. * * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the * description of the Key MIC calculation. It includes packet data from the * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change * happened during final editing of the standard and the correct behavior is * defined in the last draft (IEEE 802.11i/D10). */ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver, const u8 *buf, size_t len, u8 *mic) { u8 hash[SHA384_MAC_LEN]; switch (ver) { #ifndef CONFIG_FIPS case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: return hmac_md5(key, key_len, buf, len, mic); #endif /* CONFIG_FIPS */ case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: if (hmac_sha1(key, key_len, buf, len, hash)) return -1; os_memcpy(mic, hash, MD5_MAC_LEN); break; #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) case WPA_KEY_INFO_TYPE_AES_128_CMAC: return omac1_aes_128(key, buf, len, mic); #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ case WPA_KEY_INFO_TYPE_AKM_DEFINED: switch (akmp) { #ifdef CONFIG_HS20 case WPA_KEY_MGMT_OSEN: return omac1_aes_128(key, buf, len, mic); #endif /* CONFIG_HS20 */ #ifdef CONFIG_SUITEB case WPA_KEY_MGMT_IEEE8021X_SUITE_B: if (hmac_sha256(key, key_len, buf, len, hash)) return -1; os_memcpy(mic, hash, MD5_MAC_LEN); break; #endif /* CONFIG_SUITEB */ #ifdef CONFIG_SUITEB192 case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: if (hmac_sha384(key, key_len, buf, len, hash)) return -1; os_memcpy(mic, hash, 24); break; #endif /* CONFIG_SUITEB192 */ default: return -1; } break; default: return -1; } return 0; }
/** * ieee802_1x_icv_128bits_aes_cmac * * IEEE Std 802.1X-2010, 9.4.1 * ICV = AES-CMAC(ICK, M, 128) */ int ieee802_1x_icv_128bits_aes_cmac(const u8 *ick, const u8 *msg, size_t msg_bytes, u8 *icv) { if (omac1_aes_128(ick, msg, msg_bytes, icv)) { wpa_printf(MSG_ERROR, "MKA: omac1_aes_128 failed"); return -1; } return 0; }
static int tdls_verify_mic_teardown(struct wlantest *wt, struct wlantest_tdls *tdls, u8 trans_seq, const u8 *reason_code, struct ieee802_11_elems *elems) { u8 *buf, *pos; int len; u8 mic[16]; int ret; const struct rsn_ftie *rx_ftie; struct rsn_ftie *tmp_ftie; if (elems->link_id == NULL || elems->ftie == NULL || elems->ftie_len < sizeof(struct rsn_ftie)) return -1; len = 2 + 18 + 2 + 1 + 1 + 2 + elems->ftie_len; buf = os_zalloc(len); if (buf == NULL) return -1; pos = buf; /* 1) Link Identifier IE */ os_memcpy(pos, elems->link_id - 2, 2 + 18); pos += 2 + 18; /* 2) Reason Code */ os_memcpy(pos, reason_code, 2); pos += 2; /* 3) Dialog token */ *pos++ = tdls->dialog_token; /* 4) Transaction Sequence number */ *pos++ = trans_seq; /* 5) FTIE, with the MIC field of the FTIE set to 0 */ os_memcpy(pos, elems->ftie - 2, 2 + elems->ftie_len); pos += 2; tmp_ftie = (struct rsn_ftie *) pos; os_memset(tmp_ftie->mic, 0, 16); pos += elems->ftie_len; wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", tdls->tpk.kck, 16); ret = omac1_aes_128(tdls->tpk.kck, buf, pos - buf, mic); os_free(buf); if (ret) return -1; wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); rx_ftie = (const struct rsn_ftie *) elems->ftie; if (os_memcmp(mic, rx_ftie->mic, 16) == 0) { add_note(wt, MSG_DEBUG, "TDLS: Valid MIC"); return 0; } add_note(wt, MSG_DEBUG, "TDLS: Invalid MIC"); return -1; }
int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, const u8 *ftie, size_t ftie_len, const u8 *rsnie, size_t rsnie_len, const u8 *ric, size_t ric_len, u8 *mic) { u8 *buf, *pos; size_t buf_len; buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len; buf = os_malloc(buf_len); if (buf == NULL) return -1; pos = buf; os_memcpy(pos, sta_addr, ETH_ALEN); pos += ETH_ALEN; os_memcpy(pos, ap_addr, ETH_ALEN); pos += ETH_ALEN; *pos++ = transaction_seqnum; if (rsnie) { os_memcpy(pos, rsnie, rsnie_len); pos += rsnie_len; } if (mdie) { os_memcpy(pos, mdie, mdie_len); pos += mdie_len; } if (ftie) { struct rsn_ftie *_ftie; os_memcpy(pos, ftie, ftie_len); if (ftie_len < 2 + sizeof(*_ftie)) { os_free(buf); return -1; } _ftie = (struct rsn_ftie *) (pos + 2); os_memset(_ftie->mic, 0, sizeof(_ftie->mic)); pos += ftie_len; } if (ric) { os_memcpy(pos, ric, ric_len); pos += ric_len; } wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf); if (omac1_aes_128(kck, buf, pos - buf, mic)) { os_free(buf); return -1; } os_free(buf); return 0; }
static int eap_gpsk_compute_mic_aes(const u8 *sk, size_t sk_len, const u8 *data, size_t len, u8 *mic) { if (sk_len != 16) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid SK length %lu for " "AES-CMAC MIC", (unsigned long) sk_len); return -1; } return omac1_aes_128(sk, data, len, mic); }
u8 * bip_protect(const u8 *igtk, u8 *frame, size_t len, u8 *ipn, int keyid, size_t *prot_len) { u8 *prot, *pos, *buf; u8 mic[16]; u16 fc; struct ieee80211_hdr *hdr; size_t plen; plen = len + 18; prot = os_malloc(plen); if (prot == NULL) return NULL; os_memcpy(prot, frame, len); pos = prot + len; *pos++ = WLAN_EID_MMIE; *pos++ = 16; WPA_PUT_LE16(pos, keyid); pos += 2; os_memcpy(pos, ipn, 6); pos += 6; os_memset(pos, 0, 8); /* MIC */ buf = os_malloc(plen + 20 - 24); if (buf == NULL) { os_free(prot); return NULL; } /* BIP AAD: FC(masked) A1 A2 A3 */ hdr = (struct ieee80211_hdr *) frame; fc = le_to_host16(hdr->frame_control); fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA); WPA_PUT_LE16(buf, fc); os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN); os_memcpy(buf + 20, prot + 24, plen - 24); wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, plen + 20 - 24); /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */ if (omac1_aes_128(igtk, buf, plen + 20 - 24, mic) < 0) { os_free(prot); os_free(buf); return NULL; } os_free(buf); os_memcpy(pos, mic, 8); wpa_hexdump(MSG_DEBUG, "BIP MMIE MIC", pos, 8); *prot_len = plen; return prot; }
/* IEEE Std 802.1X-2010, 6.2.1 KDF */ static int aes_kdf_128(const u8 *kdk, const char *label, const u8 *context, int ctx_bits, int ret_bits, u8 *ret) { const int h = 128; const int r = 8; int i, n; int lab_len, ctx_len, ret_len, buf_len; u8 *buf; lab_len = os_strlen(label); ctx_len = (ctx_bits + 7) / 8; ret_len = ((ret_bits & 0xffff) + 7) / 8; buf_len = lab_len + ctx_len + 4; os_memset(ret, 0, ret_len); n = (ret_bits + h - 1) / h; if (n > ((0x1 << r) - 1)) return -1; buf = os_zalloc(buf_len); if (buf == NULL) return -1; os_memcpy(buf + 1, label, lab_len); os_memcpy(buf + lab_len + 2, context, ctx_len); WPA_PUT_BE16(&buf[buf_len - 2], ret_bits); for (i = 0; i < n; i++) { buf[0] = (u8) (i + 1); if (omac1_aes_128(kdk, buf, buf_len, ret)) { os_free(buf); return -1; } ret = ret + h / 8; } os_free(buf); return 0; }
/** * wpa_eapol_key_mic - Calculate EAPOL-Key MIC * @key: EAPOL-Key Key Confirmation Key (KCK) * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*) * @buf: Pointer to the beginning of the EAPOL header (version field) * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame) * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written * Returns: 0 on success, -1 on failure * * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has * to be cleared (all zeroes) when calling this function. * * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the * description of the Key MIC calculation. It includes packet data from the * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change * happened during final editing of the standard and the correct behavior is * defined in the last draft (IEEE 802.11i/D10). */ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len, u8 *mic) { u8 hash[SHA1_MAC_LEN]; switch (ver) { case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: return hmac_md5(key, 16, buf, len, mic); case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: if (hmac_sha1(key, 16, buf, len, hash)) return -1; os_memcpy(mic, hash, MD5_MAC_LEN); break; #if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) case WPA_KEY_INFO_TYPE_AES_128_CMAC: return omac1_aes_128(key, buf, len, mic); #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ default: return -1; } return 0; }
int main(int argc, char *argv[]) { u8 kek[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; u8 plain[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; u8 crypt[] = { 0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47, 0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82, 0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5 }; u8 result[24]; int ret = 0; unsigned int i; struct omac1_test_vector *tv; if (aes_wrap(kek, 2, plain, result)) { printf("AES-WRAP-128-128 reported failure\n"); ret++; } if (memcmp(result, crypt, 24) != 0) { printf("AES-WRAP-128-128 failed\n"); ret++; } if (aes_unwrap(kek, 2, crypt, result)) { printf("AES-UNWRAP-128-128 reported failure\n"); ret++; } if (memcmp(result, plain, 16) != 0) { printf("AES-UNWRAP-128-128 failed\n"); ret++; for (i = 0; i < 16; i++) printf(" %02x", result[i]); printf("\n"); } test_aes_perf(); for (i = 0; i < ARRAY_SIZE(test_vectors); i++) { tv = &test_vectors[i]; if (omac1_aes_128(tv->k, tv->msg, tv->msg_len, result) || memcmp(result, tv->tag, 16) != 0) { printf("OMAC1-AES-128 test vector %d failed\n", i); ret++; } if (tv->msg_len > 1) { const u8 *addr[2]; size_t len[2]; addr[0] = tv->msg; len[0] = 1; addr[1] = tv->msg + 1; len[1] = tv->msg_len - 1; if (omac1_aes_128_vector(tv->k, 2, addr, len, result) || memcmp(result, tv->tag, 16) != 0) { printf("OMAC1-AES-128(vector) test vector %d " "failed\n", i); ret++; } } } ret += test_eax(); ret += test_cbc(); ret += test_gcm(); if (ret) printf("FAILED!\n"); return ret; }
static int tdls_verify_mic(struct wlantest *wt, struct wlantest_tdls *tdls, u8 trans_seq, struct ieee802_11_elems *elems) { u8 *buf, *pos; int len; u8 mic[16]; int ret; const struct rsn_ftie *rx_ftie; struct rsn_ftie *tmp_ftie; if (elems->link_id == NULL || elems->rsn_ie == NULL || elems->timeout_int == NULL || elems->ftie == NULL || elems->ftie_len < sizeof(struct rsn_ftie)) return -1; len = 2 * ETH_ALEN + 1 + 2 + 18 + 2 + elems->rsn_ie_len + 2 + 5 + 2 + elems->ftie_len; buf = os_zalloc(len); if (buf == NULL) return -1; pos = buf; /* 1) TDLS initiator STA MAC address */ os_memcpy(pos, elems->link_id + ETH_ALEN, ETH_ALEN); pos += ETH_ALEN; /* 2) TDLS responder STA MAC address */ os_memcpy(pos, elems->link_id + 2 * ETH_ALEN, ETH_ALEN); pos += ETH_ALEN; /* 3) Transaction Sequence number */ *pos++ = trans_seq; /* 4) Link Identifier IE */ os_memcpy(pos, elems->link_id - 2, 2 + 18); pos += 2 + 18; /* 5) RSN IE */ os_memcpy(pos, elems->rsn_ie - 2, 2 + elems->rsn_ie_len); pos += 2 + elems->rsn_ie_len; /* 6) Timeout Interval IE */ os_memcpy(pos, elems->timeout_int - 2, 2 + 5); pos += 2 + 5; /* 7) FTIE, with the MIC field of the FTIE set to 0 */ os_memcpy(pos, elems->ftie - 2, 2 + elems->ftie_len); pos += 2; tmp_ftie = (struct rsn_ftie *) pos; os_memset(tmp_ftie->mic, 0, 16); pos += elems->ftie_len; wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", tdls->tpk.kck, 16); ret = omac1_aes_128(tdls->tpk.kck, buf, pos - buf, mic); os_free(buf); if (ret) return -1; wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); rx_ftie = (const struct rsn_ftie *) elems->ftie; if (os_memcmp(mic, rx_ftie->mic, 16) == 0) { add_note(wt, MSG_DEBUG, "TDLS: Valid MIC"); return 0; } add_note(wt, MSG_DEBUG, "TDLS: Invalid MIC"); return -1; }
static struct wpabuf * eap_psk_process_1(struct eap_psk_data *data, struct eap_method_ret *ret, const struct wpabuf *reqData) { const struct eap_psk_hdr_1 *hdr1; struct eap_psk_hdr_2 *hdr2; struct wpabuf *resp; u8 *buf, *pos; size_t buflen, len; const u8 *cpos; wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state"); cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); hdr1 = (const struct eap_psk_hdr_1 *) cpos; if (cpos == NULL || len < sizeof(*hdr1)) { wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message " "length (%lu; expected %lu or more)", (unsigned long) len, (unsigned long) sizeof(*hdr1)); ret->ignore = TRUE; return NULL; } wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags); if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) { wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)", EAP_PSK_FLAGS_GET_T(hdr1->flags)); ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; return NULL; } wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s, EAP_PSK_RAND_LEN); os_free(data->id_s); data->id_s_len = len - sizeof(*hdr1); data->id_s = os_malloc(data->id_s_len); if (data->id_s == NULL) { wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for " "ID_S (len=%lu)", (unsigned long) data->id_s_len); ret->ignore = TRUE; return NULL; } os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len); wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S", data->id_s, data->id_s_len); if (os_get_random(data->rand_p, EAP_PSK_RAND_LEN)) { wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data"); ret->ignore = TRUE; return NULL; } resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, sizeof(*hdr2) + data->id_p_len, EAP_CODE_RESPONSE, eap_get_id(reqData)); if (resp == NULL) return NULL; hdr2 = wpabuf_put(resp, sizeof(*hdr2)); hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */ os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN); os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN); wpabuf_put_data(resp, data->id_p, data->id_p_len); /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */ buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN; buf = os_malloc(buflen); if (buf == NULL) { wpabuf_free(resp); return NULL; } os_memcpy(buf, data->id_p, data->id_p_len); pos = buf + data->id_p_len; os_memcpy(pos, data->id_s, data->id_s_len); pos += data->id_s_len; os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN); pos += EAP_PSK_RAND_LEN; os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN); if (omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p)) { os_free(buf); wpabuf_free(resp); return NULL; } os_free(buf); wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p, EAP_PSK_RAND_LEN); wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN); wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P", data->id_p, data->id_p_len); data->state = PSK_MAC_SENT; return resp; }
static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data, struct eap_method_ret *ret, const struct wpabuf *reqData) { const struct eap_psk_hdr_3 *hdr3; struct eap_psk_hdr_4 *hdr4; struct wpabuf *resp; u8 *buf, *rpchannel, nonce[16], *decrypted; const u8 *pchannel, *tag, *msg; u8 mac[EAP_PSK_MAC_LEN]; size_t buflen, left, data_len, len, plen; int failed = 0; const u8 *pos; wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state"); pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, reqData, &len); hdr3 = (const struct eap_psk_hdr_3 *) pos; if (pos == NULL || len < sizeof(*hdr3)) { wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message " "length (%lu; expected %lu or more)", (unsigned long) len, (unsigned long) sizeof(*hdr3)); ret->ignore = TRUE; return NULL; } left = len - sizeof(*hdr3); pchannel = (const u8 *) (hdr3 + 1); wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags); if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) { wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)", EAP_PSK_FLAGS_GET_T(hdr3->flags)); ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; return NULL; } wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s, EAP_PSK_RAND_LEN); wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN); wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left); if (left < 4 + 16 + 1) { wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in " "third message (len=%lu, expected 21)", (unsigned long) left); ret->ignore = TRUE; return NULL; } /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */ buflen = data->id_s_len + EAP_PSK_RAND_LEN; buf = os_malloc(buflen); if (buf == NULL) return NULL; os_memcpy(buf, data->id_s, data->id_s_len); os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN); if (omac1_aes_128(data->ak, buf, buflen, mac)) { os_free(buf); return NULL; } os_free(buf); if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) { wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third " "message"); ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; return NULL; } wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully"); if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk, data->emsk)) { ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; return NULL; } wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN); os_memset(nonce, 0, 12); os_memcpy(nonce + 12, pchannel, 4); pchannel += 4; left -= 4; tag = pchannel; pchannel += 16; left -= 16; msg = pchannel; wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce", nonce, sizeof(nonce)); wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", wpabuf_head(reqData), 5); wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left); decrypted = os_malloc(left); if (decrypted == NULL) { ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; return NULL; } os_memcpy(decrypted, msg, left); if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce), wpabuf_head(reqData), sizeof(struct eap_hdr) + 1 + sizeof(*hdr3) - EAP_PSK_MAC_LEN, decrypted, left, tag)) { wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed"); os_free(decrypted); return NULL; } wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message", decrypted, left); /* Verify R flag */ switch (decrypted[0] >> 6) { case EAP_PSK_R_FLAG_CONT: wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported"); failed = 1; break; case EAP_PSK_R_FLAG_DONE_SUCCESS: wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS"); break; case EAP_PSK_R_FLAG_DONE_FAILURE: wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE"); wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected " "authentication"); failed = 1; break; } data_len = 1; if ((decrypted[0] & EAP_PSK_E_FLAG) && left > 1) data_len++; plen = sizeof(*hdr4) + 4 + 16 + data_len; resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, plen, EAP_CODE_RESPONSE, eap_get_id(reqData)); if (resp == NULL) { os_free(decrypted); return NULL; } hdr4 = wpabuf_put(resp, sizeof(*hdr4)); hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */ os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN); rpchannel = wpabuf_put(resp, 4 + 16 + data_len); /* nonce++ */ inc_byte_array(nonce, sizeof(nonce)); os_memcpy(rpchannel, nonce + 12, 4); if (decrypted[0] & EAP_PSK_E_FLAG) { wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag"); failed = 1; rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) | EAP_PSK_E_FLAG; if (left > 1) { /* Add empty EXT_Payload with same EXT_Type */ rpchannel[4 + 16 + 1] = decrypted[1]; } } else if (failed) rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6; else rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)", rpchannel + 4 + 16, data_len); if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), wpabuf_head(resp), sizeof(struct eap_hdr) + 1 + sizeof(*hdr4), rpchannel + 4 + 16, data_len, rpchannel + 4)) { os_free(decrypted); wpabuf_free(resp); return NULL; } wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)", rpchannel, 4 + 16 + data_len); wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully", failed ? "un" : ""); data->state = PSK_DONE; ret->methodState = METHOD_DONE; ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC; os_free(decrypted); return resp; }
static struct wpabuf * eap_psk_build_3(struct eap_sm *sm, struct eap_psk_data *data, u8 id) { struct wpabuf *req; struct eap_psk_hdr_3 *psk; u8 *buf, *pchannel, nonce[16]; size_t buflen; wpa_printf(MSG_DEBUG, "EAP-PSK: PSK-3 (sending)"); req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PSK, sizeof(*psk) + 4 + 16 + 1, EAP_CODE_REQUEST, id); if (req == NULL) { wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory " "request"); data->state = FAILURE; return NULL; } psk = wpabuf_put(req, sizeof(*psk)); psk->flags = EAP_PSK_FLAGS_SET_T(2); /* T=2 */ os_memcpy(psk->rand_s, data->rand_s, EAP_PSK_RAND_LEN); /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */ buflen = data->id_s_len + EAP_PSK_RAND_LEN; buf = os_malloc(buflen); if (buf == NULL) goto fail; os_memcpy(buf, data->id_s, data->id_s_len); os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN); if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) goto fail; os_free(buf); if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk, data->emsk)) goto fail; wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN); os_memset(nonce, 0, sizeof(nonce)); pchannel = wpabuf_put(req, 4 + 16 + 1); os_memcpy(pchannel, nonce + 12, 4); os_memset(pchannel + 4, 0, 16); /* Tag */ pchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (plaintext)", pchannel, 4 + 16 + 1); if (aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), wpabuf_head(req), 22, pchannel + 4 + 16, 1, pchannel + 4)) goto fail; wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL (encrypted)", pchannel, 4 + 16 + 1); return req; fail: wpabuf_free(req); data->state = FAILURE; return NULL; }
static void eap_psk_process_2(struct eap_sm *sm, struct eap_psk_data *data, struct wpabuf *respData) { const struct eap_psk_hdr_2 *resp; u8 *pos, mac[EAP_PSK_MAC_LEN], *buf; size_t left, buflen; int i; const u8 *cpos; if (data->state != PSK_1) return; wpa_printf(MSG_DEBUG, "EAP-PSK: Received PSK-2"); cpos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, respData, &left); if (cpos == NULL || left < sizeof(*resp)) { wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame"); return; } resp = (const struct eap_psk_hdr_2 *) cpos; cpos = (const u8 *) (resp + 1); left -= sizeof(*resp); os_free(data->id_p); data->id_p = os_malloc(left); if (data->id_p == NULL) { wpa_printf(MSG_INFO, "EAP-PSK: Failed to allocate memory for " "ID_P"); return; } os_memcpy(data->id_p, cpos, left); data->id_p_len = left; wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PSK: ID_P", data->id_p, data->id_p_len); if (eap_user_get(sm, data->id_p, data->id_p_len, 0) < 0) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: unknown ID_P", data->id_p, data->id_p_len); data->state = FAILURE; return; } for (i = 0; i < EAP_MAX_METHODS && (sm->user->methods[i].vendor != EAP_VENDOR_IETF || sm->user->methods[i].method != EAP_TYPE_NONE); i++) { if (sm->user->methods[i].vendor == EAP_VENDOR_IETF && sm->user->methods[i].method == EAP_TYPE_PSK) break; } if (i >= EAP_MAX_METHODS || sm->user->methods[i].vendor != EAP_VENDOR_IETF || sm->user->methods[i].method != EAP_TYPE_PSK) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: EAP-PSK not enabled for ID_P", data->id_p, data->id_p_len); data->state = FAILURE; return; } if (sm->user->password == NULL || sm->user->password_len != EAP_PSK_PSK_LEN) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: invalid password in " "user database for ID_P", data->id_p, data->id_p_len); data->state = FAILURE; return; } if (eap_psk_key_setup(sm->user->password, data->ak, data->kdk)) { data->state = FAILURE; return; } wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: RAND_P (client rand)", resp->rand_p, EAP_PSK_RAND_LEN); os_memcpy(data->rand_p, resp->rand_p, EAP_PSK_RAND_LEN); /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */ buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN; buf = os_malloc(buflen); if (buf == NULL) { data->state = FAILURE; return; } os_memcpy(buf, data->id_p, data->id_p_len); pos = buf + data->id_p_len; os_memcpy(pos, data->id_s, data->id_s_len); pos += data->id_s_len; os_memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN); pos += EAP_PSK_RAND_LEN; os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN); if (omac1_aes_128(data->ak, buf, buflen, mac)) { os_free(buf); data->state = FAILURE; return; } os_free(buf); wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", resp->mac_p, EAP_PSK_MAC_LEN); if (os_memcmp(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-PSK: Invalid MAC_P"); wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Expected MAC_P", mac, EAP_PSK_MAC_LEN); data->state = FAILURE; return; } data->state = PSK_3; }