2 * chap_ms.c - Microsoft MS-CHAP compatible implementation.
4 * Copyright (c) 1995 Eric Rosenquist. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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
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.
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.
32 * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
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.
39 * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
43 * Modifications by Frank Cusack, frank@google.com, March 2002.
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.
49 * Copyright (c) 2002 Google, Inc. All rights reserved.
51 * Redistribution and use in source and binary forms, with or without
52 * modification, are permitted provided that the following conditions
55 * 1. Redistributions of source code must retain the above copyright
56 * notice, this list of conditions and the following disclaimer.
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
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.
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.
77 #define RCSID "$Id: chap_ms.c,v 1.32 2004/11/04 12:00:07 paulus Exp $"
85 #include <sys/types.h>
97 static const char rcsid[] = RCSID;
100 static void ascii2unicode __P((char[], int, u_char[]));
101 static void NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
102 static void ChallengeResponse __P((u_char *, u_char *, u_char[24]));
103 static void ChapMS_NT __P((u_char *, char *, int, u_char[24]));
104 static void ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
106 static void GenerateAuthenticatorResponsePlain
107 __P((char*, int, u_char[24], u_char[16], u_char *,
108 char *, u_char[41]));
110 static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
114 static void Set_Start_Key __P((u_char *, char *, int));
115 static void SetMasterKeys __P((char *, int, u_char[24], int));
119 bool ms_lanman = 0; /* Use LanMan password instead of NT */
120 /* Has meaning only with MS-CHAP challenges */
124 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
125 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
126 int mppe_keys_set = 0; /* Have the MPPE keys been set? */
129 /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
130 static char *mschap_challenge = NULL;
131 /* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
132 static char *mschap2_peer_challenge = NULL;
134 #include "fsm.h" /* Need to poke MPPE options */
136 #include <net/ppp-comp.h>
140 * Command-line options.
142 static option_t chapms_option_list[] = {
144 { "ms-lanman", o_bool, &ms_lanman,
145 "Use LanMan passwd when using MS-CHAP", 1 },
148 { "mschap-challenge", o_string, &mschap_challenge,
149 "specify CHAP challenge" },
150 { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
151 "specify CHAP peer challenge" },
157 * chapms_generate_challenge - generate a challenge for MS-CHAP.
158 * For MS-CHAP the challenge length is fixed at 8 bytes.
159 * The length goes in challenge[0] and the actual challenge starts
163 chapms_generate_challenge(unsigned char *challenge)
167 if (mschap_challenge && strlen(mschap_challenge) == 8)
168 memcpy(challenge, mschap_challenge, 8);
171 random_bytes(challenge, 8);
175 chapms2_generate_challenge(unsigned char *challenge)
179 if (mschap_challenge && strlen(mschap_challenge) == 16)
180 memcpy(challenge, mschap_challenge, 16);
183 random_bytes(challenge, 16);
187 chapms_verify_response(int id, char *name,
188 unsigned char *secret, int secret_len,
189 unsigned char *challenge, unsigned char *response,
190 char *message, int message_space)
192 MS_ChapResponse *rmd;
195 int challenge_len, response_len;
197 challenge_len = *challenge++; /* skip length, is 8 */
198 response_len = *response++;
199 if (response_len != MS_CHAP_RESPONSE_LEN)
202 rmd = (MS_ChapResponse *) response;
205 if (!rmd->UseNT[0]) {
206 /* Should really propagate this into the error packet. */
207 notice("Peer request for LANMAN auth not supported");
212 /* Generate the expected response. */
213 ChapMS(challenge, (char *)secret, secret_len, &md);
216 /* Determine which part of response to verify against */
218 diff = memcmp(&rmd->LANManResp, &md.LANManResp,
219 sizeof(md.LANManResp));
222 diff = memcmp(&rmd->NTResp, &md.NTResp, sizeof(md.NTResp));
225 slprintf(message, message_space, "Access granted");
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);
237 chapms2_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)
242 MS_Chap2Response *rmd;
244 char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
245 int challenge_len, response_len;
247 challenge_len = *challenge++; /* skip length, is 16 */
248 response_len = *response++;
249 if (response_len != MS_CHAP2_RESPONSE_LEN)
250 goto bad; /* not even the right length */
252 rmd = (MS_Chap2Response *) response;
254 /* Generate the expected response and our mutual auth. */
255 ChapMS2(challenge, rmd->PeerChallenge, name,
256 (char *)secret, secret_len, &md,
257 (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
259 /* compare MDs and send the appropriate status */
261 * Per RFC 2759, success message must be formatted as
262 * "S=<auth_string> M=<message>"
264 * <auth_string> is the Authenticator Response (mutual auth)
265 * <message> is a text message
267 * However, some versions of Windows (win98 tested) do not know
268 * about the M=<message> part (required per RFC 2759) and flag
269 * it as an error (reported incorrectly as an encryption error
270 * to the user). Since the RFC requires it, and it can be
271 * useful information, we supply it if the peer is a conforming
272 * system. Luckily (?), win98 sets the Flags field to 0x04
273 * (contrary to RFC requirements) so we can use that to
274 * distinguish between conforming and non-conforming systems.
276 * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
277 * help debugging this.
279 if (memcmp(md.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) {
281 slprintf(message, message_space, "S=%s", saresponse);
283 slprintf(message, message_space, "S=%s M=%s",
284 saresponse, "Access granted");
290 * Failure message must be formatted as
291 * "E=e R=r C=c V=v M=m"
293 * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
294 * r = retry (we use 1, ok to retry)
295 * c = challenge to use for next response, we reuse previous
296 * v = Change Password version supported, we use 0
299 * The M=m part is only for MS-CHAPv2. Neither win2k nor
300 * win98 (others untested) display the message to the user anyway.
301 * They also both ignore the E=e code.
303 * Note that it's safe to reuse the same challenge as we don't
304 * actually accept another response based on the error message
305 * (and no clients try to resend a response anyway).
307 * Basically, this whole bit is useless code, even the small
308 * implementation here is only because of overspecification.
310 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
311 challenge_len, challenge, "Access denied");
316 chapms_make_response(unsigned char *response, int id, char *our_name,
317 unsigned char *challenge, char *secret, int secret_len,
318 unsigned char *private)
320 challenge++; /* skip length, should be 8 */
321 *response++ = MS_CHAP_RESPONSE_LEN;
322 ChapMS(challenge, secret, secret_len, (MS_ChapResponse *) response);
326 chapms2_make_response(unsigned char *response, int id, char *our_name,
327 unsigned char *challenge, char *secret, int secret_len,
328 unsigned char *private)
330 challenge++; /* skip length, should be 16 */
331 *response++ = MS_CHAP2_RESPONSE_LEN;
334 mschap2_peer_challenge,
338 our_name, secret, secret_len,
339 (MS_Chap2Response *) response, private,
340 MS_CHAP2_AUTHENTICATEE);
344 chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
346 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
347 strncmp((char *)msg, "S=", 2) != 0) {
348 /* Packet does not start with "S=" */
349 error("MS-CHAPv2 Success packet is badly formed.");
354 if (len < MS_AUTH_RESPONSE_LENGTH
355 || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
356 /* Authenticator Response did not match expected. */
357 error("MS-CHAPv2 mutual authentication failed.");
360 /* Authenticator Response matches. */
361 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
362 len -= MS_AUTH_RESPONSE_LENGTH;
363 if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
364 msg += 3; /* Eat the delimiter */
366 /* Packet has extra text which does not begin " M=" */
367 error("MS-CHAPv2 Success packet is badly formed.");
374 chapms_handle_failure(unsigned char *inp, int len)
379 /* We want a null-terminated string for strxxx(). */
380 msg = malloc(len + 1);
382 notice("Out of memory in chapms_handle_failure");
385 BCOPY(inp, msg, len);
390 * Deal with MS-CHAP formatted failure messages; just print the
391 * M=<message> part (if any). For MS-CHAP we're not really supposed
392 * to use M=<message>, but it shouldn't hurt. See
393 * chapms[2]_verify_response.
395 if (!strncmp(p, "E=", 2))
396 err = strtol(p, NULL, 10); /* Remember the error code. */
398 goto print_msg; /* Message is badly formatted. */
400 if (len && ((p = strstr(p, " M=")) != NULL)) {
401 /* M=<message> field found. */
404 /* No M=<message>; use the error code. */
406 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
407 p = "E=646 Restricted logon hours";
410 case MS_CHAP_ERROR_ACCT_DISABLED:
411 p = "E=647 Account disabled";
414 case MS_CHAP_ERROR_PASSWD_EXPIRED:
415 p = "E=648 Password expired";
418 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
419 p = "E=649 No dialin permission";
422 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
423 p = "E=691 Authentication failure";
426 case MS_CHAP_ERROR_CHANGING_PASSWORD:
427 /* Should never see this, we don't support Change Password. */
428 p = "E=709 Error changing password";
433 error("Unknown MS-CHAP authentication failure: %.*v",
440 error("MS-CHAP authentication failed: %v", p);
445 ChallengeResponse(u_char *challenge,
446 u_char PasswordHash[MD4_SIGNATURE_SIZE],
449 u_char ZPasswordHash[21];
451 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
452 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
455 dbglog("ChallengeResponse - ZPasswordHash %.*B",
456 sizeof(ZPasswordHash), ZPasswordHash);
459 (void) DesSetkey(ZPasswordHash + 0);
460 DesEncrypt(challenge, response + 0);
461 (void) DesSetkey(ZPasswordHash + 7);
462 DesEncrypt(challenge, response + 8);
463 (void) DesSetkey(ZPasswordHash + 14);
464 DesEncrypt(challenge, response + 16);
467 dbglog("ChallengeResponse - response %.24B", response);
472 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
473 char *username, u_char Challenge[8])
476 SHA1_CTX sha1Context;
477 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
480 /* remove domain from "domain\username" */
481 if ((user = strrchr(username, '\\')) != NULL)
486 SHA1_Init(&sha1Context);
487 SHA1_Update(&sha1Context, PeerChallenge, 16);
488 SHA1_Update(&sha1Context, rchallenge, 16);
489 SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
490 SHA1_Final(sha1Hash, &sha1Context);
492 BCOPY(sha1Hash, Challenge, 8);
496 * Convert the ASCII version of the password to Unicode.
497 * This implicitly supports 8-bit ISO8859/1 characters.
498 * This gives us the little-endian representation, which
499 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
500 * is machine-dependent.)
503 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
507 BZERO(unicode, ascii_len * 2);
508 for (i = 0; i < ascii_len; i++)
509 unicode[i * 2] = (u_char) ascii[i];
513 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
516 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
517 int mdlen = secret_len;
519 int mdlen = secret_len * 8;
523 MD4Init(&md4Context);
524 MD4Update(&md4Context, (unsigned char *)secret, mdlen);
525 MD4Final(hash, &md4Context);
530 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
531 u_char NTResponse[24])
533 u_char unicodePassword[MAX_NT_PASSWORD * 2];
534 u_char PasswordHash[MD4_SIGNATURE_SIZE];
536 /* Hash the Unicode version of the secret (== password). */
537 ascii2unicode(secret, secret_len, unicodePassword);
538 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
540 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
544 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
545 char *secret, int secret_len, u_char NTResponse[24])
547 u_char unicodePassword[MAX_NT_PASSWORD * 2];
548 u_char PasswordHash[MD4_SIGNATURE_SIZE];
551 ChallengeHash(PeerChallenge, (unsigned char *)rchallenge, username,
554 /* Hash the Unicode version of the secret (== password). */
555 ascii2unicode(secret, secret_len, unicodePassword);
556 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
558 ChallengeResponse(Challenge, PasswordHash, NTResponse);
562 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
565 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
566 MS_ChapResponse *response)
569 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
570 u_char PasswordHash[MD4_SIGNATURE_SIZE];
572 /* LANMan password is case insensitive */
573 BZERO(UcasePassword, sizeof(UcasePassword));
574 for (i = 0; i < secret_len; i++)
575 UcasePassword[i] = (u_char)toupper(secret[i]);
576 (void) DesSetkey(UcasePassword + 0);
577 DesEncrypt( StdText, PasswordHash + 0 );
578 (void) DesSetkey(UcasePassword + 7);
579 DesEncrypt( StdText, PasswordHash + 8 );
580 ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
586 GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
587 u_char NTResponse[24], u_char PeerChallenge[16],
588 u_char *rchallenge, char *username,
589 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
592 * "Magic" constants used in response generation, from RFC 2759.
594 u_char Magic1[39] = /* "Magic server to client signing constant" */
595 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
596 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
597 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
598 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
599 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
600 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
601 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
602 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
603 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
607 SHA1_CTX sha1Context;
608 u_char Digest[SHA1_SIGNATURE_SIZE];
611 SHA1_Init(&sha1Context);
612 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
613 SHA1_Update(&sha1Context, NTResponse, 24);
614 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
615 SHA1_Final(Digest, &sha1Context);
617 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
619 SHA1_Init(&sha1Context);
620 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
621 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
622 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
623 SHA1_Final(Digest, &sha1Context);
625 /* Convert to ASCII hex string. */
626 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
627 sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
632 GenerateAuthenticatorResponsePlain
633 (char *secret, int secret_len,
634 u_char NTResponse[24], u_char PeerChallenge[16],
635 u_char *rchallenge, char *username,
636 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
638 u_char unicodePassword[MAX_NT_PASSWORD * 2];
639 u_char PasswordHash[MD4_SIGNATURE_SIZE];
640 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
642 /* Hash (x2) the Unicode version of the secret (== password). */
643 ascii2unicode(secret, secret_len, unicodePassword);
644 NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
645 NTPasswordHash((char *)PasswordHash, sizeof(PasswordHash),
648 GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
649 rchallenge, username, authResponse);
655 * Set mppe_xxxx_key from the NTPasswordHashHash.
656 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
659 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
661 SHA1_CTX sha1Context;
662 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
664 SHA1_Init(&sha1Context);
665 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
666 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
667 SHA1_Update(&sha1Context, rchallenge, 8);
668 SHA1_Final(Digest, &sha1Context);
670 /* Same key in both directions. */
671 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
672 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
678 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
681 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
683 u_char unicodePassword[MAX_NT_PASSWORD * 2];
684 u_char PasswordHash[MD4_SIGNATURE_SIZE];
685 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
687 /* Hash (x2) the Unicode version of the secret (== password). */
688 ascii2unicode(secret, secret_len, unicodePassword);
689 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
690 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
692 mppe_set_keys(rchallenge, PasswordHashHash);
696 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
698 * This helper function used in the Winbind module, which gets the
699 * NTHashHash from the server.
702 mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
703 u_char NTResponse[24], int IsServer)
705 SHA1_CTX sha1Context;
706 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
707 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
710 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
711 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
712 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
713 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
715 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
716 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
717 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
718 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
720 /* "This is the MPPE Master Key" */
722 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
723 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
724 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
725 /* "On the client side, this is the send key; "
726 "on the server side, it is the receive key." */
728 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
729 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
730 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
731 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
732 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
733 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
734 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
735 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
736 0x6b, 0x65, 0x79, 0x2e };
737 /* "On the client side, this is the receive key; "
738 "on the server side, it is the send key." */
740 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
741 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
742 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
743 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
744 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
745 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
746 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
747 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
748 0x6b, 0x65, 0x79, 0x2e };
751 SHA1_Init(&sha1Context);
752 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
753 SHA1_Update(&sha1Context, NTResponse, 24);
754 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
755 SHA1_Final(MasterKey, &sha1Context);
764 SHA1_Init(&sha1Context);
765 SHA1_Update(&sha1Context, MasterKey, 16);
766 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
767 SHA1_Update(&sha1Context, s, 84);
768 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
769 SHA1_Final(Digest, &sha1Context);
771 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
780 SHA1_Init(&sha1Context);
781 SHA1_Update(&sha1Context, MasterKey, 16);
782 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
783 SHA1_Update(&sha1Context, s, 84);
784 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
785 SHA1_Final(Digest, &sha1Context);
787 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
793 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
796 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
798 u_char unicodePassword[MAX_NT_PASSWORD * 2];
799 u_char PasswordHash[MD4_SIGNATURE_SIZE];
800 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
801 /* Hash (x2) the Unicode version of the secret (== password). */
802 ascii2unicode(secret, secret_len, unicodePassword);
803 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
804 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
805 mppe_set_keys2(PasswordHashHash, NTResponse, IsServer);
812 ChapMS(u_char *rchallenge, char *secret, int secret_len,
813 MS_ChapResponse *response)
815 BZERO(response, sizeof(*response));
817 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
820 ChapMS_LANMan(rchallenge, secret, secret_len, response);
822 /* preferred method is set by option */
823 response->UseNT[0] = !ms_lanman;
825 response->UseNT[0] = 1;
829 Set_Start_Key(rchallenge, secret, secret_len);
835 * If PeerChallenge is NULL, one is generated and response->PeerChallenge
836 * is filled in. Call this way when generating a response.
837 * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
838 * Call this way when verifying a response (or debugging).
839 * Do not call with PeerChallenge = response->PeerChallenge.
841 * response->PeerChallenge is then used for calculation of the
842 * Authenticator Response.
845 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
846 char *user, char *secret, int secret_len, MS_Chap2Response *response,
847 u_char authResponse[], int authenticator)
850 u_char *p = response->PeerChallenge;
853 BZERO(response, sizeof(*response));
855 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
857 for (i = 0; i < sizeof(response->PeerChallenge); i++)
858 *p++ = (u_char) (drand48() * 0xff);
860 BCOPY(PeerChallenge, response->PeerChallenge,
861 sizeof(response->PeerChallenge));
863 /* Generate the NT-Response */
864 ChapMS2_NT((char *)rchallenge, response->PeerChallenge, user,
865 secret, secret_len, response->NTResp);
867 /* Generate the Authenticator Response. */
868 GenerateAuthenticatorResponsePlain(secret, secret_len, response->NTResp,
869 response->PeerChallenge, rchallenge,
873 SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
879 * Set MPPE options from plugins.
882 set_mppe_enc_types(int policy, int types)
884 /* Early exit for unknown policies. */
885 if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
886 policy != MPPE_ENC_POL_ENC_REQUIRED)
889 /* Don't modify MPPE if it's optional and wasn't already configured. */
890 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
894 * Disable undesirable encryption types. Note that we don't ENABLE
895 * any encryption types, to avoid overriding manual configuration.
898 case MPPE_ENC_TYPES_RC4_40:
899 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
901 case MPPE_ENC_TYPES_RC4_128:
902 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */
910 static struct chap_digest_type chapms_digest = {
911 CHAP_MICROSOFT, /* code */
912 chapms_generate_challenge,
913 chapms_verify_response,
914 chapms_make_response,
915 NULL, /* check_success */
916 chapms_handle_failure,
919 static struct chap_digest_type chapms2_digest = {
920 CHAP_MICROSOFT_V2, /* code */
921 chapms2_generate_challenge,
922 chapms2_verify_response,
923 chapms2_make_response,
924 chapms2_check_success,
925 chapms_handle_failure,
931 chap_register_digest(&chapms_digest);
932 chap_register_digest(&chapms2_digest);
933 add_options(chapms_option_list);