Home | History | Annotate | Download | only in eap_peer
      1 /*
      2  * EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994)
      3  * Copyright (c) 2004-2006, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include "includes.h"
     16 
     17 #include "common.h"
     18 #include "eap_i.h"
     19 #include "eap_common/chap.h"
     20 
     21 
     22 static void * eap_md5_init(struct eap_sm *sm)
     23 {
     24 	/* No need for private data. However, must return non-NULL to indicate
     25 	 * success. */
     26 	return (void *) 1;
     27 }
     28 
     29 
     30 static void eap_md5_deinit(struct eap_sm *sm, void *priv)
     31 {
     32 }
     33 
     34 
     35 static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
     36 				       struct eap_method_ret *ret,
     37 				       const struct wpabuf *reqData)
     38 {
     39 	struct wpabuf *resp;
     40 	const u8 *pos, *challenge, *password;
     41 	u8 *rpos, id;
     42 	size_t len, challenge_len, password_len;
     43 
     44 	password = eap_get_config_password(sm, &password_len);
     45 	if (password == NULL) {
     46 		wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
     47 		eap_sm_request_password(sm);
     48 		ret->ignore = TRUE;
     49 		return NULL;
     50 	}
     51 
     52 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, reqData, &len);
     53 	if (pos == NULL || len == 0) {
     54 		wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)",
     55 			   pos, (unsigned long) len);
     56 		ret->ignore = TRUE;
     57 		return NULL;
     58 	}
     59 
     60 	/*
     61 	 * CHAP Challenge:
     62 	 * Value-Size (1 octet) | Value(Challenge) | Name(optional)
     63 	 */
     64 	challenge_len = *pos++;
     65 	if (challenge_len == 0 || challenge_len > len - 1) {
     66 		wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge "
     67 			   "(challenge_len=%lu len=%lu)",
     68 			   (unsigned long) challenge_len, (unsigned long) len);
     69 		ret->ignore = TRUE;
     70 		return NULL;
     71 	}
     72 	ret->ignore = FALSE;
     73 	challenge = pos;
     74 	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge",
     75 		    challenge, challenge_len);
     76 
     77 	wpa_printf(MSG_DEBUG, "EAP-MD5: Generating Challenge Response");
     78 	ret->methodState = METHOD_DONE;
     79 	ret->decision = DECISION_UNCOND_SUCC;
     80 	ret->allowNotifications = TRUE;
     81 
     82 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHAP_MD5_LEN,
     83 			     EAP_CODE_RESPONSE, eap_get_id(reqData));
     84 	if (resp == NULL)
     85 		return NULL;
     86 
     87 	/*
     88 	 * CHAP Response:
     89 	 * Value-Size (1 octet) | Value(Response) | Name(optional)
     90 	 */
     91 	wpabuf_put_u8(resp, CHAP_MD5_LEN);
     92 
     93 	id = eap_get_id(resp);
     94 	rpos = wpabuf_put(resp, CHAP_MD5_LEN);
     95 	chap_md5(id, password, password_len, challenge, challenge_len, rpos);
     96 	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, CHAP_MD5_LEN);
     97 
     98 	return resp;
     99 }
    100 
    101 
    102 int eap_peer_md5_register(void)
    103 {
    104 	struct eap_method *eap;
    105 	int ret;
    106 
    107 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
    108 				    EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
    109 	if (eap == NULL)
    110 		return -1;
    111 
    112 	eap->init = eap_md5_init;
    113 	eap->deinit = eap_md5_deinit;
    114 	eap->process = eap_md5_process;
    115 
    116 	ret = eap_peer_method_register(eap);
    117 	if (ret)
    118 		eap_peer_method_free(eap);
    119 	return ret;
    120 }
    121