1189251Ssam/*
2189251Ssam * EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994)
3189251Ssam * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
4189251Ssam *
5189251Ssam * This program is free software; you can redistribute it and/or modify
6189251Ssam * it under the terms of the GNU General Public License version 2 as
7189251Ssam * published by the Free Software Foundation.
8189251Ssam *
9189251Ssam * Alternatively, this software may be distributed under the terms of BSD
10189251Ssam * license.
11189251Ssam *
12189251Ssam * See README and COPYING for more details.
13189251Ssam */
14189251Ssam
15189251Ssam#include "includes.h"
16189251Ssam
17189251Ssam#include "common.h"
18189251Ssam#include "eap_i.h"
19189251Ssam#include "eap_common/chap.h"
20189251Ssam
21189251Ssam
22189251Ssamstatic void * eap_md5_init(struct eap_sm *sm)
23189251Ssam{
24189251Ssam	/* No need for private data. However, must return non-NULL to indicate
25189251Ssam	 * success. */
26189251Ssam	return (void *) 1;
27189251Ssam}
28189251Ssam
29189251Ssam
30189251Ssamstatic void eap_md5_deinit(struct eap_sm *sm, void *priv)
31189251Ssam{
32189251Ssam}
33189251Ssam
34189251Ssam
35189251Ssamstatic struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
36189251Ssam				       struct eap_method_ret *ret,
37189251Ssam				       const struct wpabuf *reqData)
38189251Ssam{
39189251Ssam	struct wpabuf *resp;
40189251Ssam	const u8 *pos, *challenge, *password;
41189251Ssam	u8 *rpos, id;
42189251Ssam	size_t len, challenge_len, password_len;
43189251Ssam
44189251Ssam	password = eap_get_config_password(sm, &password_len);
45189251Ssam	if (password == NULL) {
46189251Ssam		wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
47189251Ssam		eap_sm_request_password(sm);
48189251Ssam		ret->ignore = TRUE;
49189251Ssam		return NULL;
50189251Ssam	}
51189251Ssam
52189251Ssam	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, reqData, &len);
53189251Ssam	if (pos == NULL || len == 0) {
54189251Ssam		wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)",
55189251Ssam			   pos, (unsigned long) len);
56189251Ssam		ret->ignore = TRUE;
57189251Ssam		return NULL;
58189251Ssam	}
59189251Ssam
60189251Ssam	/*
61189251Ssam	 * CHAP Challenge:
62189251Ssam	 * Value-Size (1 octet) | Value(Challenge) | Name(optional)
63189251Ssam	 */
64189251Ssam	challenge_len = *pos++;
65189251Ssam	if (challenge_len == 0 || challenge_len > len - 1) {
66189251Ssam		wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge "
67189251Ssam			   "(challenge_len=%lu len=%lu)",
68189251Ssam			   (unsigned long) challenge_len, (unsigned long) len);
69189251Ssam		ret->ignore = TRUE;
70189251Ssam		return NULL;
71189251Ssam	}
72189251Ssam	ret->ignore = FALSE;
73189251Ssam	challenge = pos;
74189251Ssam	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge",
75189251Ssam		    challenge, challenge_len);
76189251Ssam
77189251Ssam	wpa_printf(MSG_DEBUG, "EAP-MD5: Generating Challenge Response");
78189251Ssam	ret->methodState = METHOD_DONE;
79214734Srpaulo	ret->decision = DECISION_COND_SUCC;
80189251Ssam	ret->allowNotifications = TRUE;
81189251Ssam
82189251Ssam	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHAP_MD5_LEN,
83189251Ssam			     EAP_CODE_RESPONSE, eap_get_id(reqData));
84189251Ssam	if (resp == NULL)
85189251Ssam		return NULL;
86189251Ssam
87189251Ssam	/*
88189251Ssam	 * CHAP Response:
89189251Ssam	 * Value-Size (1 octet) | Value(Response) | Name(optional)
90189251Ssam	 */
91189251Ssam	wpabuf_put_u8(resp, CHAP_MD5_LEN);
92189251Ssam
93189251Ssam	id = eap_get_id(resp);
94189251Ssam	rpos = wpabuf_put(resp, CHAP_MD5_LEN);
95189251Ssam	chap_md5(id, password, password_len, challenge, challenge_len, rpos);
96189251Ssam	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, CHAP_MD5_LEN);
97189251Ssam
98189251Ssam	return resp;
99189251Ssam}
100189251Ssam
101189251Ssam
102189251Ssamint eap_peer_md5_register(void)
103189251Ssam{
104189251Ssam	struct eap_method *eap;
105189251Ssam	int ret;
106189251Ssam
107189251Ssam	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
108189251Ssam				    EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
109189251Ssam	if (eap == NULL)
110189251Ssam		return -1;
111189251Ssam
112189251Ssam	eap->init = eap_md5_init;
113189251Ssam	eap->deinit = eap_md5_deinit;
114189251Ssam	eap->process = eap_md5_process;
115189251Ssam
116189251Ssam	ret = eap_peer_method_register(eap);
117189251Ssam	if (ret)
118189251Ssam		eap_peer_method_free(eap);
119189251Ssam	return ret;
120189251Ssam}
121