1 /* 2 * chap_ms.c - Microsoft MS-CHAP compatible implementation. 3 * 4 * Copyright (c) 1995 Eric Rosenquist. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 18 * 3. The name(s) of the authors of this software must not be used to 19 * endorse or promote products derived from this software without 20 * prior written permission. 21 * 22 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 23 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 24 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 25 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 26 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 27 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 28 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 29 */ 30 31 /* 32 * Modifications by Lauri Pesonen / lpesonen (at) clinet.fi, april 1997 33 * 34 * Implemented LANManager type password response to MS-CHAP challenges. 35 * Now pppd provides both NT style and LANMan style blocks, and the 36 * prefered is set by option "ms-lanman". Default is to use NT. 37 * The hash text (StdText) was taken from Win95 RASAPI32.DLL. 38 * 39 * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80 40 */ 41 42 /* 43 * Modifications by Frank Cusack, frank (at) google.com, March 2002. 44 * 45 * Implemented MS-CHAPv2 functionality, heavily based on sample 46 * implementation in RFC 2759. Implemented MPPE functionality, 47 * heavily based on sample implementation in RFC 3079. 48 * 49 * Copyright (c) 2002 The Android Open Source Project 50 * 51 * Redistribution and use in source and binary forms, with or without 52 * modification, are permitted provided that the following conditions 53 * are met: 54 * 55 * 1. Redistributions of source code must retain the above copyright 56 * notice, this list of conditions and the following disclaimer. 57 * 58 * 2. Redistributions in binary form must reproduce the above copyright 59 * notice, this list of conditions and the following disclaimer in 60 * the documentation and/or other materials provided with the 61 * distribution. 62 * 63 * 3. The name(s) of the authors of this software must not be used to 64 * endorse or promote products derived from this software without 65 * prior written permission. 66 * 67 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO 68 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 69 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY 70 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 71 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 72 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 73 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 74 * 75 */ 76 77 #define RCSID "$Id: chap_ms.c,v 1.33 2004/11/12 09:57:43 paulus Exp $" 78 79 #ifdef CHAPMS 80 81 #include <stdio.h> 82 #include <stdlib.h> 83 #include <string.h> 84 #include <ctype.h> 85 #include <sys/types.h> 86 #include <sys/time.h> 87 #include <unistd.h> 88 89 #include "pppd.h" 90 #include "chap-new.h" 91 #include "chap_ms.h" 92 #ifdef ANDROID_CHANGES 93 #include "openssl-hash.h" 94 #else 95 #include "md4.h" 96 #include "sha1.h" 97 #endif 98 #include "pppcrypt.h" 99 #include "magic.h" 100 101 static const char rcsid[] = RCSID; 102 103 104 static void ascii2unicode __P((char[], int, u_char[])); 105 static void NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE])); 106 static void ChallengeResponse __P((u_char *, u_char *, u_char[24])); 107 static void ChapMS_NT __P((u_char *, char *, int, u_char[24])); 108 static void ChapMS2_NT __P((char *, u_char[16], char *, char *, int, 109 u_char[24])); 110 static void GenerateAuthenticatorResponsePlain 111 __P((char*, int, u_char[24], u_char[16], u_char *, 112 char *, u_char[41])); 113 #ifdef MSLANMAN 114 static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *)); 115 #endif 116 117 #ifdef MPPE 118 static void Set_Start_Key __P((u_char *, char *, int)); 119 static void SetMasterKeys __P((char *, int, u_char[24], int)); 120 #endif 121 122 #ifdef MSLANMAN 123 bool ms_lanman = 0; /* Use LanMan password instead of NT */ 124 /* Has meaning only with MS-CHAP challenges */ 125 #endif 126 127 #ifdef MPPE 128 u_char mppe_send_key[MPPE_MAX_KEY_LEN]; 129 u_char mppe_recv_key[MPPE_MAX_KEY_LEN]; 130 int mppe_keys_set = 0; /* Have the MPPE keys been set? */ 131 132 #ifdef DEBUGMPPEKEY 133 /* For MPPE debug */ 134 /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */ 135 static char *mschap_challenge = NULL; 136 /* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */ 137 static char *mschap2_peer_challenge = NULL; 138 #endif 139 140 #include "fsm.h" /* Need to poke MPPE options */ 141 #include "ccp.h" 142 #include <net/ppp-comp.h> 143 #endif 144 145 /* 146 * Command-line options. 147 */ 148 static option_t chapms_option_list[] = { 149 #ifdef MSLANMAN 150 { "ms-lanman", o_bool, &ms_lanman, 151 "Use LanMan passwd when using MS-CHAP", 1 }, 152 #endif 153 #ifdef DEBUGMPPEKEY 154 { "mschap-challenge", o_string, &mschap_challenge, 155 "specify CHAP challenge" }, 156 { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge, 157 "specify CHAP peer challenge" }, 158 #endif 159 { NULL } 160 }; 161 162 /* 163 * chapms_generate_challenge - generate a challenge for MS-CHAP. 164 * For MS-CHAP the challenge length is fixed at 8 bytes. 165 * The length goes in challenge[0] and the actual challenge starts 166 * at challenge[1]. 167 */ 168 static void 169 chapms_generate_challenge(unsigned char *challenge) 170 { 171 *challenge++ = 8; 172 #ifdef DEBUGMPPEKEY 173 if (mschap_challenge && strlen(mschap_challenge) == 8) 174 memcpy(challenge, mschap_challenge, 8); 175 else 176 #endif 177 random_bytes(challenge, 8); 178 } 179 180 static void 181 chapms2_generate_challenge(unsigned char *challenge) 182 { 183 *challenge++ = 16; 184 #ifdef DEBUGMPPEKEY 185 if (mschap_challenge && strlen(mschap_challenge) == 16) 186 memcpy(challenge, mschap_challenge, 16); 187 else 188 #endif 189 random_bytes(challenge, 16); 190 } 191 192 static int 193 chapms_verify_response(int id, char *name, 194 unsigned char *secret, int secret_len, 195 unsigned char *challenge, unsigned char *response, 196 char *message, int message_space) 197 { 198 MS_ChapResponse *rmd; 199 MS_ChapResponse md; 200 int diff; 201 int challenge_len, response_len; 202 203 challenge_len = *challenge++; /* skip length, is 8 */ 204 response_len = *response++; 205 if (response_len != MS_CHAP_RESPONSE_LEN) 206 goto bad; 207 208 rmd = (MS_ChapResponse *) response; 209 210 #ifndef MSLANMAN 211 if (!rmd->UseNT[0]) { 212 /* Should really propagate this into the error packet. */ 213 notice("Peer request for LANMAN auth not supported"); 214 goto bad; 215 } 216 #endif 217 218 /* Generate the expected response. */ 219 ChapMS(challenge, (char *)secret, secret_len, &md); 220 221 #ifdef MSLANMAN 222 /* Determine which part of response to verify against */ 223 if (!rmd->UseNT[0]) 224 diff = memcmp(&rmd->LANManResp, &md.LANManResp, 225 sizeof(md.LANManResp)); 226 else 227 #endif 228 diff = memcmp(&rmd->NTResp, &md.NTResp, sizeof(md.NTResp)); 229 230 if (diff == 0) { 231 slprintf(message, message_space, "Access granted"); 232 return 1; 233 } 234 235 bad: 236 /* See comments below for MS-CHAP V2 */ 237 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0", 238 challenge_len, challenge); 239 return 0; 240 } 241 242 static int 243 chapms2_verify_response(int id, char *name, 244 unsigned char *secret, int secret_len, 245 unsigned char *challenge, unsigned char *response, 246 char *message, int message_space) 247 { 248 MS_Chap2Response *rmd; 249 MS_Chap2Response md; 250 char saresponse[MS_AUTH_RESPONSE_LENGTH+1]; 251 int challenge_len, response_len; 252 253 challenge_len = *challenge++; /* skip length, is 16 */ 254 response_len = *response++; 255 if (response_len != MS_CHAP2_RESPONSE_LEN) 256 goto bad; /* not even the right length */ 257 258 rmd = (MS_Chap2Response *) response; 259 260 /* Generate the expected response and our mutual auth. */ 261 ChapMS2(challenge, rmd->PeerChallenge, name, 262 (char *)secret, secret_len, &md, 263 (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR); 264 265 /* compare MDs and send the appropriate status */ 266 /* 267 * Per RFC 2759, success message must be formatted as 268 * "S=<auth_string> M=<message>" 269 * where 270 * <auth_string> is the Authenticator Response (mutual auth) 271 * <message> is a text message 272 * 273 * However, some versions of Windows (win98 tested) do not know 274 * about the M=<message> part (required per RFC 2759) and flag 275 * it as an error (reported incorrectly as an encryption error 276 * to the user). Since the RFC requires it, and it can be 277 * useful information, we supply it if the peer is a conforming 278 * system. Luckily (?), win98 sets the Flags field to 0x04 279 * (contrary to RFC requirements) so we can use that to 280 * distinguish between conforming and non-conforming systems. 281 * 282 * Special thanks to Alex Swiridov <say (at) real.kharkov.ua> for 283 * help debugging this. 284 */ 285 if (memcmp(md.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) { 286 if (rmd->Flags[0]) 287 slprintf(message, message_space, "S=%s", saresponse); 288 else 289 slprintf(message, message_space, "S=%s M=%s", 290 saresponse, "Access granted"); 291 return 1; 292 } 293 294 bad: 295 /* 296 * Failure message must be formatted as 297 * "E=e R=r C=c V=v M=m" 298 * where 299 * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE) 300 * r = retry (we use 1, ok to retry) 301 * c = challenge to use for next response, we reuse previous 302 * v = Change Password version supported, we use 0 303 * m = text message 304 * 305 * The M=m part is only for MS-CHAPv2. Neither win2k nor 306 * win98 (others untested) display the message to the user anyway. 307 * They also both ignore the E=e code. 308 * 309 * Note that it's safe to reuse the same challenge as we don't 310 * actually accept another response based on the error message 311 * (and no clients try to resend a response anyway). 312 * 313 * Basically, this whole bit is useless code, even the small 314 * implementation here is only because of overspecification. 315 */ 316 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s", 317 challenge_len, challenge, "Access denied"); 318 return 0; 319 } 320 321 static void 322 chapms_make_response(unsigned char *response, int id, char *our_name, 323 unsigned char *challenge, char *secret, int secret_len, 324 unsigned char *private) 325 { 326 challenge++; /* skip length, should be 8 */ 327 *response++ = MS_CHAP_RESPONSE_LEN; 328 ChapMS(challenge, secret, secret_len, (MS_ChapResponse *) response); 329 } 330 331 static void 332 chapms2_make_response(unsigned char *response, int id, char *our_name, 333 unsigned char *challenge, char *secret, int secret_len, 334 unsigned char *private) 335 { 336 challenge++; /* skip length, should be 16 */ 337 *response++ = MS_CHAP2_RESPONSE_LEN; 338 ChapMS2(challenge, 339 #ifdef DEBUGMPPEKEY 340 mschap2_peer_challenge, 341 #else 342 NULL, 343 #endif 344 our_name, secret, secret_len, 345 (MS_Chap2Response *) response, private, 346 MS_CHAP2_AUTHENTICATEE); 347 } 348 349 static int 350 chapms2_check_success(unsigned char *msg, int len, unsigned char *private) 351 { 352 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) || 353 strncmp((char *)msg, "S=", 2) != 0) { 354 /* Packet does not start with "S=" */ 355 error("MS-CHAPv2 Success packet is badly formed."); 356 return 0; 357 } 358 msg += 2; 359 len -= 2; 360 if (len < MS_AUTH_RESPONSE_LENGTH 361 || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) { 362 /* Authenticator Response did not match expected. */ 363 error("MS-CHAPv2 mutual authentication failed."); 364 return 0; 365 } 366 /* Authenticator Response matches. */ 367 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */ 368 len -= MS_AUTH_RESPONSE_LENGTH; 369 if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) { 370 msg += 3; /* Eat the delimiter */ 371 } else if (len) { 372 /* Packet has extra text which does not begin " M=" */ 373 error("MS-CHAPv2 Success packet is badly formed."); 374 return 0; 375 } 376 return 1; 377 } 378 379 static void 380 chapms_handle_failure(unsigned char *inp, int len) 381 { 382 int err; 383 char *p, *msg; 384 385 /* We want a null-terminated string for strxxx(). */ 386 msg = malloc(len + 1); 387 if (!msg) { 388 notice("Out of memory in chapms_handle_failure"); 389 return; 390 } 391 BCOPY(inp, msg, len); 392 msg[len] = 0; 393 p = msg; 394 395 /* 396 * Deal with MS-CHAP formatted failure messages; just print the 397 * M=<message> part (if any). For MS-CHAP we're not really supposed 398 * to use M=<message>, but it shouldn't hurt. See 399 * chapms[2]_verify_response. 400 */ 401 if (!strncmp(p, "E=", 2)) 402 err = strtol(p, NULL, 10); /* Remember the error code. */ 403 else 404 goto print_msg; /* Message is badly formatted. */ 405 406 if (len && ((p = strstr(p, " M=")) != NULL)) { 407 /* M=<message> field found. */ 408 p += 3; 409 } else { 410 /* No M=<message>; use the error code. */ 411 switch (err) { 412 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS: 413 p = "E=646 Restricted logon hours"; 414 break; 415 416 case MS_CHAP_ERROR_ACCT_DISABLED: 417 p = "E=647 Account disabled"; 418 break; 419 420 case MS_CHAP_ERROR_PASSWD_EXPIRED: 421 p = "E=648 Password expired"; 422 break; 423 424 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION: 425 p = "E=649 No dialin permission"; 426 break; 427 428 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE: 429 p = "E=691 Authentication failure"; 430 break; 431 432 case MS_CHAP_ERROR_CHANGING_PASSWORD: 433 /* Should never see this, we don't support Change Password. */ 434 p = "E=709 Error changing password"; 435 break; 436 437 default: 438 free(msg); 439 error("Unknown MS-CHAP authentication failure: %.*v", 440 len, inp); 441 return; 442 } 443 } 444 print_msg: 445 if (p != NULL) 446 error("MS-CHAP authentication failed: %v", p); 447 free(msg); 448 } 449 450 static void 451 ChallengeResponse(u_char *challenge, 452 u_char PasswordHash[MD4_SIGNATURE_SIZE], 453 u_char response[24]) 454 { 455 u_char ZPasswordHash[21]; 456 457 BZERO(ZPasswordHash, sizeof(ZPasswordHash)); 458 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE); 459 460 #if 0 461 dbglog("ChallengeResponse - ZPasswordHash %.*B", 462 sizeof(ZPasswordHash), ZPasswordHash); 463 #endif 464 465 (void) DesSetkey(ZPasswordHash + 0); 466 DesEncrypt(challenge, response + 0); 467 (void) DesSetkey(ZPasswordHash + 7); 468 DesEncrypt(challenge, response + 8); 469 (void) DesSetkey(ZPasswordHash + 14); 470 DesEncrypt(challenge, response + 16); 471 472 #if 0 473 dbglog("ChallengeResponse - response %.24B", response); 474 #endif 475 } 476 477 void 478 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge, 479 char *username, u_char Challenge[8]) 480 481 { 482 SHA1_CTX sha1Context; 483 u_char sha1Hash[SHA1_SIGNATURE_SIZE]; 484 char *user; 485 486 /* remove domain from "domain\username" */ 487 if ((user = strrchr(username, '\\')) != NULL) 488 ++user; 489 else 490 user = username; 491 492 SHA1_Init(&sha1Context); 493 SHA1_Update(&sha1Context, PeerChallenge, 16); 494 SHA1_Update(&sha1Context, rchallenge, 16); 495 SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user)); 496 SHA1_Final(sha1Hash, &sha1Context); 497 498 BCOPY(sha1Hash, Challenge, 8); 499 } 500 501 /* 502 * Convert the ASCII version of the password to Unicode. 503 * This implicitly supports 8-bit ISO8859/1 characters. 504 * This gives us the little-endian representation, which 505 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering 506 * is machine-dependent.) 507 */ 508 static void 509 ascii2unicode(char ascii[], int ascii_len, u_char unicode[]) 510 { 511 int i; 512 513 BZERO(unicode, ascii_len * 2); 514 for (i = 0; i < ascii_len; i++) 515 unicode[i * 2] = (u_char) ascii[i]; 516 } 517 518 static void 519 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE]) 520 { 521 #ifdef ANDROID_CHANGES 522 /* We link with MD4 routines in openssl, we have to take bytes instead */ 523 int mdlen = secret_len; 524 #else 525 #ifdef __NetBSD__ 526 /* NetBSD uses the libc md4 routines which take bytes instead of bits */ 527 int mdlen = secret_len; 528 #else 529 int mdlen = secret_len * 8; 530 #endif 531 #endif 532 MD4_CTX md4Context; 533 534 MD4Init(&md4Context); 535 MD4Update(&md4Context, (unsigned char *)secret, mdlen); 536 MD4Final(hash, &md4Context); 537 538 } 539 540 static void 541 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len, 542 u_char NTResponse[24]) 543 { 544 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 545 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 546 547 /* Hash the Unicode version of the secret (== password). */ 548 ascii2unicode(secret, secret_len, unicodePassword); 549 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash); 550 551 ChallengeResponse(rchallenge, PasswordHash, NTResponse); 552 } 553 554 static void 555 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username, 556 char *secret, int secret_len, u_char NTResponse[24]) 557 { 558 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 559 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 560 u_char Challenge[8]; 561 562 ChallengeHash(PeerChallenge, (unsigned char *)rchallenge, username, 563 Challenge); 564 565 /* Hash the Unicode version of the secret (== password). */ 566 ascii2unicode(secret, secret_len, unicodePassword); 567 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash); 568 569 ChallengeResponse(Challenge, PasswordHash, NTResponse); 570 } 571 572 #ifdef MSLANMAN 573 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ 574 575 static void 576 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len, 577 MS_ChapResponse *response) 578 { 579 int i; 580 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ 581 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 582 583 /* LANMan password is case insensitive */ 584 BZERO(UcasePassword, sizeof(UcasePassword)); 585 for (i = 0; i < secret_len; i++) 586 UcasePassword[i] = (u_char)toupper(secret[i]); 587 (void) DesSetkey(UcasePassword + 0); 588 DesEncrypt( StdText, PasswordHash + 0 ); 589 (void) DesSetkey(UcasePassword + 7); 590 DesEncrypt( StdText, PasswordHash + 8 ); 591 ChallengeResponse(rchallenge, PasswordHash, response->LANManResp); 592 } 593 #endif 594 595 596 void 597 GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], 598 u_char NTResponse[24], u_char PeerChallenge[16], 599 u_char *rchallenge, char *username, 600 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) 601 { 602 /* 603 * "Magic" constants used in response generation, from RFC 2759. 604 */ 605 u_char Magic1[39] = /* "Magic server to client signing constant" */ 606 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 607 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 608 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 609 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; 610 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */ 611 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 612 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 613 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 614 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 615 0x6E }; 616 617 int i; 618 SHA1_CTX sha1Context; 619 u_char Digest[SHA1_SIGNATURE_SIZE]; 620 u_char Challenge[8]; 621 622 SHA1_Init(&sha1Context); 623 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 624 SHA1_Update(&sha1Context, NTResponse, 24); 625 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1)); 626 SHA1_Final(Digest, &sha1Context); 627 628 ChallengeHash(PeerChallenge, rchallenge, username, Challenge); 629 630 SHA1_Init(&sha1Context); 631 SHA1_Update(&sha1Context, Digest, sizeof(Digest)); 632 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge)); 633 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2)); 634 SHA1_Final(Digest, &sha1Context); 635 636 /* Convert to ASCII hex string. */ 637 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++) 638 sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]); 639 } 640 641 642 static void 643 GenerateAuthenticatorResponsePlain 644 (char *secret, int secret_len, 645 u_char NTResponse[24], u_char PeerChallenge[16], 646 u_char *rchallenge, char *username, 647 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) 648 { 649 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 650 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 651 u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; 652 653 /* Hash (x2) the Unicode version of the secret (== password). */ 654 ascii2unicode(secret, secret_len, unicodePassword); 655 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash); 656 NTPasswordHash((char *)PasswordHash, sizeof(PasswordHash), 657 PasswordHashHash); 658 659 GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge, 660 rchallenge, username, authResponse); 661 } 662 663 664 #ifdef MPPE 665 /* 666 * Set mppe_xxxx_key from the NTPasswordHashHash. 667 * RFC 2548 (RADIUS support) requires us to export this function (ugh). 668 */ 669 void 670 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE]) 671 { 672 SHA1_CTX sha1Context; 673 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ 674 675 SHA1_Init(&sha1Context); 676 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 677 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 678 SHA1_Update(&sha1Context, rchallenge, 8); 679 SHA1_Final(Digest, &sha1Context); 680 681 /* Same key in both directions. */ 682 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); 683 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); 684 685 mppe_keys_set = 1; 686 } 687 688 /* 689 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079) 690 */ 691 static void 692 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len) 693 { 694 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 695 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 696 u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; 697 698 /* Hash (x2) the Unicode version of the secret (== password). */ 699 ascii2unicode(secret, secret_len, unicodePassword); 700 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 701 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); 702 703 mppe_set_keys(rchallenge, PasswordHashHash); 704 } 705 706 /* 707 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) 708 * 709 * This helper function used in the Winbind module, which gets the 710 * NTHashHash from the server. 711 */ 712 void 713 mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], 714 u_char NTResponse[24], int IsServer) 715 { 716 SHA1_CTX sha1Context; 717 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ 718 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ 719 720 u_char SHApad1[40] = 721 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 722 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 723 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 724 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 725 u_char SHApad2[40] = 726 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 727 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 728 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 729 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 }; 730 731 /* "This is the MPPE Master Key" */ 732 u_char Magic1[27] = 733 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 734 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 735 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 }; 736 /* "On the client side, this is the send key; " 737 "on the server side, it is the receive key." */ 738 u_char Magic2[84] = 739 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 740 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 741 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 742 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 743 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 744 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 745 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 746 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 747 0x6b, 0x65, 0x79, 0x2e }; 748 /* "On the client side, this is the receive key; " 749 "on the server side, it is the send key." */ 750 u_char Magic3[84] = 751 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 752 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 753 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 754 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 755 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 756 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 757 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 758 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 759 0x6b, 0x65, 0x79, 0x2e }; 760 u_char *s; 761 762 SHA1_Init(&sha1Context); 763 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 764 SHA1_Update(&sha1Context, NTResponse, 24); 765 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1)); 766 SHA1_Final(MasterKey, &sha1Context); 767 768 /* 769 * generate send key 770 */ 771 if (IsServer) 772 s = Magic3; 773 else 774 s = Magic2; 775 SHA1_Init(&sha1Context); 776 SHA1_Update(&sha1Context, MasterKey, 16); 777 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1)); 778 SHA1_Update(&sha1Context, s, 84); 779 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2)); 780 SHA1_Final(Digest, &sha1Context); 781 782 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); 783 784 /* 785 * generate recv key 786 */ 787 if (IsServer) 788 s = Magic2; 789 else 790 s = Magic3; 791 SHA1_Init(&sha1Context); 792 SHA1_Update(&sha1Context, MasterKey, 16); 793 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1)); 794 SHA1_Update(&sha1Context, s, 84); 795 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2)); 796 SHA1_Final(Digest, &sha1Context); 797 798 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); 799 800 mppe_keys_set = 1; 801 } 802 803 /* 804 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) 805 */ 806 static void 807 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer) 808 { 809 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 810 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 811 u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; 812 /* Hash (x2) the Unicode version of the secret (== password). */ 813 ascii2unicode(secret, secret_len, unicodePassword); 814 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 815 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); 816 mppe_set_keys2(PasswordHashHash, NTResponse, IsServer); 817 } 818 819 #endif /* MPPE */ 820 821 822 void 823 ChapMS(u_char *rchallenge, char *secret, int secret_len, 824 MS_ChapResponse *response) 825 { 826 BZERO(response, sizeof(*response)); 827 828 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp); 829 830 #ifdef MSLANMAN 831 ChapMS_LANMan(rchallenge, secret, secret_len, response); 832 833 /* preferred method is set by option */ 834 response->UseNT[0] = !ms_lanman; 835 #else 836 response->UseNT[0] = 1; 837 #endif 838 839 #ifdef MPPE 840 Set_Start_Key(rchallenge, secret, secret_len); 841 #endif 842 } 843 844 845 /* 846 * If PeerChallenge is NULL, one is generated and response->PeerChallenge 847 * is filled in. Call this way when generating a response. 848 * If PeerChallenge is supplied, it is copied into response->PeerChallenge. 849 * Call this way when verifying a response (or debugging). 850 * Do not call with PeerChallenge = response->PeerChallenge. 851 * 852 * response->PeerChallenge is then used for calculation of the 853 * Authenticator Response. 854 */ 855 void 856 ChapMS2(u_char *rchallenge, u_char *PeerChallenge, 857 char *user, char *secret, int secret_len, MS_Chap2Response *response, 858 u_char authResponse[], int authenticator) 859 { 860 /* ARGSUSED */ 861 u_char *p = response->PeerChallenge; 862 int i; 863 864 BZERO(response, sizeof(*response)); 865 866 /* Generate the Peer-Challenge if requested, or copy it if supplied. */ 867 if (!PeerChallenge) 868 for (i = 0; i < sizeof(response->PeerChallenge); i++) 869 *p++ = (u_char) (drand48() * 0xff); 870 else 871 BCOPY(PeerChallenge, response->PeerChallenge, 872 sizeof(response->PeerChallenge)); 873 874 /* Generate the NT-Response */ 875 ChapMS2_NT((char *)rchallenge, response->PeerChallenge, user, 876 secret, secret_len, response->NTResp); 877 878 /* Generate the Authenticator Response. */ 879 GenerateAuthenticatorResponsePlain(secret, secret_len, response->NTResp, 880 response->PeerChallenge, rchallenge, 881 user, authResponse); 882 883 #ifdef MPPE 884 SetMasterKeys(secret, secret_len, response->NTResp, authenticator); 885 #endif 886 } 887 888 #ifdef MPPE 889 /* 890 * Set MPPE options from plugins. 891 */ 892 void 893 set_mppe_enc_types(int policy, int types) 894 { 895 /* Early exit for unknown policies. */ 896 if (policy != MPPE_ENC_POL_ENC_ALLOWED || 897 policy != MPPE_ENC_POL_ENC_REQUIRED) 898 return; 899 900 /* Don't modify MPPE if it's optional and wasn't already configured. */ 901 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe) 902 return; 903 904 /* 905 * Disable undesirable encryption types. Note that we don't ENABLE 906 * any encryption types, to avoid overriding manual configuration. 907 */ 908 switch(types) { 909 case MPPE_ENC_TYPES_RC4_40: 910 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */ 911 break; 912 case MPPE_ENC_TYPES_RC4_128: 913 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */ 914 break; 915 default: 916 break; 917 } 918 } 919 #endif /* MPPE */ 920 921 static struct chap_digest_type chapms_digest = { 922 CHAP_MICROSOFT, /* code */ 923 chapms_generate_challenge, 924 chapms_verify_response, 925 chapms_make_response, 926 NULL, /* check_success */ 927 chapms_handle_failure, 928 }; 929 930 static struct chap_digest_type chapms2_digest = { 931 CHAP_MICROSOFT_V2, /* code */ 932 chapms2_generate_challenge, 933 chapms2_verify_response, 934 chapms2_make_response, 935 chapms2_check_success, 936 chapms_handle_failure, 937 }; 938 939 void 940 chapms_init(void) 941 { 942 chap_register_digest(&chapms_digest); 943 chap_register_digest(&chapms2_digest); 944 add_options(chapms_option_list); 945 } 946 947 #endif /* CHAPMS */ 948