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