1 /* $NetBSD: chap_ms.c,v 1.5 2021/01/09 16:39:28 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.5 2021/01/09 16:39:28 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 (char[], int, u_char[]); 110 static void NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]); 111 static void ChallengeResponse (u_char *, u_char *, u_char[24]); 112 static void ChapMS_NT (u_char *, char *, int, u_char[24]); 113 static void ChapMS2_NT (u_char *, u_char[16], char *, char *, int, 114 u_char[24]); 115 static void GenerateAuthenticatorResponsePlain 116 (char*, int, u_char[24], u_char[16], u_char *, 117 char *, u_char[41]); 118 #ifdef MSLANMAN 119 static void ChapMS_LANMan (u_char *, char *, int, u_char *); 120 #endif 121 122 #ifdef MPPE 123 static void Set_Start_Key (u_char *, char *, int); 124 static void SetMasterKeys (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 >= 2) && !strncmp((char *)msg, "M=", 2)) { 437 msg += 2; /* Eat the delimiter */ 438 } else if (len) { 439 /* Packet has extra text which does not begin " M=" */ 440 error("MS-CHAPv2 Success packet is badly formed."); 441 return 0; 442 } 443 return 1; 444 } 445 446 static void 447 chapms_handle_failure(unsigned char *inp, int len) 448 { 449 int err; 450 char *p, *msg; 451 452 /* We want a null-terminated string for strxxx(). */ 453 msg = malloc(len + 1); 454 if (!msg) { 455 notice("Out of memory in chapms_handle_failure"); 456 return; 457 } 458 BCOPY(inp, msg, len); 459 msg[len] = 0; 460 p = msg; 461 462 /* 463 * Deal with MS-CHAP formatted failure messages; just print the 464 * M=<message> part (if any). For MS-CHAP we're not really supposed 465 * to use M=<message>, but it shouldn't hurt. See 466 * chapms[2]_verify_response. 467 */ 468 if (!strncmp(p, "E=", 2)) 469 err = strtol(p+2, NULL, 10); /* Remember the error code. */ 470 else 471 goto print_msg; /* Message is badly formatted. */ 472 473 if (len && ((p = strstr(p, " M=")) != NULL)) { 474 /* M=<message> field found. */ 475 p += 3; 476 } else { 477 /* No M=<message>; use the error code. */ 478 switch (err) { 479 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS: 480 p = "E=646 Restricted logon hours"; 481 break; 482 483 case MS_CHAP_ERROR_ACCT_DISABLED: 484 p = "E=647 Account disabled"; 485 break; 486 487 case MS_CHAP_ERROR_PASSWD_EXPIRED: 488 p = "E=648 Password expired"; 489 break; 490 491 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION: 492 p = "E=649 No dialin permission"; 493 break; 494 495 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE: 496 p = "E=691 Authentication failure"; 497 break; 498 499 case MS_CHAP_ERROR_CHANGING_PASSWORD: 500 /* Should never see this, we don't support Change Password. */ 501 p = "E=709 Error changing password"; 502 break; 503 504 default: 505 free(msg); 506 error("Unknown MS-CHAP authentication failure: %.*v", 507 len, inp); 508 return; 509 } 510 } 511 print_msg: 512 if (p != NULL) 513 error("MS-CHAP authentication failed: %v", p); 514 free(msg); 515 } 516 517 static void 518 ChallengeResponse(u_char *challenge, 519 u_char PasswordHash[MD4_SIGNATURE_SIZE], 520 u_char response[24]) 521 { 522 u_char ZPasswordHash[21]; 523 524 BZERO(ZPasswordHash, sizeof(ZPasswordHash)); 525 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE); 526 527 #if 0 528 dbglog("ChallengeResponse - ZPasswordHash %.*B", 529 sizeof(ZPasswordHash), ZPasswordHash); 530 #endif 531 532 (void) DesSetkey(ZPasswordHash + 0); 533 DesEncrypt(challenge, response + 0); 534 (void) DesSetkey(ZPasswordHash + 7); 535 DesEncrypt(challenge, response + 8); 536 (void) DesSetkey(ZPasswordHash + 14); 537 DesEncrypt(challenge, response + 16); 538 539 #if 0 540 dbglog("ChallengeResponse - response %.24B", response); 541 #endif 542 } 543 544 void 545 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge, 546 char *username, u_char Challenge[8]) 547 548 { 549 SHA1_CTX sha1Context; 550 u_char sha1Hash[SHA1_SIGNATURE_SIZE]; 551 char *user; 552 553 /* remove domain from "domain\username" */ 554 if ((user = strrchr(username, '\\')) != NULL) 555 ++user; 556 else 557 user = username; 558 559 SHA1Init(&sha1Context); 560 SHA1Update(&sha1Context, PeerChallenge, 16); 561 SHA1Update(&sha1Context, rchallenge, 16); 562 SHA1Update(&sha1Context, (unsigned char *)user, strlen(user)); 563 SHA1Final(sha1Hash, &sha1Context); 564 565 BCOPY(sha1Hash, Challenge, 8); 566 } 567 568 /* 569 * Convert the ASCII version of the password to Unicode. 570 * This implicitly supports 8-bit ISO8859/1 characters. 571 * This gives us the little-endian representation, which 572 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering 573 * is machine-dependent.) 574 */ 575 static void 576 ascii2unicode(char ascii[], int ascii_len, u_char unicode[]) 577 { 578 int i; 579 580 BZERO(unicode, ascii_len * 2); 581 for (i = 0; i < ascii_len; i++) 582 unicode[i * 2] = (u_char) ascii[i]; 583 } 584 585 static void 586 NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE]) 587 { 588 #ifdef __NetBSD__ 589 /* NetBSD uses the libc md4 routines which take bytes instead of bits */ 590 int mdlen = secret_len; 591 #else 592 int mdlen = secret_len * 8; 593 #endif 594 MD4_CTX md4Context; 595 596 MD4Init(&md4Context); 597 /* MD4Update can take at most 64 bytes at a time */ 598 while (mdlen > 512) { 599 MD4Update(&md4Context, secret, 512); 600 secret += 64; 601 mdlen -= 512; 602 } 603 MD4Update(&md4Context, secret, mdlen); 604 MD4Final(hash, &md4Context); 605 606 } 607 608 static void 609 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len, 610 u_char NTResponse[24]) 611 { 612 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 613 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 614 615 /* Hash the Unicode version of the secret (== password). */ 616 ascii2unicode(secret, secret_len, unicodePassword); 617 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 618 619 ChallengeResponse(rchallenge, PasswordHash, NTResponse); 620 } 621 622 static void 623 ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username, 624 char *secret, int secret_len, u_char NTResponse[24]) 625 { 626 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 627 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 628 u_char Challenge[8]; 629 630 ChallengeHash(PeerChallenge, rchallenge, username, Challenge); 631 632 /* Hash the Unicode version of the secret (== password). */ 633 ascii2unicode(secret, secret_len, unicodePassword); 634 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 635 636 ChallengeResponse(Challenge, PasswordHash, NTResponse); 637 } 638 639 #ifdef MSLANMAN 640 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ 641 642 static void 643 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len, 644 unsigned char *response) 645 { 646 int i; 647 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ 648 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 649 650 /* LANMan password is case insensitive */ 651 BZERO(UcasePassword, sizeof(UcasePassword)); 652 for (i = 0; i < secret_len; i++) 653 UcasePassword[i] = (u_char)toupper((unsigned char)secret[i]); 654 (void) DesSetkey(UcasePassword + 0); 655 DesEncrypt( StdText, PasswordHash + 0 ); 656 (void) DesSetkey(UcasePassword + 7); 657 DesEncrypt( StdText, PasswordHash + 8 ); 658 ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]); 659 } 660 #endif 661 662 663 void 664 GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], 665 u_char NTResponse[24], u_char PeerChallenge[16], 666 u_char *rchallenge, char *username, 667 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) 668 { 669 /* 670 * "Magic" constants used in response generation, from RFC 2759. 671 */ 672 u_char Magic1[39] = /* "Magic server to client signing constant" */ 673 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 674 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 675 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 676 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; 677 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */ 678 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 679 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 680 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 681 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 682 0x6E }; 683 684 int i; 685 SHA1_CTX sha1Context; 686 u_char Digest[SHA1_SIGNATURE_SIZE]; 687 u_char Challenge[8]; 688 689 SHA1Init(&sha1Context); 690 SHA1Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 691 SHA1Update(&sha1Context, NTResponse, 24); 692 SHA1Update(&sha1Context, Magic1, sizeof(Magic1)); 693 SHA1Final(Digest, &sha1Context); 694 695 ChallengeHash(PeerChallenge, rchallenge, username, Challenge); 696 697 SHA1Init(&sha1Context); 698 SHA1Update(&sha1Context, Digest, sizeof(Digest)); 699 SHA1Update(&sha1Context, Challenge, sizeof(Challenge)); 700 SHA1Update(&sha1Context, Magic2, sizeof(Magic2)); 701 SHA1Final(Digest, &sha1Context); 702 703 /* Convert to ASCII hex string. */ 704 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++) 705 sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]); 706 } 707 708 709 static void 710 GenerateAuthenticatorResponsePlain 711 (char *secret, int secret_len, 712 u_char NTResponse[24], u_char PeerChallenge[16], 713 u_char *rchallenge, char *username, 714 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) 715 { 716 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 717 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 718 u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; 719 720 /* Hash (x2) the Unicode version of the secret (== password). */ 721 ascii2unicode(secret, secret_len, unicodePassword); 722 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 723 NTPasswordHash(PasswordHash, sizeof(PasswordHash), 724 PasswordHashHash); 725 726 GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge, 727 rchallenge, username, authResponse); 728 } 729 730 731 #ifdef MPPE 732 /* 733 * Set mppe_xxxx_key from the NTPasswordHashHash. 734 * RFC 2548 (RADIUS support) requires us to export this function (ugh). 735 */ 736 void 737 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE]) 738 { 739 SHA1_CTX sha1Context; 740 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ 741 742 SHA1Init(&sha1Context); 743 SHA1Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 744 SHA1Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 745 SHA1Update(&sha1Context, rchallenge, 8); 746 SHA1Final(Digest, &sha1Context); 747 748 /* Same key in both directions. */ 749 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); 750 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); 751 752 mppe_keys_set = 1; 753 } 754 755 /* 756 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079) 757 */ 758 static void 759 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len) 760 { 761 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 762 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 763 u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; 764 765 /* Hash (x2) the Unicode version of the secret (== password). */ 766 ascii2unicode(secret, secret_len, unicodePassword); 767 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 768 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); 769 770 mppe_set_keys(rchallenge, PasswordHashHash); 771 } 772 773 /* 774 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) 775 * 776 * This helper function used in the Winbind module, which gets the 777 * NTHashHash from the server. 778 */ 779 void 780 mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], 781 u_char NTResponse[24], int IsServer) 782 { 783 SHA1_CTX sha1Context; 784 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ 785 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ 786 787 u_char SHApad1[40] = 788 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 789 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 790 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 791 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 792 u_char SHApad2[40] = 793 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 794 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 795 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 796 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 }; 797 798 /* "This is the MPPE Master Key" */ 799 u_char Magic1[27] = 800 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 801 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 802 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 }; 803 /* "On the client side, this is the send key; " 804 "on the server side, it is the receive key." */ 805 u_char Magic2[84] = 806 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 807 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 808 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 809 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 810 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 811 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 812 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 813 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 814 0x6b, 0x65, 0x79, 0x2e }; 815 /* "On the client side, this is the receive key; " 816 "on the server side, it is the send key." */ 817 u_char Magic3[84] = 818 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 819 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 820 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 821 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 822 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 823 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 824 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 825 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 826 0x6b, 0x65, 0x79, 0x2e }; 827 u_char *s; 828 829 SHA1Init(&sha1Context); 830 SHA1Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 831 SHA1Update(&sha1Context, NTResponse, 24); 832 SHA1Update(&sha1Context, Magic1, sizeof(Magic1)); 833 SHA1Final(MasterKey, &sha1Context); 834 835 /* 836 * generate send key 837 */ 838 if (IsServer) 839 s = Magic3; 840 else 841 s = Magic2; 842 SHA1Init(&sha1Context); 843 SHA1Update(&sha1Context, MasterKey, 16); 844 SHA1Update(&sha1Context, SHApad1, sizeof(SHApad1)); 845 SHA1Update(&sha1Context, s, 84); 846 SHA1Update(&sha1Context, SHApad2, sizeof(SHApad2)); 847 SHA1Final(Digest, &sha1Context); 848 849 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); 850 851 /* 852 * generate recv key 853 */ 854 if (IsServer) 855 s = Magic2; 856 else 857 s = Magic3; 858 SHA1Init(&sha1Context); 859 SHA1Update(&sha1Context, MasterKey, 16); 860 SHA1Update(&sha1Context, SHApad1, sizeof(SHApad1)); 861 SHA1Update(&sha1Context, s, 84); 862 SHA1Update(&sha1Context, SHApad2, sizeof(SHApad2)); 863 SHA1Final(Digest, &sha1Context); 864 865 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); 866 867 mppe_keys_set = 1; 868 } 869 870 /* 871 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) 872 */ 873 static void 874 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer) 875 { 876 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 877 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 878 u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; 879 /* Hash (x2) the Unicode version of the secret (== password). */ 880 ascii2unicode(secret, secret_len, unicodePassword); 881 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 882 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); 883 mppe_set_keys2(PasswordHashHash, NTResponse, IsServer); 884 } 885 886 #endif /* MPPE */ 887 888 889 void 890 ChapMS(u_char *rchallenge, char *secret, int secret_len, 891 unsigned char *response) 892 { 893 BZERO(response, MS_CHAP_RESPONSE_LEN); 894 895 ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]); 896 897 #ifdef MSLANMAN 898 ChapMS_LANMan(rchallenge, secret, secret_len, 899 &response[MS_CHAP_LANMANRESP]); 900 901 /* preferred method is set by option */ 902 response[MS_CHAP_USENT] = !ms_lanman; 903 #else 904 response[MS_CHAP_USENT] = 1; 905 #endif 906 907 #ifdef MPPE 908 Set_Start_Key(rchallenge, secret, secret_len); 909 #endif 910 } 911 912 913 /* 914 * If PeerChallenge is NULL, one is generated and the PeerChallenge 915 * field of response is filled in. Call this way when generating a response. 916 * If PeerChallenge is supplied, it is copied into the PeerChallenge field. 917 * Call this way when verifying a response (or debugging). 918 * Do not call with PeerChallenge = response. 919 * 920 * The PeerChallenge field of response is then used for calculation of the 921 * Authenticator Response. 922 */ 923 void 924 ChapMS2(u_char *rchallenge, u_char *PeerChallenge, 925 char *user, char *secret, int secret_len, unsigned char *response, 926 u_char authResponse[], int authenticator) 927 { 928 /* ARGSUSED */ 929 u_char *p = &response[MS_CHAP2_PEER_CHALLENGE]; 930 int i; 931 932 BZERO(response, MS_CHAP2_RESPONSE_LEN); 933 934 /* Generate the Peer-Challenge if requested, or copy it if supplied. */ 935 if (!PeerChallenge) 936 for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++) 937 *p++ = (u_char) (drand48() * 0xff); 938 else 939 BCOPY(PeerChallenge, &response[MS_CHAP2_PEER_CHALLENGE], 940 MS_CHAP2_PEER_CHAL_LEN); 941 942 /* Generate the NT-Response */ 943 ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user, 944 secret, secret_len, &response[MS_CHAP2_NTRESP]); 945 946 /* Generate the Authenticator Response. */ 947 GenerateAuthenticatorResponsePlain(secret, secret_len, 948 &response[MS_CHAP2_NTRESP], 949 &response[MS_CHAP2_PEER_CHALLENGE], 950 rchallenge, user, authResponse); 951 952 #ifdef MPPE 953 SetMasterKeys(secret, secret_len, 954 &response[MS_CHAP2_NTRESP], authenticator); 955 #endif 956 } 957 958 #ifdef MPPE 959 /* 960 * Set MPPE options from plugins. 961 */ 962 void 963 set_mppe_enc_types(int policy, int types) 964 { 965 /* Early exit for unknown policies. */ 966 if (policy != MPPE_ENC_POL_ENC_ALLOWED || 967 policy != MPPE_ENC_POL_ENC_REQUIRED) 968 return; 969 970 /* Don't modify MPPE if it's optional and wasn't already configured. */ 971 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe) 972 return; 973 974 /* 975 * Disable undesirable encryption types. Note that we don't ENABLE 976 * any encryption types, to avoid overriding manual configuration. 977 */ 978 switch(types) { 979 case MPPE_ENC_TYPES_RC4_40: 980 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */ 981 break; 982 case MPPE_ENC_TYPES_RC4_128: 983 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */ 984 break; 985 default: 986 break; 987 } 988 } 989 #endif /* MPPE */ 990 991 static struct chap_digest_type chapms_digest = { 992 CHAP_MICROSOFT, /* code */ 993 chapms_generate_challenge, 994 chapms_verify_response, 995 chapms_make_response, 996 NULL, /* check_success */ 997 chapms_handle_failure, 998 }; 999 1000 static struct chap_digest_type chapms2_digest = { 1001 CHAP_MICROSOFT_V2, /* code */ 1002 chapms2_generate_challenge, 1003 chapms2_verify_response, 1004 chapms2_make_response, 1005 chapms2_check_success, 1006 chapms_handle_failure, 1007 }; 1008 1009 void 1010 chapms_init(void) 1011 { 1012 chap_register_digest(&chapms_digest); 1013 chap_register_digest(&chapms2_digest); 1014 add_options(chapms_option_list); 1015 } 1016 1017 #endif /* CHAPMS */ 1018