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>
99 static void ascii2unicode (char[], int, u_char[]);
100 static void NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]);
101 static void ChallengeResponse (u_char *, u_char *, u_char[24]);
102 static void ChapMS_NT (u_char *, char *, int, u_char[24]);
103 static void ChapMS2_NT (u_char *, u_char[16], char *, char *, int,
105 static void GenerateAuthenticatorResponsePlain
106 (char*, int, u_char[24], u_char[16], u_char *,
109 static void ChapMS_LANMan (u_char *, char *, int, u_char *);
113 static void Set_Start_Key (u_char *, char *, int);
114 static void SetMasterKeys (char *, int, u_char[24], int);
118 bool ms_lanman = 0; /* Use LanMan password instead of NT */
119 /* Has meaning only with MS-CHAP challenges */
123 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
124 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
125 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;
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)
168 if (mschap_challenge && strlen(mschap_challenge) == 8)
169 memcpy(challenge, mschap_challenge, 8);
172 random_bytes(challenge, 8);
176 chapms2_generate_challenge(unsigned char *challenge)
180 if (mschap_challenge && strlen(mschap_challenge) == 16)
181 memcpy(challenge, mschap_challenge, 16);
184 random_bytes(challenge, 16);
188 chapms_verify_response(int id, char *name,
189 unsigned char *secret, int secret_len,
190 unsigned char *challenge, unsigned char *response,
191 char *message, int message_space)
193 unsigned char md[MS_CHAP_RESPONSE_LEN];
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)
203 if (!response[MS_CHAP_USENT]) {
204 /* Should really propagate this into the error packet. */
205 notice("Peer request for LANMAN auth not supported");
210 /* Generate the expected response. */
211 ChapMS(challenge, (char *)secret, secret_len, md);
214 /* Determine which part of response to verify against */
215 if (!response[MS_CHAP_USENT])
216 diff = memcmp(&response[MS_CHAP_LANMANRESP],
217 &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN);
220 diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP],
224 slprintf(message, message_space, "Access granted");
229 /* See comments below for MS-CHAP V2 */
230 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
231 challenge_len, challenge);
236 chapms2_verify_response(int id, char *name,
237 unsigned char *secret, int secret_len,
238 unsigned char *challenge, unsigned char *response,
239 char *message, int message_space)
241 unsigned char md[MS_CHAP2_RESPONSE_LEN];
242 char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
243 int challenge_len, response_len;
245 challenge_len = *challenge++; /* skip length, is 16 */
246 response_len = *response++;
247 if (response_len != MS_CHAP2_RESPONSE_LEN)
248 goto bad; /* not even the right length */
250 /* Generate the expected response and our mutual auth. */
251 ChapMS2(challenge, &response[MS_CHAP2_PEER_CHALLENGE], name,
252 (char *)secret, secret_len, md,
253 (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
255 /* compare MDs and send the appropriate status */
257 * Per RFC 2759, success message must be formatted as
258 * "S=<auth_string> M=<message>"
260 * <auth_string> is the Authenticator Response (mutual auth)
261 * <message> is a text message
263 * However, some versions of Windows (win98 tested) do not know
264 * about the M=<message> part (required per RFC 2759) and flag
265 * it as an error (reported incorrectly as an encryption error
266 * to the user). Since the RFC requires it, and it can be
267 * useful information, we supply it if the peer is a conforming
268 * system. Luckily (?), win98 sets the Flags field to 0x04
269 * (contrary to RFC requirements) so we can use that to
270 * distinguish between conforming and non-conforming systems.
272 * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
273 * help debugging this.
275 if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP],
276 MS_CHAP2_NTRESP_LEN) == 0) {
277 if (response[MS_CHAP2_FLAGS])
278 slprintf(message, message_space, "S=%s", saresponse);
280 slprintf(message, message_space, "S=%s M=%s",
281 saresponse, "Access granted");
287 * Failure message must be formatted as
288 * "E=e R=r C=c V=v M=m"
290 * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
291 * r = retry (we use 1, ok to retry)
292 * c = challenge to use for next response, we reuse previous
293 * v = Change Password version supported, we use 0
296 * The M=m part is only for MS-CHAPv2. Neither win2k nor
297 * win98 (others untested) display the message to the user anyway.
298 * They also both ignore the E=e code.
300 * Note that it's safe to reuse the same challenge as we don't
301 * actually accept another response based on the error message
302 * (and no clients try to resend a response anyway).
304 * Basically, this whole bit is useless code, even the small
305 * implementation here is only because of overspecification.
307 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
308 challenge_len, challenge, "Access denied");
313 chapms_make_response(unsigned char *response, int id, char *our_name,
314 unsigned char *challenge, char *secret, int secret_len,
315 unsigned char *private)
317 challenge++; /* skip length, should be 8 */
318 *response++ = MS_CHAP_RESPONSE_LEN;
319 ChapMS(challenge, secret, secret_len, response);
322 struct chapms2_response_cache_entry {
324 unsigned char challenge[16];
325 unsigned char response[MS_CHAP2_RESPONSE_LEN];
326 unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH];
329 #define CHAPMS2_MAX_RESPONSE_CACHE_SIZE 10
330 static struct chapms2_response_cache_entry
331 chapms2_response_cache[CHAPMS2_MAX_RESPONSE_CACHE_SIZE];
332 static int chapms2_response_cache_next_index = 0;
333 static int chapms2_response_cache_size = 0;
336 chapms2_add_to_response_cache(int id, unsigned char *challenge,
337 unsigned char *response,
338 unsigned char *auth_response)
340 int i = chapms2_response_cache_next_index;
342 chapms2_response_cache[i].id = id;
343 memcpy(chapms2_response_cache[i].challenge, challenge, 16);
344 memcpy(chapms2_response_cache[i].response, response,
345 MS_CHAP2_RESPONSE_LEN);
346 memcpy(chapms2_response_cache[i].auth_response,
347 auth_response, MS_AUTH_RESPONSE_LENGTH);
348 chapms2_response_cache_next_index =
349 (i + 1) % CHAPMS2_MAX_RESPONSE_CACHE_SIZE;
350 if (chapms2_response_cache_next_index > chapms2_response_cache_size)
351 chapms2_response_cache_size = chapms2_response_cache_next_index;
352 dbglog("added response cache entry %d", i);
355 static struct chapms2_response_cache_entry*
356 chapms2_find_in_response_cache(int id, unsigned char *challenge,
357 unsigned char *auth_response)
361 for (i = 0; i < chapms2_response_cache_size; i++) {
362 if (id == chapms2_response_cache[i].id
365 chapms2_response_cache[i].challenge,
368 || memcmp(auth_response,
369 chapms2_response_cache[i].auth_response,
370 MS_AUTH_RESPONSE_LENGTH) == 0)) {
371 dbglog("response found in cache (entry %d)", i);
372 return &chapms2_response_cache[i];
375 return NULL; /* not found */
379 chapms2_make_response(unsigned char *response, int id, char *our_name,
380 unsigned char *challenge, char *secret, int secret_len,
381 unsigned char *private)
383 const struct chapms2_response_cache_entry *cache_entry;
384 unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH+1];
386 challenge++; /* skip length, should be 16 */
387 *response++ = MS_CHAP2_RESPONSE_LEN;
388 cache_entry = chapms2_find_in_response_cache(id, challenge, NULL);
390 memcpy(response, cache_entry->response, MS_CHAP2_RESPONSE_LEN);
395 mschap2_peer_challenge,
399 our_name, secret, secret_len, response, auth_response,
400 MS_CHAP2_AUTHENTICATEE);
401 chapms2_add_to_response_cache(id, challenge, response, auth_response);
405 chapms2_check_success(int id, unsigned char *msg, int len)
407 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
408 strncmp((char *)msg, "S=", 2) != 0) {
409 /* Packet does not start with "S=" */
410 error("MS-CHAPv2 Success packet is badly formed.");
415 if (len < MS_AUTH_RESPONSE_LENGTH
416 || !chapms2_find_in_response_cache(id, NULL /* challenge */, msg)) {
417 /* Authenticator Response did not match expected. */
418 error("MS-CHAPv2 mutual authentication failed.");
421 /* Authenticator Response matches. */
422 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
423 len -= MS_AUTH_RESPONSE_LENGTH;
424 if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
425 msg += 3; /* Eat the delimiter */
426 } else if ((len >= 2) && !strncmp((char *)msg, "M=", 2)) {
427 msg += 2; /* Eat the delimiter */
429 /* Packet has extra text which does not begin " M=" */
430 error("MS-CHAPv2 Success packet is badly formed.");
437 chapms_handle_failure(unsigned char *inp, int len)
442 /* We want a null-terminated string for strxxx(). */
443 msg = malloc(len + 1);
445 notice("Out of memory in chapms_handle_failure");
448 BCOPY(inp, msg, len);
453 * Deal with MS-CHAP formatted failure messages; just print the
454 * M=<message> part (if any). For MS-CHAP we're not really supposed
455 * to use M=<message>, but it shouldn't hurt. See
456 * chapms[2]_verify_response.
458 if (!strncmp(p, "E=", 2))
459 err = strtol(p+2, NULL, 10); /* Remember the error code. */
461 goto print_msg; /* Message is badly formatted. */
463 if (len && ((p = strstr(p, " M=")) != NULL)) {
464 /* M=<message> field found. */
467 /* No M=<message>; use the error code. */
469 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
470 p = "E=646 Restricted logon hours";
473 case MS_CHAP_ERROR_ACCT_DISABLED:
474 p = "E=647 Account disabled";
477 case MS_CHAP_ERROR_PASSWD_EXPIRED:
478 p = "E=648 Password expired";
481 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
482 p = "E=649 No dialin permission";
485 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
486 p = "E=691 Authentication failure";
489 case MS_CHAP_ERROR_CHANGING_PASSWORD:
490 /* Should never see this, we don't support Change Password. */
491 p = "E=709 Error changing password";
496 error("Unknown MS-CHAP authentication failure: %.*v",
503 error("MS-CHAP authentication failed: %v", p);
508 ChallengeResponse(u_char *challenge,
509 u_char PasswordHash[MD4_SIGNATURE_SIZE],
512 u_char ZPasswordHash[21];
514 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
515 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
518 dbglog("ChallengeResponse - ZPasswordHash %.*B",
519 sizeof(ZPasswordHash), ZPasswordHash);
522 (void) DesSetkey(ZPasswordHash + 0);
523 DesEncrypt(challenge, response + 0);
524 (void) DesSetkey(ZPasswordHash + 7);
525 DesEncrypt(challenge, response + 8);
526 (void) DesSetkey(ZPasswordHash + 14);
527 DesEncrypt(challenge, response + 16);
530 dbglog("ChallengeResponse - response %.24B", response);
535 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
536 char *username, u_char Challenge[8])
539 SHA1_CTX sha1Context;
540 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
543 /* remove domain from "domain\username" */
544 if ((user = strrchr(username, '\\')) != NULL)
549 SHA1_Init(&sha1Context);
550 SHA1_Update(&sha1Context, PeerChallenge, 16);
551 SHA1_Update(&sha1Context, rchallenge, 16);
552 SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
553 SHA1_Final(sha1Hash, &sha1Context);
555 BCOPY(sha1Hash, Challenge, 8);
559 * Convert the ASCII version of the password to Unicode.
560 * This implicitly supports 8-bit ISO8859/1 characters.
561 * This gives us the little-endian representation, which
562 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
563 * is machine-dependent.)
566 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
570 BZERO(unicode, ascii_len * 2);
571 for (i = 0; i < ascii_len; i++)
572 unicode[i * 2] = (u_char) ascii[i];
576 NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
579 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
580 int mdlen = secret_len;
582 int mdlen = secret_len * 8;
586 MD4Init(&md4Context);
587 /* MD4Update can take at most 64 bytes at a time */
588 while (mdlen > 512) {
589 MD4Update(&md4Context, secret, 512);
593 MD4Update(&md4Context, secret, mdlen);
594 MD4Final(hash, &md4Context);
599 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
600 u_char NTResponse[24])
602 u_char unicodePassword[MAX_NT_PASSWORD * 2];
603 u_char PasswordHash[MD4_SIGNATURE_SIZE];
605 /* Hash the Unicode version of the secret (== password). */
606 ascii2unicode(secret, secret_len, unicodePassword);
607 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
609 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
613 ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username,
614 char *secret, int secret_len, u_char NTResponse[24])
616 u_char unicodePassword[MAX_NT_PASSWORD * 2];
617 u_char PasswordHash[MD4_SIGNATURE_SIZE];
620 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
622 /* Hash the Unicode version of the secret (== password). */
623 ascii2unicode(secret, secret_len, unicodePassword);
624 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
626 ChallengeResponse(Challenge, PasswordHash, NTResponse);
630 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
633 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
634 unsigned char *response)
637 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
638 u_char PasswordHash[MD4_SIGNATURE_SIZE];
640 /* LANMan password is case insensitive */
641 BZERO(UcasePassword, sizeof(UcasePassword));
642 for (i = 0; i < secret_len; i++)
643 UcasePassword[i] = (u_char)toupper(secret[i]);
644 (void) DesSetkey(UcasePassword + 0);
645 DesEncrypt( StdText, PasswordHash + 0 );
646 (void) DesSetkey(UcasePassword + 7);
647 DesEncrypt( StdText, PasswordHash + 8 );
648 ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]);
654 GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
655 u_char NTResponse[24], u_char PeerChallenge[16],
656 u_char *rchallenge, char *username,
657 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
660 * "Magic" constants used in response generation, from RFC 2759.
662 u_char Magic1[39] = /* "Magic server to client signing constant" */
663 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
664 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
665 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
666 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
667 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
668 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
669 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
670 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
671 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
675 SHA1_CTX sha1Context;
676 u_char Digest[SHA1_SIGNATURE_SIZE];
679 SHA1_Init(&sha1Context);
680 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
681 SHA1_Update(&sha1Context, NTResponse, 24);
682 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
683 SHA1_Final(Digest, &sha1Context);
685 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
687 SHA1_Init(&sha1Context);
688 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
689 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
690 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
691 SHA1_Final(Digest, &sha1Context);
693 /* Convert to ASCII hex string. */
694 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
695 sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
700 GenerateAuthenticatorResponsePlain
701 (char *secret, int secret_len,
702 u_char NTResponse[24], u_char PeerChallenge[16],
703 u_char *rchallenge, char *username,
704 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
706 u_char unicodePassword[MAX_NT_PASSWORD * 2];
707 u_char PasswordHash[MD4_SIGNATURE_SIZE];
708 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
710 /* Hash (x2) the Unicode version of the secret (== password). */
711 ascii2unicode(secret, secret_len, unicodePassword);
712 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
713 NTPasswordHash(PasswordHash, sizeof(PasswordHash),
716 GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
717 rchallenge, username, authResponse);
723 * Set mppe_xxxx_key from the NTPasswordHashHash.
724 * RFC 2548 (RADIUS support) requires us to export this function (ugh).
727 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
729 SHA1_CTX sha1Context;
730 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
732 SHA1_Init(&sha1Context);
733 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
734 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
735 SHA1_Update(&sha1Context, rchallenge, 8);
736 SHA1_Final(Digest, &sha1Context);
738 /* Same key in both directions. */
739 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
740 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
746 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
749 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
751 u_char unicodePassword[MAX_NT_PASSWORD * 2];
752 u_char PasswordHash[MD4_SIGNATURE_SIZE];
753 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
755 /* Hash (x2) the Unicode version of the secret (== password). */
756 ascii2unicode(secret, secret_len, unicodePassword);
757 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
758 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
760 mppe_set_keys(rchallenge, PasswordHashHash);
764 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
766 * This helper function used in the Winbind module, which gets the
767 * NTHashHash from the server.
770 mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
771 u_char NTResponse[24], int IsServer)
773 SHA1_CTX sha1Context;
774 u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
775 u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
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,
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
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,
786 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
788 /* "This is the MPPE Master Key" */
790 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
791 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
792 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
793 /* "On the client side, this is the send key; "
794 "on the server side, it is the receive key." */
796 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
797 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
798 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
799 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
800 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
801 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
802 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
803 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
804 0x6b, 0x65, 0x79, 0x2e };
805 /* "On the client side, this is the receive key; "
806 "on the server side, it is the send key." */
808 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
809 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
810 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
811 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
812 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
813 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
814 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
815 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
816 0x6b, 0x65, 0x79, 0x2e };
819 SHA1_Init(&sha1Context);
820 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
821 SHA1_Update(&sha1Context, NTResponse, 24);
822 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
823 SHA1_Final(MasterKey, &sha1Context);
832 SHA1_Init(&sha1Context);
833 SHA1_Update(&sha1Context, MasterKey, 16);
834 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
835 SHA1_Update(&sha1Context, s, 84);
836 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
837 SHA1_Final(Digest, &sha1Context);
839 BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
848 SHA1_Init(&sha1Context);
849 SHA1_Update(&sha1Context, MasterKey, 16);
850 SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
851 SHA1_Update(&sha1Context, s, 84);
852 SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
853 SHA1_Final(Digest, &sha1Context);
855 BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
861 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
864 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
866 u_char unicodePassword[MAX_NT_PASSWORD * 2];
867 u_char PasswordHash[MD4_SIGNATURE_SIZE];
868 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
869 /* Hash (x2) the Unicode version of the secret (== password). */
870 ascii2unicode(secret, secret_len, unicodePassword);
871 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
872 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
873 mppe_set_keys2(PasswordHashHash, NTResponse, IsServer);
880 ChapMS(u_char *rchallenge, char *secret, int secret_len,
881 unsigned char *response)
883 BZERO(response, MS_CHAP_RESPONSE_LEN);
885 ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
888 ChapMS_LANMan(rchallenge, secret, secret_len,
889 &response[MS_CHAP_LANMANRESP]);
891 /* preferred method is set by option */
892 response[MS_CHAP_USENT] = !ms_lanman;
894 response[MS_CHAP_USENT] = 1;
898 Set_Start_Key(rchallenge, secret, secret_len);
904 * If PeerChallenge is NULL, one is generated and the PeerChallenge
905 * field of response is filled in. Call this way when generating a response.
906 * If PeerChallenge is supplied, it is copied into the PeerChallenge field.
907 * Call this way when verifying a response (or debugging).
908 * Do not call with PeerChallenge = response.
910 * The PeerChallenge field of response is then used for calculation of the
911 * Authenticator Response.
914 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
915 char *user, char *secret, int secret_len, unsigned char *response,
916 u_char authResponse[], int authenticator)
919 u_char *p = &response[MS_CHAP2_PEER_CHALLENGE];
922 BZERO(response, MS_CHAP2_RESPONSE_LEN);
924 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
926 for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++)
927 *p++ = (u_char) (drand48() * 0xff);
929 BCOPY(PeerChallenge, &response[MS_CHAP2_PEER_CHALLENGE],
930 MS_CHAP2_PEER_CHAL_LEN);
932 /* Generate the NT-Response */
933 ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
934 secret, secret_len, &response[MS_CHAP2_NTRESP]);
936 /* Generate the Authenticator Response. */
937 GenerateAuthenticatorResponsePlain(secret, secret_len,
938 &response[MS_CHAP2_NTRESP],
939 &response[MS_CHAP2_PEER_CHALLENGE],
940 rchallenge, user, authResponse);
943 SetMasterKeys(secret, secret_len,
944 &response[MS_CHAP2_NTRESP], authenticator);
950 * Set MPPE options from plugins.
953 set_mppe_enc_types(int policy, int types)
955 /* Early exit for unknown policies. */
956 if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
957 policy != MPPE_ENC_POL_ENC_REQUIRED)
960 /* Don't modify MPPE if it's optional and wasn't already configured. */
961 if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
965 * Disable undesirable encryption types. Note that we don't ENABLE
966 * any encryption types, to avoid overriding manual configuration.
969 case MPPE_ENC_TYPES_RC4_40:
970 ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */
972 case MPPE_ENC_TYPES_RC4_128:
973 ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */
981 static struct chap_digest_type chapms_digest = {
982 CHAP_MICROSOFT, /* code */
983 chapms_generate_challenge,
984 chapms_verify_response,
985 chapms_make_response,
986 NULL, /* check_success */
987 chapms_handle_failure,
990 static struct chap_digest_type chapms2_digest = {
991 CHAP_MICROSOFT_V2, /* code */
992 chapms2_generate_challenge,
993 chapms2_verify_response,
994 chapms2_make_response,
995 chapms2_check_success,
996 chapms_handle_failure,
1002 chap_register_digest(&chapms_digest);
1003 chap_register_digest(&chapms2_digest);
1004 add_options(chapms_option_list);