1 /* 2 * EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994) 3 * Copyright (c) 2004-2012, Jouni Malinen <j@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