eap_md5.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
1/*
2 * EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994)
3 * Copyright (c) 2004-2006, Jouni Malinen <j@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
22static 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
30static void eap_md5_deinit(struct eap_sm *sm, void *priv)
31{
32}
33
34
35static 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_COND_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
102int 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