libwifi 0.0.3
An 802.11 Frame Parsing and Generation library in C
eapol.c
Go to the documentation of this file.
1/* Copyright 2021 The libwifi Authors
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
16#include "eapol.h"
17#include "../../core/frame/frame.h"
18#include "../../core/misc/byteswap.h"
19#include "../../core/misc/llc.h"
20#include "../../core/misc/security.h"
21
22#include <arpa/inet.h>
23#include <errno.h>
24#include <netinet/in.h>
25#include <stdlib.h>
26#include <string.h>
27
35 // WPA Handshakes are transmitted in EAPOL frames
36 if (frame->frame_control.type != TYPE_DATA) {
37 return -EINVAL;
38 }
39
40 // Data frame must be at least the length of the header plus the encapsulating LLC
41 if (frame->len < (frame->header_len + sizeof(struct libwifi_logical_link_ctrl))) {
42 return -EINVAL;
43 }
44
45 // Represent the LLC layer so that we can check the OUI and ensure it is correct
46 struct libwifi_logical_link_ctrl *llc = (struct libwifi_logical_link_ctrl *) (frame->body);
47 if (memcmp(llc->oui, XEROX_OUI, sizeof(llc->oui)) != 0) {
48 return -EINVAL;
49 }
50
51 // Match the network byte-order of LLC and ensure we have a frame containing 802.1X information
52 if (ntohs(llc->type) != LLC_TYPE_AUTH) {
53 return -EINVAL;
54 }
55
56 // Ensure we have enough information in the frame to fill a libwifi_wpa_auth_data struct
57 // This value is calculated by ensuring the frame is at least the length of the LLC layer, plus the length
58 // of the libwifi_wpa_auth_data struct, however, the length of an unsigned char pointer is subtracted due
59 // to the possibility of the frame having no WPA key data.
60 size_t required_data_length =
61 frame->header_len + (sizeof(struct libwifi_logical_link_ctrl) +
62 (sizeof(struct libwifi_wpa_auth_data) - sizeof(unsigned char *)));
63 if (frame->len < required_data_length) {
64 return -EINVAL;
65 }
66
67 return 1;
68}
69
70/*
71 * The specific EAPOL message in the supplied libwifi_frame is determined via the 802.1X key information
72 * field.
73 */
75 // Ensure we have enough information in the frame to fill a libwifi_wpa_auth_data struct
76 // This value is calculated by ensuring the frame is at least the length of the LLC layer, plus the length
77 // of the libwifi_wpa_auth_data struct, however, the length of an unsigned char pointer is subtracted due
78 // to the possibility of the frame having no WPA key data.
79 size_t required_data_length =
80 frame->header_len + (sizeof(struct libwifi_logical_link_ctrl) +
81 (sizeof(struct libwifi_wpa_auth_data) - sizeof(unsigned char *)));
82 if (frame->len < required_data_length) {
83 return HANDSHAKE_INVALID;
84 }
85
86 struct libwifi_wpa_auth_data *auth_data =
87 (struct libwifi_wpa_auth_data *) (frame->body + sizeof(struct libwifi_logical_link_ctrl));
88 switch (ntohs(auth_data->key_info.information)) {
90 return HANDSHAKE_M1;
92 return HANDSHAKE_M2;
94 return HANDSHAKE_M3;
96 return HANDSHAKE_M4;
97 default:
98 return HANDSHAKE_INVALID;
99 }
100}
101
102/*
103 * Simple helper function to print a string depending on the EAPOL message
104 */
106 int message = libwifi_check_wpa_message(frame);
107
108 switch (message) {
109 case HANDSHAKE_M1:
110 return "Message 1";
111 case HANDSHAKE_M2:
112 return "Message 2";
113 case HANDSHAKE_M3:
114 return "Message 3";
115 case HANDSHAKE_M4:
116 return "Message 4";
118 default:
119 return "Invalid";
120 }
121}
122
123/*
124 * The value returned here is the length of the data available _after_ the rest of the EAPOL data,
125 * and should be used for obtaining the EAPOL Key Data, if present.
126 */
128 if (libwifi_check_wpa_handshake(frame) < 0) {
129 return -EINVAL;
130 }
131
132 struct libwifi_wpa_auth_data *auth_data =
133 (struct libwifi_wpa_auth_data *) (frame->body + sizeof(struct libwifi_logical_link_ctrl));
134
135 // Byte-swap the multi-byte length key_data_length for the host system
136 return ntohs(auth_data->key_info.key_data_length);
137}
138
139/*
140 * Data in the supplied libwifi_frame is expected to be in network byte order. To avoid confusion, this
141 * data is byte-swapped to the host system's endianess.
142 *
143 * If the supplied key_data is not NULL, any key data at the end of the frame will be written into the
144 * supplied key_data buffer. You can obtain the length to malloc such a buffer with
145 * libwifi_get_wpa_key_data_length.
146 */
148 memset(data, 0, sizeof(struct libwifi_wpa_auth_data));
149
150 if (libwifi_check_wpa_handshake(frame) < 0) {
151 return -EINVAL;
152 }
153
154 struct libwifi_wpa_auth_data *auth_data =
155 (struct libwifi_wpa_auth_data *) (frame->body + sizeof(struct libwifi_logical_link_ctrl));
156
157 // Multi-byte fields will be byte-swapped to the host byte order
158 data->version = auth_data->version;
159 data->type = auth_data->type;
160 data->length = ntohs(auth_data->length);
161 data->descriptor = auth_data->descriptor;
162 memcpy(&data->key_info, &auth_data->key_info, sizeof(struct libwifi_wpa_key_info));
163 data->key_info.information = ntohs(auth_data->key_info.information);
164 data->key_info.key_length = ntohs(auth_data->key_info.key_length);
165 data->key_info.replay_counter = be64toh(auth_data->key_info.replay_counter);
166 data->key_info.key_data_length = ntohs(auth_data->key_info.key_data_length);
167
168 if (data->key_info.key_data_length > 0) {
169 // Prevent huge allocations in corrupted or malicious frames
170 if (data->key_info.key_data_length > 1024) {
171 data->key_info.key_data_length = 1024;
172 }
173
174 data->key_info.key_data = malloc(data->key_info.key_data_length);
175 if (data->key_info.key_data == NULL) {
176 return -ENOMEM;
177 }
178 size_t key_data_offset = sizeof(struct libwifi_logical_link_ctrl) +
179 sizeof(struct libwifi_wpa_auth_data) - sizeof(unsigned char *);
180 memcpy(data->key_info.key_data, frame->body + key_data_offset, data->key_info.key_data_length);
181 }
182
183 return 0;
184}
185
187 if (data->key_info.key_data_length > 0) {
188 free(data->key_info.key_data);
189 }
190}
#define EAPOL_KEY_INFO_M2
Definition: security.h:23
#define EAPOL_KEY_INFO_M3
Definition: security.h:24
#define EAPOL_KEY_INFO_M4
Definition: security.h:25
#define EAPOL_KEY_INFO_M1
Definition: security.h:22
const char * libwifi_get_wpa_message_string(struct libwifi_frame *frame)
Get a string describing the WPA handshake message inside a supplied libwifi_frame.
Definition: eapol.c:105
int libwifi_check_wpa_message(struct libwifi_frame *frame)
Check what message of the WPA1/2 handshake is in the given frame.
Definition: eapol.c:74
int libwifi_check_wpa_handshake(struct libwifi_frame *frame)
A libwifi_frame is deemed to be an EAPOL handshake if the following criteria is met:
Definition: eapol.c:34
void libwifi_free_wpa_data(struct libwifi_wpa_auth_data *data)
Free any memory allocated inside of a libwifi_wpa_auth data, such as a buffer for WPA key data alloca...
Definition: eapol.c:186
int libwifi_get_wpa_data(struct libwifi_frame *frame, struct libwifi_wpa_auth_data *data)
Get the EAPOL/WPA information from a given libwifi_frame.
Definition: eapol.c:147
int libwifi_get_wpa_key_data_length(struct libwifi_frame *frame)
Get the length of the key data, if any, present at the end of an EAPOL frame.
Definition: eapol.c:127
@ HANDSHAKE_M2
Definition: eapol.h:24
@ HANDSHAKE_INVALID
Definition: eapol.h:27
@ HANDSHAKE_M1
Definition: eapol.h:23
@ HANDSHAKE_M3
Definition: eapol.h:25
@ HANDSHAKE_M4
Definition: eapol.h:26
@ TYPE_DATA
Definition: frame.h:33
#define XEROX_OUI
Definition: llc.h:21
#define LLC_TYPE_AUTH
Definition: llc.h:23
unsigned int type
Definition: frame.h:123
unsigned char * body
Definition: frame.h:314
size_t len
Definition: frame.h:311
struct libwifi_frame_ctrl frame_control
Definition: frame.h:310
size_t header_len
Definition: frame.h:313
libwifi Representation of the encapsulating 802.1X data in an EAPOL frame ┌─────────────────┐ │ Versi...
Definition: security.h:281
struct libwifi_wpa_key_info key_info
Definition: security.h:286
uint64_t replay_counter
Definition: security.h:257
uint16_t information
Definition: security.h:255
unsigned char * key_data
Definition: security.h:264
uint16_t key_data_length
Definition: security.h:263
uint16_t key_length
Definition: security.h:256