eap_peer_procedures.c
Go to the documentation of this file.
1 /**
2  * @file eap_peer_procedures.c
3  * @brief EAP peer state machine procedures
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2022-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneEAP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SUPPLICANT_TRACE_LEVEL
33 
34 //Dependencies
35 #include "supplicant/supplicant.h"
37 #include "eap/eap_md5.h"
38 #include "eap/eap_tls.h"
39 #include "eap/eap_debug.h"
40 #include "debug.h"
41 
42 //Check EAP library configuration
43 #if (SUPPLICANT_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Determine the code, identifier value, and type of the current request
48  * @param[in] context Pointer to the 802.1X supplicant context
49  **/
50 
52 {
53  const EapPacket *packet;
54  const EapRequest *request;
55 
56  //Debug message
57  TRACE_DEBUG("parseEapReq() procedure...\r\n");
58 
59  //In the case of a parsing error, rxReq, rxSuccess, and rxFailure will all
60  //be set to FALSE. The values of reqId and reqMethod may be undefined as a
61  //result (refer to RFC 4137, section 4.4)
62  context->rxReq = 0;
63  context->rxSuccess = 0;
64  context->rxFailure = 0;
65 
66  //Point to the EAP packet
67  packet = (EapPacket *) context->eapReqData;
68 
69  //Save the identifier value associated with the current EAP request
70  context->reqId = packet->identifier;
71 
72  //Check code field
73  if(packet->code == EAP_CODE_REQUEST)
74  {
75  //Valid EAP request?
76  if(context->eapReqDataLen >= sizeof(EapRequest))
77  {
78  //The current received packet is an EAP Request
79  context->rxReq = TRUE;
80 
81  //Point to the EAP request
82  request = (EapRequest *) context->eapReqData;
83  //Determine the type of the current request
84  context->reqMethod = (EapMethodType) request->type;
85  }
86  }
87  else if(packet->code == EAP_CODE_SUCCESS)
88  {
89  //The current received packet is an EAP Success
90  context->rxSuccess = TRUE;
91  }
92  else if(packet->code == EAP_CODE_FAILURE)
93  {
94  //The current received packet is an EAP Failure
95  context->rxFailure = TRUE;
96  }
97  else
98  {
99  //Unless a host implements an EAP authenticator layer, EAP Response
100  //packets will be silently discarded (refer to RFC 3748, section 2.3)
101  }
102 }
103 
104 
105 /**
106  * @brief Test for the validity of a message
107  * @param[in] context Pointer to the 802.1X supplicant context
108  * @return TRUE if the message is invalid and must be ignored, else FALSE
109  **/
110 
112 {
113  error_t error;
114 
115  //Debug message
116  TRACE_DEBUG("m.check() procedure...\r\n");
117 
118 #if (EAP_MD5_SUPPORT == ENABLED)
119  //EAP-MD5 method?
120  if(context->selectedMethod == EAP_METHOD_TYPE_MD5_CHALLENGE)
121  {
122  //Test the validity of the message
123  error = eapMd5CheckRequest(context, (EapMd5Packet *) context->eapReqData,
124  context->eapReqDataLen);
125  }
126  else
127 #endif
128 #if (EAP_TLS_SUPPORT == ENABLED)
129  //EAP-TLS method?
130  if(context->selectedMethod == EAP_METHOD_TYPE_TLS)
131  {
132  //Test the validity of the message
133  error = eapTlsCheckRequest(context, (EapTlsPacket *) context->eapReqData,
134  context->eapReqDataLen);
135  }
136  else
137 #endif
138  //Unknown EAP method?
139  {
140  //Report an error
141  error = ERROR_INVALID_TYPE;
142  }
143 
144  //Return TRUE if the message is invalid and must be ignored
145  return error ? TRUE : FALSE;
146 }
147 
148 
149 /**
150  * @brief Parse and process a request
151  * @param[in] context Pointer to the 802.1X supplicant context
152  **/
153 
155 {
156  //Debug message
157  TRACE_DEBUG("m.process() procedure...\r\n");
158 
159 #if (EAP_MD5_SUPPORT == ENABLED)
160  //EAP-MD5 method?
161  if(context->selectedMethod == EAP_METHOD_TYPE_MD5_CHALLENGE)
162  {
163  //Parse and process the incoming request
164  eapMd5ProcessRequest(context, (EapMd5Packet *) context->eapReqData,
165  context->eapReqDataLen);
166  }
167  else
168 #endif
169 #if (EAP_TLS_SUPPORT == ENABLED)
170  //EAP-TLS method?
171  if(context->selectedMethod == EAP_METHOD_TYPE_TLS)
172  {
173  //Parse and process the incoming request
174  eapTlsProcessRequest(context, (EapTlsPacket *) context->eapReqData,
175  context->eapReqDataLen);
176  }
177  else
178 #endif
179  //Unknown EAP method?
180  {
181  //Just for sanity
182  }
183 
184  //Finally, the method must set the allowNotifications variable (refer to
185  //RFC 4137, section 4.2)
186  if(context->methodState == EAP_METHOD_STATE_CONT ||
187  context->methodState == EAP_METHOD_STATE_MAY_CONT)
188  {
189  //If the new methodState is either CONT or MAY_CONT, and if the method
190  //specification does not forbid the use of Notification messages, set
191  //allowNotifications to TRUE
192  context->allowNotifications = TRUE;
193  }
194  else
195  {
196  //Otherwise, set allowNotifications to FALSE
197  context->allowNotifications = FALSE;
198  }
199 }
200 
201 
202 /**
203  * @brief Create a response message
204  * @param[in] context Pointer to the 802.1X supplicant context
205  **/
206 
208 {
209  //Debug message
210  TRACE_DEBUG("m.buildResp() procedure...\r\n");
211 
212 #if (EAP_MD5_SUPPORT == ENABLED)
213  //EAP-MD5 method?
214  if(context->selectedMethod == EAP_METHOD_TYPE_MD5_CHALLENGE)
215  {
216  //Create a response message
217  eapMd5BuildResponse(context);
218  }
219  else
220 #endif
221 #if (EAP_TLS_SUPPORT == ENABLED)
222  //EAP-TLS method?
223  if(context->selectedMethod == EAP_METHOD_TYPE_TLS)
224  {
225  //Create a response message
226  eapTlsBuildResponse(context);
227  }
228  else
229 #endif
230  //Unknown EAP method?
231  {
232  //Just for sanity
233  }
234 }
235 
236 
237 /**
238  * @brief Process the contents of Identity request
239  * @param[in] context Pointer to the 802.1X supplicant context
240  **/
241 
243 {
244  //Debug message
245  TRACE_DEBUG("processIdentity() procedure...\r\n");
246 }
247 
248 
249 /**
250  * @brief Create the appropriate Identity response
251  * @param[in] context Pointer to the 802.1X supplicant context
252  **/
253 
255 {
256  size_t n;
257  EapResponse *response;
258 
259  //Debug message
260  TRACE_DEBUG("buildIdentity() procedure...\r\n");
261 
262  //Point to the buffer where to format the EAP packet
263  response = (EapResponse *) context->eapRespData;
264 
265  //A response of type 1 (Identity) should be sent in response to a request
266  //with a type of 1 (Identity)
267  response->code = EAP_CODE_RESPONSE;
268  response->identifier = context->reqId;
269  response->type = EAP_METHOD_TYPE_IDENTITY;
270 
271  //Retrieve the length of the user name
272  n = osStrlen(context->username);
273  //Copy user name
274  osMemcpy(response->data, context->username, n);
275 
276  //Total length of the EAP packet
277  n += sizeof(EapResponse);
278  //Convert the length field to network byte order
279  response->length = htons(n);
280 
281  //Debug message
282  TRACE_DEBUG("Sending EAP packet (%" PRIuSIZE " bytes)\r\n", n);
283  //Dump EAP header contents for debugging purpose
284  eapDumpHeader((EapPacket *) response);
285 
286  //Save the length of the EAP response
287  context->eapRespDataLen = n;
288 }
289 
290 
291 /**
292  * @brief Process the contents of Notification request
293  * @param[in] context Pointer to the 802.1X supplicant context
294  **/
295 
297 {
298  //Debug message
299  TRACE_DEBUG("processNotify() procedure...\r\n");
300 }
301 
302 
303 /**
304  * @brief Create the appropriate Notification response
305  * @param[in] context Pointer to the 802.1X supplicant context
306  **/
307 
309 {
310  size_t n;
311  EapResponse *response;
312 
313  //Debug message
314  TRACE_DEBUG("buildNotify() procedure...\r\n");
315 
316  //Point to the buffer where to format the EAP packet
317  response = (EapResponse *) context->eapRespData;
318 
319  //A response must be sent in reply to the request with a Type field of
320  //2 (Notification)
321  response->code = EAP_CODE_RESPONSE;
322  response->identifier = context->reqId;
323  response->type = EAP_METHOD_TYPE_NOTIFICATION;
324 
325  //The Type-Data field of the response is zero octets in length
326  n = sizeof(EapResponse);
327  //Convert the length field to network byte order
328  response->length = htons(n);
329 
330  //Debug message
331  TRACE_DEBUG("Sending EAP packet (%" PRIuSIZE " bytes)\r\n", n);
332  //Dump EAP header contents for debugging purpose
333  eapDumpHeader((EapPacket *) response);
334 
335  //Save the length of the EAP response
336  context->eapRespDataLen = n;
337 }
338 
339 
340 /**
341  * @brief Create a NAK response
342  * @param[in] context Pointer to the 802.1X supplicant context
343  **/
344 
346 {
347  size_t n;
348  EapResponse *response;
349 
350  //Debug message
351  TRACE_DEBUG("buildNak() procedure...\r\n");
352 
353  //Point to the buffer where to format the EAP packet
354  response = (EapResponse *) context->eapRespData;
355 
356  //The legacy Nak Type is valid only in response messages. It is sent in
357  //reply to a request where the desired authentication type is unacceptable
358  //(refer to RFC 3748, section 5.3.1)
359  response->code = EAP_CODE_RESPONSE;
360  response->identifier = context->reqId;
361  response->type = EAP_METHOD_TYPE_NAK;
362 
363  //The response contains one or more authentication types desired by the peer
364  n = 0;
365 
366 #if (EAP_MD5_SUPPORT == ENABLED)
367  //Check whether EAP-MD5 method is acceptable
368  if(osStrlen(context->password) > 0)
369  {
370  response->data[n++] = EAP_METHOD_TYPE_MD5_CHALLENGE;
371  }
372 #endif
373 
374 #if (EAP_TLS_SUPPORT == ENABLED)
375  //Check whether EAP-TLS method is acceptable
376  if(context->tlsInitCallback != NULL)
377  {
378  response->data[n++] = EAP_METHOD_TYPE_TLS;
379  }
380 #endif
381 
382  //Type zero is used to indicate that the sender has no viable alternatives,
383  //and therefore the authenticator should not send another request after
384  //receiving a Nak Response containing a zero value
385  if(n == 0)
386  {
387  response->data[n++] = EAP_METHOD_TYPE_NONE;
388  }
389 
390  //Total length of the EAP packet
391  n += sizeof(EapResponse);
392  //Convert the length field to network byte order
393  response->length = htons(n);
394 
395  //Debug message
396  TRACE_DEBUG("Sending EAP packet (%" PRIuSIZE " bytes)\r\n", n);
397  //Dump EAP header contents for debugging purpose
398  eapDumpHeader((EapPacket *) response);
399 
400  //Save the length of the EAP response
401  context->eapRespDataLen = n;
402 }
403 
404 
405 /**
406  * @brief Obtain key material for use by EAP or lower layers
407  * @param[in] context Pointer to the 802.1X supplicant context
408  * @return EAP key
409  **/
410 
412 {
413  //Debug message
414  TRACE_DEBUG("m.getKey() procedure...\r\n");
415 
416  //Not implemented
417  return NULL;
418 }
419 
420 
421 /**
422  * @brief Check whether EAP key is available
423  * @param[in] context Pointer to the 802.1X supplicant context
424  * @return Boolean
425  **/
426 
428 {
429  //Debug message
430  TRACE_DEBUG("m.isKeyAvailable() procedure...\r\n");
431 
432  //Not implemented
433  return FALSE;
434 }
435 
436 
437 /**
438  * @brief Check whether the specified EAP method is allowed
439  * @param[in] context Pointer to the 802.1X supplicant context
440  * @param[in] method EAP method
441  * @return TRUE if the method is allowed, else FALSE
442  **/
443 
445 {
446  bool_t acceptable;
447 
448  //Debug message
449  TRACE_DEBUG("allowMethod() procedure...\r\n");
450 
451  //Initialize flag
452  acceptable = FALSE;
453 
454 #if (EAP_MD5_SUPPORT == ENABLED)
455  //EAP-MD5 method?
456  if(method == EAP_METHOD_TYPE_MD5_CHALLENGE)
457  {
458  //Check whether EAP-MD5 method is acceptable
459  if(osStrlen(context->password) > 0)
460  {
461  acceptable = TRUE;
462  }
463  }
464  else
465 #endif
466 #if (EAP_TLS_SUPPORT == ENABLED)
467  //EAP-TLS method?
468  if(method == EAP_METHOD_TYPE_TLS)
469  {
470  //Check whether EAP-TLS method is acceptable
471  if(context->tlsInitCallback != NULL)
472  {
473  acceptable = TRUE;
474  }
475  }
476  else
477 #endif
478  //Unknown EAP method?
479  {
480  //Just for sanity
481  }
482 
483  //Return TRUE if the EAP method is allowed
484  return acceptable;
485 }
486 
487 #endif
#define htons(value)
Definition: cpu_endian.h:413
@ EAP_METHOD_TYPE_TLS
EAP-TLS.
Definition: eap.h:172
int bool_t
Definition: compiler_port.h:53
void eapDumpHeader(const EapPacket *header)
Dump EAP header for debugging purpose.
Definition: eap_debug.c:105
EapMethodType
EAP method types.
Definition: eap.h:164
@ EAP_CODE_RESPONSE
Response.
Definition: eap.h:153
uint8_t * eapPeerGetKey(SupplicantContext *context)
Obtain key material for use by EAP or lower layers.
@ EAP_METHOD_TYPE_NONE
None.
Definition: eap.h:165
Supplicant state machine procedures.
802.1X supplicant
#define TRUE
Definition: os_port.h:50
EapMd5Packet
Definition: eap_md5.h:63
@ EAP_CODE_FAILURE
Failure.
Definition: eap.h:155
void eapTlsBuildResponse(SupplicantContext *context)
Build EAP-TLS response.
Definition: eap_tls.c:234
#define SupplicantContext
Definition: supplicant.h:36
EapTlsPacket
Definition: eap.h:267
void eapProcessIdentity(SupplicantContext *context)
Process the contents of Identity request.
@ EAP_METHOD_TYPE_NAK
Legacy Nak.
Definition: eap.h:168
EAP-TLS authentication method.
#define osStrlen(s)
Definition: os_port.h:165
bool_t eapAllowMethod(SupplicantContext *context, EapMethodType method)
Check whether the specified EAP method is allowed.
void eapBuildResp(SupplicantContext *context)
Create a response message.
void eapParseReq(SupplicantContext *context)
Determine the code, identifier value, and type of the current request.
#define FALSE
Definition: os_port.h:46
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
error_t
Error codes.
Definition: error.h:43
@ EAP_METHOD_TYPE_IDENTITY
Identity.
Definition: eap.h:166
void eapBuildIdentity(SupplicantContext *context)
Create the appropriate Identity response.
void eapTlsProcessRequest(SupplicantContext *context, const EapTlsPacket *request, size_t length)
Process incoming EAP-TLS request.
Definition: eap_tls.c:79
@ EAP_CODE_SUCCESS
Success.
Definition: eap.h:154
#define EAP_MD5_SUPPORT
Definition: eap.h:84
@ ERROR_INVALID_TYPE
Definition: error.h:115
void eapProcessNotify(SupplicantContext *context)
Process the contents of Notification request.
@ EAP_CODE_REQUEST
Request.
Definition: eap.h:152
void eapBuildNotify(SupplicantContext *context)
Create the appropriate Notification response.
void eapMd5ProcessRequest(SupplicantContext *context, const EapMd5Packet *request, size_t length)
Process incoming MD5 challenge request.
Definition: eap_md5.c:75
#define ENABLED
Definition: os_port.h:37
@ EAP_METHOD_STATE_CONT
Definition: eap_peer_fsm.h:78
EapResponse
Definition: eap.h:252
EapRequest
Definition: eap.h:238
#define TRACE_DEBUG(...)
Definition: debug.h:107
@ EAP_METHOD_TYPE_NOTIFICATION
Notification.
Definition: eap.h:167
Data logging functions for debugging purpose (EAP)
bool_t eapIsKeyAvailable(SupplicantContext *context)
Check whether EAP key is available.
uint8_t n
EapPacket
Definition: eap.h:224
error_t eapMd5CheckRequest(SupplicantContext *context, const EapMd5Packet *request, size_t length)
Check incoming MD5 challenge request.
Definition: eap_md5.c:52
error_t eapTlsCheckRequest(SupplicantContext *context, const EapTlsPacket *request, size_t length)
Check incoming EAP-TLS request.
Definition: eap_tls.c:51
void eapProcessReq(SupplicantContext *context)
Parse and process a request.
bool_t eapCheckReq(SupplicantContext *context)
Test for the validity of a message.
@ EAP_METHOD_STATE_MAY_CONT
Definition: eap_peer_fsm.h:79
#define PRIuSIZE
MD5-Challenge authentication method.
Debugging facilities.
@ EAP_METHOD_TYPE_MD5_CHALLENGE
MD5-Challenge.
Definition: eap.h:169
void eapBuildNak(SupplicantContext *context)
Create a NAK response.
void eapMd5BuildResponse(SupplicantContext *context)
Build MD5 challenge response.
Definition: eap_md5.c:102