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.29 2003/06/11 23:56:26 paulus Exp $"
85 #include <sys/types.h>
97 static const char rcsid[] = RCSID;
100 static void ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
101 static void ascii2unicode __P((char[], int, u_char[]));
102 static void NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
103 static void ChallengeResponse __P((u_char *, u_char *, u_char[24]));
104 static void ChapMS_NT __P((u_char *, char *, int, u_char[24]));
105 static void ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
107 static void GenerateAuthenticatorResponse __P((char*, int, u_char[24],
108 u_char[16], u_char *,
109 char *, u_char[41]));
111 static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
115 static void Set_Start_Key __P((u_char *, char *, int));
116 static void SetMasterKeys __P((char *, int, u_char[24], int));
120 bool ms_lanman = 0; /* Use LanMan password instead of NT */
121 /* Has meaning only with MS-CHAP challenges */
125 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
126 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
127 int mppe_keys_set = 0; /* Have the MPPE keys been set? */
130 /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
131 static char *mschap_challenge = NULL;
132 /* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
133 static char *mschap2_peer_challenge = NULL;
135 #include "fsm.h" /* Need to poke MPPE options */
137 #include <net/ppp-comp.h>
141 * Command-line options.
143 static option_t chapms_option_list[] = {
145 { "ms-lanman", o_bool, &ms_lanman,
146 "Use LanMan passwd when using MS-CHAP", 1 },
149 { "mschap-challenge", o_string, &mschap_challenge,
150 "specify CHAP challenge" },
151 { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
152 "specify CHAP peer challenge" },
158 * chapms_generate_challenge - generate a challenge for MS-CHAP.
159 * For MS-CHAP the challenge length is fixed at 8 bytes.
160 * The length goes in challenge[0] and the actual challenge starts
164 chapms_generate_challenge(unsigned char *challenge)
167 if (mschap_challenge && strlen(mschap_challenge) == 8)
168 memcpy(challenge, mschap_challenge, 8);
170 random_bytes(challenge, 8);
174 chapms2_generate_challenge(unsigned char *challenge)
177 if (mschap_challenge && strlen(mschap_challenge) == 16)
178 memcpy(challenge, mschap_challenge, 16);
180 random_bytes(challenge, 16);
184 chapms_verify_response(int id, char *name,
185 unsigned char *secret, int secret_len,
186 unsigned char *challenge, unsigned char *response,
187 char *message, int message_space)
189 MS_ChapResponse *rmd = (MS_ChapResponse *) response;
192 int challenge_len, response_len;
194 challenge_len = *challenge++; /* skip length, is 8 */
196 response_len = *response++;
197 if (response_len != MS_CHAP_RESPONSE_LEN)
201 if (!rmd->UseNT[0]) {
202 /* Should really propagate this into the error packet. */
203 notice("Peer request for LANMAN auth not supported");
208 /* Generate the expected response. */
209 ChapMS(challenge, secret, secret_len, &md);
212 /* Determine which part of response to verify against */
214 diff = memcmp(&rmd->LANManResp, &md.LANManResp,
215 sizeof(md.LANManResp));
218 diff = memcmp(&rmd->NTResp, &md.NTResp, sizeof(md.NTResp));
221 slprintf(message, message_space, "Access granted");
226 /* See comments below for MS-CHAP V2 */
227 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
228 challenge_len, challenge);
233 chapms2_verify_response(int id, char *name,
234 unsigned char *secret, int secret_len,
235 unsigned char *challenge, unsigned char *response,
236 char *message, int message_space)
238 MS_Chap2Response *rmd = (MS_Chap2Response *) response;
240 char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
241 int challenge_len, response_len;
243 challenge_len = *challenge++; /* skip length, is 16 */
244 response_len = *response++;
245 if (response_len != MS_CHAP2_RESPONSE_LEN)
246 goto bad; /* not even the right length */
248 /* Generate the expected response and our mutual auth. */
249 ChapMS2(challenge, rmd->PeerChallenge, name,
250 secret, secret_len, &md,
251 saresponse, MS_CHAP2_AUTHENTICATOR);
253 /* compare MDs and send the appropriate status */
255 * Per RFC 2759, success message must be formatted as
256 * "S=<auth_string> M=<message>"
258 * <auth_string> is the Authenticator Response (mutual auth)
259 * <message> is a text message
261 * However, some versions of Windows (win98 tested) do not know
262 * about the M=<message> part (required per RFC 2759) and flag
263 * it as an error (reported incorrectly as an encryption error
264 * to the user). Since the RFC requires it, and it can be
265 * useful information, we supply it if the peer is a conforming
266 * system. Luckily (?), win98 sets the Flags field to 0x04
267 * (contrary to RFC requirements) so we can use that to
268 * distinguish between conforming and non-conforming systems.
270 * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
271 * help debugging this.
273 if (memcmp(md.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) {
275 slprintf(message, message_space, "S=%s", saresponse);
277 slprintf(message, message_space, "S=%s M=%s",
278 saresponse, "Access granted");
284 * Failure message must be formatted as
285 * "E=e R=r C=c V=v M=m"
287 * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
288 * r = retry (we use 1, ok to retry)
289 * c = challenge to use for next response, we reuse previous
290 * v = Change Password version supported, we use 0
293 * The M=m part is only for MS-CHAPv2. Neither win2k nor
294 * win98 (others untested) display the message to the user anyway.
295 * They also both ignore the E=e code.
297 * Note that it's safe to reuse the same challenge as we don't
298 * actually accept another response based on the error message
299 * (and no clients try to resend a response anyway).
301 * Basically, this whole bit is useless code, even the small
302 * implementation here is only because of overspecification.
304 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
305 challenge_len, challenge, "Access denied");
310 chapms_make_response(unsigned char *response, int id, char *our_name,
311 unsigned char *challenge, char *secret, int secret_len,
312 unsigned char *private)
314 challenge++; /* skip length, should be 8 */
315 *response++ = MS_CHAP_RESPONSE_LEN;
316 ChapMS(challenge, secret, secret_len, (MS_ChapResponse *) response);
320 chapms2_make_response(unsigned char *response, int id, char *our_name,
321 unsigned char *challenge, char *secret, int secret_len,
322 unsigned char *private)
324 challenge++; /* skip length, should be 16 */
325 *response++ = MS_CHAP2_RESPONSE_LEN;
326 ChapMS2(challenge, mschap2_peer_challenge, our_name,
328 (MS_Chap2Response *) response, private,
329 MS_CHAP2_AUTHENTICATEE);
333 chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
335 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) || strncmp(msg, "S=", 2)) {
336 /* Packet does not start with "S=" */
337 error("MS-CHAPv2 Success packet is badly formed.");
342 if (len < MS_AUTH_RESPONSE_LENGTH
343 || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
344 /* Authenticator Response did not match expected. */
345 error("MS-CHAPv2 mutual authentication failed.");
348 /* Authenticator Response matches. */
349 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
350 len -= MS_AUTH_RESPONSE_LENGTH;
351 if ((len >= 3) && !strncmp(msg, " M=", 3)) {
352 msg += 3; /* Eat the delimiter */
354 /* Packet has extra text which does not begin " M=" */
355 error("MS-CHAPv2 Success packet is badly formed.");
362 chapms_handle_failure(unsigned char *inp, int len)
367 /* We want a null-terminated string for strxxx(). */
368 msg = malloc(len + 1);
370 notice("Out of memory in chapms_handle_failure");
373 BCOPY(inp, msg, len);
378 * Deal with MS-CHAP formatted failure messages; just print the
379 * M=<message> part (if any). For MS-CHAP we're not really supposed
380 * to use M=<message>, but it shouldn't hurt. See
381 * chapms[2]_verify_response.
383 if (!strncmp(p, "E=", 2))
384 err = strtol(p, NULL, 10); /* Remember the error code. */
386 goto print_msg; /* Message is badly formatted. */
388 if (len && ((p = strstr(p, " M=")) != NULL)) {
389 /* M=<message> field found. */
392 /* No M=<message>; use the error code. */
394 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
395 p = "E=646 Restricted logon hours";
398 case MS_CHAP_ERROR_ACCT_DISABLED:
399 p = "E=647 Account disabled";
402 case MS_CHAP_ERROR_PASSWD_EXPIRED:
403 p = "E=648 Password expired";
406 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
407 p = "E=649 No dialin permission";
410 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
411 p = "E=691 Authentication failure";
414 case MS_CHAP_ERROR_CHANGING_PASSWORD:
415 /* Should never see this, we don't support Change Password. */
416 p = "E=709 Error changing password";
421 error("Unknown MS-CHAP authentication failure: %.*v",
428 error("MS-CHAP authentication failed: %v", p);
433 ChallengeResponse(u_char *challenge,
434 u_char PasswordHash[MD4_SIGNATURE_SIZE],
437 u_char ZPasswordHash[21];
439 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
440 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
443 dbglog("ChallengeResponse - ZPasswordHash %.*B",
444 sizeof(ZPasswordHash), ZPasswordHash);
447 (void) DesSetkey(ZPasswordHash + 0);
448 DesEncrypt(challenge, response + 0);
449 (void) DesSetkey(ZPasswordHash + 7);
450 DesEncrypt(challenge, response + 8);
451 (void) DesSetkey(ZPasswordHash + 14);
452 DesEncrypt(challenge, response + 16);
455 dbglog("ChallengeResponse - response %.24B", response);
460 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
461 char *username, u_char Challenge[8])
464 SHA1_CTX sha1Context;
465 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
468 /* remove domain from "domain\username" */
469 if ((user = strrchr(username, '\\')) != NULL)
474 SHA1_Init(&sha1Context);
475 SHA1_Update(&sha1Context, PeerChallenge, 16);
476 SHA1_Update(&sha1Context, rchallenge, 16);
477 SHA1_Update(&sha1Context, user, strlen(user));
478 SHA1_Final(sha1Hash, &sha1Context);
480 BCOPY(sha1Hash, Challenge, 8);
484 * Convert the ASCII version of the password to Unicode.
485 * This implicitly supports 8-bit ISO8859/1 characters.
486 * This gives us the little-endian representation, which
487 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
488 * is machine-dependent.)
491 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
495 BZERO(unicode, ascii_len * 2);
496 for (i = 0; i < ascii_len; i++)
497 unicode[i * 2] = (u_char) ascii[i];
501 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
504 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
505 int mdlen = secret_len;
507 int mdlen = secret_len * 8;
511 MD4Init(&md4Context);
512 MD4Update(&md4Context, secret, mdlen);
513 MD4Final(hash, &md4Context);
518 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
519 u_char NTResponse[24])
521 u_char unicodePassword[MAX_NT_PASSWORD * 2];
522 u_char PasswordHash[MD4_SIGNATURE_SIZE];
524 /* Hash the Unicode version of the secret (== password). */
525 ascii2unicode(secret, secret_len, unicodePassword);
526 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
528 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
532 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
533 char *secret, int secret_len, u_char NTResponse[24])
535 u_char unicodePassword[MAX_NT_PASSWORD * 2];
536 u_char PasswordHash[MD4_SIGNATURE_SIZE];
539 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
541 /* Hash the Unicode version of the secret (== password). */
542 ascii2unicode(secret, secret_len, unicodePassword);
543 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
545 ChallengeResponse(Challenge, PasswordHash, NTResponse);
549 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
552 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
553 MS_ChapResponse *response)
556 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
557 u_char PasswordHash[MD4_SIGNATURE_SIZE];
559 /* LANMan password is case insensitive */
560 BZERO(UcasePassword, sizeof(UcasePassword));
561 for (i = 0; i < secret_len; i++)
562 UcasePassword[i] = (u_char)toupper(secret[i]);
563 (void) DesSetkey(UcasePassword + 0);
564 DesEncrypt( StdText, PasswordHash + 0 );
565 (void) DesSetkey(UcasePassword + 7);
566 DesEncrypt( StdText, PasswordHash + 8 );
567 ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
573 GenerateAuthenticatorResponse(char *secret, int secret_len,
574 u_char NTResponse[24], u_char PeerChallenge[16],
575 u_char *rchallenge, char *username,
576 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
579 * "Magic" constants used in response generation, from RFC 2759.
581 u_char Magic1[39] = /* "Magic server to client signing constant" */
582 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
583 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
584 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
585 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
586 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
587 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
588 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
589 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
590 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
594 SHA1_CTX sha1Context;
595 u_char unicodePassword[MAX_NT_PASSWORD * 2];
596 u_char PasswordHash[MD4_SIGNATURE_SIZE];
597 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
598 u_char Digest[SHA1_SIGNATURE_SIZE];
601 /* Hash (x2) the Unicode version of the secret (== password). */
602 ascii2unicode(secret, secret_len, unicodePassword);
603 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
604 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
606 SHA1_Init(&sha1Context);
607 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
608 SHA1_Update(&sha1Context, NTResponse, 24);
609 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
610 SHA1_Final(Digest, &sha1Context);
612 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
614 SHA1_Init(&sha1Context);
615 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
616 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
617 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
618 SHA1_Final(Digest, &sha1Context);
620 /* Convert to ASCII hex string. */
621 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
622 sprintf(&authResponse[i * 2], "%02X", Digest[i]);
628 * Set mppe_xxxx_key from the NTPasswordHashHash.
629 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
632 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
634 SHA1_CTX sha1Context;
635 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
637 SHA1_Init(&sha1Context);
638 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
639 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
640 SHA1_Update(&sha1Context, rchallenge, 8);
641 SHA1_Final(Digest, &sha1Context);
643 /* Same key in both directions. */
644 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
645 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
649 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
652 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
654 u_char unicodePassword[MAX_NT_PASSWORD * 2];
655 u_char PasswordHash[MD4_SIGNATURE_SIZE];
656 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
658 /* Hash (x2) the Unicode version of the secret (== password). */
659 ascii2unicode(secret, secret_len, unicodePassword);
660 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
661 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
663 mppe_set_keys(rchallenge, PasswordHashHash);
667 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
670 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
672 SHA1_CTX sha1Context;
673 u_char unicodePassword[MAX_NT_PASSWORD * 2];
674 u_char PasswordHash[MD4_SIGNATURE_SIZE];
675 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
676 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
677 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
680 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
682 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
683 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
685 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
686 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
687 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
688 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
690 /* "This is the MPPE Master Key" */
692 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
693 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
694 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
695 /* "On the client side, this is the send key; "
696 "on the server side, it is the receive key." */
698 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
699 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
700 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
701 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
702 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
703 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
704 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
705 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
706 0x6b, 0x65, 0x79, 0x2e };
707 /* "On the client side, this is the receive key; "
708 "on the server side, it is the send key." */
710 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
711 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
712 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
713 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
714 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
715 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
716 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
717 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
718 0x6b, 0x65, 0x79, 0x2e };
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), PasswordHashHash);
726 SHA1_Init(&sha1Context);
727 SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
728 SHA1_Update(&sha1Context, NTResponse, 24);
729 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
730 SHA1_Final(MasterKey, &sha1Context);
739 SHA1_Init(&sha1Context);
740 SHA1_Update(&sha1Context, MasterKey, 16);
741 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
742 SHA1_Update(&sha1Context, s, 84);
743 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
744 SHA1_Final(Digest, &sha1Context);
746 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
755 SHA1_Init(&sha1Context);
756 SHA1_Update(&sha1Context, MasterKey, 16);
757 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
758 SHA1_Update(&sha1Context, s, 84);
759 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
760 SHA1_Final(Digest, &sha1Context);
762 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
769 ChapMS(u_char *rchallenge, char *secret, int secret_len,
770 MS_ChapResponse *response)
773 CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
775 BZERO(response, sizeof(*response));
777 ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
780 ChapMS_LANMan(rchallenge, secret, secret_len, response);
782 /* preferred method is set by option */
783 response->UseNT[0] = !ms_lanman;
785 response->UseNT[0] = 1;
789 Set_Start_Key(rchallenge, secret, secret_len);
796 * If PeerChallenge is NULL, one is generated and response->PeerChallenge
797 * is filled in. Call this way when generating a response.
798 * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
799 * Call this way when verifying a response (or debugging).
800 * Do not call with PeerChallenge = response->PeerChallenge.
802 * response->PeerChallenge is then used for calculation of the
803 * Authenticator Response.
806 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
807 char *user, char *secret, int secret_len, MS_Chap2Response *response,
808 u_char authResponse[], int authenticator)
811 u_char *p = response->PeerChallenge;
814 BZERO(response, sizeof(*response));
816 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
818 for (i = 0; i < sizeof(response->PeerChallenge); i++)
819 *p++ = (u_char) (drand48() * 0xff);
821 BCOPY(PeerChallenge, response->PeerChallenge,
822 sizeof(response->PeerChallenge));
824 /* Generate the NT-Response */
825 ChapMS2_NT(rchallenge, response->PeerChallenge, user,
826 secret, secret_len, response->NTResp);
828 /* Generate the Authenticator Response. */
829 GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
830 response->PeerChallenge, rchallenge,
834 SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
841 * Set MPPE options from plugins.
844 set_mppe_enc_types(int policy, int types)
846 /* Early exit for unknown policies. */
847 if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
848 policy != MPPE_ENC_POL_ENC_REQUIRED)
851 /* Don't modify MPPE if it's optional and wasn't already configured. */
852 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
856 * Disable undesirable encryption types. Note that we don't ENABLE
857 * any encryption types, to avoid overriding manual configuration.
860 case MPPE_ENC_TYPES_RC4_40:
861 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
863 case MPPE_ENC_TYPES_RC4_128:
864 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */
872 static struct chap_digest_type chapms_digest = {
873 CHAP_MICROSOFT, /* code */
874 chapms_generate_challenge,
875 chapms_verify_response,
876 chapms_make_response,
877 NULL, /* check_success */
878 chapms_handle_failure,
881 static struct chap_digest_type chapms2_digest = {
882 CHAP_MICROSOFT_V2, /* code */
883 chapms2_generate_challenge,
884 chapms2_verify_response,
885 chapms2_make_response,
886 chapms2_check_success,
887 chapms_handle_failure,
893 chap_register_digest(&chapms_digest);
894 chap_register_digest(&chapms2_digest);
895 add_options(chapms_option_list);