/** * A client-side 802.1x implementation supporting EAP/MD5 * * This code is released under both the GPL version 2 and BSD licenses. * Either license may be used. The respective licenses are found below. * * Copyright (C) 2002 Chris Hessing & Terry Simons * All Rights Reserved * * --- GPL Version 2 License --- * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * --- BSD License --- * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * Maryland at College Park and its contributors. * - Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /******************************************************************* * EAPOL Function implementations for supplicant * * File: eapmd5.c * * Authors: Chris.Hessing@utah.edu, Terry.Simons@utah.edu * *******************************************************************/ #include #include #include #include #include #include "eapmd5.h" #include "../../configparse.h" #include "dot1x_globals.h" #include "eap.h" #include "userconf.h" #include "logging.h" #include "auth_methods/auth_tools.h" #ifndef MD5_DEBUG #define MD5_DEBUG 0 #endif char *eapmd5_netid; char *eapmd5_config; int init_eapmd5(char *config, char *netid) { #ifdef MD5_DEBUG xlogf(DEBUG_AUTHTYPES, "(EAPMD5) Initalized\n"); #endif eapmd5_netid = netid; eapmd5_config = config; return 0; } /************************************************************* eapmd5_decode_packet - decode an MD5 challenge, and answer it When an MD5 challenge is sent in, the header, up to the actual challenge string is stripped off before we get here. Since the ID is needed to generate the return md5 hash, we need to have it passed in too. The way that the MD5 challenge response works is fairly simple. The authenticator sends us a random stream of bytes. The first byte in this stream is the length of the stream. From this, we build our response by building a string that contains ID + password + challenge stream, and then MD5 it. The resulting value, with our username concatinated to the end is returned in the response packet. ************************************************************/ int eapmd5_decode_packet(u_char *in, int in_size, u_char *out, int *out_size) { u_char challen = 0; int hashlen =0; char *chal =NULL; char *answer =NULL; char md5_result[16]; int md5_length=0; // Should always be 16, but get it anyway. EVP_MD_CTX *ctx=NULL; char *username; char *password; // Get our username and password out of our configuration structure in memory username = get_username(); password = get_password(); #ifdef MD5_DEBUG xlogf(DEBUG_AUTHTYPES, "(EAPMD5) ID : %d\n",get_receivedId()); xlogf(DEBUG_AUTHTYPES, "Username = %s -- Password = %s\n",username,password); #endif challen = in[0]; #ifdef MD5_DEBUG xlogf(DEBUG_AUTHTYPES, "Incoming hex string (Length = %d) : ",challen); print_hex((uint8_t *)&in[1],challen); #endif if (chal == NULL) //Which it *always* should { chal = (char *)malloc(challen); if (chal == NULL) { xlogf(DEBUG_NORMAL, "chal is NULL after malloc!\n"); } } else { xlogf(DEBUG_NORMAL, "ACK! chal != NULL, but it should!\n"); } memcpy(chal, &in[1], challen); // We should have our hash info. answer = (char *)malloc(1+challen+strlen(password)+1); if (answer == NULL) { xlogf(DEBUG_NORMAL, "answer was NULL!\n"); return -1; // Something is wrong. } answer[0] = get_receivedId(); #ifdef MD5_DEBUG xlogf(DEBUG_AUTHTYPES, "Using ID of %d\n", (u_char)answer[0]); #endif memcpy(&answer[1], password, strlen(password)); memcpy(&answer[1+strlen(password)],chal,challen); #ifdef MD5_DEBUG xlogf(DEBUG_AUTHTYPES, "Challenge Response : %s\n",answer); #endif ctx = (EVP_MD_CTX *)malloc(sizeof(EVP_MD_CTX)); hashlen = 1+strlen(password)+challen; // Save us from nulls in answer. EVP_DigestInit(ctx, EVP_md5()); //Initialize MD5 EVP_DigestUpdate(ctx, answer, hashlen); EVP_DigestFinal(ctx, (char *)&md5_result, (int *)&md5_length); if (md5_length != 16) { xlogf(DEBUG_NORMAL,"MD5 length was not 16! We have a problem! (Actual length %d)\n",md5_length); } free(ctx); #ifdef MD5_DEBUG xlogf(DEBUG_AUTHTYPES, "Return hash : "); print_hex((uint8_t *)&md5_result, 16); #endif free(answer); // We are done with these values. answer = NULL; free(chal); chal = NULL; // Probably shouldn't reuse the same variable.... // We need to malloc 1 for the length byte, // 16 for the MD5 string, // strlen(username) for the username, // and 1 for a NULL byte for good measure. 8-) answer = (char *)malloc(1+16+strlen(username)+1); if (answer == NULL) { xlogf(DEBUG_NORMAL, "answer is NULL(2)!!!\n"); free(username); username=NULL; free(password); password=NULL; return -1; } answer[0] = 0x10; memcpy(&answer[1],&md5_result,16); memcpy(&answer[17],username,strlen(username)+1); // xlogf(DEBUG_AUTHTYPES, "Username = %s Answer = %s\n",&answer[17], answer); // We now have an answer! memcpy(out, answer, 17+strlen(username)+1); *out_size = 17+strlen(username)+1; if (answer != NULL) free(answer); answer=NULL; #ifdef MD5_DEBUG xlogf(DEBUG_AUTHTYPES, "(EAPMD5) Packet Built\n"); #endif free(username); username = NULL; free(password); password = NULL; return 0; // Everything is okay. } /****************************************************************** * Get the password for the found in the config file. ******************************************************************/ int eapmd5_auth_challenge() { char *temp_username=NULL; char *temp_password=NULL; char *trash; // We may want to ask for the user's password. temp_username = get_username(); // We need to think of a better way to handle this. Right now, if you // put in an incorrect password, you can never fix it. trash = get_password(); if (trash == NULL) { xlogf(DEBUG_NORMAL, "(MD5 Authentication) %s's Password : ",temp_username); temp_password = getpass(""); //This is obsolete, fix it! set_password(temp_password); // Update our config values. } else { xlogf(DEBUG_AUTHTYPES, "get_password returned a value!\n"); } free(trash); free(temp_username); temp_username = NULL; return 0; } // Clean up any memory we have allocated, and destroy anything we need to. int eapmd5_shutdown() { // Don't free one_x_globals as it is a copy of a pointer to memory, and // the shutdown_eap function will free it. #ifdef MD5_DEBUG xlogf(DEBUG_AUTHTYPES, "(EAPMD5) Cleaning up.\n"); #endif return 0; }