mbed-os for GR-LYCHEE

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_chap_ms.c Source File

lwip_chap_ms.c

00001 /*
00002  * chap_ms.c - Microsoft MS-CHAP compatible implementation.
00003  *
00004  * Copyright (c) 1995 Eric Rosenquist.  All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in
00015  *    the documentation and/or other materials provided with the
00016  *    distribution.
00017  *
00018  * 3. The name(s) of the authors of this software must not be used to
00019  *    endorse or promote products derived from this software without
00020  *    prior written permission.
00021  *
00022  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
00023  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00024  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
00025  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00026  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
00027  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
00028  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00029  */
00030 
00031 /*
00032  * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
00033  *
00034  *   Implemented LANManager type password response to MS-CHAP challenges.
00035  *   Now pppd provides both NT style and LANMan style blocks, and the
00036  *   prefered is set by option "ms-lanman". Default is to use NT.
00037  *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
00038  *
00039  *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
00040  */
00041 
00042 /*
00043  * Modifications by Frank Cusack, frank@google.com, March 2002.
00044  *
00045  *   Implemented MS-CHAPv2 functionality, heavily based on sample
00046  *   implementation in RFC 2759.  Implemented MPPE functionality,
00047  *   heavily based on sample implementation in RFC 3079.
00048  *
00049  * Copyright (c) 2002 Google, Inc.  All rights reserved.
00050  *
00051  * Redistribution and use in source and binary forms, with or without
00052  * modification, are permitted provided that the following conditions
00053  * are met:
00054  *
00055  * 1. Redistributions of source code must retain the above copyright
00056  *    notice, this list of conditions and the following disclaimer.
00057  *
00058  * 2. Redistributions in binary form must reproduce the above copyright
00059  *    notice, this list of conditions and the following disclaimer in
00060  *    the documentation and/or other materials provided with the
00061  *    distribution.
00062  *
00063  * 3. The name(s) of the authors of this software must not be used to
00064  *    endorse or promote products derived from this software without
00065  *    prior written permission.
00066  *
00067  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
00068  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00069  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
00070  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00071  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
00072  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
00073  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00074  *
00075  */
00076 
00077 #include "netif/ppp/ppp_opts.h"
00078 #if PPP_SUPPORT && MSCHAP_SUPPORT  /* don't build if not configured for use in lwipopts.h */
00079 
00080 #if 0 /* UNUSED */
00081 #include <stdio.h>
00082 #include <stdlib.h>
00083 #include <string.h>
00084 #include <ctype.h>
00085 #include <sys/types.h>
00086 #include <sys/time.h>
00087 #include <unistd.h>
00088 #endif /* UNUSED */
00089 
00090 #include "netif/ppp/ppp_impl.h"
00091 
00092 #include "netif/ppp/chap-new.h"
00093 #include "netif/ppp/chap_ms.h"
00094 #include "netif/ppp/pppcrypt.h"
00095 #include "netif/ppp/magic.h"
00096 #if MPPE_SUPPORT
00097 #include "netif/ppp/mppe.h" /* For mppe_sha1_pad*, mppe_set_key() */
00098 #endif /* MPPE_SUPPORT */
00099 
00100 #define SHA1_SIGNATURE_SIZE 20
00101 #define MD4_SIGNATURE_SIZE  16  /* 16 bytes in a MD4 message digest */
00102 #define MAX_NT_PASSWORD     256 /* Max (Unicode) chars in an NT pass */
00103 
00104 #define MS_CHAP_RESPONSE_LEN    49  /* Response length for MS-CHAP */
00105 #define MS_CHAP2_RESPONSE_LEN   49  /* Response length for MS-CHAPv2 */
00106 #define MS_AUTH_RESPONSE_LENGTH 40  /* MS-CHAPv2 authenticator response, */
00107                     /* as ASCII */
00108 
00109 /* Error codes for MS-CHAP failure messages. */
00110 #define MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS    646
00111 #define MS_CHAP_ERROR_ACCT_DISABLED     647
00112 #define MS_CHAP_ERROR_PASSWD_EXPIRED        648
00113 #define MS_CHAP_ERROR_NO_DIALIN_PERMISSION  649
00114 #define MS_CHAP_ERROR_AUTHENTICATION_FAILURE    691
00115 #define MS_CHAP_ERROR_CHANGING_PASSWORD     709
00116 
00117 /*
00118  * Offsets within the response field for MS-CHAP
00119  */
00120 #define MS_CHAP_LANMANRESP  0
00121 #define MS_CHAP_LANMANRESP_LEN  24
00122 #define MS_CHAP_NTRESP      24
00123 #define MS_CHAP_NTRESP_LEN  24
00124 #define MS_CHAP_USENT       48
00125 
00126 /*
00127  * Offsets within the response field for MS-CHAP2
00128  */
00129 #define MS_CHAP2_PEER_CHALLENGE 0
00130 #define MS_CHAP2_PEER_CHAL_LEN  16
00131 #define MS_CHAP2_RESERVED_LEN   8
00132 #define MS_CHAP2_NTRESP     24
00133 #define MS_CHAP2_NTRESP_LEN 24
00134 #define MS_CHAP2_FLAGS      48
00135 
00136 #if MPPE_SUPPORT
00137 #if 0 /* UNUSED */
00138 /* These values are the RADIUS attribute values--see RFC 2548. */
00139 #define MPPE_ENC_POL_ENC_ALLOWED 1
00140 #define MPPE_ENC_POL_ENC_REQUIRED 2
00141 #define MPPE_ENC_TYPES_RC4_40 2
00142 #define MPPE_ENC_TYPES_RC4_128 4
00143 
00144 /* used by plugins (using above values) */
00145 extern void set_mppe_enc_types(int, int);
00146 #endif /* UNUSED */
00147 #endif /* MPPE_SUPPORT */
00148 
00149 /* Are we the authenticator or authenticatee?  For MS-CHAPv2 key derivation. */
00150 #define MS_CHAP2_AUTHENTICATEE 0
00151 #define MS_CHAP2_AUTHENTICATOR 1
00152 
00153 static void ascii2unicode (const char[], int, u_char[]);
00154 static void NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]);
00155 static void ChallengeResponse (const u_char *, const u_char *, u_char[24]);
00156 static void ChallengeHash (const u_char[16], const u_char *, const char *, u_char[8]);
00157 static void ChapMS_NT (const u_char *, const char *, int, u_char[24]);
00158 static void ChapMS2_NT (const u_char *, const u_char[16], const char *, const char *, int,
00159                 u_char[24]);
00160 static void GenerateAuthenticatorResponsePlain
00161             (const char*, int, u_char[24], const u_char[16], const u_char *,
00162                  const char *, u_char[41]);
00163 #ifdef MSLANMAN
00164 static void ChapMS_LANMan (u_char *, char *, int, u_char *);
00165 #endif
00166 
00167 static void GenerateAuthenticatorResponse(const u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
00168             u_char NTResponse[24], const u_char PeerChallenge[16],
00169             const u_char *rchallenge, const char *username,
00170             u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]);
00171 
00172 #if MPPE_SUPPORT
00173 static void Set_Start_Key (ppp_pcb *pcb, const u_char *, const char *, int);
00174 static void SetMasterKeys (ppp_pcb *pcb, const char *, int, u_char[24], int);
00175 #endif /* MPPE_SUPPORT */
00176 
00177 static void ChapMS (ppp_pcb *pcb, const u_char *, const char *, int, u_char *);
00178 static void ChapMS2 (ppp_pcb *pcb, const u_char *, const u_char *, const char *, const char *, int,
00179           u_char *, u_char[MS_AUTH_RESPONSE_LENGTH+1], int);
00180 
00181 #ifdef MSLANMAN
00182 bool    ms_lanman = 0;      /* Use LanMan password instead of NT */
00183                 /* Has meaning only with MS-CHAP challenges */
00184 #endif
00185 
00186 #if MPPE_SUPPORT
00187 #ifdef DEBUGMPPEKEY
00188 /* For MPPE debug */
00189 /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
00190 static char *mschap_challenge = NULL;
00191 /* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
00192 static char *mschap2_peer_challenge = NULL;
00193 #endif
00194 
00195 #include "netif/ppp/fsm.h"      /* Need to poke MPPE options */
00196 #include "netif/ppp/ccp.h"
00197 #endif /* MPPE_SUPPORT */
00198 
00199 #if PPP_OPTIONS
00200 /*
00201  * Command-line options.
00202  */
00203 static option_t chapms_option_list[] = {
00204 #ifdef MSLANMAN
00205     { "ms-lanman", o_bool, &ms_lanman,
00206       "Use LanMan passwd when using MS-CHAP", 1 },
00207 #endif
00208 #ifdef DEBUGMPPEKEY
00209     { "mschap-challenge", o_string, &mschap_challenge,
00210       "specify CHAP challenge" },
00211     { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
00212       "specify CHAP peer challenge" },
00213 #endif
00214     { NULL }
00215 };
00216 #endif /* PPP_OPTIONS */
00217 
00218 #if PPP_SERVER
00219 /*
00220  * chapms_generate_challenge - generate a challenge for MS-CHAP.
00221  * For MS-CHAP the challenge length is fixed at 8 bytes.
00222  * The length goes in challenge[0] and the actual challenge starts
00223  * at challenge[1].
00224  */
00225 static void chapms_generate_challenge(ppp_pcb *pcb, unsigned char *challenge) {
00226     LWIP_UNUSED_ARG(pcb);
00227 
00228     *challenge++ = 8;
00229 #ifdef DEBUGMPPEKEY
00230     if (mschap_challenge && strlen(mschap_challenge) == 8)
00231         memcpy(challenge, mschap_challenge, 8);
00232     else
00233 #endif
00234         magic_random_bytes(challenge, 8);
00235 }
00236 
00237 static void chapms2_generate_challenge(ppp_pcb *pcb, unsigned char *challenge) {
00238     LWIP_UNUSED_ARG(pcb);
00239 
00240     *challenge++ = 16;
00241 #ifdef DEBUGMPPEKEY
00242     if (mschap_challenge && strlen(mschap_challenge) == 16)
00243         memcpy(challenge, mschap_challenge, 16);
00244     else
00245 #endif
00246         magic_random_bytes(challenge, 16);
00247 }
00248 
00249 static int chapms_verify_response(ppp_pcb *pcb, int id, const char *name,
00250                const unsigned char *secret, int secret_len,
00251                const unsigned char *challenge, const unsigned char *response,
00252                char *message, int message_space) {
00253     unsigned char md[MS_CHAP_RESPONSE_LEN];
00254     int diff;
00255     int challenge_len, response_len;
00256     LWIP_UNUSED_ARG(id);
00257     LWIP_UNUSED_ARG(name);
00258 
00259     challenge_len = *challenge++;   /* skip length, is 8 */
00260     response_len = *response++;
00261     if (response_len != MS_CHAP_RESPONSE_LEN)
00262         goto bad;
00263 
00264 #ifndef MSLANMAN
00265     if (!response[MS_CHAP_USENT]) {
00266         /* Should really propagate this into the error packet. */
00267         ppp_notice("Peer request for LANMAN auth not supported");
00268         goto bad;
00269     }
00270 #endif
00271 
00272     /* Generate the expected response. */
00273     ChapMS(pcb, (const u_char *)challenge, (const char *)secret, secret_len, md);
00274 
00275 #ifdef MSLANMAN
00276     /* Determine which part of response to verify against */
00277     if (!response[MS_CHAP_USENT])
00278         diff = memcmp(&response[MS_CHAP_LANMANRESP],
00279                   &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN);
00280     else
00281 #endif
00282         diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP],
00283                   MS_CHAP_NTRESP_LEN);
00284 
00285     if (diff == 0) {
00286         ppp_slprintf(message, message_space, "Access granted");
00287         return 1;
00288     }
00289 
00290  bad:
00291     /* See comments below for MS-CHAP V2 */
00292     ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
00293          challenge_len, challenge);
00294     return 0;
00295 }
00296 
00297 static int chapms2_verify_response(ppp_pcb *pcb, int id, const char *name,
00298             const unsigned char *secret, int secret_len,
00299             const unsigned char *challenge, const unsigned char *response,
00300             char *message, int message_space) {
00301     unsigned char md[MS_CHAP2_RESPONSE_LEN];
00302     char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
00303     int challenge_len, response_len;
00304     LWIP_UNUSED_ARG(id);
00305 
00306     challenge_len = *challenge++;   /* skip length, is 16 */
00307     response_len = *response++;
00308     if (response_len != MS_CHAP2_RESPONSE_LEN)
00309         goto bad;   /* not even the right length */
00310 
00311     /* Generate the expected response and our mutual auth. */
00312     ChapMS2(pcb, (const u_char*)challenge, (const u_char*)&response[MS_CHAP2_PEER_CHALLENGE], name,
00313         (const char *)secret, secret_len, md,
00314         (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
00315 
00316     /* compare MDs and send the appropriate status */
00317     /*
00318      * Per RFC 2759, success message must be formatted as
00319      *     "S=<auth_string> M=<message>"
00320      * where
00321      *     <auth_string> is the Authenticator Response (mutual auth)
00322      *     <message> is a text message
00323      *
00324      * However, some versions of Windows (win98 tested) do not know
00325      * about the M=<message> part (required per RFC 2759) and flag
00326      * it as an error (reported incorrectly as an encryption error
00327      * to the user).  Since the RFC requires it, and it can be
00328      * useful information, we supply it if the peer is a conforming
00329      * system.  Luckily (?), win98 sets the Flags field to 0x04
00330      * (contrary to RFC requirements) so we can use that to
00331      * distinguish between conforming and non-conforming systems.
00332      *
00333      * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
00334      * help debugging this.
00335      */
00336     if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP],
00337            MS_CHAP2_NTRESP_LEN) == 0) {
00338         if (response[MS_CHAP2_FLAGS])
00339             ppp_slprintf(message, message_space, "S=%s", saresponse);
00340         else
00341             ppp_slprintf(message, message_space, "S=%s M=%s",
00342                  saresponse, "Access granted");
00343         return 1;
00344     }
00345 
00346  bad:
00347     /*
00348      * Failure message must be formatted as
00349      *     "E=e R=r C=c V=v M=m"
00350      * where
00351      *     e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
00352      *     r = retry (we use 1, ok to retry)
00353      *     c = challenge to use for next response, we reuse previous
00354      *     v = Change Password version supported, we use 0
00355      *     m = text message
00356      *
00357      * The M=m part is only for MS-CHAPv2.  Neither win2k nor
00358      * win98 (others untested) display the message to the user anyway.
00359      * They also both ignore the E=e code.
00360      *
00361      * Note that it's safe to reuse the same challenge as we don't
00362      * actually accept another response based on the error message
00363      * (and no clients try to resend a response anyway).
00364      *
00365      * Basically, this whole bit is useless code, even the small
00366      * implementation here is only because of overspecification.
00367      */
00368     ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
00369          challenge_len, challenge, "Access denied");
00370     return 0;
00371 }
00372 #endif /* PPP_SERVER */
00373 
00374 static void chapms_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name,
00375              const unsigned char *challenge, const char *secret, int secret_len,
00376              unsigned char *private_) {
00377     LWIP_UNUSED_ARG(id);
00378     LWIP_UNUSED_ARG(our_name);
00379     LWIP_UNUSED_ARG(private_);
00380     challenge++;    /* skip length, should be 8 */
00381     *response++ = MS_CHAP_RESPONSE_LEN;
00382     ChapMS(pcb, challenge, secret, secret_len, response);
00383 }
00384 
00385 static void chapms2_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name,
00386               const unsigned char *challenge, const char *secret, int secret_len,
00387               unsigned char *private_) {
00388     LWIP_UNUSED_ARG(id);
00389     challenge++;    /* skip length, should be 16 */
00390     *response++ = MS_CHAP2_RESPONSE_LEN;
00391     ChapMS2(pcb, challenge,
00392 #ifdef DEBUGMPPEKEY
00393         mschap2_peer_challenge,
00394 #else
00395         NULL,
00396 #endif
00397         our_name, secret, secret_len, response, private_,
00398         MS_CHAP2_AUTHENTICATEE);
00399 }
00400 
00401 static int chapms2_check_success(ppp_pcb *pcb, unsigned char *msg, int len, unsigned char *private_) {
00402     LWIP_UNUSED_ARG(pcb);
00403 
00404     if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
00405         strncmp((char *)msg, "S=", 2) != 0) {
00406         /* Packet does not start with "S=" */
00407         ppp_error("MS-CHAPv2 Success packet is badly formed.");
00408         return 0;
00409     }
00410     msg += 2;
00411     len -= 2;
00412     if (len < MS_AUTH_RESPONSE_LENGTH
00413         || memcmp(msg, private_, MS_AUTH_RESPONSE_LENGTH)) {
00414         /* Authenticator Response did not match expected. */
00415         ppp_error("MS-CHAPv2 mutual authentication failed.");
00416         return 0;
00417     }
00418     /* Authenticator Response matches. */
00419     msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
00420     len -= MS_AUTH_RESPONSE_LENGTH;
00421     if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
00422         msg += 3; /* Eat the delimiter */
00423     } else if (len) {
00424         /* Packet has extra text which does not begin " M=" */
00425         ppp_error("MS-CHAPv2 Success packet is badly formed.");
00426         return 0;
00427     }
00428     return 1;
00429 }
00430 
00431 static void chapms_handle_failure(ppp_pcb *pcb, unsigned char *inp, int len) {
00432     int err;
00433     const char *p;
00434     char msg[64];
00435     LWIP_UNUSED_ARG(pcb);
00436 
00437     /* We want a null-terminated string for strxxx(). */
00438     len = LWIP_MIN(len, 63);
00439     MEMCPY(msg, inp, len);
00440     msg[len] = 0;
00441     p = msg;
00442 
00443     /*
00444      * Deal with MS-CHAP formatted failure messages; just print the
00445      * M=<message> part (if any).  For MS-CHAP we're not really supposed
00446      * to use M=<message>, but it shouldn't hurt.  See
00447      * chapms[2]_verify_response.
00448      */
00449     if (!strncmp(p, "E=", 2))
00450         err = strtol(p+2, NULL, 10); /* Remember the error code. */
00451     else
00452         goto print_msg; /* Message is badly formatted. */
00453 
00454     if (len && ((p = strstr(p, " M=")) != NULL)) {
00455         /* M=<message> field found. */
00456         p += 3;
00457     } else {
00458         /* No M=<message>; use the error code. */
00459         switch (err) {
00460         case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
00461             p = "E=646 Restricted logon hours";
00462             break;
00463 
00464         case MS_CHAP_ERROR_ACCT_DISABLED:
00465             p = "E=647 Account disabled";
00466             break;
00467 
00468         case MS_CHAP_ERROR_PASSWD_EXPIRED:
00469             p = "E=648 Password expired";
00470             break;
00471 
00472         case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
00473             p = "E=649 No dialin permission";
00474             break;
00475 
00476         case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
00477             p = "E=691 Authentication failure";
00478             break;
00479 
00480         case MS_CHAP_ERROR_CHANGING_PASSWORD:
00481             /* Should never see this, we don't support Change Password. */
00482             p = "E=709 Error changing password";
00483             break;
00484 
00485         default:
00486             ppp_error("Unknown MS-CHAP authentication failure: %.*v",
00487                   len, inp);
00488             return;
00489         }
00490     }
00491 print_msg:
00492     if (p != NULL)
00493         ppp_error("MS-CHAP authentication failed: %v", p);
00494 }
00495 
00496 static void ChallengeResponse(const u_char *challenge,
00497           const u_char PasswordHash[MD4_SIGNATURE_SIZE],
00498           u_char response[24]) {
00499     u_char    ZPasswordHash[21];
00500     lwip_des_context des;
00501     u_char des_key[8];
00502 
00503     BZERO(ZPasswordHash, sizeof(ZPasswordHash));
00504     MEMCPY(ZPasswordHash, PasswordHash, MD4_SIGNATURE_SIZE);
00505 
00506 #if 0
00507     dbglog("ChallengeResponse - ZPasswordHash %.*B",
00508        sizeof(ZPasswordHash), ZPasswordHash);
00509 #endif
00510 
00511     pppcrypt_56_to_64_bit_key(ZPasswordHash + 0, des_key);
00512     lwip_des_init(&des);
00513     lwip_des_setkey_enc(&des, des_key);
00514     lwip_des_crypt_ecb(&des, challenge, response +0);
00515     lwip_des_free(&des);
00516 
00517     pppcrypt_56_to_64_bit_key(ZPasswordHash + 7, des_key);
00518     lwip_des_init(&des);
00519     lwip_des_setkey_enc(&des, des_key);
00520     lwip_des_crypt_ecb(&des, challenge, response +8);
00521     lwip_des_free(&des);
00522 
00523     pppcrypt_56_to_64_bit_key(ZPasswordHash + 14, des_key);
00524     lwip_des_init(&des);
00525     lwip_des_setkey_enc(&des, des_key);
00526     lwip_des_crypt_ecb(&des, challenge, response +16);
00527     lwip_des_free(&des);
00528 
00529 #if 0
00530     dbglog("ChallengeResponse - response %.24B", response);
00531 #endif
00532 }
00533 
00534 static void ChallengeHash(const u_char PeerChallenge[16], const u_char *rchallenge,
00535           const char *username, u_char Challenge[8]) {
00536     lwip_sha1_context   sha1Context;
00537     u_char  sha1Hash[SHA1_SIGNATURE_SIZE];
00538     const char  *user;
00539 
00540     /* remove domain from "domain\username" */
00541     if ((user = strrchr(username, '\\')) != NULL)
00542     ++user;
00543     else
00544     user = username;
00545 
00546     lwip_sha1_init(&sha1Context);
00547     lwip_sha1_starts(&sha1Context);
00548     lwip_sha1_update(&sha1Context, PeerChallenge, 16);
00549     lwip_sha1_update(&sha1Context, rchallenge, 16);
00550     lwip_sha1_update(&sha1Context, (const unsigned char*)user, strlen(user));
00551     lwip_sha1_finish(&sha1Context, sha1Hash);
00552     lwip_sha1_free(&sha1Context);
00553 
00554     MEMCPY(Challenge, sha1Hash, 8);
00555 }
00556 
00557 /*
00558  * Convert the ASCII version of the password to Unicode.
00559  * This implicitly supports 8-bit ISO8859/1 characters.
00560  * This gives us the little-endian representation, which
00561  * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
00562  * is machine-dependent.)
00563  */
00564 static void ascii2unicode(const char ascii[], int ascii_len, u_char unicode[]) {
00565     int i;
00566 
00567     BZERO(unicode, ascii_len * 2);
00568     for (i = 0; i < ascii_len; i++)
00569     unicode[i * 2] = (u_char) ascii[i];
00570 }
00571 
00572 static void NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE]) {
00573     lwip_md4_context        md4Context;
00574 
00575     lwip_md4_init(&md4Context);
00576     lwip_md4_starts(&md4Context);
00577     lwip_md4_update(&md4Context, secret, secret_len);
00578     lwip_md4_finish(&md4Context, hash);
00579     lwip_md4_free(&md4Context);
00580 }
00581 
00582 static void ChapMS_NT(const u_char *rchallenge, const char *secret, int secret_len,
00583       u_char NTResponse[24]) {
00584     u_char  unicodePassword[MAX_NT_PASSWORD * 2];
00585     u_char  PasswordHash[MD4_SIGNATURE_SIZE];
00586 
00587     /* Hash the Unicode version of the secret (== password). */
00588     ascii2unicode(secret, secret_len, unicodePassword);
00589     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
00590 
00591     ChallengeResponse(rchallenge, PasswordHash, NTResponse);
00592 }
00593 
00594 static void ChapMS2_NT(const u_char *rchallenge, const u_char PeerChallenge[16], const char *username,
00595        const char *secret, int secret_len, u_char NTResponse[24]) {
00596     u_char  unicodePassword[MAX_NT_PASSWORD * 2];
00597     u_char  PasswordHash[MD4_SIGNATURE_SIZE];
00598     u_char  Challenge[8];
00599 
00600     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
00601 
00602     /* Hash the Unicode version of the secret (== password). */
00603     ascii2unicode(secret, secret_len, unicodePassword);
00604     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
00605 
00606     ChallengeResponse(Challenge, PasswordHash, NTResponse);
00607 }
00608 
00609 #ifdef MSLANMAN
00610 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
00611 
00612 static void ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
00613           unsigned char *response) {
00614     int         i;
00615     u_char      UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
00616     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
00617     lwip_des_context des;
00618     u_char des_key[8];
00619 
00620     /* LANMan password is case insensitive */
00621     BZERO(UcasePassword, sizeof(UcasePassword));
00622     for (i = 0; i < secret_len; i++)
00623        UcasePassword[i] = (u_char)toupper(secret[i]);
00624 
00625     pppcrypt_56_to_64_bit_key(UcasePassword +0, des_key);
00626     lwip_des_init(&des);
00627     lwip_des_setkey_enc(&des, des_key);
00628     lwip_des_crypt_ecb(&des, StdText, PasswordHash +0);
00629     lwip_des_free(&des);
00630 
00631     pppcrypt_56_to_64_bit_key(UcasePassword +7, des_key);
00632     lwip_des_init(&des);
00633     lwip_des_setkey_enc(&des, des_key);
00634     lwip_des_crypt_ecb(&des, StdText, PasswordHash +8);
00635     lwip_des_free(&des);
00636 
00637     ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]);
00638 }
00639 #endif
00640 
00641 
00642 static void GenerateAuthenticatorResponse(const u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
00643                   u_char NTResponse[24], const u_char PeerChallenge[16],
00644                   const u_char *rchallenge, const char *username,
00645                   u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) {
00646     /*
00647      * "Magic" constants used in response generation, from RFC 2759.
00648      */
00649     static const u_char Magic1[39] = /* "Magic server to client signing constant" */
00650     { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
00651       0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
00652       0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
00653       0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
00654     static const u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
00655     { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
00656       0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
00657       0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
00658       0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
00659       0x6E };
00660 
00661     int     i;
00662     lwip_sha1_context   sha1Context;
00663     u_char  Digest[SHA1_SIGNATURE_SIZE];
00664     u_char  Challenge[8];
00665 
00666     lwip_sha1_init(&sha1Context);
00667     lwip_sha1_starts(&sha1Context);
00668     lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
00669     lwip_sha1_update(&sha1Context, NTResponse, 24);
00670     lwip_sha1_update(&sha1Context, Magic1, sizeof(Magic1));
00671     lwip_sha1_finish(&sha1Context, Digest);
00672     lwip_sha1_free(&sha1Context);
00673 
00674     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
00675 
00676     lwip_sha1_init(&sha1Context);
00677     lwip_sha1_starts(&sha1Context);
00678     lwip_sha1_update(&sha1Context, Digest, sizeof(Digest));
00679     lwip_sha1_update(&sha1Context, Challenge, sizeof(Challenge));
00680     lwip_sha1_update(&sha1Context, Magic2, sizeof(Magic2));
00681     lwip_sha1_finish(&sha1Context, Digest);
00682     lwip_sha1_free(&sha1Context);
00683 
00684     /* Convert to ASCII hex string. */
00685     for (i = 0; i < LWIP_MAX((MS_AUTH_RESPONSE_LENGTH / 2), (int)sizeof(Digest)); i++)
00686     sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
00687 }
00688 
00689 
00690 static void GenerateAuthenticatorResponsePlain(
00691          const char *secret, int secret_len,
00692          u_char NTResponse[24], const u_char PeerChallenge[16],
00693          const u_char *rchallenge, const char *username,
00694          u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) {
00695     u_char  unicodePassword[MAX_NT_PASSWORD * 2];
00696     u_char  PasswordHash[MD4_SIGNATURE_SIZE];
00697     u_char  PasswordHashHash[MD4_SIGNATURE_SIZE];
00698 
00699     /* Hash (x2) the Unicode version of the secret (== password). */
00700     ascii2unicode(secret, secret_len, unicodePassword);
00701     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
00702     NTPasswordHash(PasswordHash, sizeof(PasswordHash),
00703            PasswordHashHash);
00704 
00705     GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
00706                   rchallenge, username, authResponse);
00707 }
00708 
00709 
00710 #if MPPE_SUPPORT
00711 /*
00712  * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
00713  */
00714 static void Set_Start_Key(ppp_pcb *pcb, const u_char *rchallenge, const char *secret, int secret_len) {
00715     u_char  unicodePassword[MAX_NT_PASSWORD * 2];
00716     u_char  PasswordHash[MD4_SIGNATURE_SIZE];
00717     u_char  PasswordHashHash[MD4_SIGNATURE_SIZE];
00718     lwip_sha1_context   sha1Context;
00719     u_char  Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
00720 
00721     /* Hash (x2) the Unicode version of the secret (== password). */
00722     ascii2unicode(secret, secret_len, unicodePassword);
00723     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
00724     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
00725 
00726     lwip_sha1_init(&sha1Context);
00727     lwip_sha1_starts(&sha1Context);
00728     lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
00729     lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
00730     lwip_sha1_update(&sha1Context, rchallenge, 8);
00731     lwip_sha1_finish(&sha1Context, Digest);
00732     lwip_sha1_free(&sha1Context);
00733 
00734     /* Same key in both directions. */
00735     mppe_set_key(pcb, &pcb->mppe_comp, Digest);
00736     mppe_set_key(pcb, &pcb->mppe_decomp, Digest);
00737 
00738     pcb->mppe_keys_set = 1;
00739 }
00740 
00741 /*
00742  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
00743  */
00744 static void SetMasterKeys(ppp_pcb *pcb, const char *secret, int secret_len, u_char NTResponse[24], int IsServer) {
00745     u_char  unicodePassword[MAX_NT_PASSWORD * 2];
00746     u_char  PasswordHash[MD4_SIGNATURE_SIZE];
00747     u_char  PasswordHashHash[MD4_SIGNATURE_SIZE];
00748     lwip_sha1_context   sha1Context;
00749     u_char  MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
00750     u_char  Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
00751     const u_char *s;
00752 
00753     /* "This is the MPPE Master Key" */
00754     static const u_char Magic1[27] =
00755     { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
00756       0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
00757       0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
00758     /* "On the client side, this is the send key; "
00759        "on the server side, it is the receive key." */
00760     static const u_char Magic2[84] =
00761     { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
00762       0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
00763       0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
00764       0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
00765       0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
00766       0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
00767       0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
00768       0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
00769       0x6b, 0x65, 0x79, 0x2e };
00770     /* "On the client side, this is the receive key; "
00771        "on the server side, it is the send key." */
00772     static const u_char Magic3[84] =
00773     { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
00774       0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
00775       0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
00776       0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
00777       0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
00778       0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
00779       0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
00780       0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
00781       0x6b, 0x65, 0x79, 0x2e };
00782 
00783     /* Hash (x2) the Unicode version of the secret (== password). */
00784     ascii2unicode(secret, secret_len, unicodePassword);
00785     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
00786     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
00787 
00788     lwip_sha1_init(&sha1Context);
00789     lwip_sha1_starts(&sha1Context);
00790     lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
00791     lwip_sha1_update(&sha1Context, NTResponse, 24);
00792     lwip_sha1_update(&sha1Context, Magic1, sizeof(Magic1));
00793     lwip_sha1_finish(&sha1Context, MasterKey);
00794     lwip_sha1_free(&sha1Context);
00795 
00796     /*
00797      * generate send key
00798      */
00799     if (IsServer)
00800     s = Magic3;
00801     else
00802     s = Magic2;
00803     lwip_sha1_init(&sha1Context);
00804     lwip_sha1_starts(&sha1Context);
00805     lwip_sha1_update(&sha1Context, MasterKey, 16);
00806     lwip_sha1_update(&sha1Context, mppe_sha1_pad1, SHA1_PAD_SIZE);
00807     lwip_sha1_update(&sha1Context, s, 84);
00808     lwip_sha1_update(&sha1Context, mppe_sha1_pad2, SHA1_PAD_SIZE);
00809     lwip_sha1_finish(&sha1Context, Digest);
00810     lwip_sha1_free(&sha1Context);
00811 
00812     mppe_set_key(pcb, &pcb->mppe_comp, Digest);
00813 
00814     /*
00815      * generate recv key
00816      */
00817     if (IsServer)
00818     s = Magic2;
00819     else
00820     s = Magic3;
00821     lwip_sha1_init(&sha1Context);
00822     lwip_sha1_starts(&sha1Context);
00823     lwip_sha1_update(&sha1Context, MasterKey, 16);
00824     lwip_sha1_update(&sha1Context, mppe_sha1_pad1, SHA1_PAD_SIZE);
00825     lwip_sha1_update(&sha1Context, s, 84);
00826     lwip_sha1_update(&sha1Context, mppe_sha1_pad2, SHA1_PAD_SIZE);
00827     lwip_sha1_finish(&sha1Context, Digest);
00828     lwip_sha1_free(&sha1Context);
00829 
00830     mppe_set_key(pcb, &pcb->mppe_decomp, Digest);
00831 
00832     pcb->mppe_keys_set = 1;
00833 }
00834 
00835 #endif /* MPPE_SUPPORT */
00836 
00837 
00838 static void ChapMS(ppp_pcb *pcb, const u_char *rchallenge, const char *secret, int secret_len,
00839        unsigned char *response) {
00840 #if !MPPE_SUPPORT
00841     LWIP_UNUSED_ARG(pcb);
00842 #endif /* !MPPE_SUPPORT */
00843     BZERO(response, MS_CHAP_RESPONSE_LEN);
00844 
00845     ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
00846 
00847 #ifdef MSLANMAN
00848     ChapMS_LANMan(rchallenge, secret, secret_len,
00849           &response[MS_CHAP_LANMANRESP]);
00850 
00851     /* preferred method is set by option  */
00852     response[MS_CHAP_USENT] = !ms_lanman;
00853 #else
00854     response[MS_CHAP_USENT] = 1;
00855 #endif
00856 
00857 #if MPPE_SUPPORT
00858     Set_Start_Key(pcb, rchallenge, secret, secret_len);
00859 #endif /* MPPE_SUPPORT */
00860 }
00861 
00862 
00863 /*
00864  * If PeerChallenge is NULL, one is generated and the PeerChallenge
00865  * field of response is filled in.  Call this way when generating a response.
00866  * If PeerChallenge is supplied, it is copied into the PeerChallenge field.
00867  * Call this way when verifying a response (or debugging).
00868  * Do not call with PeerChallenge = response.
00869  *
00870  * The PeerChallenge field of response is then used for calculation of the
00871  * Authenticator Response.
00872  */
00873 static void ChapMS2(ppp_pcb *pcb, const u_char *rchallenge, const u_char *PeerChallenge,
00874     const char *user, const char *secret, int secret_len, unsigned char *response,
00875     u_char authResponse[], int authenticator) {
00876     /* ARGSUSED */
00877     LWIP_UNUSED_ARG(authenticator);
00878 #if !MPPE_SUPPORT
00879     LWIP_UNUSED_ARG(pcb);
00880 #endif /* !MPPE_SUPPORT */
00881 
00882     BZERO(response, MS_CHAP2_RESPONSE_LEN);
00883 
00884     /* Generate the Peer-Challenge if requested, or copy it if supplied. */
00885     if (!PeerChallenge)
00886     magic_random_bytes(&response[MS_CHAP2_PEER_CHALLENGE], MS_CHAP2_PEER_CHAL_LEN);
00887     else
00888     MEMCPY(&response[MS_CHAP2_PEER_CHALLENGE], PeerChallenge,
00889           MS_CHAP2_PEER_CHAL_LEN);
00890 
00891     /* Generate the NT-Response */
00892     ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
00893            secret, secret_len, &response[MS_CHAP2_NTRESP]);
00894 
00895     /* Generate the Authenticator Response. */
00896     GenerateAuthenticatorResponsePlain(secret, secret_len,
00897                        &response[MS_CHAP2_NTRESP],
00898                        &response[MS_CHAP2_PEER_CHALLENGE],
00899                        rchallenge, user, authResponse);
00900 
00901 #if MPPE_SUPPORT
00902     SetMasterKeys(pcb, secret, secret_len,
00903           &response[MS_CHAP2_NTRESP], authenticator);
00904 #endif /* MPPE_SUPPORT */
00905 }
00906 
00907 #if 0 /* UNUSED */
00908 #if MPPE_SUPPORT
00909 /*
00910  * Set MPPE options from plugins.
00911  */
00912 void set_mppe_enc_types(int policy, int types) {
00913     /* Early exit for unknown policies. */
00914     if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
00915     policy != MPPE_ENC_POL_ENC_REQUIRED)
00916     return;
00917 
00918     /* Don't modify MPPE if it's optional and wasn't already configured. */
00919     if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
00920     return;
00921 
00922     /*
00923      * Disable undesirable encryption types.  Note that we don't ENABLE
00924      * any encryption types, to avoid overriding manual configuration.
00925      */
00926     switch(types) {
00927     case MPPE_ENC_TYPES_RC4_40:
00928         ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;   /* disable 128-bit */
00929         break;
00930     case MPPE_ENC_TYPES_RC4_128:
00931         ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;    /* disable 40-bit */
00932         break;
00933     default:
00934         break;
00935     }
00936 }
00937 #endif /* MPPE_SUPPORT */
00938 #endif /* UNUSED */
00939 
00940 const struct chap_digest_type chapms_digest = {
00941     CHAP_MICROSOFT,     /* code */
00942 #if PPP_SERVER
00943     chapms_generate_challenge,
00944     chapms_verify_response,
00945 #endif /* PPP_SERVER */
00946     chapms_make_response,
00947     NULL,           /* check_success */
00948     chapms_handle_failure,
00949 };
00950 
00951 const struct chap_digest_type chapms2_digest = {
00952     CHAP_MICROSOFT_V2,  /* code */
00953 #if PPP_SERVER
00954     chapms2_generate_challenge,
00955     chapms2_verify_response,
00956 #endif /* PPP_SERVER */
00957     chapms2_make_response,
00958     chapms2_check_success,
00959     chapms_handle_failure,
00960 };
00961 
00962 #endif /* PPP_SUPPORT && MSCHAP_SUPPORT */