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