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