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.36 2006/05/21 11:56:40 paulus Exp $" 78 79#ifdef CHAPMS 80 81#include <stdio.h> 82#include <stdlib.h> 83#include <string.h> 84#include <ctype.h> 85#include <sys/types.h> 86#include <sys/time.h> 87#include <unistd.h> 88 89#include "pppd.h" 90#include "chap-new.h" 91#include "chap_ms.h" 92#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 unsigned char *private) 317{ 318 challenge++; /* skip length, should be 8 */ 319 *response++ = MS_CHAP_RESPONSE_LEN; 320 ChapMS(challenge, secret, secret_len, response); 321} 322 323static void 324chapms2_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 16 */ 329 *response++ = MS_CHAP2_RESPONSE_LEN; 330 ChapMS2(challenge, 331#ifdef DEBUGMPPEKEY 332 mschap2_peer_challenge, 333#else 334 NULL, 335#endif 336 our_name, secret, secret_len, response, private, 337 MS_CHAP2_AUTHENTICATEE); 338} 339 340static int 341chapms2_check_success(unsigned char *msg, int len, unsigned char *private) 342{ 343 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) || 344 strncmp((char *)msg, "S=", 2) != 0) { 345 /* Packet does not start with "S=" */ 346 error("MS-CHAPv2 Success packet is badly formed."); 347 return 0; 348 } 349 msg += 2; 350 len -= 2; 351 if (len < MS_AUTH_RESPONSE_LENGTH 352 || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) { 353 /* Authenticator Response did not match expected. */ 354 error("MS-CHAPv2 mutual authentication failed."); 355 return 0; 356 } 357 /* Authenticator Response matches. */ 358 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */ 359 len -= MS_AUTH_RESPONSE_LENGTH; 360 if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) { 361 msg += 3; /* Eat the delimiter */ 362 } else if (len) { 363 /* Packet has extra text which does not begin " M=" */ 364 error("MS-CHAPv2 Success packet is badly formed."); 365 return 0; 366 } 367 return 1; 368} 369 370static void 371chapms_handle_failure(unsigned char *inp, int len) 372{ 373 int err; 374 char *p, *msg; 375 376 /* We want a null-terminated string for strxxx(). */ 377 msg = malloc(len + 1); 378 if (!msg) { 379 notice("Out of memory in chapms_handle_failure"); 380 return; 381 } 382 BCOPY(inp, msg, len); 383 msg[len] = 0; 384 p = msg; 385 386 /* 387 * Deal with MS-CHAP formatted failure messages; just print the 388 * M=<message> part (if any). For MS-CHAP we're not really supposed 389 * to use M=<message>, but it shouldn't hurt. See 390 * chapms[2]_verify_response. 391 */ 392 if (!strncmp(p, "E=", 2)) 393 err = strtol(p+2, NULL, 10); /* Remember the error code. */ 394 else 395 goto print_msg; /* Message is badly formatted. */ 396 397 if (len && ((p = strstr(p, " M=")) != NULL)) { 398 /* M=<message> field found. */ 399 p += 3; 400 } else { 401 /* No M=<message>; use the error code. */ 402 switch (err) { 403 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS: 404 p = "E=646 Restricted logon hours"; 405 break; 406 407 case MS_CHAP_ERROR_ACCT_DISABLED: 408 p = "E=647 Account disabled"; 409 break; 410 411 case MS_CHAP_ERROR_PASSWD_EXPIRED: 412 p = "E=648 Password expired"; 413 break; 414 415 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION: 416 p = "E=649 No dialin permission"; 417 break; 418 419 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE: 420 p = "E=691 Authentication failure"; 421 break; 422 423 case MS_CHAP_ERROR_CHANGING_PASSWORD: 424 /* Should never see this, we don't support Change Password. */ 425 p = "E=709 Error changing password"; 426 break; 427 428 default: 429 free(msg); 430 error("Unknown MS-CHAP authentication failure: %.*v", 431 len, inp); 432 return; 433 } 434 } 435print_msg: 436 if (p != NULL) 437 error("MS-CHAP authentication failed: %v", p); 438 free(msg); 439} 440 441static void 442ChallengeResponse(u_char *challenge, 443 u_char PasswordHash[MD4_SIGNATURE_SIZE], 444 u_char response[24]) 445{ 446 u_char ZPasswordHash[21]; 447 448 BZERO(ZPasswordHash, sizeof(ZPasswordHash)); 449 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE); 450 451#if 0 452 dbglog("ChallengeResponse - ZPasswordHash %.*B", 453 sizeof(ZPasswordHash), ZPasswordHash); 454#endif 455 456 (void) DesSetkey(ZPasswordHash + 0); 457 DesEncrypt(challenge, response + 0); 458 (void) DesSetkey(ZPasswordHash + 7); 459 DesEncrypt(challenge, response + 8); 460 (void) DesSetkey(ZPasswordHash + 14); 461 DesEncrypt(challenge, response + 16); 462 463#if 0 464 dbglog("ChallengeResponse - response %.24B", response); 465#endif 466} 467 468void 469ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge, 470 char *username, u_char Challenge[8]) 471 472{ 473 SHA1_CTX sha1Context; 474 u_char sha1Hash[SHA1_SIGNATURE_SIZE]; 475 char *user; 476 477 /* remove domain from "domain\username" */ 478 if ((user = strrchr(username, '\\')) != NULL) 479 ++user; 480 else 481 user = username; 482 483 SHA1_Init(&sha1Context); 484 SHA1_Update(&sha1Context, PeerChallenge, 16); 485 SHA1_Update(&sha1Context, rchallenge, 16); 486 SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user)); 487 SHA1_Final(sha1Hash, &sha1Context); 488 489 BCOPY(sha1Hash, Challenge, 8); 490} 491 492/* 493 * Convert the ASCII version of the password to Unicode. 494 * This implicitly supports 8-bit ISO8859/1 characters. 495 * This gives us the little-endian representation, which 496 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering 497 * is machine-dependent.) 498 */ 499static void 500ascii2unicode(char ascii[], int ascii_len, u_char unicode[]) 501{ 502 int i; 503 504 BZERO(unicode, ascii_len * 2); 505 for (i = 0; i < ascii_len; i++) 506 unicode[i * 2] = (u_char) ascii[i]; 507} 508 509static void 510NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE]) 511{ 512#ifdef __NetBSD__ 513 /* NetBSD uses the libc md4 routines which take bytes instead of bits */ 514 int mdlen = secret_len; 515#else 516 int mdlen = secret_len * 8; 517#endif 518 MD4_CTX md4Context; 519 520 MD4Init(&md4Context); 521 /* MD4Update can take at most 64 bytes at a time */ 522 while (mdlen > 512) { 523 MD4Update(&md4Context, secret, 512); 524 secret += 64; 525 mdlen -= 512; 526 } 527 MD4Update(&md4Context, secret, mdlen); 528 MD4Final(hash, &md4Context); 529 530} 531 532static void 533ChapMS_NT(u_char *rchallenge, char *secret, int secret_len, 534 u_char NTResponse[24]) 535{ 536 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 537 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 538 539 /* Hash the Unicode version of the secret (== password). */ 540 ascii2unicode(secret, secret_len, unicodePassword); 541 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 542 543 ChallengeResponse(rchallenge, PasswordHash, NTResponse); 544} 545 546static void 547ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username, 548 char *secret, int secret_len, u_char NTResponse[24]) 549{ 550 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 551 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 552 u_char Challenge[8]; 553 554 ChallengeHash(PeerChallenge, rchallenge, username, Challenge); 555 556 /* Hash the Unicode version of the secret (== password). */ 557 ascii2unicode(secret, secret_len, unicodePassword); 558 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 559 560 ChallengeResponse(Challenge, PasswordHash, NTResponse); 561} 562 563#ifdef MSLANMAN 564static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ 565 566static void 567ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len, 568 unsigned char *response) 569{ 570 int i; 571 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ 572 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 573 574 /* LANMan password is case insensitive */ 575 BZERO(UcasePassword, sizeof(UcasePassword)); 576 for (i = 0; i < secret_len; i++) 577 UcasePassword[i] = (u_char)toupper(secret[i]); 578 (void) DesSetkey(UcasePassword + 0); 579 DesEncrypt( StdText, PasswordHash + 0 ); 580 (void) DesSetkey(UcasePassword + 7); 581 DesEncrypt( StdText, PasswordHash + 8 ); 582 ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]); 583} 584#endif 585 586 587void 588GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], 589 u_char NTResponse[24], u_char PeerChallenge[16], 590 u_char *rchallenge, char *username, 591 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) 592{ 593 /* 594 * "Magic" constants used in response generation, from RFC 2759. 595 */ 596 u_char Magic1[39] = /* "Magic server to client signing constant" */ 597 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 598 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 599 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 600 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; 601 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */ 602 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 603 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 604 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 605 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 606 0x6E }; 607 608 int i; 609 SHA1_CTX sha1Context; 610 u_char Digest[SHA1_SIGNATURE_SIZE]; 611 u_char Challenge[8]; 612 613 SHA1_Init(&sha1Context); 614 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 615 SHA1_Update(&sha1Context, NTResponse, 24); 616 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1)); 617 SHA1_Final(Digest, &sha1Context); 618 619 ChallengeHash(PeerChallenge, rchallenge, username, Challenge); 620 621 SHA1_Init(&sha1Context); 622 SHA1_Update(&sha1Context, Digest, sizeof(Digest)); 623 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge)); 624 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2)); 625 SHA1_Final(Digest, &sha1Context); 626 627 /* Convert to ASCII hex string. */ 628 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++) 629 sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]); 630} 631 632 633static void 634GenerateAuthenticatorResponsePlain 635 (char *secret, int secret_len, 636 u_char NTResponse[24], u_char PeerChallenge[16], 637 u_char *rchallenge, char *username, 638 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) 639{ 640 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 641 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 642 u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; 643 644 /* Hash (x2) the Unicode version of the secret (== password). */ 645 ascii2unicode(secret, secret_len, unicodePassword); 646 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 647 NTPasswordHash(PasswordHash, sizeof(PasswordHash), 648 PasswordHashHash); 649 650 GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge, 651 rchallenge, username, authResponse); 652} 653 654 655#ifdef MPPE 656/* 657 * Set mppe_xxxx_key from the NTPasswordHashHash. 658 * RFC 2548 (RADIUS support) requires us to export this function (ugh). 659 */ 660void 661mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE]) 662{ 663 SHA1_CTX sha1Context; 664 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ 665 666 SHA1_Init(&sha1Context); 667 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 668 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 669 SHA1_Update(&sha1Context, rchallenge, 8); 670 SHA1_Final(Digest, &sha1Context); 671 672 /* Same key in both directions. */ 673 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); 674 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); 675 676 mppe_keys_set = 1; 677} 678 679/* 680 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079) 681 */ 682static void 683Set_Start_Key(u_char *rchallenge, char *secret, int secret_len) 684{ 685 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 686 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 687 u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; 688 689 /* Hash (x2) the Unicode version of the secret (== password). */ 690 ascii2unicode(secret, secret_len, unicodePassword); 691 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 692 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); 693 694 mppe_set_keys(rchallenge, PasswordHashHash); 695} 696 697/* 698 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) 699 * 700 * This helper function used in the Winbind module, which gets the 701 * NTHashHash from the server. 702 */ 703void 704mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], 705 u_char NTResponse[24], int IsServer) 706{ 707 SHA1_CTX sha1Context; 708 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ 709 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ 710 711 u_char SHApad1[40] = 712 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 713 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 714 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 715 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 716 u_char SHApad2[40] = 717 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 718 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 719 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 720 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 }; 721 722 /* "This is the MPPE Master Key" */ 723 u_char Magic1[27] = 724 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 725 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 726 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 }; 727 /* "On the client side, this is the send key; " 728 "on the server side, it is the receive key." */ 729 u_char Magic2[84] = 730 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 731 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 732 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 733 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 734 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 735 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 736 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 737 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 738 0x6b, 0x65, 0x79, 0x2e }; 739 /* "On the client side, this is the receive key; " 740 "on the server side, it is the send key." */ 741 u_char Magic3[84] = 742 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 743 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 744 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 745 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 746 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 747 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 748 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 749 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 750 0x6b, 0x65, 0x79, 0x2e }; 751 u_char *s; 752 753 SHA1_Init(&sha1Context); 754 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); 755 SHA1_Update(&sha1Context, NTResponse, 24); 756 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1)); 757 SHA1_Final(MasterKey, &sha1Context); 758 759 /* 760 * generate send key 761 */ 762 if (IsServer) 763 s = Magic3; 764 else 765 s = Magic2; 766 SHA1_Init(&sha1Context); 767 SHA1_Update(&sha1Context, MasterKey, 16); 768 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1)); 769 SHA1_Update(&sha1Context, s, 84); 770 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2)); 771 SHA1_Final(Digest, &sha1Context); 772 773 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); 774 775 /* 776 * generate recv key 777 */ 778 if (IsServer) 779 s = Magic2; 780 else 781 s = Magic3; 782 SHA1_Init(&sha1Context); 783 SHA1_Update(&sha1Context, MasterKey, 16); 784 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1)); 785 SHA1_Update(&sha1Context, s, 84); 786 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2)); 787 SHA1_Final(Digest, &sha1Context); 788 789 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); 790 791 mppe_keys_set = 1; 792} 793 794/* 795 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) 796 */ 797static void 798SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer) 799{ 800 u_char unicodePassword[MAX_NT_PASSWORD * 2]; 801 u_char PasswordHash[MD4_SIGNATURE_SIZE]; 802 u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; 803 /* Hash (x2) the Unicode version of the secret (== password). */ 804 ascii2unicode(secret, secret_len, unicodePassword); 805 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); 806 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); 807 mppe_set_keys2(PasswordHashHash, NTResponse, IsServer); 808} 809 810#endif /* MPPE */ 811 812 813void 814ChapMS(u_char *rchallenge, char *secret, int secret_len, 815 unsigned char *response) 816{ 817 BZERO(response, MS_CHAP_RESPONSE_LEN); 818 819 ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]); 820 821#ifdef MSLANMAN 822 ChapMS_LANMan(rchallenge, secret, secret_len, &response); 823 824 /* preferred method is set by option */ 825 response[MS_CHAP_USENT] = !ms_lanman; 826#else 827 response[MS_CHAP_USENT] = 1; 828#endif 829 830#ifdef MPPE 831 Set_Start_Key(rchallenge, secret, secret_len); 832#endif 833} 834 835 836/* 837 * If PeerChallenge is NULL, one is generated and the PeerChallenge 838 * field of response is filled in. Call this way when generating a response. 839 * If PeerChallenge is supplied, it is copied into the PeerChallenge field. 840 * Call this way when verifying a response (or debugging). 841 * Do not call with PeerChallenge = response. 842 * 843 * The PeerChallenge field of response is then used for calculation of the 844 * Authenticator Response. 845 */ 846void 847ChapMS2(u_char *rchallenge, u_char *PeerChallenge, 848 char *user, char *secret, int secret_len, unsigned char *response, 849 u_char authResponse[], int authenticator) 850{ 851 /* ARGSUSED */ 852 u_char *p = &response[MS_CHAP2_PEER_CHALLENGE]; 853 int i; 854 855 BZERO(response, sizeof(*response)); 856 857 /* Generate the Peer-Challenge if requested, or copy it if supplied. */ 858 if (!PeerChallenge) 859 for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++) 860 *p++ = (u_char) (drand48() * 0xff); 861 else 862 BCOPY(PeerChallenge, &response[MS_CHAP2_PEER_CHALLENGE], 863 MS_CHAP2_PEER_CHAL_LEN); 864 865 /* Generate the NT-Response */ 866 ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user, 867 secret, secret_len, &response[MS_CHAP2_NTRESP]); 868 869 /* Generate the Authenticator Response. */ 870 GenerateAuthenticatorResponsePlain(secret, secret_len, 871 &response[MS_CHAP2_NTRESP], 872 &response[MS_CHAP2_PEER_CHALLENGE], 873 rchallenge, user, authResponse); 874 875#ifdef MPPE 876 SetMasterKeys(secret, secret_len, 877 &response[MS_CHAP2_NTRESP], authenticator); 878#endif 879} 880 881#ifdef MPPE 882/* 883 * Set MPPE options from plugins. 884 */ 885void 886set_mppe_enc_types(int policy, int types) 887{ 888 /* Early exit for unknown policies. */ 889 if (policy != MPPE_ENC_POL_ENC_ALLOWED || 890 policy != MPPE_ENC_POL_ENC_REQUIRED) 891 return; 892 893 /* Don't modify MPPE if it's optional and wasn't already configured. */ 894 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe) 895 return; 896 897 /* 898 * Disable undesirable encryption types. Note that we don't ENABLE 899 * any encryption types, to avoid overriding manual configuration. 900 */ 901 switch(types) { 902 case MPPE_ENC_TYPES_RC4_40: 903 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */ 904 break; 905 case MPPE_ENC_TYPES_RC4_128: 906 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */ 907 break; 908 default: 909 break; 910 } 911} 912#endif /* MPPE */ 913 914static struct chap_digest_type chapms_digest = { 915 CHAP_MICROSOFT, /* code */ 916 chapms_generate_challenge, 917 chapms_verify_response, 918 chapms_make_response, 919 NULL, /* check_success */ 920 chapms_handle_failure, 921}; 922 923static struct chap_digest_type chapms2_digest = { 924 CHAP_MICROSOFT_V2, /* code */ 925 chapms2_generate_challenge, 926 chapms2_verify_response, 927 chapms2_make_response, 928 chapms2_check_success, 929 chapms_handle_failure, 930}; 931 932void 933chapms_init(void) 934{ 935 chap_register_digest(&chapms_digest); 936 chap_register_digest(&chapms2_digest); 937 add_options(chapms_option_list); 938} 939 940#endif /* CHAPMS */ 941