Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
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 */
Generated on Sun Jul 17 2022 08:25:24 by 1.7.2