iPXE
eap.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <stdlib.h>
28#include <errno.h>
29#include <string.h>
30#include <byteswap.h>
31#include <ipxe/netdevice.h>
32#include <ipxe/eap.h>
33
34/** @file
35 *
36 * Extensible Authentication Protocol
37 *
38 */
39
40/**
41 * Transmit EAP response
42 *
43 * @v supplicant EAP supplicant
44 * @v rsp Response type data
45 * @v rsp_len Length of response type data
46 * @ret rc Return status code
47 */
48int eap_tx_response ( struct eap_supplicant *supplicant,
49 const void *rsp, size_t rsp_len ) {
50 struct net_device *netdev = supplicant->netdev;
51 struct eap_message *msg;
52 size_t len;
53 int rc;
54
55 /* Allocate and populate response */
56 len = ( sizeof ( *msg ) + rsp_len );
57 msg = malloc ( len );
58 if ( ! msg ) {
59 rc = -ENOMEM;
60 goto err_alloc;
61 }
62 msg->hdr.code = EAP_CODE_RESPONSE;
63 msg->hdr.id = supplicant->id;
64 msg->hdr.len = htons ( len );
65 msg->type = supplicant->type;
66 memcpy ( msg->data, rsp, rsp_len );
67 DBGC ( netdev, "EAP %s Response id %#02x type %d\n",
68 netdev->name, msg->hdr.id, msg->type );
69
70 /* Transmit response */
71 if ( ( rc = supplicant->tx ( supplicant, msg, len ) ) != 0 ) {
72 DBGC ( netdev, "EAP %s could not transmit: %s\n",
73 netdev->name, strerror ( rc ) );
74 goto err_tx;
75 }
76
77 err_tx:
78 free ( msg );
79 err_alloc:
80 return rc;
81}
82
83/**
84 * Transmit EAP NAK
85 *
86 * @v supplicant EAP supplicant
87 * @ret rc Return status code
88 */
89static int eap_tx_nak ( struct eap_supplicant *supplicant ) {
90 struct net_device *netdev = supplicant->netdev;
91 unsigned int max = table_num_entries ( EAP_METHODS );
92 uint8_t methods[ max + 1 /* potential EAP_TYPE_NONE */ ];
93 unsigned int count = 0;
94 struct eap_method *method;
95
96 /* Populate methods list */
97 DBGC ( netdev, "EAP %s Nak offering types {", netdev->name );
99 if ( method->type > EAP_TYPE_NAK ) {
100 DBGC ( netdev, "%s%d",
101 ( count ? ", " : "" ), method->type );
102 methods[count++] = method->type;
103 }
104 }
105 if ( ! count )
106 methods[count++] = EAP_TYPE_NONE;
107 DBGC ( netdev, "}\n" );
108 assert ( count <= max );
109
110 /* Transmit response */
111 supplicant->type = EAP_TYPE_NAK;
112 return eap_tx_response ( supplicant, methods, count );
113}
114
115/**
116 * Handle EAP Request-Identity
117 *
118 * @v supplicant EAP supplicant
119 * @v req Request type data
120 * @v req_len Length of request type data
121 * @ret rc Return status code
122 */
123static int eap_rx_identity ( struct eap_supplicant *supplicant,
124 const void *req, size_t req_len ) {
125 struct net_device *netdev = supplicant->netdev;
126 void *rsp;
127 int rsp_len;
128 int rc;
129
130 /* Treat Request-Identity as blocking the link */
131 DBGC ( netdev, "EAP %s Request-Identity blocking link\n",
132 netdev->name );
133 DBGC_HDA ( netdev, 0, req, req_len );
135
136 /* Mark EAP as in progress */
137 supplicant->flags |= EAP_FL_ONGOING;
138
139 /* Construct response, if applicable */
141 &username_setting, &rsp );
142 if ( rsp_len < 0 ) {
143 /* We have no identity to offer, so wait until the
144 * switch times out and switches to MAC Authentication
145 * Bypass (MAB).
146 */
147 DBGC2 ( netdev, "EAP %s has no identity\n", netdev->name );
148 supplicant->flags |= EAP_FL_PASSIVE;
149 rc = 0;
150 goto no_response;
151 }
152
153 /* Transmit response */
154 if ( ( rc = eap_tx_response ( supplicant, rsp, rsp_len ) ) != 0 )
155 goto err_tx;
156
157 err_tx:
158 free ( rsp );
159 no_response:
160 return rc;
161}
162
163/** EAP Request-Identity method */
164struct eap_method eap_identity_method __eap_method = {
165 .type = EAP_TYPE_IDENTITY,
166 .rx = eap_rx_identity,
167};
168
169/**
170 * Handle EAP Request
171 *
172 * @v supplicant EAP supplicant
173 * @v msg EAP request
174 * @v len Length of EAP request
175 * @ret rc Return status code
176 */
177static int eap_rx_request ( struct eap_supplicant *supplicant,
178 const struct eap_message *msg, size_t len ) {
179 struct net_device *netdev = supplicant->netdev;
180 struct eap_method *method;
181 const void *req;
182 size_t req_len;
183
184 /* Sanity checks */
185 if ( len < sizeof ( *msg ) ) {
186 DBGC ( netdev, "EAP %s underlength request:\n", netdev->name );
187 DBGC_HDA ( netdev, 0, msg, len );
188 return -EINVAL;
189 }
190 req = msg->data;
191 req_len = ( len - sizeof ( *msg ) );
192
193 /* Record request details */
194 supplicant->id = msg->hdr.id;
195 supplicant->type = msg->type;
196 DBGC ( netdev, "EAP %s Request id %#02x type %d\n",
197 netdev->name, msg->hdr.id, msg->type );
198
199 /* Handle according to type */
201 if ( msg->type == method->type )
202 return method->rx ( supplicant, req, req_len );
203 }
204 DBGC ( netdev, "EAP %s requested type %d unknown:\n",
205 netdev->name, msg->type );
206 DBGC_HDA ( netdev, 0, msg, len );
207
208 /* Send NAK if applicable */
209 if ( msg->type > EAP_TYPE_NAK )
210 return eap_tx_nak ( supplicant );
211
212 return -ENOTSUP;
213}
214
215/**
216 * Handle EAP Success
217 *
218 * @v supplicant EAP supplicant
219 * @ret rc Return status code
220 */
221static int eap_rx_success ( struct eap_supplicant *supplicant ) {
222 struct net_device *netdev = supplicant->netdev;
223
224 /* Mark authentication as complete */
225 supplicant->flags = EAP_FL_PASSIVE;
226
227 /* Mark link as unblocked */
228 DBGC ( netdev, "EAP %s Success\n", netdev->name );
230
231 return 0;
232}
233
234/**
235 * Handle EAP Failure
236 *
237 * @v supplicant EAP supplicant
238 * @ret rc Return status code
239 */
240static int eap_rx_failure ( struct eap_supplicant *supplicant ) {
241 struct net_device *netdev = supplicant->netdev;
242
243 /* Mark authentication as complete */
244 supplicant->flags = EAP_FL_PASSIVE;
245
246 /* Record error */
247 DBGC ( netdev, "EAP %s Failure\n", netdev->name );
248 return -EPERM;
249}
250
251/**
252 * Handle EAP packet
253 *
254 * @v supplicant EAP supplicant
255 * @v data EAP packet
256 * @v len Length of EAP packet
257 * @ret rc Return status code
258 */
259int eap_rx ( struct eap_supplicant *supplicant, const void *data,
260 size_t len ) {
261 struct net_device *netdev = supplicant->netdev;
262 const union eap_packet *eap = data;
263 size_t msg_len;
264
265 /* Sanity checks */
266 if ( len < sizeof ( eap->hdr ) ) {
267 DBGC ( netdev, "EAP %s underlength header:\n", netdev->name );
268 DBGC_HDA ( netdev, 0, eap, len );
269 return -EINVAL;
270 }
271 msg_len = ntohs ( eap->hdr.len );
272 if ( msg_len < sizeof ( eap->hdr ) ) {
273 DBGC ( netdev, "EAP %s underlength packet:\n", netdev->name );
274 DBGC_HDA ( netdev, 0, eap, len );
275 return -EINVAL;
276 }
277 if ( msg_len > len ) {
278 DBGC ( netdev, "EAP %s truncated packet:\n", netdev->name );
279 DBGC_HDA ( netdev, 0, eap, len );
280 return -EINVAL;
281 }
282
283 /* Handle according to code */
284 switch ( eap->hdr.code ) {
285 case EAP_CODE_REQUEST:
286 return eap_rx_request ( supplicant, &eap->msg, msg_len );
288 DBGC2 ( netdev, "EAP %s ignoring response\n", netdev->name );
289 return 0;
290 case EAP_CODE_SUCCESS:
291 return eap_rx_success ( supplicant );
292 case EAP_CODE_FAILURE:
293 return eap_rx_failure ( supplicant );
294 default:
295 DBGC ( netdev, "EAP %s unsupported code %d\n",
296 netdev->name, eap->hdr.code );
297 DBGC_HDA ( netdev, 0, eap, len );
298 return -ENOTSUP;
299 }
300}
301
302/* Drag in objects via eap_rx() */
304
305/* Drag in EAP configuration */
306REQUIRE_OBJECT ( config_eap );
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned char uint8_t
Definition stdint.h:10
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:61
#define max(x, y)
Definition ath.h:41
ring len
Length.
Definition dwmac.h:226
static int eap_rx_request(struct eap_supplicant *supplicant, const struct eap_message *msg, size_t len)
Handle EAP Request.
Definition eap.c:177
int eap_rx(struct eap_supplicant *supplicant, const void *data, size_t len)
Handle EAP packet.
Definition eap.c:259
static int eap_tx_nak(struct eap_supplicant *supplicant)
Transmit EAP NAK.
Definition eap.c:89
static int eap_rx_success(struct eap_supplicant *supplicant)
Handle EAP Success.
Definition eap.c:221
static int eap_rx_failure(struct eap_supplicant *supplicant)
Handle EAP Failure.
Definition eap.c:240
static int eap_rx_identity(struct eap_supplicant *supplicant, const void *req, size_t req_len)
Handle EAP Request-Identity.
Definition eap.c:123
int eap_tx_response(struct eap_supplicant *supplicant, const void *rsp, size_t rsp_len)
Transmit EAP response.
Definition eap.c:48
Extensible Authentication Protocol.
#define EAP_CODE_RESPONSE
EAP response.
Definition eap.h:32
#define EAP_TYPE_IDENTITY
EAP identity.
Definition eap.h:48
#define __eap_method
Declare an EAP method.
Definition eap.h:197
#define EAP_METHODS
EAP method table.
Definition eap.h:194
#define EAP_CODE_REQUEST
EAP request.
Definition eap.h:29
#define EAP_TYPE_NONE
EAP "no available types" marker.
Definition eap.h:45
#define EAP_CODE_FAILURE
EAP failure.
Definition eap.h:97
#define EAP_FL_ONGOING
EAP authentication is in progress.
Definition eap.h:165
#define EAP_FL_PASSIVE
EAP supplicant is passive.
Definition eap.h:175
#define EAP_CODE_SUCCESS
EAP success.
Definition eap.h:94
#define EAP_TYPE_NAK
EAP NAK.
Definition eap.h:51
#define EAP_BLOCK_TIMEOUT
EAP link block timeout.
Definition eap.h:118
uint8_t data[48]
Additional event data.
Definition ena.h:11
Error codes.
static struct net_device * netdev
Definition gdbudp.c:53
#define DBGC2(...)
Definition compiler.h:547
#define DBGC(...)
Definition compiler.h:530
#define DBGC_HDA(...)
Definition compiler.h:531
static unsigned int count
Number of entries.
Definition dwmac.h:220
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:921
#define REQUIRE_OBJECT(object)
Require an object.
Definition compiler.h:227
#define EINVAL
Invalid argument.
Definition errno.h:472
#define ENOMEM
Not enough space.
Definition errno.h:578
#define ENOTSUP
Operation not supported.
Definition errno.h:633
#define EPERM
Operation not permitted.
Definition errno.h:658
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:951
#define REQUIRING_SYMBOL(symbol)
Specify the file's requiring symbol.
Definition compiler.h:140
uint8_t method
Definition ib_mad.h:3
#define htons(value)
Definition byteswap.h:136
#define ntohs(value)
Definition byteswap.h:137
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
uint64_t rsp
Definition librm.h:18
void * malloc(size_t size)
Allocate memory.
Definition malloc.c:677
void msg(unsigned int row, const char *fmt,...)
Print message centred on specified row.
Definition message.c:62
void netdev_link_block(struct net_device *netdev, unsigned long timeout)
Mark network device link as being blocked.
Definition netdevice.c:248
void netdev_link_unblock(struct net_device *netdev)
Mark network device link as being unblocked.
Definition netdevice.c:263
Network device management.
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition netdevice.h:590
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
int fetch_raw_setting_copy(struct settings *settings, const struct setting *setting, void **data)
Fetch value of setting.
Definition settings.c:822
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
uint8_t code
Code.
Definition eap.h:21
uint16_t len
Length.
Definition eap.h:25
EAP request/response message.
Definition eap.h:35
An EAP method.
Definition eap.h:178
An EAP supplicant.
Definition eap.h:139
uint8_t id
ID for current request/response.
Definition eap.h:145
uint8_t type
Type for current request/response.
Definition eap.h:147
uint16_t flags
Flags.
Definition eap.h:143
struct net_device * netdev
Network device.
Definition eap.h:141
int(* tx)(struct eap_supplicant *supplicant, const void *data, size_t len)
Transmit EAP response.
Definition eap.h:156
A network device.
Definition netdevice.h:353
#define table_num_entries(table)
Get number of entries in linker table.
Definition tables.h:336
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition tables.h:386
EAP packet.
Definition eap.h:100
struct eap_message msg
Request/response message.
Definition eap.h:104
struct eap_header hdr
Header.
Definition eap.h:102