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