aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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