aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2024-01-10 15:23:07 +0000
committerMichael Brown <mcb30@ipxe.org>2024-01-10 15:33:49 +0000
commit2ae26de3ec54f041809dc73369e1792ebec52b89 (patch)
tree5a3eec5575c5144010b3b186696ffca98679a98e
parent6db299dc0f0b674dacab49a8e92ea219f0ff00fd (diff)
downloadipxe-8021x.zip
ipxe-8021x.tar.gz
ipxe-8021x.tar.bz2
[eap] Add support for the MD5-Challenge authentication type8021x
RFC 3748 states that support for MD5-Challenge is mandatory for EAP implementations. The MD5 and CHAP code is already included in the default build since it is required by iSCSI, and so this does not substantially increase the binary size. Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/include/ipxe/eap.h11
-rw-r--r--src/net/eap.c80
2 files changed, 91 insertions, 0 deletions
diff --git a/src/include/ipxe/eap.h b/src/include/ipxe/eap.h
index bbae517..cf1c7c0 100644
--- a/src/include/ipxe/eap.h
+++ b/src/include/ipxe/eap.h
@@ -49,6 +49,17 @@ struct eap_message {
/** EAP NAK */
#define EAP_TYPE_NAK 3
+/** EAP MD5 challenge request/response */
+#define EAP_TYPE_MD5 4
+
+/** EAP MD5 challenge request/response type data */
+struct eap_md5 {
+ /** Value length */
+ uint8_t len;
+ /** Value */
+ uint8_t value[0];
+} __attribute__ (( packed ));
+
/** EAP success */
#define EAP_CODE_SUCCESS 3
diff --git a/src/net/eap.c b/src/net/eap.c
index fe01f13..3a1c372 100644
--- a/src/net/eap.c
+++ b/src/net/eap.c
@@ -28,6 +28,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <byteswap.h>
#include <ipxe/netdevice.h>
+#include <ipxe/md5.h>
+#include <ipxe/chap.h>
#include <ipxe/eap.h>
/** @file
@@ -158,6 +160,84 @@ struct eap_method eap_identity_method __eap_method = {
};
/**
+ * Handle EAP Challenge-MD5
+ *
+ * @v req Request type data
+ * @v req_len Length of request type data
+ * @ret rc Return status code
+ */
+static int eap_rx_md5 ( struct eap_supplicant *supplicant,
+ const void *req, size_t req_len ) {
+ struct net_device *netdev = supplicant->netdev;
+ const struct eap_md5 *md5req = req;
+ struct {
+ uint8_t len;
+ uint8_t value[MD5_DIGEST_SIZE];
+ } __attribute__ (( packed )) md5rsp;
+ struct chap_response chap;
+ void *secret;
+ int secret_len;
+ int rc;
+
+ /* Sanity checks */
+ if ( req_len < sizeof ( *md5req ) ) {
+ DBGC ( netdev, "EAP %s underlength Challenge-MD5:\n",
+ netdev->name );
+ DBGC_HDA ( netdev, 0, req, req_len );
+ rc = -EINVAL;
+ goto err_sanity;
+ }
+ if ( ( req_len - sizeof ( *md5req ) ) < md5req->len ) {
+ DBGC ( netdev, "EAP %s truncated Challenge-MD5:\n",
+ netdev->name );
+ DBGC_HDA ( netdev, 0, req, req_len );
+ rc = -EINVAL;
+ goto err_sanity;
+ }
+
+ /* Construct response */
+ if ( ( rc = chap_init ( &chap, &md5_algorithm ) ) != 0 ) {
+ DBGC ( netdev, "EAP %s could not initialise CHAP: %s\n",
+ netdev->name, strerror ( rc ) );
+ goto err_chap;
+ }
+ chap_set_identifier ( &chap, supplicant->id );
+ secret_len = fetch_raw_setting_copy ( netdev_settings ( netdev ),
+ &password_setting, &secret );
+ if ( secret_len < 0 ) {
+ rc = secret_len;
+ DBGC ( netdev, "EAP %s has no secret: %s\n",
+ netdev->name, strerror ( rc ) );
+ goto err_secret;
+ }
+ chap_update ( &chap, secret, secret_len );
+ chap_update ( &chap, md5req->value, md5req->len );
+ chap_respond ( &chap );
+ assert ( chap.response_len == sizeof ( md5rsp.value ) );
+ md5rsp.len = sizeof ( md5rsp.value );
+ memcpy ( md5rsp.value, chap.response, sizeof ( md5rsp.value ) );
+
+ /* Transmit response */
+ if ( ( rc = eap_tx_response ( supplicant, &md5rsp,
+ sizeof ( md5rsp ) ) ) != 0 )
+ goto err_tx;
+
+ err_tx:
+ free ( secret );
+ err_secret:
+ chap_finish ( &chap );
+ err_chap:
+ err_sanity:
+ return rc;
+}
+
+/** EAP Challenge-MD5 method */
+struct eap_method eap_md5_method __eap_method = {
+ .type = EAP_TYPE_MD5,
+ .rx = eap_rx_md5,
+};
+
+/**
* Handle EAP Request
*
* @v supplicant EAP supplicant