iPXE
eap_mschapv2.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2024 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 <string.h>
29#include <errno.h>
30#include <byteswap.h>
31#include <ipxe/mschapv2.h>
32#include <ipxe/eap.h>
33
34/** @file
35 *
36 * EAP MS-CHAPv2 authentication method
37 *
38 * EAP-MSCHAPv2 was described in a draft RFC first published in 2002
39 * (draft-kamath-pppext-eap-mschapv2-02.txt). The draft eventually
40 * expired in 2007 without becoming an official RFC, quite possibly
41 * because the protocol design was too ugly to be called an IETF
42 * standard. It is, however, fairly widely used.
43 */
44
45/** An EAP MS-CHAPv2 request message */
47 /** EAP-MSCHAPv2 header */
49 /** MS-CHAPv2 challenge length (fixed value) */
51 /** MS-CHAPv2 challenge */
53} __attribute__ (( packed ));
54
55/** An EAP MS-CHAPv2 response message */
57 /** EAP-MSCHAPv2 header */
59 /** MS-CHAPv2 response length (fixed value) */
61 /** MS-CHAPv2 response */
63 /** User name */
64 char name[0];
65} __attribute__ (( packed ));
66
67/** An EAP MS-CHAPv2 success request message */
69 /** EAP-MSCHAPv2 header */
71 /** Message */
72 char message[0];
73} __attribute__ (( packed ));
74
75/** An EAP MS-CHAPv2 success response message */
77 /** Opcode */
79} __attribute__ (( packed ));
80
81/**
82 * Handle EAP MS-CHAPv2 request
83 *
84 * @v supplicant EAP supplicant
85 * @v hdr EAP-MSCHAPv2 header
86 * @v len Message length
87 * @ret rc Return status code
88 */
89static int eap_rx_mschapv2_request ( struct eap_supplicant *supplicant,
90 const struct eap_mschapv2 *hdr,
91 size_t len ) {
92 struct net_device *netdev = supplicant->netdev;
94 const struct eap_mschapv2_request *msreq =
96 struct eap_mschapv2_response *msrsp;
98 char *username;
99 char *password;
100 int username_len;
101 int password_len;
102 size_t msrsp_len;
103 unsigned int i;
104 int rc;
105
106 /* Sanity check */
107 if ( len < sizeof ( *msreq ) ) {
108 DBGC ( netdev, "EAP %s underlength MS-CHAPv2 request\n",
109 netdev->name );
110 DBGC_HDA ( netdev, 0, hdr, len );
111 rc = -EINVAL;
112 goto err_sanity;
113 }
114
115 /* Fetch username and password */
116 username_len = fetch_string_setting_copy ( settings, &username_setting,
117 &username );
118 if ( username_len < 0 ) {
119 rc = username_len;
120 DBGC ( netdev, "EAP %s has no username: %s\n",
121 netdev->name, strerror ( rc ) );
122 goto err_username;
123 }
124 password_len = fetch_string_setting_copy ( settings, &password_setting,
125 &password );
126 if ( password_len < 0 ) {
127 rc = password_len;
128 DBGC ( netdev, "EAP %s has no password: %s\n",
129 netdev->name, strerror ( rc ) );
130 goto err_password;
131 }
132
133 /* Construct a peer challenge. We do not perform mutual
134 * authentication, so this does not need to be strong.
135 */
136 for ( i = 0 ; i < ( sizeof ( peer.byte ) /
137 sizeof ( peer.byte[0] ) ) ; i++ ) {
138 peer.byte[i] = random();
139 }
140
141 /* Allocate response */
142 msrsp_len = ( sizeof ( *msrsp ) + username_len );
143 msrsp = malloc ( msrsp_len );
144 if ( ! msrsp ) {
145 rc = -ENOMEM;
146 goto err_alloc;
147 }
148
149 /* Construct response */
150 msrsp->hdr.code = EAP_CODE_RESPONSE;
151 msrsp->hdr.id = msreq->hdr.id;
152 msrsp->hdr.len = htons ( msrsp_len );
153 msrsp->len = sizeof ( msrsp->msg );
155 &msrsp->msg );
156 memcpy ( msrsp->name, username, username_len );
157
158 /* Send response */
159 if ( ( rc = eap_tx_response ( supplicant, msrsp, msrsp_len ) ) != 0 )
160 goto err_tx;
161
162 err_tx:
163 free ( msrsp );
164 err_alloc:
165 free ( password );
166 err_password:
167 free ( username );
168 err_username:
169 err_sanity:
170 return rc;
171}
172
173/**
174 * Handle EAP MS-CHAPv2 success request
175 *
176 * @v supplicant EAP supplicant
177 * @v hdr EAP-MSCHAPv2 header
178 * @v len Message length
179 * @ret rc Return status code
180 */
181static int eap_rx_mschapv2_success ( struct eap_supplicant *supplicant,
182 const struct eap_mschapv2 *hdr,
183 size_t len ) {
184 const struct eap_mschapv2_success_request *msreq =
186 static const struct eap_mschapv2_success_response msrsp = {
187 .code = EAP_CODE_SUCCESS,
188 };
189
190 /* Sanity check */
191 assert ( len >= sizeof ( *msreq ) );
192
193 /* The success request contains the MS-CHAPv2 authenticator
194 * response, which could potentially be used to verify that
195 * the EAP authenticator also knew the password (or, at least,
196 * the MD4 hash of the password).
197 *
198 * Our model for EAP does not encompass mutual authentication:
199 * we will starting sending plaintext packets (e.g. DHCP
200 * requests) over the link even before EAP completes, and our
201 * only use for an EAP success is to mark the link as
202 * unblocked.
203 *
204 * We therefore ignore the content of the success request and
205 * just send back a success response, so that the EAP
206 * authenticator will complete the process and send through
207 * the real EAP success packet (which will, in turn, cause us
208 * to unblock the link).
209 */
210 return eap_tx_response ( supplicant, &msrsp, sizeof ( msrsp ) );
211}
212
213/**
214 * Handle EAP MS-CHAPv2
215 *
216 * @v supplicant EAP supplicant
217 * @v req Request type data
218 * @v req_len Length of request type data
219 * @ret rc Return status code
220 */
221static int eap_rx_mschapv2 ( struct eap_supplicant *supplicant,
222 const void *req, size_t req_len ) {
223 struct net_device *netdev = supplicant->netdev;
224 const struct eap_mschapv2 *hdr = req;
225
226 /* Sanity check */
227 if ( req_len < sizeof ( *hdr ) ) {
228 DBGC ( netdev, "EAP %s underlength MS-CHAPv2:\n",
229 netdev->name );
230 DBGC_HDA ( netdev, 0, req, req_len );
231 return -EINVAL;
232 }
233
234 /* Handle according to opcode */
235 switch ( hdr->code ) {
236 case EAP_CODE_REQUEST:
237 return eap_rx_mschapv2_request ( supplicant, hdr, req_len );
238 case EAP_CODE_SUCCESS:
239 return eap_rx_mschapv2_success ( supplicant, hdr, req_len );
240 default:
241 DBGC ( netdev, "EAP %s unsupported MS-CHAPv2 opcode %d\n",
242 netdev->name, hdr->code );
243 DBGC_HDA ( netdev, 0, req, req_len );
244 return -ENOTSUP;
245 }
246}
247
248/** EAP MS-CHAPv2 method */
249struct eap_method eap_mschapv2_method __eap_method = {
250 .type = EAP_TYPE_MSCHAPV2,
251 .rx = eap_rx_mschapv2,
252};
struct golan_inbox_hdr hdr
Message header.
Definition CIB_PRM.h:0
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:50
ring len
Length.
Definition dwmac.h:226
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_method
Declare an EAP method.
Definition eap.h:197
#define EAP_CODE_REQUEST
EAP request.
Definition eap.h:29
#define EAP_CODE_SUCCESS
EAP success.
Definition eap.h:94
#define EAP_TYPE_MSCHAPV2
EAP MS-CHAPv2 request/response.
Definition eap.h:65
static int eap_rx_mschapv2(struct eap_supplicant *supplicant, const void *req, size_t req_len)
Handle EAP MS-CHAPv2.
static int eap_rx_mschapv2_success(struct eap_supplicant *supplicant, const struct eap_mschapv2 *hdr, size_t len)
Handle EAP MS-CHAPv2 success request.
static int eap_rx_mschapv2_request(struct eap_supplicant *supplicant, const struct eap_mschapv2 *hdr, size_t len)
Handle EAP MS-CHAPv2 request.
Error codes.
static struct net_device * netdev
Definition gdbudp.c:53
#define DBGC(...)
Definition compiler.h:505
#define DBGC_HDA(...)
Definition compiler.h:506
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
#define htons(value)
Definition byteswap.h:136
#define __attribute__(x)
Definition compiler.h:10
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static struct dynamic_item username
Definition login_ui.c:36
static struct dynamic_item password
Definition login_ui.c:37
void * malloc(size_t size)
Allocate memory.
Definition malloc.c:621
void mschapv2_response(const char *username, const char *password, const struct mschapv2_challenge *challenge, const struct mschapv2_challenge *peer, struct mschapv2_response *response)
Calculate MS-CHAPv2 challenge response.
Definition mschapv2.c:270
MS-CHAPv2 authentication.
struct mschapv2_challenge peer
Peer challenge.
Definition mschapv2.h:1
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition netdevice.h:587
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition random.c:32
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
int fetch_string_setting_copy(struct settings *settings, const struct setting *setting, char **data)
Fetch value of string setting.
Definition settings.c:874
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
An EAP method.
Definition eap.h:178
An EAP MS-CHAPv2 request message.
uint8_t len
MS-CHAPv2 challenge length (fixed value)
struct eap_mschapv2 hdr
EAP-MSCHAPv2 header.
struct mschapv2_challenge msg
MS-CHAPv2 challenge.
An EAP MS-CHAPv2 response message.
struct eap_mschapv2 hdr
EAP-MSCHAPv2 header.
char name[0]
User name.
struct mschapv2_response msg
MS-CHAPv2 response.
uint8_t len
MS-CHAPv2 response length (fixed value)
An EAP MS-CHAPv2 success request message.
struct eap_mschapv2 hdr
EAP-MSCHAPv2 header.
An EAP MS-CHAPv2 success response message.
EAP MS-CHAPv2 request/response type data.
Definition eap.h:68
uint16_t len
Length.
Definition eap.h:90
uint8_t code
Code.
Definition eap.h:75
uint8_t id
Identifier.
Definition eap.h:82
An EAP supplicant.
Definition eap.h:139
struct net_device * netdev
Network device.
Definition eap.h:141
An MS-CHAPv2 challenge.
Definition mschapv2.h:16
An MS-CHAPv2 challenge response.
Definition mschapv2.h:28
A network device.
Definition netdevice.h:353
A settings block.
Definition settings.h:133