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.38 2007/12/01 20:10:51 carlsonj 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((u_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((u_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, u_char *));
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? */
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;
136 #include "fsm.h" /* Need to poke MPPE options */
138 #include <net/ppp-comp.h>
142 * Command-line options.
144 static option_t chapms_option_list[] = {
146 { "ms-lanman", o_bool, &ms_lanman,
147 "Use LanMan passwd when using MS-CHAP", 1 },
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" },
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
165 chapms_generate_challenge(unsigned char *challenge)
169 if (mschap_challenge && strlen(mschap_challenge) == 8)
170 memcpy(challenge, mschap_challenge, 8);
173 random_bytes(challenge, 8);
177 chapms2_generate_challenge(unsigned char *challenge)
181 if (mschap_challenge && strlen(mschap_challenge) == 16)
182 memcpy(challenge, mschap_challenge, 16);
185 random_bytes(challenge, 16);
189 chapms_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)
194 unsigned char md[MS_CHAP_RESPONSE_LEN];
196 int challenge_len, response_len;
198 challenge_len = *challenge++; /* skip length, is 8 */
199 response_len = *response++;
200 if (response_len != MS_CHAP_RESPONSE_LEN)
204 if (!response[MS_CHAP_USENT]) {
205 /* Should really propagate this into the error packet. */
206 notice("Peer request for LANMAN auth not supported");
211 /* Generate the expected response. */
212 ChapMS(challenge, (char *)secret, secret_len, md);
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);
221 diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_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 unsigned char md[MS_CHAP2_RESPONSE_LEN];
243 char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
244 int challenge_len, response_len;
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 */
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);
256 /* compare MDs and send the appropriate status */
258 * Per RFC 2759, success message must be formatted as
259 * "S=<auth_string> M=<message>"
261 * <auth_string> is the Authenticator Response (mutual auth)
262 * <message> is a text message
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.
273 * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
274 * help debugging this.
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);
281 slprintf(message, message_space, "S=%s M=%s",
282 saresponse, "Access granted");
288 * Failure message must be formatted as
289 * "E=e R=r C=c V=v M=m"
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
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.
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).
305 * Basically, this whole bit is useless code, even the small
306 * implementation here is only because of overspecification.
308 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
309 challenge_len, challenge, "Access denied");
314 chapms_make_response(unsigned char *response, int id, char *our_name,
315 unsigned char *challenge, char *secret, int secret_len,
316 unsigned char *private)
318 challenge++; /* skip length, should be 8 */
319 *response++ = MS_CHAP_RESPONSE_LEN;
320 ChapMS(challenge, secret, secret_len, response);
323 struct chapms2_response_cache_entry {
325 unsigned char challenge[16];
326 unsigned char response[MS_CHAP2_RESPONSE_LEN];
327 unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH];
330 #define CHAPMS2_MAX_RESPONSE_CACHE_SIZE 10
331 static struct chapms2_response_cache_entry
332 chapms2_response_cache[CHAPMS2_MAX_RESPONSE_CACHE_SIZE];
333 static int chapms2_response_cache_next_index = 0;
334 static int chapms2_response_cache_size = 0;
337 chapms2_add_to_response_cache(int id, unsigned char *challenge,
338 unsigned char *response,
339 unsigned char *auth_response)
341 int i = chapms2_response_cache_next_index;
343 chapms2_response_cache[i].id = id;
344 memcpy(chapms2_response_cache[i].challenge, challenge, 16);
345 memcpy(chapms2_response_cache[i].response, response,
346 MS_CHAP2_RESPONSE_LEN);
347 memcpy(chapms2_response_cache[i].auth_response,
348 auth_response, MS_AUTH_RESPONSE_LENGTH);
349 chapms2_response_cache_next_index =
350 (i + 1) % CHAPMS2_MAX_RESPONSE_CACHE_SIZE;
351 if (chapms2_response_cache_next_index > chapms2_response_cache_size)
352 chapms2_response_cache_size = chapms2_response_cache_next_index;
353 dbglog("added response cache entry %d", i);
356 static struct chapms2_response_cache_entry*
357 chapms2_find_in_response_cache(int id, unsigned char *challenge,
358 unsigned char *auth_response)
362 for (i = 0; i < chapms2_response_cache_size; i++) {
363 if (id == chapms2_response_cache[i].id
366 chapms2_response_cache[i].challenge,
369 || memcmp(auth_response,
370 chapms2_response_cache[i].auth_response,
371 MS_AUTH_RESPONSE_LENGTH) == 0)) {
372 dbglog("response found in cache (entry %d)", i);
373 return &chapms2_response_cache[i];
376 return NULL; /* not found */
380 chapms2_make_response(unsigned char *response, int id, char *our_name,
381 unsigned char *challenge, char *secret, int secret_len,
382 unsigned char *private)
384 const struct chapms2_response_cache_entry *cache_entry;
385 unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH];
387 challenge++; /* skip length, should be 16 */
388 *response++ = MS_CHAP2_RESPONSE_LEN;
389 cache_entry = chapms2_find_in_response_cache(id, challenge, NULL);
391 memcpy(response, cache_entry->response, MS_CHAP2_RESPONSE_LEN);
396 mschap2_peer_challenge,
400 our_name, secret, secret_len, response, auth_response,
401 MS_CHAP2_AUTHENTICATEE);
402 chapms2_add_to_response_cache(id, challenge, response, auth_response);
406 chapms2_check_success(int id, unsigned char *msg, int len)
408 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
409 strncmp((char *)msg, "S=", 2) != 0) {
410 /* Packet does not start with "S=" */
411 error("MS-CHAPv2 Success packet is badly formed.");
416 if (len < MS_AUTH_RESPONSE_LENGTH
417 || !chapms2_find_in_response_cache(id, NULL /* challenge */, msg)) {
418 /* Authenticator Response did not match expected. */
419 error("MS-CHAPv2 mutual authentication failed.");
422 /* Authenticator Response matches. */
423 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
424 len -= MS_AUTH_RESPONSE_LENGTH;
425 if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
426 msg += 3; /* Eat the delimiter */
428 /* Packet has extra text which does not begin " M=" */
429 error("MS-CHAPv2 Success packet is badly formed.");
436 chapms_handle_failure(unsigned char *inp, int len)
441 /* We want a null-terminated string for strxxx(). */
442 msg = malloc(len + 1);
444 notice("Out of memory in chapms_handle_failure");
447 BCOPY(inp, msg, len);
452 * Deal with MS-CHAP formatted failure messages; just print the
453 * M=<message> part (if any). For MS-CHAP we're not really supposed
454 * to use M=<message>, but it shouldn't hurt. See
455 * chapms[2]_verify_response.
457 if (!strncmp(p, "E=", 2))
458 err = strtol(p+2, NULL, 10); /* Remember the error code. */
460 goto print_msg; /* Message is badly formatted. */
462 if (len && ((p = strstr(p, " M=")) != NULL)) {
463 /* M=<message> field found. */
466 /* No M=<message>; use the error code. */
468 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
469 p = "E=646 Restricted logon hours";
472 case MS_CHAP_ERROR_ACCT_DISABLED:
473 p = "E=647 Account disabled";
476 case MS_CHAP_ERROR_PASSWD_EXPIRED:
477 p = "E=648 Password expired";
480 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
481 p = "E=649 No dialin permission";
484 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
485 p = "E=691 Authentication failure";
488 case MS_CHAP_ERROR_CHANGING_PASSWORD:
489 /* Should never see this, we don't support Change Password. */
490 p = "E=709 Error changing password";
495 error("Unknown MS-CHAP authentication failure: %.*v",
502 error("MS-CHAP authentication failed: %v", p);
507 ChallengeResponse(u_char *challenge,
508 u_char PasswordHash[MD4_SIGNATURE_SIZE],
511 u_char ZPasswordHash[21];
513 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
514 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
517 dbglog("ChallengeResponse - ZPasswordHash %.*B",
518 sizeof(ZPasswordHash), ZPasswordHash);
521 (void) DesSetkey(ZPasswordHash + 0);
522 DesEncrypt(challenge, response + 0);
523 (void) DesSetkey(ZPasswordHash + 7);
524 DesEncrypt(challenge, response + 8);
525 (void) DesSetkey(ZPasswordHash + 14);
526 DesEncrypt(challenge, response + 16);
529 dbglog("ChallengeResponse - response %.24B", response);
534 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
535 char *username, u_char Challenge[8])
538 SHA1_CTX sha1Context;
539 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
542 /* remove domain from "domain\username" */
543 if ((user = strrchr(username, '\\')) != NULL)
548 SHA1_Init(&sha1Context);
549 SHA1_Update(&sha1Context, PeerChallenge, 16);
550 SHA1_Update(&sha1Context, rchallenge, 16);
551 SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
552 SHA1_Final(sha1Hash, &sha1Context);
554 BCOPY(sha1Hash, Challenge, 8);
558 * Convert the ASCII version of the password to Unicode.
559 * This implicitly supports 8-bit ISO8859/1 characters.
560 * This gives us the little-endian representation, which
561 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
562 * is machine-dependent.)
565 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
569 BZERO(unicode, ascii_len * 2);
570 for (i = 0; i < ascii_len; i++)
571 unicode[i * 2] = (u_char) ascii[i];
575 NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
578 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
579 int mdlen = secret_len;
581 int mdlen = secret_len * 8;
585 MD4Init(&md4Context);
586 /* MD4Update can take at most 64 bytes at a time */
587 while (mdlen > 512) {
588 MD4Update(&md4Context, secret, 512);
592 MD4Update(&md4Context, secret, mdlen);
593 MD4Final(hash, &md4Context);
598 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
599 u_char NTResponse[24])
601 u_char unicodePassword[MAX_NT_PASSWORD * 2];
602 u_char PasswordHash[MD4_SIGNATURE_SIZE];
604 /* Hash the Unicode version of the secret (== password). */
605 ascii2unicode(secret, secret_len, unicodePassword);
606 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
608 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
612 ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username,
613 char *secret, int secret_len, u_char NTResponse[24])
615 u_char unicodePassword[MAX_NT_PASSWORD * 2];
616 u_char PasswordHash[MD4_SIGNATURE_SIZE];
619 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
621 /* Hash the Unicode version of the secret (== password). */
622 ascii2unicode(secret, secret_len, unicodePassword);
623 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
625 ChallengeResponse(Challenge, PasswordHash, NTResponse);
629 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
632 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
633 unsigned char *response)
636 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
637 u_char PasswordHash[MD4_SIGNATURE_SIZE];
639 /* LANMan password is case insensitive */
640 BZERO(UcasePassword, sizeof(UcasePassword));
641 for (i = 0; i < secret_len; i++)
642 UcasePassword[i] = (u_char)toupper(secret[i]);
643 (void) DesSetkey(UcasePassword + 0);
644 DesEncrypt( StdText, PasswordHash + 0 );
645 (void) DesSetkey(UcasePassword + 7);
646 DesEncrypt( StdText, PasswordHash + 8 );
647 ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]);
653 GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
654 u_char NTResponse[24], u_char PeerChallenge[16],
655 u_char *rchallenge, char *username,
656 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
659 * "Magic" constants used in response generation, from RFC 2759.
661 u_char Magic1[39] = /* "Magic server to client signing constant" */
662 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
663 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
664 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
665 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
666 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
667 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
668 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
669 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
670 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
674 SHA1_CTX sha1Context;
675 u_char Digest[SHA1_SIGNATURE_SIZE];
678 SHA1_Init(&sha1Context);
679 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
680 SHA1_Update(&sha1Context, NTResponse, 24);
681 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
682 SHA1_Final(Digest, &sha1Context);
684 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
686 SHA1_Init(&sha1Context);
687 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
688 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
689 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
690 SHA1_Final(Digest, &sha1Context);
692 /* Convert to ASCII hex string. */
693 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
694 sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
699 GenerateAuthenticatorResponsePlain
700 (char *secret, int secret_len,
701 u_char NTResponse[24], u_char PeerChallenge[16],
702 u_char *rchallenge, char *username,
703 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
705 u_char unicodePassword[MAX_NT_PASSWORD * 2];
706 u_char PasswordHash[MD4_SIGNATURE_SIZE];
707 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
709 /* Hash (x2) the Unicode version of the secret (== password). */
710 ascii2unicode(secret, secret_len, unicodePassword);
711 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
712 NTPasswordHash(PasswordHash, sizeof(PasswordHash),
715 GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
716 rchallenge, username, authResponse);
722 * Set mppe_xxxx_key from the NTPasswordHashHash.
723 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
726 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
728 SHA1_CTX sha1Context;
729 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
731 SHA1_Init(&sha1Context);
732 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
733 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
734 SHA1_Update(&sha1Context, rchallenge, 8);
735 SHA1_Final(Digest, &sha1Context);
737 /* Same key in both directions. */
738 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
739 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
745 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
748 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
750 u_char unicodePassword[MAX_NT_PASSWORD * 2];
751 u_char PasswordHash[MD4_SIGNATURE_SIZE];
752 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
754 /* Hash (x2) the Unicode version of the secret (== password). */
755 ascii2unicode(secret, secret_len, unicodePassword);
756 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
757 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
759 mppe_set_keys(rchallenge, PasswordHashHash);
763 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
765 * This helper function used in the Winbind module, which gets the
766 * NTHashHash from the server.
769 mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
770 u_char NTResponse[24], int IsServer)
772 SHA1_CTX sha1Context;
773 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
774 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
777 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
778 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
782 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
783 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
784 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
785 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
787 /* "This is the MPPE Master Key" */
789 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
790 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
791 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
792 /* "On the client side, this is the send key; "
793 "on the server side, it is the receive key." */
795 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
796 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
797 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
798 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
799 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
800 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
801 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
802 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
803 0x6b, 0x65, 0x79, 0x2e };
804 /* "On the client side, this is the receive key; "
805 "on the server side, it is the send key." */
807 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
808 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
809 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
810 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
811 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
812 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
813 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
814 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
815 0x6b, 0x65, 0x79, 0x2e };
818 SHA1_Init(&sha1Context);
819 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
820 SHA1_Update(&sha1Context, NTResponse, 24);
821 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
822 SHA1_Final(MasterKey, &sha1Context);
831 SHA1_Init(&sha1Context);
832 SHA1_Update(&sha1Context, MasterKey, 16);
833 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
834 SHA1_Update(&sha1Context, s, 84);
835 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
836 SHA1_Final(Digest, &sha1Context);
838 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
847 SHA1_Init(&sha1Context);
848 SHA1_Update(&sha1Context, MasterKey, 16);
849 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
850 SHA1_Update(&sha1Context, s, 84);
851 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
852 SHA1_Final(Digest, &sha1Context);
854 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
860 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
863 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
865 u_char unicodePassword[MAX_NT_PASSWORD * 2];
866 u_char PasswordHash[MD4_SIGNATURE_SIZE];
867 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
868 /* Hash (x2) the Unicode version of the secret (== password). */
869 ascii2unicode(secret, secret_len, unicodePassword);
870 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
871 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
872 mppe_set_keys2(PasswordHashHash, NTResponse, IsServer);
879 ChapMS(u_char *rchallenge, char *secret, int secret_len,
880 unsigned char *response)
882 BZERO(response, MS_CHAP_RESPONSE_LEN);
884 ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
887 ChapMS_LANMan(rchallenge, secret, secret_len,
888 &response[MS_CHAP_LANMANRESP]);
890 /* preferred method is set by option */
891 response[MS_CHAP_USENT] = !ms_lanman;
893 response[MS_CHAP_USENT] = 1;
897 Set_Start_Key(rchallenge, secret, secret_len);
903 * If PeerChallenge is NULL, one is generated and the PeerChallenge
904 * field of response is filled in. Call this way when generating a response.
905 * If PeerChallenge is supplied, it is copied into the PeerChallenge field.
906 * Call this way when verifying a response (or debugging).
907 * Do not call with PeerChallenge = response.
909 * The PeerChallenge field of response is then used for calculation of the
910 * Authenticator Response.
913 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
914 char *user, char *secret, int secret_len, unsigned char *response,
915 u_char authResponse[], int authenticator)
918 u_char *p = &response[MS_CHAP2_PEER_CHALLENGE];
921 BZERO(response, MS_CHAP2_RESPONSE_LEN);
923 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
925 for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++)
926 *p++ = (u_char) (drand48() * 0xff);
928 BCOPY(PeerChallenge, &response[MS_CHAP2_PEER_CHALLENGE],
929 MS_CHAP2_PEER_CHAL_LEN);
931 /* Generate the NT-Response */
932 ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
933 secret, secret_len, &response[MS_CHAP2_NTRESP]);
935 /* Generate the Authenticator Response. */
936 GenerateAuthenticatorResponsePlain(secret, secret_len,
937 &response[MS_CHAP2_NTRESP],
938 &response[MS_CHAP2_PEER_CHALLENGE],
939 rchallenge, user, authResponse);
942 SetMasterKeys(secret, secret_len,
943 &response[MS_CHAP2_NTRESP], authenticator);
949 * Set MPPE options from plugins.
952 set_mppe_enc_types(int policy, int types)
954 /* Early exit for unknown policies. */
955 if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
956 policy != MPPE_ENC_POL_ENC_REQUIRED)
959 /* Don't modify MPPE if it's optional and wasn't already configured. */
960 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
964 * Disable undesirable encryption types. Note that we don't ENABLE
965 * any encryption types, to avoid overriding manual configuration.
968 case MPPE_ENC_TYPES_RC4_40:
969 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
971 case MPPE_ENC_TYPES_RC4_128:
972 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */
980 static struct chap_digest_type chapms_digest = {
981 CHAP_MICROSOFT, /* code */
982 chapms_generate_challenge,
983 chapms_verify_response,
984 chapms_make_response,
985 NULL, /* check_success */
986 chapms_handle_failure,
989 static struct chap_digest_type chapms2_digest = {
990 CHAP_MICROSOFT_V2, /* code */
991 chapms2_generate_challenge,
992 chapms2_verify_response,
993 chapms2_make_response,
994 chapms2_check_success,
995 chapms_handle_failure,
1001 chap_register_digest(&chapms_digest);
1002 chap_register_digest(&chapms2_digest);
1003 add_options(chapms_option_list);