1/* 2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * chap_ms.c - Microsoft MS-CHAP compatible implementation. 25 * 26 * Copyright (c) 1995 Eric Rosenquist. All rights reserved. 27 * 28 * Redistribution and use in source and binary forms, with or without 29 * modification, are permitted provided that the following conditions 30 * are met: 31 * 32 * 1. Redistributions of source code must retain the above copyright 33 * notice, this list of conditions and the following disclaimer. 34 * 35 * 2. Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in 37 * the documentation and/or other materials provided with the 38 * distribution. 39 * 40 * 3. The name(s) of the authors of this software must not be used to 41 * endorse or promote products derived from this software without 42 * prior written permission. 43 * 44 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 45 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 46 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 47 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 48 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 49 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 50 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 51 */ 52 53/* 54 * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997 55 * 56 * Implemented LANManager type password response to MS-CHAP challenges. 57 * Now pppd provides both NT style and LANMan style blocks, and the 58 * prefered is set by option "ms-lanman". Default is to use NT. 59 * The hash text (StdText) was taken from Win95 RASAPI32.DLL. 60 * 61 * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80 62 */ 63 64/* 65 * Modifications by Frank Cusack, frank@google.com, March 2002. 66 * 67 * Implemented MS-CHAPv2 functionality, heavily based on sample 68 * implementation in RFC 2759. Implemented MPPE functionality, 69 * heavily based on sample implementation in RFC 3079. 70 * 71 * Copyright (c) 2002 Google, Inc. All rights reserved. 72 * 73 * Redistribution and use in source and binary forms, with or without 74 * modification, are permitted provided that the following conditions 75 * are met: 76 * 77 * 1. Redistributions of source code must retain the above copyright 78 * notice, this list of conditions and the following disclaimer. 79 * 80 * 2. Redistributions in binary form must reproduce the above copyright 81 * notice, this list of conditions and the following disclaimer in 82 * the documentation and/or other materials provided with the 83 * distribution. 84 * 85 * 3. The name(s) of the authors of this software must not be used to 86 * endorse or promote products derived from this software without 87 * prior written permission. 88 * 89 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 90 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 91 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 92 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 93 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 94 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 95 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 96 * 97 */ 98 99#define RCSID "$Id: chap_ms.c,v 1.9 2005/08/30 22:53:50 lindak Exp $" 100 101#ifdef CHAPMS 102 103#include <stdio.h> 104#include <stdlib.h> 105#include <string.h> 106#include <ctype.h> 107#include <sys/types.h> 108#include <sys/time.h> 109#include <unistd.h> 110#include <pthread.h> 111 112#include "pppd.h" 113#include "chap-new.h" 114#include "chap_ms.h" 115#ifdef __APPLE__ 116#define SHA1_CTX SHA_CTX 117#define SHA1_SIGNATURE_SIZE SHA_DIGEST_LENGTH 118#include "CommonCrypto/CommonDigest.h" 119#else 120#include "sha1.h" 121#include "md4.h" 122#endif 123#include "pppcrypt.h" 124#include "magic.h" 125 126#ifndef lint 127static const char rcsid[] = RCSID; 128#endif 129 130 131static void ChallengeHash __P((u_char[16], u_char *, char *, u_char[8])); 132static void ascii2unicode __P((u_char[], int, u_char[])); 133static void NTPasswordHash __P((u_char *, int, u_char[MD4_SIGNATURE_SIZE])); 134static void ChallengeResponse __P((u_char *, u_char *, u_char[24])); 135static void ChapMS_NT __P((u_char *, u_char *, int, u_char[24])); 136static void ChapMS2_NT __P((u_char *, u_char[16], char *, u_char *, int, 137 u_char[24])); 138static void GenerateAuthenticatorResponse __P((u_char*, int, u_char[24], 139 u_char[16], u_char *, 140 char *, u_char[41])); 141#ifdef MSLANMAN 142static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *)); 143#endif 144 145#ifdef MPPE 146static void Set_Start_Key __P((u_char *, u_char *, int)); 147static void SetMasterKeys __P((u_char *, int, u_char[24], int)); 148#endif 149 150#ifdef MSLANMAN 151bool ms_lanman = 0; /* Use LanMan password instead of NT */ 152 /* Has meaning only with MS-CHAP challenges */ 153#endif 154 155#ifdef MPPE 156u_char mppe_send_key[MPPE_MAX_KEY_LEN]; 157u_char mppe_recv_key[MPPE_MAX_KEY_LEN]; 158int mppe_keys_set = 0; /* Have the MPPE keys been set? */ 159 160/* For MPPE debug */ 161/* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */ 162static char *mschap_challenge = NULL; 163/* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */ 164static u_char *mschap2_peer_challenge = NULL; 165 166#ifdef __APPLE__ 167static u_char last_challenge_id = 0; 168static u_char last_challenge_response[16] = ""; 169#endif 170 171#include "fsm.h" /* Need to poke MPPE options */ 172#include "ccp.h" 173//#include <net/ppp-comp.h> 174#include <ppp_comp.h> 175#endif 176 177/* 178 * Command-line options. 179 */ 180static option_t chapms_option_list[] = { 181#ifdef MSLANMAN 182 { "ms-lanman", o_bool, &ms_lanman, 183 "Use LanMan passwd when using MS-CHAP", 1 }, 184#endif 185#ifdef DEBUGMPPEKEY 186 { "mschap-challenge", o_string, &mschap_challenge, 187 "specify CHAP challenge" }, 188 { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge, 189 "specify CHAP peer challenge" }, 190#endif 191 { NULL } 192}; 193 194/* 195 * chapms_generate_challenge - generate a challenge for MS-CHAP. 196 * For MS-CHAP the challenge length is fixed at 8 bytes. 197 * The length goes in challenge[0] and the actual challenge starts 198 * at challenge[1]. 199 */ 200static void 201chapms_generate_challenge(unsigned char *challenge) 202{ 203 *challenge++ = 8; 204 if (mschap_challenge && strlen(mschap_challenge) == 8) 205 memcpy(challenge, mschap_challenge, 8); 206 else 207 random_bytes(challenge, 8); 208} 209 210static void 211chapms2_generate_challenge(unsigned char *challenge) 212{ 213 *challenge++ = 16; 214 if (mschap_challenge && strlen(mschap_challenge) == 16) 215 memcpy(challenge, mschap_challenge, 16); 216 else 217 random_bytes(challenge, 16); 218} 219 220static int 221chapms_verify_response(int id, char *name, 222 unsigned char *secret, int secret_len, 223 unsigned char *challenge, unsigned char *response, 224 char *message, int message_space) 225{ 226 MS_ChapResponse *rmd; 227 MS_ChapResponse md; 228 int diff; 229 int challenge_len, response_len; 230 231 challenge_len = *challenge++; /* skip length, is 8 */ 232 response_len = *response++; 233 if (response_len != MS_CHAP_RESPONSE_LEN) 234 goto bad; 235 236 rmd = (MS_ChapResponse *) response; 237 238#ifndef MSLANMAN 239 if (!rmd->UseNT[0]) { 240 /* Should really propagate this into the error packet. */ 241 notice("Peer request for LANMAN auth not supported"); 242 goto bad; 243 } 244#endif 245 246 /* Generate the expected response. */ 247 ChapMS(challenge, secret, secret_len, &md); 248 249#ifdef MSLANMAN 250 /* Determine which part of response to verify against */ 251 if (!rmd->UseNT[0]) 252 diff = memcmp(&rmd->LANManResp, &md.LANManResp, 253 sizeof(md.LANManResp)); 254 else 255#endif 256 diff = memcmp(&rmd->NTResp, &md.NTResp, sizeof(md.NTResp)); 257 258 if (diff == 0) { 259 slprintf(message, message_space, "Access granted"); 260 return 1; 261 } 262 263 bad: 264 /* See comments below for MS-CHAP V2 */ 265 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0", 266 challenge_len, challenge); 267 return 0; 268} 269 270static int 271chapms2_verify_response(int id, char *name, 272 unsigned char *secret, int secret_len, 273 unsigned char *challenge, unsigned char *response, 274 char *message, int message_space) 275{ 276 MS_Chap2Response *rmd; 277 MS_Chap2Response md; 278 u_char saresponse[MS_AUTH_RESPONSE_LENGTH+1]; 279 int challenge_len, response_len; 280 281 challenge_len = *challenge++; /* skip length, is 16 */ 282 response_len = *response++; 283 if (response_len != MS_CHAP2_RESPONSE_LEN) 284 goto bad; /* not even the right length */ 285 286 rmd = (MS_Chap2Response *) response; 287 288 /* Generate the expected response and our mutual auth. */ 289 ChapMS2(challenge, rmd->PeerChallenge, name, 290 secret, secret_len, &md, 291 saresponse, MS_CHAP2_AUTHENTICATOR); 292 293 /* compare MDs and send the appropriate status */ 294 /* 295 * Per RFC 2759, success message must be formatted as 296 * "S=<auth_string> M=<message>" 297 * where 298 * <auth_string> is the Authenticator Response (mutual auth) 299 * <message> is a text message 300 * 301 * However, some versions of Windows (win98 tested) do not know 302 * about the M=<message> part (required per RFC 2759) and flag 303 * it as an error (reported incorrectly as an encryption error 304 * to the user). Since the RFC requires it, and it can be 305 * useful information, we supply it if the peer is a conforming 306 * system. Luckily (?), win98 sets the Flags field to 0x04 307 * (contrary to RFC requirements) so we can use that to 308 * distinguish between conforming and non-conforming systems. 309 * 310 * Special thanks to Alex Swiridov <say@real.kharkov.ua> for 311 * help debugging this. 312 */ 313 if (memcmp(md.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) { 314 if (rmd->Flags[0]) 315 slprintf(message, message_space, "S=%s", saresponse); 316 else 317 slprintf(message, message_space, "S=%s M=%s", 318 saresponse, "Access granted"); 319 return 1; 320 } 321 322 bad: 323 /* 324 * Failure message must be formatted as 325 * "E=e R=r C=c V=v M=m" 326 * where 327 * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE) 328 * r = retry (we use 1, ok to retry) 329 * c = challenge to use for next response, we reuse previous 330 * v = Change Password version supported, we use 0 331 * m = text message 332 * 333 * The M=m part is only for MS-CHAPv2. Neither win2k nor 334 * win98 (others untested) display the message to the user anyway. 335 * They also both ignore the E=e code. 336 * 337 * Note that it's safe to reuse the same challenge as we don't 338 * actually accept another response based on the error message 339 * (and no clients try to resend a response anyway). 340 * 341 * Basically, this whole bit is useless code, even the small 342 * implementation here is only because of overspecification. 343 */ 344 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s", 345 challenge_len, challenge, "Access denied"); 346 return 0; 347} 348 349static void 350chapms_make_response(unsigned char *response, int id, char *our_name, 351 unsigned char *challenge, u_char *secret, int secret_len, 352 unsigned char *private) 353{ 354 challenge++; /* skip length, should be 8 */ 355 *response++ = MS_CHAP_RESPONSE_LEN; 356 ChapMS(challenge, secret, secret_len, (MS_ChapResponse *) response); 357} 358 359static void 360chapms2_make_response(unsigned char *response, int id, char *our_name, 361 unsigned char *challenge, u_char *secret, int secret_len, 362 unsigned char *private) 363{ 364 u_char *challenge_resp; 365 366 challenge++; /* skip length, should be 16 */ 367 *response++ = MS_CHAP2_RESPONSE_LEN; 368 369 challenge_resp = mschap2_peer_challenge; 370 371#ifdef __APPLE__ 372 if(!challenge_resp) { 373 /* use the the last challenge response known if the peer 374 * hasn't supplied one 375 */ 376 if(id == last_challenge_id && last_challenge_response[0]) 377 challenge_resp = last_challenge_response; 378 else { 379 challenge_resp = NULL; 380 } 381 } 382#endif 383 384 ChapMS2(challenge, challenge_resp, 385//#ifdef __APPLE__ 386#if 0 387 ? mschap2_peer_challenge : 388 (id == last_challenge_id && last_challenge_response[0] ? last_challenge_response : NULL), 389#endif 390 our_name, 391 secret, secret_len, 392 (MS_Chap2Response *) response, private, 393 MS_CHAP2_AUTHENTICATEE); 394#ifdef __APPLE__ 395 last_challenge_id = id; 396#endif 397} 398 399struct rc4_state { 400 u_char perm[256]; 401 u_char index1; 402 u_char index2; 403}; 404 405static __inline void 406swap_bytes(u_char *a, u_char *b) 407{ 408 u_char temp; 409 410 temp = *a; 411 *a = *b; 412 *b = temp; 413} 414 415/* 416 * Initialize an RC4 state buffer using the supplied key, 417 * which can have arbitrary length. 418 */ 419static void 420rc4_init(struct rc4_state *const state, const u_char *key, int keylen) 421{ 422 u_char j; 423 int i; 424 425 /* Initialize state with identity permutation */ 426 for (i = 0; i < 256; i++) 427 state->perm[i] = (u_char)i; 428 state->index1 = 0; 429 state->index2 = 0; 430 431 /* Randomize the permutation using key data */ 432 for (j = i = 0; i < 256; i++) { 433 j += state->perm[i] + key[i % keylen]; 434 swap_bytes(&state->perm[i], &state->perm[j]); 435 } 436} 437 438/* 439 * Encrypt some data using the supplied RC4 state buffer. 440 * The input and output buffers may be the same buffer. 441 * Since RC4 is a stream cypher, this function is used 442 * for both encryption and decryption. 443 */ 444static void 445rc4_crypt(struct rc4_state *const state, 446 const u_char *inbuf, u_char *outbuf, int buflen) 447{ 448 int i; 449 u_char j; 450 451 for (i = 0; i < buflen; i++) { 452 453 /* Update modification indicies */ 454 state->index1++; 455 state->index2 += state->perm[state->index1]; 456 457 /* Modify permutation */ 458 swap_bytes(&state->perm[state->index1], 459 &state->perm[state->index2]); 460 461 /* Encrypt/decrypt next byte */ 462 j = state->perm[state->index1] + state->perm[state->index2]; 463 outbuf[i] = inbuf[i] ^ state->perm[j]; 464 } 465} 466 467 468static void 469EncryptPwBlockWithPasswordHash( 470 u_char *UnicodePassword, 471 int UnicodePasswordLen, 472 u_char *PasswordHash, 473 u_char *EncryptedPwBlock) 474{ 475 struct rc4_state rcs; 476 477 u_char ClearPwBlock[MAX_NT_PASSWORD * 2 + 4]; 478 int offset = MAX_NT_PASSWORD * 2 - UnicodePasswordLen; 479 480 /* Fill ClearPwBlock with random octet values */ 481 random_bytes(ClearPwBlock, sizeof(ClearPwBlock)); 482 483 memcpy(ClearPwBlock + offset, UnicodePassword, UnicodePasswordLen); 484 485 // Fix Me: This needs to be little endian 486 //*(u_int32_t*)&ClearPwBlock[MAX_NT_PASSWORD * 2] = UnicodePasswordLen; 487 ClearPwBlock[MAX_NT_PASSWORD*2 + 0] = UnicodePasswordLen; 488 ClearPwBlock[MAX_NT_PASSWORD*2 + 1] = UnicodePasswordLen >> 8; 489 ClearPwBlock[MAX_NT_PASSWORD*2 + 2] = UnicodePasswordLen >> 16; 490 ClearPwBlock[MAX_NT_PASSWORD*2 + 3] = UnicodePasswordLen >> 24; 491 492 rc4_init(&rcs, PasswordHash, MD4_SIGNATURE_SIZE); 493 rc4_crypt(&rcs, ClearPwBlock, EncryptedPwBlock, sizeof(ClearPwBlock)); 494} 495 496static void 497NewPasswordEncryptedWithOldNtPasswordHash(u_char *NewPassword, int NewPasswordLen, 498 u_char *OldPassword, int OldPasswordLen, 499 u_char *EncryptedPwBlock) 500{ 501 u_char unicodeOldPassword[MAX_NT_PASSWORD * 2]; 502 u_char OldPasswordHash[MD4_SIGNATURE_SIZE]; 503 u_char unicodeNewPassword[MAX_NT_PASSWORD * 2]; 504 505 /* Hash the Unicode version of the old password */ 506 ascii2unicode(OldPassword, OldPasswordLen, unicodeOldPassword); 507 NTPasswordHash(unicodeOldPassword, OldPasswordLen * 2, OldPasswordHash); 508 509 /* Unicode version of the new password */ 510 ascii2unicode(NewPassword, NewPasswordLen, unicodeNewPassword); 511 512 EncryptPwBlockWithPasswordHash(unicodeNewPassword, NewPasswordLen * 2, 513 OldPasswordHash, EncryptedPwBlock); 514} 515 516static void 517NtPasswordHashEncryptedWithBlock(u_char *PasswordHash, u_char *Block, u_char *Cypher) 518{ 519 (void) DesSetkey(Block + 0); 520 DesEncrypt(PasswordHash, Cypher + 0); 521 522 (void) DesSetkey(Block + 7); 523 DesEncrypt(PasswordHash + 8, Cypher + 8); 524} 525 526static void 527OldNtPasswordHashEncryptedWithNewNtPasswordHash(u_char *NewPassword, int NewPasswordLen, 528 u_char *OldPassword, int OldPasswordLen, 529 u_char *EncryptedPasswordHash) 530{ 531 u_char unicodeOldPassword[MAX_NT_PASSWORD * 2]; 532 u_char OldPasswordHash[MD4_SIGNATURE_SIZE]; 533 u_char unicodeNewPassword[MAX_NT_PASSWORD * 2]; 534 u_char NewPasswordHash[MD4_SIGNATURE_SIZE]; 535 536 /* Hash the Unicode version of the old password */ 537 ascii2unicode(OldPassword, OldPasswordLen, unicodeOldPassword); 538 NTPasswordHash(unicodeOldPassword, OldPasswordLen * 2, OldPasswordHash); 539 540 /* Hash the Unicode version of the new password */ 541 ascii2unicode(NewPassword, NewPasswordLen, unicodeNewPassword); 542 NTPasswordHash(unicodeNewPassword, NewPasswordLen * 2, NewPasswordHash); 543 544 NtPasswordHashEncryptedWithBlock(OldPasswordHash, NewPasswordHash, 545 EncryptedPasswordHash); 546} 547 548static void 549ascii2hex(u_char *text, int len, u_char *hex) 550{ 551 int i; 552 for (i = 0; i < len; i++) { 553 if (text[0] >= '0' && text[0] <= '9') 554 hex[i] = text[0] - '0'; 555 else if (text[0] >= 'a' && text[0] <= 'f') 556 hex[i] = text[0] - 'a' + 10; 557 else if (text[0] >= 'A' && text[0] <= 'F') 558 hex[i] = text[0] - 'A' + 10; 559 560 hex[i] <<= 4; 561 562 if (text[1] >= '0' && text[1] <= '9') 563 hex[i] |= text[1] - '0'; 564 else if (text[1] >= 'a' && text[1] <= 'f') 565 hex[i] |= text[1] - 'a' + 10; 566 else if (text[1] >= 'A' && text[1] <= 'F') 567 hex[i] |= text[1] - 'A' + 10; 568 569 text += 2; 570 } 571} 572 573static int 574chapms2_change_password(unsigned char *response, char *our_name, 575 unsigned char *status_pkt, 576 u_char *secret, int secret_len, 577 u_char *new_secret, int new_secret_len, 578 unsigned char *private) 579{ 580 int pktlen; 581 unsigned char *p = response; 582 583 /* status_pkt and response point to the beginning of the CHAP payload */ 584 pktlen = status_pkt[2]; 585 pktlen <<= 8; 586 pktlen += status_pkt[3]; 587 588 p[0] = MS_CHAP2_CHANGE_PASSWORD; 589 p[1] = status_pkt[1] + 1; // id of failure + 1 590 p[2] = (MS_CHAP2_CHANGE_PASSWORD_LEN + CHAP_HDRLEN) >> 8; 591 p[3] = (unsigned char)(MS_CHAP2_CHANGE_PASSWORD_LEN + CHAP_HDRLEN); 592 p += CHAP_HDRLEN; 593 594 /* first copy encrypted password */ 595 NewPasswordEncryptedWithOldNtPasswordHash(new_secret, new_secret_len, 596 secret, secret_len, p); 597 p += 516; 598 599 /* then copy encrypted hash */ 600 OldNtPasswordHashEncryptedWithNewNtPasswordHash(new_secret, new_secret_len, 601 secret, secret_len, p); 602 p += MD4_SIGNATURE_SIZE; 603 604 status_pkt += CHAP_HDRLEN; 605 pktlen -= CHAP_HDRLEN; 606 /* then the response */ 607 for (; pktlen; pktlen--, status_pkt++) { 608 if (!strncmp((char*)status_pkt, " C=", 3)) { 609 610 unsigned char challenge[MAX_CHALLENGE_LEN]; 611 612 ascii2hex(status_pkt + 3, sizeof(challenge), challenge); 613 614 ChapMS2(challenge, mschap2_peer_challenge, 615 our_name, 616 new_secret, new_secret_len, 617 (MS_Chap2Response *) p, private, 618 MS_CHAP2_AUTHENTICATEE); 619 break; 620 } 621 } 622 623 /* then add one zero value flag, not in regular response */ 624 p += sizeof(MS_Chap2Response); 625 *p = 0; 626 627 return 0; 628} 629 630static int 631chapms2_retry_password(unsigned char *response, char *our_name, 632 unsigned char *status_pkt, 633 u_char *secret, int secret_len, 634 unsigned char *private) 635{ 636 int pktlen, namelen = strlen(our_name); 637 unsigned char *p = response; 638 639 /* status_pkt and response point to the beginning of the CHAP payload */ 640 pktlen = status_pkt[2]; 641 pktlen <<= 8; 642 pktlen += status_pkt[3]; 643 644 p[0] = CHAP_RESPONSE; 645 p[1] = status_pkt[1] + 1; // id of failure + 1 646 p[2] = (MS_CHAP2_RESPONSE_LEN + 1 + namelen + CHAP_HDRLEN) >> 8; 647 p[3] = (unsigned char)(MS_CHAP2_RESPONSE_LEN + 1 + namelen + CHAP_HDRLEN); 648 p += CHAP_HDRLEN; 649 650 status_pkt += CHAP_HDRLEN; 651 pktlen -= CHAP_HDRLEN; 652 /* then the response */ 653 for (; pktlen; pktlen--, status_pkt++) { 654 if (!strncmp((char*)status_pkt, " C=", 3)) { 655 unsigned char challenge[MAX_CHALLENGE_LEN]; 656 657 ascii2hex(status_pkt + 3, sizeof(challenge), challenge); 658 659 *p++ = MS_CHAP2_RESPONSE_LEN; 660 ChapMS2(challenge, mschap2_peer_challenge, 661 our_name, 662 secret, secret_len, 663 (MS_Chap2Response *) p, private, 664 MS_CHAP2_AUTHENTICATEE); 665 666 p += MS_CHAP2_RESPONSE_LEN; 667 memcpy(p, our_name, namelen); 668 break; 669 } 670 } 671 672 return 0; 673} 674 675static int 676chapms2_check_success(unsigned char *msg, int len, unsigned char *private) 677{ 678 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) || strncmp((char*)msg, "S=", 2)) { 679 /* Packet does not start with "S=" */ 680 error("MS-CHAPv2 Success packet is badly formed."); 681 return 0; 682 } 683 msg += 2; 684 len -= 2; 685 if (len < MS_AUTH_RESPONSE_LENGTH 686 || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) { 687 /* Authenticator Response did not match expected. */ 688 error("MS-CHAPv2 mutual authentication failed."); 689 return 0; 690 } 691 /* Authenticator Response matches. */ 692 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */ 693 len -= MS_AUTH_RESPONSE_LENGTH; 694 if ((len >= 3) && !strncmp((char*)msg, " M=", 3)) 695 { 696 //spec-conformant 697 msg += 3; /* Eat the delimiter */ 698 } else if (len) { 699 /* Packet has extra text which does not begin " M=" */ 700 701 //we'll allow the missing-space case from the server, even though 702 //it's non-conforming to spec! 703 dbglog("Rcvd non-conforming MSCHAPv2 Success packet, len=%d", len); 704 if(len >= 2 && !strncmp((char*)msg, "M=", 2)) 705 msg += 2; 706 else 707 { 708 error("MS-CHAPv2 Success packet is badly formed."); 709 return 0; 710 } 711 } 712 return 1; 713} 714 715static int 716chapms_handle_failure(unsigned char *inp, int len, char *message, int message_max_len) 717{ 718 int err, ret = 0; 719 char *p, *p1, *msg; 720 721 /* We want a null-terminated string for strxxx(). */ 722 msg = malloc(len + 1); 723 if (!msg) { 724 notice("Out of memory in chapms_handle_failure"); 725 return 0; 726 } 727 BCOPY(inp, msg, len); 728 msg[len] = 0; 729 p = msg; 730 731 /* 732 * Deal with MS-CHAP formatted failure messages; just print the 733 * M=<message> part (if any). For MS-CHAP we're not really supposed 734 * to use M=<message>, but it shouldn't hurt. See 735 * chapms[2]_verify_response. 736 */ 737 if (!strncmp(p, "E=", 2)) 738 err = strtol(p + 2, NULL, 10); /* Remember the error code. */ 739 else { 740#ifdef __APPLE__ 741 p += len; 742#endif 743 goto print_msg; /* Message is badly formatted. */ 744 } 745 746 if (len && ((p1 = strstr(p, " R=")) != NULL)) { 747 /* R=x field found. */ 748 p1 += 3; 749 if (*p1 == '1' && retry_password_hook) 750 ret = 2; 751 } 752 753#ifdef __APPLE__ 754 if (err == MS_CHAP_ERROR_PASSWD_EXPIRED && change_password_hook) 755 ret = 1; 756#endif 757 758 if (len && ((p = strstr(p, " M=")) != NULL)) { 759 /* M=<message> field found. */ 760 p += 3; 761#ifdef __APPLE__ 762 strncpy(message, p, message_max_len-1); 763 message[message_max_len] = 0; 764#endif 765 } else { 766 /* No M=<message>; use the error code. */ 767 switch (err) { 768 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS: 769 p = "E=646 Restricted logon hours"; 770 break; 771 772 case MS_CHAP_ERROR_ACCT_DISABLED: 773 p = "E=647 Account disabled"; 774 break; 775 776 case MS_CHAP_ERROR_PASSWD_EXPIRED: 777 p = "E=648 Password expired"; 778 break; 779 780 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION: 781 p = "E=649 No dialin permission"; 782 break; 783 784 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE: 785 p = "E=691 Authentication failure"; 786 break; 787 788 case MS_CHAP_ERROR_CHANGING_PASSWORD: 789#ifndef __APPLE__ 790 /* Should never see this, we don't support Change Password. */ 791#endif 792 p = "E=709 Error changing password"; 793 break; 794 795 default: 796 free(msg); 797 error("error %d", err); 798 error("Unknown MS-CHAP authentication failure: %.*v", 799 len, inp); 800 return 0; 801 } 802 } 803print_msg: 804 if (p != NULL) 805 error("MS-CHAP authentication failed: %v", p); 806 free(msg); 807 return ret; 808} 809 810 811static void 812ChallengeResponse(u_char *challenge, 813 u_char PasswordHash[MD4_SIGNATURE_SIZE], 814 u_char response[24]) 815{ 816 u_char ZPasswordHash[21]; 817 818 BZERO(ZPasswordHash, sizeof(ZPasswordHash)); 819 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE); 820 821#if 0 822 dbglog("ChallengeResponse - ZPasswordHash %.*B", 823 sizeof(ZPasswordHash), ZPasswordHash); 824#endif 825 826 (void) DesSetkey(ZPasswordHash + 0); 827 DesEncrypt(challenge, response + 0); 828 (void) DesSetkey(ZPasswordHash + 7); 829 DesEncrypt(challenge, response + 8); 830 (void) DesSetkey(ZPasswordHash + 14); 831 DesEncrypt(challenge, response + 16); 832 833#if 0 834 dbglog("ChallengeResponse - response %.24B", response); 835#endif 836} 837 838static void 839ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge, 840 char *username, u_char Challenge[8]) 841 842{ 843 SHA1_CTX sha1Context; 844 u_char sha1Hash[SHA1_SIGNATURE_SIZE]; 845 char *user; 846 847 /* remove domain from "domain\username" */ 848 if ((user = strrchr(username, '\\')) != NULL) 849 ++user; 850 else 851 user = username; 852 853 SHA1_Init(&sha1Context); 854 SHA1_Update(&sha1Context, PeerChallenge, 16); 855 SHA1_Update(&sha1Context, rchallenge, 16); 856 SHA1_Update(&sha1Context, user, strlen(user)); 857 SHA1_Final(sha1Hash, &sha1Context); 858 859 BCOPY(sha1Hash, Challenge, 8); 860} 861 862/* 863 * Convert the ASCII version of the password to Unicode. 864 * This implicitly supports 8-bit ISO8859/1 characters. 865 * This gives us the little-endian representation, which 866 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering 867 * is machine-dependent.) 868 */ 869static void 870ascii2unicode(u_char ascii[], int ascii_len, u_char unicode[]) 871{ 872 int i; 873 874 BZERO(unicode, ascii_len * 2); 875 for (i = 0; i < ascii_len; i++) 876 unicode[i * 2] = (u_char) ascii[i]; 877} 878 879static void 880NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE]) 881{ 882#ifdef __APPLE__ 883 CC_MD4(secret, secret_len, hash); 884 885#else 886#ifdef __NetBSD__ 887 /* NetBSD uses the libc md4 routines which take bytes instead of bits */ 888 int mdlen = secret_len; 889#else 890 int mdlen = secret_len * 8; 891#endif 892 MD4_CTX md4Context; 893 894 MD4Init(&md4Context); 895 /* MD4Update can take at most 64 bytes at a time */ 896 while (mdlen > 512) { 897 MD4Update(&md4Context, secret, 512); 898 secret += 64; 899 mdlen -= 512; 900 } 901 MD4Update(&md4Context, secret, mdlen); 902 MD4Final(hash, &md4Context); 903#endif 904 905} 906 907static void 908ChapMS_NT(u_char *rchallenge, u_char *secret, int secret_len, 909 u_char NTResponse[24]) 910{ 911 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 912 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 913 914 /* Hash the Unicode version of the secret (== password). */ 915 ascii2unicode(secret, secret_len, unicodePassword); 916 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 917 918 ChallengeResponse(rchallenge, PasswordHash, NTResponse); 919} 920 921static void 922ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username, 923 u_char *secret, int secret_len, u_char NTResponse[24]) 924{ 925 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 926 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 927 u_char Challenge[8]; 928 929 ChallengeHash(PeerChallenge, rchallenge, username, Challenge); 930 931 /* Hash the Unicode version of the secret (== password). */ 932 ascii2unicode(secret, secret_len, unicodePassword); 933 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 934 935 ChallengeResponse(Challenge, PasswordHash, NTResponse); 936} 937 938#ifdef MSLANMAN 939static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ 940 941static void 942ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len, 943 MS_ChapResponse *response) 944{ 945 int i; 946 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ 947 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 948 949 /* LANMan password is case insensitive */ 950 BZERO(UcasePassword, sizeof(UcasePassword)); 951 for (i = 0; i < secret_len; i++) 952 UcasePassword[i] = (u_char)toupper(secret[i]); 953 (void) DesSetkey(UcasePassword + 0); 954 DesEncrypt( StdText, PasswordHash + 0 ); 955 (void) DesSetkey(UcasePassword + 7); 956 DesEncrypt( StdText, PasswordHash + 8 ); 957 ChallengeResponse(rchallenge, PasswordHash, response->LANManResp); 958} 959#endif 960 961 962static void 963GenerateAuthenticatorResponse(u_char *secret, int secret_len, 964 u_char NTResponse[24], u_char PeerChallenge[16], 965 u_char *rchallenge, char *username, 966 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) 967{ 968 /* 969 * "Magic" constants used in response generation, from RFC 2759. 970 */ 971 u_char Magic1[39] = /* "Magic server to client signing constant" */ 972 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 973 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 974 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 975 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; 976 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */ 977 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 978 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 979 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 980 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 981 0x6E }; 982 983 int i; 984 SHA1_CTX sha1Context; 985 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 986 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 987 u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; 988 u_char Digest[SHA1_SIGNATURE_SIZE]; 989 u_char Challenge[8]; 990 991 /* Hash (x2) the Unicode version of the secret (== password). */ 992 ascii2unicode(secret, secret_len, unicodePassword); 993 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 994 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); 995 996 SHA1_Init(&sha1Context); 997 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash)); 998 SHA1_Update(&sha1Context, NTResponse, 24); 999 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1)); 1000 SHA1_Final(Digest, &sha1Context); 1001 1002 ChallengeHash(PeerChallenge, rchallenge, username, Challenge); 1003 1004 SHA1_Init(&sha1Context); 1005 SHA1_Update(&sha1Context, Digest, sizeof(Digest)); 1006 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge)); 1007 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2)); 1008 SHA1_Final(Digest, &sha1Context); 1009 1010 /* Convert to ASCII hex string. */ 1011 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++) 1012 snprintf((char*)&authResponse[i * 2], MS_AUTH_RESPONSE_LENGTH+1 - i * 2, "%02X", Digest[i]); 1013} 1014 1015 1016#ifdef MPPE 1017/* 1018 * Set mppe_xxxx_key from the NTPasswordHashHash. 1019 * RFC 2548 (RADIUS support) requires us to export this function (ugh). 1020 */ 1021void 1022mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE]) 1023{ 1024 SHA1_CTX sha1Context; 1025 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ 1026 1027 SHA1_Init(&sha1Context); 1028 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 1029 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 1030 SHA1_Update(&sha1Context, rchallenge, 8); 1031 SHA1_Final(Digest, &sha1Context); 1032 1033 /* Same key in both directions. */ 1034 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); 1035 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); 1036} 1037 1038/* 1039 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079) 1040 */ 1041static void 1042Set_Start_Key(u_char *rchallenge, u_char *secret, int secret_len) 1043{ 1044 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 1045 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 1046 u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; 1047 1048 /* Hash (x2) the Unicode version of the secret (== password). */ 1049 ascii2unicode(secret, secret_len, unicodePassword); 1050 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 1051 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); 1052 1053 mppe_set_keys(rchallenge, PasswordHashHash); 1054} 1055 1056/* 1057 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) 1058 */ 1059static void 1060SetMasterKeys(u_char *secret, int secret_len, u_char NTResponse[24], int IsServer) 1061{ 1062 SHA1_CTX sha1Context; 1063 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 1064 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 1065 u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; 1066 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ 1067 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ 1068 1069 u_char SHApad1[40] = 1070 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1071 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1072 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1073 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 1074 u_char SHApad2[40] = 1075 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 1076 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 1077 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 1078 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 }; 1079 1080 /* "This is the MPPE Master Key" */ 1081 u_char Magic1[27] = 1082 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 1083 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 1084 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 }; 1085 /* "On the client side, this is the send key; " 1086 "on the server side, it is the receive key." */ 1087 u_char Magic2[84] = 1088 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 1089 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 1090 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 1091 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 1092 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 1093 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 1094 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 1095 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 1096 0x6b, 0x65, 0x79, 0x2e }; 1097 /* "On the client side, this is the receive key; " 1098 "on the server side, it is the send key." */ 1099 u_char Magic3[84] = 1100 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 1101 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 1102 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 1103 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 1104 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 1105 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 1106 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 1107 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 1108 0x6b, 0x65, 0x79, 0x2e }; 1109 u_char *s; 1110 1111 /* Hash (x2) the Unicode version of the secret (== password). */ 1112 ascii2unicode(secret, secret_len, unicodePassword); 1113 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 1114 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); 1115 1116 SHA1_Init(&sha1Context); 1117 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash)); 1118 SHA1_Update(&sha1Context, NTResponse, 24); 1119 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1)); 1120 SHA1_Final(MasterKey, &sha1Context); 1121 1122 /* 1123 * generate send key 1124 */ 1125 if (IsServer) 1126 s = Magic3; 1127 else 1128 s = Magic2; 1129 SHA1_Init(&sha1Context); 1130 SHA1_Update(&sha1Context, MasterKey, 16); 1131 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1)); 1132 SHA1_Update(&sha1Context, s, 84); 1133 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2)); 1134 SHA1_Final(Digest, &sha1Context); 1135 1136 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); 1137 1138 /* 1139 * generate recv key 1140 */ 1141 if (IsServer) 1142 s = Magic2; 1143 else 1144 s = Magic3; 1145 SHA1_Init(&sha1Context); 1146 SHA1_Update(&sha1Context, MasterKey, 16); 1147 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1)); 1148 SHA1_Update(&sha1Context, s, 84); 1149 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2)); 1150 SHA1_Final(Digest, &sha1Context); 1151 1152 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); 1153} 1154 1155#endif /* MPPE */ 1156 1157 1158void 1159ChapMS(u_char *rchallenge, u_char *secret, int secret_len, 1160 MS_ChapResponse *response) 1161{ 1162#if 0 1163 CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret)); 1164#endif 1165 BZERO(response, sizeof(*response)); 1166 1167 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp); 1168 1169#ifdef MSLANMAN 1170 ChapMS_LANMan(rchallenge, secret, secret_len, response); 1171 1172 /* preferred method is set by option */ 1173 response->UseNT[0] = !ms_lanman; 1174#else 1175 response->UseNT[0] = 1; 1176#endif 1177 1178#ifdef MPPE 1179 Set_Start_Key(rchallenge, secret, secret_len); 1180 mppe_keys_set = 1; 1181#endif 1182} 1183 1184 1185/* 1186 * If PeerChallenge is NULL, one is generated and response->PeerChallenge 1187 * is filled in. Call this way when generating a response. 1188 * If PeerChallenge is supplied, it is copied into response->PeerChallenge. 1189 * Call this way when verifying a response (or debugging). 1190 * Do not call with PeerChallenge = response->PeerChallenge. 1191 * 1192 * response->PeerChallenge is then used for calculation of the 1193 * Authenticator Response. 1194 */ 1195void 1196ChapMS2(u_char *rchallenge, u_char *PeerChallenge, 1197 char *user, u_char *secret, int secret_len, MS_Chap2Response *response, 1198 u_char authResponse[], int authenticator) 1199{ 1200 /* ARGSUSED */ 1201 u_char *p = response->PeerChallenge; 1202 int i; 1203 1204 BZERO(response, sizeof(*response)); 1205 1206 /* Generate the Peer-Challenge if requested, or copy it if supplied. */ 1207 if (!PeerChallenge) 1208 for (i = 0; i < sizeof(response->PeerChallenge); i++) { 1209#ifdef __APPLE__ 1210 last_challenge_response[i] = *p++ = (u_char) (drand48() * 0xff); 1211#else 1212 *p++ = (u_char) (drand48() * 0xff); 1213#endif 1214 } 1215 else 1216 BCOPY(PeerChallenge, response->PeerChallenge, 1217 sizeof(response->PeerChallenge)); 1218 1219 /* Generate the NT-Response */ 1220 ChapMS2_NT(rchallenge, response->PeerChallenge, user, 1221 secret, secret_len, response->NTResp); 1222 1223 /* Generate the Authenticator Response. */ 1224 GenerateAuthenticatorResponse(secret, secret_len, response->NTResp, 1225 response->PeerChallenge, rchallenge, 1226 user, authResponse); 1227 1228#ifdef MPPE 1229 SetMasterKeys(secret, secret_len, response->NTResp, authenticator); 1230 mppe_keys_set = 1; 1231#endif 1232} 1233 1234#ifdef MPPE 1235/* 1236 * Set MPPE options from plugins. 1237 */ 1238void 1239set_mppe_enc_types(int policy, int types) 1240{ 1241 /* Early exit for unknown policies. */ 1242 if (policy != MPPE_ENC_POL_ENC_ALLOWED || 1243 policy != MPPE_ENC_POL_ENC_REQUIRED) 1244 return; 1245 1246 /* Don't modify MPPE if it's optional and wasn't already configured. */ 1247 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe) 1248 return; 1249 1250 /* 1251 * Disable undesirable encryption types. Note that we don't ENABLE 1252 * any encryption types, to avoid overriding manual configuration. 1253 */ 1254 switch(types) { 1255 case MPPE_ENC_TYPES_RC4_40: 1256 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */ 1257 break; 1258 case MPPE_ENC_TYPES_RC4_128: 1259 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */ 1260 break; 1261 default: 1262 break; 1263 } 1264} 1265#endif /* MPPE */ 1266 1267static struct chap_digest_type chapms_digest = { 1268 CHAP_MICROSOFT, /* code */ 1269 chapms_generate_challenge, 1270 chapms_verify_response, 1271 chapms_make_response, 1272 NULL, /* check_success */ 1273 chapms_handle_failure, 1274#ifdef __APPLE__ 1275 0, 1276 0 1277#endif 1278}; 1279 1280static struct chap_digest_type chapms2_digest = { 1281 CHAP_MICROSOFT_V2, /* code */ 1282 chapms2_generate_challenge, 1283 chapms2_verify_response, 1284 chapms2_make_response, 1285 chapms2_check_success, 1286 chapms_handle_failure, 1287#ifdef __APPLE__ 1288 chapms2_change_password, 1289 chapms2_retry_password 1290#endif 1291}; 1292 1293void 1294chapms_init(void) 1295{ 1296 chap_register_digest(&chapms_digest); 1297 chap_register_digest(&chapms2_digest); 1298 add_options(chapms_option_list); 1299} 1300 1301#ifdef __APPLE__ 1302void 1303chapms_reinit(void) 1304{ 1305 last_challenge_id = 0; 1306 last_challenge_response[0] = 0; 1307} 1308#endif 1309 1310#endif /* CHAPMS */ 1311