Skip to content

Commit 1802ee7

Browse files
Juha HeiskanenMika Leppänen
authored andcommitted
EAPOL message parser and write helper function.
Defined when eapol PDU frmae for encode and write.
1 parent da15653 commit 1802ee7

File tree

3 files changed

+358
-2
lines changed

3 files changed

+358
-2
lines changed

source/Security/PANA/pana_eap_header.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@
5252
*
5353
*/
5454

55-
typedef struct {
55+
typedef struct eap_header{
5656
uint16_t length;
5757
uint8_t eap_code;
5858
uint8_t id_seq;
5959
uint8_t type;
6060
uint8_t *data_ptr;
6161
} eap_header_t;
6262

63-
typedef struct {
63+
typedef struct eap_tls_header{
6464
uint8_t *data_ptr;
6565
uint8_t eap_tls_flags;
6666
uint16_t tls_frame_length;

source/Security/eapol/eapol_helper.c

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
/*
2+
* Copyright (c) 2018, Arm Limited and affiliates.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
19+
20+
#include "nsconfig.h"
21+
22+
#include "ns_types.h"
23+
#include "eventOS_event.h"
24+
#include "ns_trace.h"
25+
#include "string.h"
26+
#include "common_functions.h"
27+
#include "Security/PANA/pana_eap_header.h"
28+
#include "Security/eapol/eapol_helper.h"
29+
30+
31+
#define KEY_INFO_VERSION_BIT_MASK 0x0007
32+
#define KEY_INFO_VERSION_BIT_SHIFT 0
33+
#define KEY_INFO_KEY_TYPE_BIT_MASK 0x0008
34+
#define KEY_INFO_KEY_TYPE_BIT_SHIFT 3
35+
#define KEY_INFO_INSTALL_BIT_MASK 0x0040
36+
#define KEY_INFO_INSTALL_BIT_SHIFT 6
37+
#define KEY_INFO_ACK_BIT_MASK 0x0080
38+
#define KEY_INFO_ACK_BIT_SHIFT 7
39+
#define KEY_INFO_MIC_MASK 0x0100
40+
#define KEY_INFO_MIC_SHIFT 8
41+
#define KEY_INFO_SECURE_MASK 0x0200
42+
#define KEY_INFO_SECURE_SHIFT 9
43+
#define KEY_INFO_ERROR_MASK 0x0400
44+
#define KEY_INFO_ERROR_SHIFT 10
45+
#define KEY_INFO_REQUEST_MASK 0x0800
46+
#define KEY_INFO_REQUEST_SHIFT 11
47+
#define KEY_INFO_ENC_KEY_DATA_MASK 0x1000
48+
#define KEY_INFO_ENC_KEY_DATA_SHIFT 12
49+
#define KEY_INFO_SMK_MASK 0x2000
50+
#define KEY_INFO_SMK_SHIFT 13
51+
52+
static uint8_t *eapol_key_information_write(eapol_key_information_t *key_information, uint8_t *ptr)
53+
{
54+
uint16_t key_info = 0;
55+
key_info |= (key_information->description_version << KEY_INFO_VERSION_BIT_SHIFT);
56+
key_info |= (key_information->pairwise_key << KEY_INFO_KEY_TYPE_BIT_SHIFT);
57+
key_info |= (key_information->install << KEY_INFO_INSTALL_BIT_SHIFT);
58+
key_info |= (key_information->key_ack << KEY_INFO_ACK_BIT_SHIFT);
59+
key_info |= (key_information->key_mic << KEY_INFO_MIC_SHIFT);
60+
key_info |= (key_information->secured_key_frame << KEY_INFO_SECURE_SHIFT);
61+
key_info |= (key_information->error << KEY_INFO_ERROR_SHIFT);
62+
key_info |= (key_information->request << KEY_INFO_REQUEST_SHIFT);
63+
key_info |= (key_information->encrypted_key_data << KEY_INFO_ENC_KEY_DATA_SHIFT);
64+
key_info |= (key_information->smk_handshake << KEY_INFO_SMK_SHIFT);
65+
return common_write_16_bit(key_info, ptr);
66+
}
67+
68+
static uint8_t *eapol_key_information_read(eapol_key_information_t *key_information, uint8_t *ptr)
69+
{
70+
uint16_t key_info = common_read_16_bit(ptr);
71+
key_information->description_version = ((key_info & KEY_INFO_VERSION_BIT_MASK) >> KEY_INFO_VERSION_BIT_SHIFT);
72+
key_information->pairwise_key = ((key_info & KEY_INFO_KEY_TYPE_BIT_MASK) >> KEY_INFO_KEY_TYPE_BIT_SHIFT);
73+
key_information->install = ((key_info & KEY_INFO_INSTALL_BIT_MASK) >> KEY_INFO_INSTALL_BIT_SHIFT);
74+
key_information->key_ack = ((key_info & KEY_INFO_ACK_BIT_MASK) >> KEY_INFO_ACK_BIT_SHIFT);
75+
key_information->key_mic = ((key_info & KEY_INFO_MIC_MASK) >> KEY_INFO_MIC_SHIFT);
76+
key_information->secured_key_frame = ((key_info & KEY_INFO_SECURE_MASK) >> KEY_INFO_SECURE_SHIFT);
77+
key_information->error = ((key_info & KEY_INFO_ERROR_MASK) >> KEY_INFO_ERROR_SHIFT);
78+
key_information->request = ((key_info & KEY_INFO_REQUEST_MASK) >> KEY_INFO_REQUEST_SHIFT);
79+
key_information->encrypted_key_data = ((key_info & KEY_INFO_ENC_KEY_DATA_MASK) >> KEY_INFO_ENC_KEY_DATA_SHIFT);
80+
key_information->smk_handshake = ((key_info & KEY_INFO_SMK_MASK) >> KEY_INFO_SMK_SHIFT);
81+
return ptr + 2;
82+
}
83+
84+
85+
static bool eapol_parse_eap_packet(eapol_pdu_t * eapol_pdu)
86+
{
87+
return eap_header_parse(eapol_pdu->packet_body, eapol_pdu->packet_length, &eapol_pdu->msg.eap);
88+
}
89+
90+
91+
static bool eapol_parse_key_packet(eapol_pdu_t * eapol_pdu)
92+
{
93+
if (eapol_pdu->packet_length < EAPOL_KEY_FRAME_BASE_SIZE) {
94+
return false;
95+
}
96+
uint8_t * ptr = eapol_pdu->packet_body;
97+
eapol_key_frame_t *key_frame = &eapol_pdu->msg.key;
98+
key_frame->key_description = *ptr++;
99+
if (key_frame->key_description != EAPOL_RSN_KEY_DESCRIPTION) {
100+
return false;
101+
}
102+
ptr = eapol_key_information_read(&key_frame->key_information, ptr);
103+
if (key_frame->key_information.description_version != KEY_DESCRIPTION_HMAC_SHA1_MIC_AES_ENC) {
104+
return false;
105+
}
106+
key_frame->key_length = common_read_16_bit(ptr);
107+
ptr += 2;
108+
109+
key_frame->replay_counter = common_read_64_bit(ptr);
110+
ptr += 8;
111+
112+
key_frame->key_nonce = ptr;
113+
ptr += 32;
114+
115+
key_frame->key_iv = ptr;
116+
ptr += 16;
117+
118+
key_frame->key_rsc = ptr;
119+
ptr += 16; //Skip 8 byte RSC + RESERVED 8
120+
121+
key_frame->key_mic = ptr;
122+
ptr += 16;
123+
124+
key_frame->key_data_length = common_read_16_bit(ptr);
125+
ptr += 2;
126+
key_frame->key_data = ptr;
127+
if (key_frame->key_data_length > (eapol_pdu->packet_length - EAPOL_KEY_FRAME_BASE_SIZE)) {
128+
return false;
129+
}
130+
131+
return true;
132+
133+
}
134+
135+
bool eapol_parse_pdu_header(uint8_t *ptr, uint16_t data_length, eapol_pdu_t * eapol_pdu)
136+
{
137+
//Validate MIN length
138+
if (data_length < EAPOL_BASE_LENGTH) {
139+
return false;
140+
}
141+
//Validate Protocol version
142+
uint8_t protocol = *ptr++;
143+
if (protocol != EAPOL_PROTOCOL_VERSION) {
144+
return false;
145+
}
146+
eapol_pdu->packet_type = *ptr++;
147+
eapol_pdu->packet_length = common_read_16_bit(ptr);
148+
ptr += 2;
149+
//Validate Body Length
150+
if (eapol_pdu->packet_length > data_length - EAPOL_BASE_LENGTH) {
151+
return false;
152+
}
153+
eapol_pdu->packet_body = ptr;
154+
155+
if (eapol_pdu->packet_type == EAPOL_EAP_TYPE) {
156+
return eapol_parse_eap_packet(eapol_pdu);
157+
} else if (eapol_pdu->packet_type == EAPOL_KEY_TYPE) {
158+
return eapol_parse_key_packet(eapol_pdu);
159+
} else {
160+
return false;
161+
}
162+
163+
}
164+
165+
void eapol_write_pdu_frame(uint8_t *ptr, eapol_pdu_t * eapol_pdu)
166+
{
167+
*ptr++ = EAPOL_PROTOCOL_VERSION;
168+
*ptr++ = eapol_pdu->packet_type;
169+
ptr = common_write_16_bit(eapol_pdu->packet_length, ptr);
170+
eapol_pdu->packet_body = ptr;
171+
172+
if (eapol_pdu->packet_type == EAPOL_EAP_TYPE) {
173+
eap_header_t *eap_header = &eapol_pdu->msg.eap;
174+
ptr = eap_header_build(ptr, eap_header->length, eap_header->eap_code, eap_header->id_seq, eap_header->type);
175+
memcpy(ptr, eap_header->data_ptr, eap_header->length);
176+
177+
} else if (eapol_pdu->packet_type == EAPOL_KEY_TYPE) {
178+
eapol_key_frame_t *key_frame = &eapol_pdu->msg.key;
179+
*ptr++ = key_frame->key_description;
180+
ptr = eapol_key_information_write(&key_frame->key_information, ptr);
181+
ptr = common_write_16_bit(key_frame->key_length, ptr);
182+
ptr = common_write_64_bit(key_frame->replay_counter, ptr);
183+
184+
if (key_frame->key_nonce) {
185+
memcpy(ptr, key_frame->key_nonce, 32);
186+
} else {
187+
memset(ptr, 0, 32);
188+
}
189+
ptr += 32;
190+
191+
if (key_frame->key_iv) {
192+
memcpy(ptr, key_frame->key_iv, 16);
193+
} else {
194+
memset(ptr, 0, 16);
195+
}
196+
ptr += 16;
197+
198+
if (key_frame->key_rsc) {
199+
memcpy(ptr, key_frame->key_rsc, 8);
200+
} else {
201+
memset(ptr, 0, 8);
202+
}
203+
ptr += 8;
204+
205+
//Reserved 8bytes
206+
memset(ptr, 0, 8);
207+
ptr += 8;
208+
209+
if (key_frame->key_mic && key_frame->key_information.key_mic) {
210+
memcpy(ptr, key_frame->key_mic, 16);
211+
} else {
212+
memset(ptr, 0, 16);
213+
}
214+
ptr += 16;
215+
ptr = common_write_16_bit(key_frame->key_data_length, ptr);
216+
if (key_frame->key_data_length) {
217+
memcpy(ptr, key_frame->key_data, key_frame->key_data_length);
218+
}
219+
}
220+
}
221+
222+
223+
224+
uint16_t eapol_pdu_eap_frame_init(eapol_pdu_t * eapol_pdu, uint8_t eap_code, uint8_t id_seq, uint8_t type, uint16_t data_length, uint8_t *data_ptr)
225+
{
226+
memset(eapol_pdu, 0, sizeof(eapol_pdu_t));
227+
228+
eapol_pdu->packet_type = EAPOL_EAP_TYPE;
229+
eapol_pdu->packet_length = data_length;
230+
eapol_pdu->msg.eap.eap_code = eap_code;
231+
eapol_pdu->msg.eap.data_ptr = data_ptr;
232+
eapol_pdu->msg.eap.length = data_length;
233+
eapol_pdu->msg.eap.id_seq = id_seq;
234+
eapol_pdu->msg.eap.type = type;
235+
236+
if (eap_code == EAP_REQ || eap_code == EAP_RESPONSE) {
237+
eapol_pdu->packet_body += 5;
238+
eapol_pdu->msg.eap.length++; // Add space for type
239+
} else {
240+
eapol_pdu->packet_body += 4;
241+
}
242+
243+
return eapol_pdu_total_length(eapol_pdu);
244+
245+
}
246+
247+
uint16_t eapol_pdu_key_frame_init(eapol_pdu_t * eapol_pdu, uint16_t data_length, uint8_t *data_ptr)
248+
{
249+
memset(eapol_pdu, 0, sizeof(eapol_pdu_t));
250+
251+
eapol_pdu->packet_type = EAPOL_KEY_TYPE;
252+
eapol_pdu->packet_length = data_length + EAPOL_KEY_FRAME_BASE_SIZE;
253+
eapol_pdu->msg.key.key_data = data_ptr;
254+
eapol_pdu->msg.key.key_description = EAPOL_RSN_KEY_DESCRIPTION;
255+
eapol_pdu->msg.key.key_data_length = data_length;
256+
eapol_pdu->msg.key.key_information.description_version = KEY_DESCRIPTION_HMAC_SHA1_MIC_AES_ENC;
257+
258+
return eapol_pdu_total_length(eapol_pdu);
259+
260+
}
261+

source/Security/eapol/eapol_helper.h

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright (c) 2018, Arm Limited and affiliates.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#ifndef EAPOL_HELPER_H_
19+
#define EAPOL_HELPER_H_
20+
21+
#define EAPOL_PROTOCOL_VERSION 3
22+
#define EAPOL_EAP_TYPE 0
23+
#define EAPOL_KEY_TYPE 3
24+
25+
#define EAPOL_BASE_LENGTH 4 //Protocol version 1 byte, Packet type 1 byte, packet length 2 byte
26+
27+
#define EAPOL_KEY_FRAME_BASE_SIZE 95
28+
29+
struct eap_header_t;
30+
31+
typedef struct eapol_key_information {
32+
unsigned description_version:3;
33+
bool pairwise_key:1;
34+
bool install:1;
35+
bool key_ack:1;
36+
bool key_mic:1;
37+
bool secured_key_frame:1;
38+
bool error:1;
39+
bool request:1;
40+
bool encrypted_key_data:1;
41+
bool smk_handshake:1;
42+
} eapol_key_information_t;
43+
44+
typedef struct eapol_key_frame {
45+
uint8_t key_description;
46+
eapol_key_information_t key_information;
47+
uint16_t key_length;
48+
uint64_t replay_counter;
49+
uint8_t *key_nonce; /*< Write operation: NULL memset are by 0, otherwise write data */
50+
uint8_t *key_iv; /*< Write operation: NULL memset are by 0, otherwise write data */
51+
uint8_t *key_rsc; /*< Write operation: NULL memset are by 0, otherwise write data */
52+
uint8_t *key_mic; /*< Write operation: NULL memset are by 0, otherwise write data */
53+
uint16_t key_data_length;
54+
uint8_t *key_data;
55+
} eapol_key_frame_t;
56+
57+
typedef struct eapol_pdu {
58+
uint8_t packet_type; /*< EAPOL_EAP_TYPE or EAPOL_KEY_TYPE */
59+
uint16_t packet_length; /*< EAPOL Total length includin full packet body and data */
60+
uint8_t *packet_body; /*< Data pointer to packet body*/
61+
union {
62+
eapol_key_frame_t key;
63+
struct eap_header eap;
64+
} msg;
65+
} eapol_pdu_t;
66+
67+
#define EAPOL_RSN_KEY_DESCRIPTION 2
68+
#define KEY_DESCRIPTION_HMAC_MD5_MIC_ARC4_ENC 1
69+
#define KEY_DESCRIPTION_HMAC_SHA1_MIC_AES_ENC 2
70+
#define KEY_DESCRIPTION_AES_128_CMAC_MIC_AES_ENC 3
71+
72+
/**
73+
* Helper macro to get full message length
74+
*/
75+
#define eapol_pdu_total_length(x) (x->packet_length + EAPOL_BASE_LENGTH)
76+
77+
/**
78+
* Helper macro to message start
79+
*/
80+
#define eapol_pdu_msg_start(x) (x->packet_body - EAPOL_BASE_LENGTH)
81+
82+
/**
83+
* Parse EAPOL message to EAPOL-pdu frame
84+
*
85+
* \return true when message is valid and supported otherwise return false
86+
*/
87+
bool eapol_parse_pdu_header(uint8_t *ptr, uint16_t data_length, eapol_pdu_t * eapol_pdu);
88+
89+
void eapol_write_pdu_frame(uint8_t *ptr, eapol_pdu_t * eapol_pdu);
90+
91+
uint16_t eapol_pdu_eap_frame_init(eapol_pdu_t * eapol_pdu, uint8_t eap_code, uint8_t id_seq, uint8_t type, uint16_t data_length, uint8_t *data_ptr);
92+
93+
uint16_t eapol_pdu_key_frame_init(eapol_pdu_t * eapol_pdu, uint16_t data_length, uint8_t *data_ptr);
94+
95+
#endif /* EAPOL_HELPER_H_ */

0 commit comments

Comments
 (0)