Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers chap.c Source File

chap.c

Go to the documentation of this file.
00001 /**
00002  * @file chap.c
00003  * @brief CHAP (Challenge Handshake Authentication Protocol)
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL PPP_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include "core/net.h"
00034 #include "ppp/ppp_debug.h"
00035 #include "ppp/lcp.h"
00036 #include "ppp/ipcp.h"
00037 #include "ppp/ipv6cp.h"
00038 #include "ppp/chap.h"
00039 #include "debug.h"
00040 
00041 //Check TCP/IP stack configuration
00042 #if (PPP_SUPPORT == ENABLED && CHAP_SUPPORT == ENABLED)
00043 
00044 //Additional dependencies
00045 #include "crypto.h"
00046 #include "md5.h"
00047 
00048 
00049 /**
00050  * @brief Start CHAP authentication
00051  * @param[in] context PPP context
00052  * @return Error code
00053  **/
00054 
00055 error_t chapStartAuth(PppContext *context)
00056 {
00057    //Debug message
00058    TRACE_INFO("\r\nStarting CHAP authentication...\r\n");
00059 
00060    //Check whether the other end of the PPP link is being authenticated
00061    if(context->localConfig.authProtocol == PPP_PROTOCOL_CHAP)
00062    {
00063       //Initialize restart counter
00064       context->chapFsm.restartCounter = CHAP_MAX_CHALLENGES;
00065       //Send a Challenge packet
00066       chapSendChallenge(context);
00067       //Switch to the Challenge-Sent state
00068       context->chapFsm.localState = CHAP_STATE_2_CHALLENGE_SENT;
00069    }
00070 
00071    //Check whether the other end of the PPP link is the authenticator
00072    if(context->peerConfig.authProtocol == PPP_PROTOCOL_CHAP)
00073    {
00074       //Switch to the Started state
00075       context->chapFsm.peerState = CHAP_STATE_1_STARTED;
00076    }
00077 
00078    //Successful processing
00079    return NO_ERROR;
00080 }
00081 
00082 
00083 /**
00084  * @brief Abort CHAP authentication
00085  * @param[in] context PPP context
00086  * @return Error code
00087  **/
00088 
00089 error_t chapAbortAuth(PppContext *context)
00090 {
00091    //Debug message
00092    TRACE_INFO("\r\nAborting CHAP authentication...\r\n");
00093 
00094    //Abort CHAP authentication process
00095    context->chapFsm.localState = CHAP_STATE_0_INITIAL;
00096    context->chapFsm.peerState = CHAP_STATE_0_INITIAL;
00097 
00098    //Successful processing
00099    return NO_ERROR;
00100 }
00101 
00102 
00103 /**
00104  * @brief CHAP timer handler
00105  * @param[in] context PPP context
00106  **/
00107 
00108 void chapTick(PppContext *context)
00109 {
00110    //Check whether the restart timer is running
00111    if(context->chapFsm.localState == CHAP_STATE_2_CHALLENGE_SENT)
00112    {
00113       //Get current time
00114       systime_t time = osGetSystemTime();
00115 
00116       //Check restart timer
00117       if((time - context->chapFsm.timestamp) >= CHAP_RESTART_TIMER)
00118       {
00119          //Debug message
00120          TRACE_INFO("\r\nCHAP Timeout event\r\n");
00121 
00122          //Check whether the restart counter is greater than zero
00123          if(context->chapFsm.restartCounter > 0)
00124          {
00125             //Retransmit the Challenge packet
00126             chapSendChallenge(context);
00127          }
00128          else
00129          {
00130             //Abort CHAP authentication
00131             context->chapFsm.localState = CHAP_STATE_0_INITIAL;
00132             //Authentication failed
00133             lcpClose(context);
00134          }
00135       }
00136    }
00137 }
00138 
00139 
00140 /**
00141  * @brief Process an incoming CHAP packet
00142  * @param[in] context PPP context
00143  * @param[in] packet CHAP packet received from the peer
00144  * @param[in] length Length of the packet, in bytes
00145  **/
00146 
00147 void chapProcessPacket(PppContext *context,
00148    const PppPacket *packet, size_t length)
00149 {
00150    //Ensure the length of the incoming CHAP packet is valid
00151    if(length < sizeof(PppPacket))
00152       return;
00153 
00154    //Check the length field
00155    if(ntohs(packet->length) > length)
00156       return;
00157    if(ntohs(packet->length) < sizeof(PppPacket))
00158       return;
00159 
00160    //Save the length of the CHAP packet
00161    length = ntohs(packet->length);
00162 
00163    //Debug message
00164    TRACE_INFO("CHAP packet received (%" PRIuSIZE " bytes)...\r\n", length);
00165    //Dump CHAP packet contents for debugging purpose
00166    pppDumpPacket(packet, length, PPP_PROTOCOL_CHAP);
00167 
00168    //CHAP is done at initial link establishment, and could also be
00169    //requested after link establishment
00170    if(context->pppPhase != PPP_PHASE_AUTHENTICATE &&
00171       context->pppPhase != PPP_PHASE_NETWORK)
00172    {
00173       //Any packets received during any other phase must be silently discarded
00174       return;
00175    }
00176 
00177    //Check CHAP code field
00178    switch(packet->code)
00179    {
00180    //Challenge packet?
00181    case CHAP_CODE_CHALLENGE:
00182       //Process Challenge packet
00183       chapProcessChallenge(context, (ChapChallengePacket *) packet, length);
00184       break;
00185    //Response packet?
00186    case CHAP_CODE_RESPONSE:
00187       //Process Response packet
00188       chapProcessResponse(context, (ChapResponsePacket *) packet, length);
00189       break;
00190    //Success packet?
00191    case CHAP_CODE_SUCCESS:
00192       //Process Success packet
00193       chapProcessSuccess(context, (ChapSuccessPacket *) packet, length);
00194       break;
00195    //Failure packet?
00196    case CHAP_CODE_FAILURE:
00197       //Process Failure packet
00198       chapProcessFailure(context, (ChapFailurePacket *) packet, length);
00199       break;
00200    //Unknown code field
00201    default:
00202       //Silently drop the incoming packet
00203       break;
00204    }
00205 }
00206 
00207 
00208 /**
00209  * @brief Process Challenge packet
00210  * @param[in] context PPP context
00211  * @param[in] challengePacket Packet received from the peer
00212  * @param[in] length Length of the packet, in bytes
00213  * @return Error code
00214  **/
00215 
00216 error_t chapProcessChallenge(PppContext *context,
00217    const ChapChallengePacket *challengePacket, size_t length)
00218 {
00219    size_t n;
00220    Md5Context md5Context;
00221 
00222    //Debug message
00223    TRACE_INFO("\r\nCHAP Challenge packet received\r\n");
00224 
00225    //Make sure the Challenge packet is acceptable
00226    if(context->peerConfig.authProtocol != PPP_PROTOCOL_CHAP)
00227       return ERROR_FAILURE;
00228 
00229    //Check the length of the packet
00230    if(length < sizeof(ChapChallengePacket))
00231       return ERROR_INVALID_LENGTH;
00232 
00233    //Malformed Challenge packet?
00234    if(length < (sizeof(ChapChallengePacket) + challengePacket->valueSize))
00235       return ERROR_INVALID_LENGTH;
00236 
00237    //Save the Identifier field
00238    context->chapFsm.peerIdentifier = challengePacket->identifier;
00239 
00240    //Retrieve the length of the password
00241    n = strlen(context->password);
00242 
00243    //The response value is the one-way hash calculated over a stream
00244    //of octets consisting of the identifier, followed by the secret,
00245    //followed by the challenge value
00246    md5Init(&md5Context);
00247    md5Update(&md5Context, &challengePacket->identifier, sizeof(uint8_t));
00248    md5Update(&md5Context, context->password, n);
00249    md5Update(&md5Context, challengePacket->value, challengePacket->valueSize);
00250    md5Final(&md5Context, NULL);
00251 
00252    //Whenever a Challenge packet is received, the peer must send a Response packet
00253    chapSendResponse(context, md5Context.digest);
00254 
00255    //Switch to the Response-Sent state
00256    context->chapFsm.peerState = CHAP_STATE_4_RESPONSE_SENT;
00257 
00258    //Successful processing
00259    return NO_ERROR;
00260 }
00261 
00262 
00263 /**
00264  * @brief Process Response packet
00265  * @param[in] context PPP context
00266  * @param[in] responsePacket Packet received from the peer
00267  * @param[in] length Length of the packet, in bytes
00268  * @return Error code
00269  **/
00270 
00271 error_t chapProcessResponse(PppContext *context,
00272    const ChapResponsePacket *responsePacket, size_t length)
00273 {
00274    bool_t status;
00275    const uint8_t *p;
00276 
00277    //Debug message
00278    TRACE_INFO("\r\nCHAP Response packet received\r\n");
00279 
00280    //Make sure the Response packet is acceptable
00281    if(context->localConfig.authProtocol != PPP_PROTOCOL_CHAP)
00282       return ERROR_FAILURE;
00283 
00284    //Check the length of the packet
00285    if(length < sizeof(ChapResponsePacket))
00286       return ERROR_INVALID_LENGTH;
00287 
00288    //When a packet is received with an invalid Identifier field, the
00289    //packet is silently discarded without affecting the automaton
00290    if(responsePacket->identifier != context->chapFsm.localIdentifier)
00291       return ERROR_WRONG_IDENTIFIER;
00292 
00293    //Malformed Response packet?
00294    if(length < (sizeof(ChapResponsePacket) + responsePacket->valueSize))
00295       return ERROR_INVALID_LENGTH;
00296 
00297    //The length of the response value depends upon the hash algorithm used
00298    if(responsePacket->valueSize != MD5_DIGEST_SIZE)
00299       return ERROR_INVALID_LENGTH;
00300 
00301    //Retrieve the response value
00302    context->chapFsm.response = responsePacket->value;
00303 
00304    //Point to the Name field
00305    p = responsePacket->value + responsePacket->valueSize;
00306    //Retrieve the length of the Name field
00307    length -= sizeof(ChapResponsePacket) + responsePacket->valueSize;
00308 
00309    //Limit the length of the string
00310    length = MIN(length, PPP_MAX_USERNAME_LEN);
00311    //Copy the name of the peer to be identified
00312    memcpy(context->peerName, p, length);
00313    //Properly terminate the string with a NULL character
00314    context->peerName[length] = '\0';
00315 
00316    //Invoke user-defined callback, if any
00317    if(context->settings.authCallback != NULL)
00318    {
00319       //Perfom username and password verification
00320       status = context->settings.authCallback(context->interface,
00321          context->peerName);
00322    }
00323    else
00324    {
00325       //Unable to perform authentication...
00326       status = FALSE;
00327    }
00328 
00329    //Whenever a Response packet is received, the authenticator compares the
00330    //Response Value with its own calculation of the expected value. Based on
00331    //this comparison, the authenticator must send a Success or Failure packet
00332    if(status)
00333    {
00334       //Send a Success packet
00335       chapSendSuccess(context);
00336 
00337       //Switch to the Success-Sent state
00338       context->chapFsm.localState = CHAP_STATE_6_SUCCESS_SENT;
00339       //The user has been successfully authenticated
00340       context->localAuthDone = TRUE;
00341 
00342       //Check whether PPP authentication is complete
00343       if(context->localAuthDone && context->peerAuthDone)
00344       {
00345          //Check current PPP phase
00346          if(context->pppPhase == PPP_PHASE_AUTHENTICATE)
00347          {
00348             //Advance to the Network phase
00349             context->pppPhase = PPP_PHASE_NETWORK;
00350 
00351 #if (IPV4_SUPPORT == ENABLED)
00352             //IPCP Open event
00353             ipcpOpen(context);
00354 #endif
00355 #if (IPV6_SUPPORT == ENABLED)
00356             //IPV6CP Open event
00357             ipv6cpOpen(context);
00358 #endif
00359          }
00360       }
00361    }
00362    else
00363    {
00364       //Send a Failure packet
00365       chapSendFailure(context);
00366 
00367       //Switch to the Failure-Sent state
00368       context->chapFsm.localState = CHAP_STATE_8_FAILURE_SENT;
00369       //The authenticator should take action to terminate the link
00370       lcpClose(context);
00371    }
00372 
00373    //Successful processing
00374    return NO_ERROR;
00375 }
00376 
00377 
00378 /**
00379  * @brief Process Success packet
00380  * @param[in] context PPP context
00381  * @param[in] successPacket Packet received from the peer
00382  * @param[in] length Length of the packet, in bytes
00383  * @return Error code
00384  **/
00385 
00386 error_t chapProcessSuccess(PppContext *context,
00387    const ChapSuccessPacket *successPacket, size_t length)
00388 {
00389    //Debug message
00390    TRACE_INFO("\r\nCHAP Success packet received\r\n");
00391 
00392    //Make sure the Success packet is acceptable
00393    if(context->peerConfig.authProtocol != PPP_PROTOCOL_CHAP)
00394       return ERROR_FAILURE;
00395 
00396    //Check the length of the packet
00397    if(length < sizeof(ChapSuccessPacket))
00398       return ERROR_INVALID_LENGTH;
00399 
00400    //When a packet is received with an invalid Identifier field, the
00401    //packet is silently discarded without affecting the automaton
00402    if(successPacket->identifier != context->chapFsm.peerIdentifier)
00403       return ERROR_WRONG_IDENTIFIER;
00404 
00405    //Switch to the Success-Rcvd state
00406    context->chapFsm.peerState = CHAP_STATE_7_SUCCESS_RCVD;
00407    //The user name has been accepted by the authenticator
00408    context->peerAuthDone = TRUE;
00409 
00410    //Check whether PPP authentication is complete
00411    if(context->localAuthDone && context->peerAuthDone)
00412    {
00413       //Check current PPP phase
00414       if(context->pppPhase == PPP_PHASE_AUTHENTICATE)
00415       {
00416          //Advance to the Network phase
00417          context->pppPhase = PPP_PHASE_NETWORK;
00418 
00419 #if (IPV4_SUPPORT == ENABLED)
00420          //IPCP Open event
00421          ipcpOpen(context);
00422 #endif
00423 #if (IPV6_SUPPORT == ENABLED)
00424          //IPV6CP Open event
00425          ipv6cpOpen(context);
00426 #endif
00427       }
00428    }
00429 
00430    //Successful processing
00431    return NO_ERROR;
00432 }
00433 
00434 
00435 /**
00436  * @brief Process Failure packet
00437  * @param[in] context PPP context
00438  * @param[in] failurePacket Packet received from the peer
00439  * @param[in] length Length of the packet, in bytes
00440  * @return Error code
00441  **/
00442 
00443 error_t chapProcessFailure(PppContext *context,
00444    const ChapFailurePacket *failurePacket, size_t length)
00445 {
00446    //Debug message
00447    TRACE_INFO("\r\nCHAP Failure packet received\r\n");
00448 
00449    //Make sure the Failure packet is acceptable
00450    if(context->peerConfig.authProtocol != PPP_PROTOCOL_CHAP)
00451       return ERROR_FAILURE;
00452 
00453    //Check the length of the packet
00454    if(length < sizeof(ChapFailurePacket))
00455       return ERROR_INVALID_LENGTH;
00456 
00457    //When a packet is received with an invalid Identifier field, the
00458    //packet is silently discarded without affecting the automaton
00459    if(failurePacket->identifier != context->chapFsm.peerIdentifier)
00460       return ERROR_WRONG_IDENTIFIER;
00461 
00462    //Switch to the Failure-Rcvd state
00463    context->chapFsm.peerState = CHAP_STATE_9_FAILURE_RCVD;
00464    //Authentication failed
00465    lcpClose(context);
00466 
00467    //Successful processing
00468    return NO_ERROR;
00469 }
00470 
00471 
00472 /**
00473  * @brief Send Challenge packet
00474  * @param[in] context PPP context
00475  * @return Error code
00476  **/
00477 
00478 error_t chapSendChallenge(PppContext *context)
00479 {
00480    error_t error;
00481    size_t n;
00482    size_t length;
00483    size_t offset;
00484    NetBuffer *buffer;
00485    ChapChallengePacket *challengePacket;
00486 
00487    //Retrieve the length of the username
00488    n = strlen(context->username);
00489    //Calculate the length of the Challenge packet
00490    length = sizeof(ChapChallengePacket) + MD5_DIGEST_SIZE + n;
00491 
00492    //Allocate a buffer memory to hold the Challenge packet
00493    buffer = pppAllocBuffer(length, &offset);
00494    //Failed to allocate memory?
00495    if(buffer == NULL)
00496       return ERROR_OUT_OF_MEMORY;
00497 
00498    //Point to the Challenge packet
00499    challengePacket = netBufferAt(buffer, offset);
00500 
00501    //Format packet header
00502    challengePacket->code = CHAP_CODE_CHALLENGE;
00503    challengePacket->identifier = ++context->chapFsm.localIdentifier;
00504    challengePacket->length = htons(length);
00505    challengePacket->valueSize = MD5_DIGEST_SIZE;
00506 
00507    //Make sure that the callback function has been registered
00508    if(context->settings.randCallback != NULL)
00509    {
00510       //Generate a random challenge value
00511       error = context->settings.randCallback(
00512          context->chapFsm.challenge, MD5_DIGEST_SIZE);
00513    }
00514    else
00515    {
00516       //Report an error
00517       error = ERROR_FAILURE;
00518    }
00519 
00520    //Check status code
00521    if(!error)
00522    {
00523       //Copy the challenge value
00524       memcpy(challengePacket->value, context->chapFsm.challenge, MD5_DIGEST_SIZE);
00525 
00526       //The Name field is one or more octets representing the
00527       //identification of the system transmitting the packet
00528       memcpy(challengePacket->value + MD5_DIGEST_SIZE, context->username, n);
00529 
00530       //Debug message
00531       TRACE_INFO("Sending CHAP Challenge packet (%" PRIuSIZE " bytes)...\r\n", length);
00532       //Dump packet contents for debugging purpose
00533       pppDumpPacket((PppPacket *) challengePacket, length, PPP_PROTOCOL_CHAP);
00534 
00535       //Send PPP frame
00536       error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_CHAP);
00537 
00538       //The restart counter is decremented each time a Challenge packet is sent
00539       if(context->chapFsm.restartCounter > 0)
00540          context->chapFsm.restartCounter--;
00541 
00542       //Save the time at which the packet was sent
00543       context->chapFsm.timestamp = osGetSystemTime();
00544    }
00545 
00546    //Free previously allocated memory block
00547    netBufferFree(buffer);
00548    //Return status code
00549    return error;
00550 }
00551 
00552 
00553 /**
00554  * @brief Send Response packet
00555  * @param[in] context PPP context
00556  * @param[in] value Response value
00557  * @return Error code
00558  **/
00559 
00560 error_t chapSendResponse(PppContext *context, const uint8_t *value)
00561 {
00562    error_t error;
00563    size_t n;
00564    size_t length;
00565    size_t offset;
00566    NetBuffer *buffer;
00567    ChapResponsePacket *responsePacket;
00568 
00569    //Retrieve the length of the username
00570    n = strlen(context->username);
00571    //Calculate the length of the Response packet
00572    length = sizeof(ChapResponsePacket) + MD5_DIGEST_SIZE + n;
00573 
00574    //Allocate a buffer memory to hold the Response packet
00575    buffer = pppAllocBuffer(length, &offset);
00576    //Failed to allocate memory?
00577    if(buffer == NULL)
00578       return ERROR_OUT_OF_MEMORY;
00579 
00580    //Point to the Response packet
00581    responsePacket = netBufferAt(buffer, offset);
00582 
00583    //Format packet header
00584    responsePacket->code = CHAP_CODE_RESPONSE;
00585    responsePacket->identifier = context->chapFsm.peerIdentifier;
00586    responsePacket->length = htons(length);
00587    responsePacket->valueSize = MD5_DIGEST_SIZE;
00588 
00589    //Copy the Response value
00590    memcpy(responsePacket->value, value, MD5_DIGEST_SIZE);
00591 
00592    //The Name field is one or more octets representing the
00593    //identification of the system transmitting the packet
00594    memcpy(responsePacket->value + MD5_DIGEST_SIZE, context->username, n);
00595 
00596    //Debug message
00597    TRACE_INFO("Sending CHAP Response packet (%" PRIuSIZE " bytes)...\r\n", length);
00598    //Dump packet contents for debugging purpose
00599    pppDumpPacket((PppPacket *) responsePacket, length, PPP_PROTOCOL_CHAP);
00600 
00601    //Send PPP frame
00602    error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_CHAP);
00603 
00604    //Free previously allocated memory block
00605    netBufferFree(buffer);
00606    //Return status code
00607    return error;
00608 }
00609 
00610 
00611 /**
00612  * @brief Send Success packet
00613  * @param[in] context PPP context
00614  * @return Error code
00615  **/
00616 
00617 error_t chapSendSuccess(PppContext *context)
00618 {
00619    error_t error;
00620    size_t length;
00621    size_t offset;
00622    NetBuffer *buffer;
00623    PppPacket *successPacket;
00624 
00625    //Retrieve the length of the Success packet
00626    length = sizeof(PppPacket);
00627 
00628    //Allocate a buffer memory to hold the Success packet
00629    buffer = pppAllocBuffer(length, &offset);
00630    //Failed to allocate memory?
00631    if(buffer == NULL)
00632       return ERROR_OUT_OF_MEMORY;
00633 
00634    //Point to the Success packet
00635    successPacket = netBufferAt(buffer, offset);
00636 
00637    //Format packet header
00638    successPacket->code = CHAP_CODE_SUCCESS;
00639    successPacket->identifier = context->chapFsm.localIdentifier;
00640    successPacket->length = htons(length);
00641 
00642    //Debug message
00643    TRACE_INFO("Sending CHAP Success packet (%" PRIuSIZE " bytes)...\r\n", length);
00644    //Dump packet contents for debugging purpose
00645    pppDumpPacket((PppPacket *) successPacket, length, PPP_PROTOCOL_CHAP);
00646 
00647    //Send PPP frame
00648    error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_CHAP);
00649 
00650    //Free previously allocated memory block
00651    netBufferFree(buffer);
00652    //Return status code
00653    return error;
00654 }
00655 
00656 
00657 /**
00658  * @brief Send Failure packet
00659  * @param[in] context PPP context
00660  * @return Error code
00661  **/
00662 
00663 error_t chapSendFailure(PppContext *context)
00664 {
00665    error_t error;
00666    size_t length;
00667    size_t offset;
00668    NetBuffer *buffer;
00669    PppPacket *failurePacket;
00670 
00671    //Retrieve the length of the Failure packet
00672    length = sizeof(PppPacket);
00673 
00674    //Allocate a buffer memory to hold the Failure packet
00675    buffer = pppAllocBuffer(length, &offset);
00676    //Failed to allocate memory?
00677    if(buffer == NULL)
00678       return ERROR_OUT_OF_MEMORY;
00679 
00680    //Point to the Failure packet
00681    failurePacket = netBufferAt(buffer, offset);
00682 
00683    //Format packet header
00684    failurePacket->code = CHAP_CODE_FAILURE;
00685    failurePacket->identifier = context->chapFsm.localIdentifier;
00686    failurePacket->length = htons(length);
00687 
00688    //Debug message
00689    TRACE_INFO("Sending CHAP Failure packet (%" PRIuSIZE " bytes)...\r\n", length);
00690    //Dump packet contents for debugging purpose
00691    pppDumpPacket((PppPacket *) failurePacket, length, PPP_PROTOCOL_CHAP);
00692 
00693    //Send PPP frame
00694    error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_CHAP);
00695 
00696    //Free previously allocated memory block
00697    netBufferFree(buffer);
00698    //Return status code
00699    return error;
00700 }
00701 
00702 
00703 /**
00704  * @brief Password verification
00705  * @param[in] context PPP context
00706  * @param[in] password NULL-terminated string containing the password to be checked
00707  * @return TRUE if the password is valid, else FALSE
00708  **/
00709 
00710 bool_t chapCheckPassword(PppContext *context, const char_t *password)
00711 {
00712    size_t n;
00713    Md5Context md5Context;
00714 
00715    //Retrieve the length of the password
00716    n = strlen(password);
00717 
00718    //The response value is the one-way hash calculated over a stream
00719    //of octets consisting of the identifier, followed by the secret,
00720    //followed by the challenge value
00721    md5Init(&md5Context);
00722    md5Update(&md5Context, &context->chapFsm.localIdentifier, sizeof(uint8_t));
00723    md5Update(&md5Context, password, n);
00724    md5Update(&md5Context, context->chapFsm.challenge, MD5_DIGEST_SIZE);
00725    md5Final(&md5Context, NULL);
00726 
00727    //Check the resulting digest value
00728    if(!memcmp(md5Context.digest, context->chapFsm.response, MD5_DIGEST_SIZE))
00729       return TRUE;
00730    else
00731       return FALSE;
00732 }
00733 
00734 #endif
00735