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