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