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 $"
89 #include <sys/types.h>
102 static void ascii2unicode (char[], int, u_char[]);
103 static void NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]);
104 static void ChallengeResponse (u_char *, u_char *, u_char[24]);
105 static void ChapMS_NT (u_char *, char *, int, u_char[24]);
106 static void ChapMS2_NT (u_char *, u_char[16], char *, char *, int,
108 static void GenerateAuthenticatorResponsePlain
109 (char*, int, u_char[24], u_char[16], u_char *,
112 static void ChapMS_LANMan (u_char *, char *, int, u_char *);
116 bool ms_lanman = 0; /* Use LanMan password instead of NT */
117 /* Has meaning only with MS-CHAP challenges */
123 /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
124 static char *mschap_challenge = NULL;
125 /* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
126 static char *mschap2_peer_challenge = NULL;
129 #include "fsm.h" /* Need to poke MPPE options */
131 #include <net/ppp-comp.h>
135 * Command-line options.
137 static option_t chapms_option_list[] = {
139 { "ms-lanman", o_bool, &ms_lanman,
140 "Use LanMan passwd when using MS-CHAP", 1 },
143 { "mschap-challenge", o_string, &mschap_challenge,
144 "specify CHAP challenge" },
145 { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
146 "specify CHAP peer challenge" },
152 * chapms_generate_challenge - generate a challenge for MS-CHAP.
153 * For MS-CHAP the challenge length is fixed at 8 bytes.
154 * The length goes in challenge[0] and the actual challenge starts
158 chapms_generate_challenge(unsigned char *challenge)
162 if (mschap_challenge && strlen(mschap_challenge) == 8)
163 memcpy(challenge, mschap_challenge, 8);
166 random_bytes(challenge, 8);
170 chapms2_generate_challenge(unsigned char *challenge)
174 if (mschap_challenge && strlen(mschap_challenge) == 16)
175 memcpy(challenge, mschap_challenge, 16);
178 random_bytes(challenge, 16);
182 chapms_verify_response(int id, char *name,
183 unsigned char *secret, int secret_len,
184 unsigned char *challenge, unsigned char *response,
185 char *message, int message_space)
187 unsigned char md[MS_CHAP_RESPONSE_LEN];
189 int challenge_len, response_len;
191 challenge_len = *challenge++; /* skip length, is 8 */
192 response_len = *response++;
193 if (response_len != MS_CHAP_RESPONSE_LEN)
197 if (!response[MS_CHAP_USENT]) {
198 /* Should really propagate this into the error packet. */
199 notice("Peer request for LANMAN auth not supported");
204 /* Generate the expected response. */
205 ChapMS(challenge, (char *)secret, secret_len, md);
208 /* Determine which part of response to verify against */
209 if (!response[MS_CHAP_USENT])
210 diff = memcmp(&response[MS_CHAP_LANMANRESP],
211 &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN);
214 diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP],
218 slprintf(message, message_space, "Access granted");
223 /* See comments below for MS-CHAP V2 */
224 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
225 challenge_len, challenge);
230 chapms2_verify_response(int id, char *name,
231 unsigned char *secret, int secret_len,
232 unsigned char *challenge, unsigned char *response,
233 char *message, int message_space)
235 unsigned char md[MS_CHAP2_RESPONSE_LEN];
236 char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
237 int challenge_len, response_len;
239 challenge_len = *challenge++; /* skip length, is 16 */
240 response_len = *response++;
241 if (response_len != MS_CHAP2_RESPONSE_LEN)
242 goto bad; /* not even the right length */
244 /* Generate the expected response and our mutual auth. */
245 ChapMS2(challenge, &response[MS_CHAP2_PEER_CHALLENGE], name,
246 (char *)secret, secret_len, md,
247 (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
249 /* compare MDs and send the appropriate status */
251 * Per RFC 2759, success message must be formatted as
252 * "S=<auth_string> M=<message>"
254 * <auth_string> is the Authenticator Response (mutual auth)
255 * <message> is a text message
257 * However, some versions of Windows (win98 tested) do not know
258 * about the M=<message> part (required per RFC 2759) and flag
259 * it as an error (reported incorrectly as an encryption error
260 * to the user). Since the RFC requires it, and it can be
261 * useful information, we supply it if the peer is a conforming
262 * system. Luckily (?), win98 sets the Flags field to 0x04
263 * (contrary to RFC requirements) so we can use that to
264 * distinguish between conforming and non-conforming systems.
266 * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
267 * help debugging this.
269 if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP],
270 MS_CHAP2_NTRESP_LEN) == 0) {
271 if (response[MS_CHAP2_FLAGS])
272 slprintf(message, message_space, "S=%s", saresponse);
274 slprintf(message, message_space, "S=%s M=%s",
275 saresponse, "Access granted");
281 * Failure message must be formatted as
282 * "E=e R=r C=c V=v M=m"
284 * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
285 * r = retry (we use 1, ok to retry)
286 * c = challenge to use for next response, we reuse previous
287 * v = Change Password version supported, we use 0
290 * The M=m part is only for MS-CHAPv2. Neither win2k nor
291 * win98 (others untested) display the message to the user anyway.
292 * They also both ignore the E=e code.
294 * Note that it's safe to reuse the same challenge as we don't
295 * actually accept another response based on the error message
296 * (and no clients try to resend a response anyway).
298 * Basically, this whole bit is useless code, even the small
299 * implementation here is only because of overspecification.
301 slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
302 challenge_len, challenge, "Access denied");
307 chapms_make_response(unsigned char *response, int id, char *our_name,
308 unsigned char *challenge, char *secret, int secret_len,
309 unsigned char *private)
311 challenge++; /* skip length, should be 8 */
312 *response++ = MS_CHAP_RESPONSE_LEN;
313 ChapMS(challenge, secret, secret_len, response);
316 struct chapms2_response_cache_entry {
318 unsigned char challenge[16];
319 unsigned char response[MS_CHAP2_RESPONSE_LEN];
320 unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH];
323 #define CHAPMS2_MAX_RESPONSE_CACHE_SIZE 10
324 static struct chapms2_response_cache_entry
325 chapms2_response_cache[CHAPMS2_MAX_RESPONSE_CACHE_SIZE];
326 static int chapms2_response_cache_next_index = 0;
327 static int chapms2_response_cache_size = 0;
330 chapms2_add_to_response_cache(int id, unsigned char *challenge,
331 unsigned char *response,
332 unsigned char *auth_response)
334 int i = chapms2_response_cache_next_index;
336 chapms2_response_cache[i].id = id;
337 memcpy(chapms2_response_cache[i].challenge, challenge, 16);
338 memcpy(chapms2_response_cache[i].response, response,
339 MS_CHAP2_RESPONSE_LEN);
340 memcpy(chapms2_response_cache[i].auth_response,
341 auth_response, MS_AUTH_RESPONSE_LENGTH);
342 chapms2_response_cache_next_index =
343 (i + 1) % CHAPMS2_MAX_RESPONSE_CACHE_SIZE;
344 if (chapms2_response_cache_next_index > chapms2_response_cache_size)
345 chapms2_response_cache_size = chapms2_response_cache_next_index;
346 dbglog("added response cache entry %d", i);
349 static struct chapms2_response_cache_entry*
350 chapms2_find_in_response_cache(int id, unsigned char *challenge,
351 unsigned char *auth_response)
355 for (i = 0; i < chapms2_response_cache_size; i++) {
356 if (id == chapms2_response_cache[i].id
359 chapms2_response_cache[i].challenge,
362 || memcmp(auth_response,
363 chapms2_response_cache[i].auth_response,
364 MS_AUTH_RESPONSE_LENGTH) == 0)) {
365 dbglog("response found in cache (entry %d)", i);
366 return &chapms2_response_cache[i];
369 return NULL; /* not found */
373 chapms2_make_response(unsigned char *response, int id, char *our_name,
374 unsigned char *challenge, char *secret, int secret_len,
375 unsigned char *private)
377 const struct chapms2_response_cache_entry *cache_entry;
378 unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH+1];
380 challenge++; /* skip length, should be 16 */
381 *response++ = MS_CHAP2_RESPONSE_LEN;
382 cache_entry = chapms2_find_in_response_cache(id, challenge, NULL);
384 memcpy(response, cache_entry->response, MS_CHAP2_RESPONSE_LEN);
389 mschap2_peer_challenge,
393 our_name, secret, secret_len, response, auth_response,
394 MS_CHAP2_AUTHENTICATEE);
395 chapms2_add_to_response_cache(id, challenge, response, auth_response);
399 chapms2_check_success(int id, unsigned char *msg, int len)
401 if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
402 strncmp((char *)msg, "S=", 2) != 0) {
403 /* Packet does not start with "S=" */
404 error("MS-CHAPv2 Success packet is badly formed.");
409 if (len < MS_AUTH_RESPONSE_LENGTH
410 || !chapms2_find_in_response_cache(id, NULL /* challenge */, msg)) {
411 /* Authenticator Response did not match expected. */
412 error("MS-CHAPv2 mutual authentication failed.");
415 /* Authenticator Response matches. */
416 msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
417 len -= MS_AUTH_RESPONSE_LENGTH;
418 if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
419 msg += 3; /* Eat the delimiter */
420 } else if ((len >= 2) && !strncmp((char *)msg, "M=", 2)) {
421 msg += 2; /* Eat the delimiter */
423 /* Packet has extra text which does not begin " M=" */
424 error("MS-CHAPv2 Success packet is badly formed.");
431 chapms_handle_failure(unsigned char *inp, int len)
436 /* We want a null-terminated string for strxxx(). */
437 msg = malloc(len + 1);
439 notice("Out of memory in chapms_handle_failure");
442 BCOPY(inp, msg, len);
447 * Deal with MS-CHAP formatted failure messages; just print the
448 * M=<message> part (if any). For MS-CHAP we're not really supposed
449 * to use M=<message>, but it shouldn't hurt. See
450 * chapms[2]_verify_response.
452 if (!strncmp(p, "E=", 2))
453 err = strtol(p+2, NULL, 10); /* Remember the error code. */
455 goto print_msg; /* Message is badly formatted. */
457 if (len && ((p = strstr(p, " M=")) != NULL)) {
458 /* M=<message> field found. */
461 /* No M=<message>; use the error code. */
463 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
464 p = "E=646 Restricted logon hours";
467 case MS_CHAP_ERROR_ACCT_DISABLED:
468 p = "E=647 Account disabled";
471 case MS_CHAP_ERROR_PASSWD_EXPIRED:
472 p = "E=648 Password expired";
475 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
476 p = "E=649 No dialin permission";
479 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
480 p = "E=691 Authentication failure";
483 case MS_CHAP_ERROR_CHANGING_PASSWORD:
484 /* Should never see this, we don't support Change Password. */
485 p = "E=709 Error changing password";
490 error("Unknown MS-CHAP authentication failure: %.*v",
497 error("MS-CHAP authentication failed: %v", p);
502 ChallengeResponse(u_char *challenge,
503 u_char PasswordHash[MD4_SIGNATURE_SIZE],
506 u_char ZPasswordHash[21];
508 BZERO(ZPasswordHash, sizeof(ZPasswordHash));
509 BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
512 dbglog("ChallengeResponse - ZPasswordHash %.*B",
513 sizeof(ZPasswordHash), ZPasswordHash);
516 (void) DesSetkey(ZPasswordHash + 0);
517 DesEncrypt(challenge, response + 0);
518 (void) DesSetkey(ZPasswordHash + 7);
519 DesEncrypt(challenge, response + 8);
520 (void) DesSetkey(ZPasswordHash + 14);
521 DesEncrypt(challenge, response + 16);
524 dbglog("ChallengeResponse - response %.24B", response);
529 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
530 char *username, u_char Challenge[8])
533 SHA1_CTX sha1Context;
534 u_char sha1Hash[SHA1_SIGNATURE_SIZE];
537 /* remove domain from "domain\username" */
538 if ((user = strrchr(username, '\\')) != NULL)
543 SHA1_Init(&sha1Context);
544 SHA1_Update(&sha1Context, PeerChallenge, 16);
545 SHA1_Update(&sha1Context, rchallenge, 16);
546 SHA1_Update(&sha1Context, (unsigned char *)user, strlen(user));
547 SHA1_Final(sha1Hash, &sha1Context);
549 BCOPY(sha1Hash, Challenge, 8);
553 * Convert the ASCII version of the password to Unicode.
554 * This implicitly supports 8-bit ISO8859/1 characters.
555 * This gives us the little-endian representation, which
556 * is assumed by all M$ CHAP RFCs. (Unicode byte ordering
557 * is machine-dependent.)
560 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
564 BZERO(unicode, ascii_len * 2);
565 for (i = 0; i < ascii_len; i++)
566 unicode[i * 2] = (u_char) ascii[i];
570 NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
573 /* NetBSD uses the libc md4 routines which take bytes instead of bits */
574 int mdlen = secret_len;
576 int mdlen = secret_len * 8;
580 MD4Init(&md4Context);
581 /* MD4Update can take at most 64 bytes at a time */
582 while (mdlen > 512) {
583 MD4Update(&md4Context, secret, 512);
587 MD4Update(&md4Context, secret, mdlen);
588 MD4Final(hash, &md4Context);
593 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
594 u_char NTResponse[24])
596 u_char unicodePassword[MAX_NT_PASSWORD * 2];
597 u_char PasswordHash[MD4_SIGNATURE_SIZE];
599 /* Hash the Unicode version of the secret (== password). */
600 ascii2unicode(secret, secret_len, unicodePassword);
601 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
603 ChallengeResponse(rchallenge, PasswordHash, NTResponse);
607 ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username,
608 char *secret, int secret_len, u_char NTResponse[24])
610 u_char unicodePassword[MAX_NT_PASSWORD * 2];
611 u_char PasswordHash[MD4_SIGNATURE_SIZE];
614 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
616 /* Hash the Unicode version of the secret (== password). */
617 ascii2unicode(secret, secret_len, unicodePassword);
618 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
620 ChallengeResponse(Challenge, PasswordHash, NTResponse);
624 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
627 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
628 unsigned char *response)
631 u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
632 u_char PasswordHash[MD4_SIGNATURE_SIZE];
634 /* LANMan password is case insensitive */
635 BZERO(UcasePassword, sizeof(UcasePassword));
636 for (i = 0; i < secret_len; i++)
637 UcasePassword[i] = (u_char)toupper(secret[i]);
638 (void) DesSetkey(UcasePassword + 0);
639 DesEncrypt( StdText, PasswordHash + 0 );
640 (void) DesSetkey(UcasePassword + 7);
641 DesEncrypt( StdText, PasswordHash + 8 );
642 ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]);
648 GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
649 u_char NTResponse[24], u_char PeerChallenge[16],
650 u_char *rchallenge, char *username,
651 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
654 * "Magic" constants used in response generation, from RFC 2759.
656 u_char Magic1[39] = /* "Magic server to client signing constant" */
657 { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
658 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
659 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
660 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
661 u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
662 { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
663 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
664 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
665 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
669 SHA1_CTX sha1Context;
670 u_char Digest[SHA1_SIGNATURE_SIZE];
673 SHA1_Init(&sha1Context);
674 SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
675 SHA1_Update(&sha1Context, NTResponse, 24);
676 SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
677 SHA1_Final(Digest, &sha1Context);
679 ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
681 SHA1_Init(&sha1Context);
682 SHA1_Update(&sha1Context, Digest, sizeof(Digest));
683 SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
684 SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
685 SHA1_Final(Digest, &sha1Context);
687 /* Convert to ASCII hex string. */
688 for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
689 sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
694 GenerateAuthenticatorResponsePlain
695 (char *secret, int secret_len,
696 u_char NTResponse[24], u_char PeerChallenge[16],
697 u_char *rchallenge, char *username,
698 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
700 u_char unicodePassword[MAX_NT_PASSWORD * 2];
701 u_char PasswordHash[MD4_SIGNATURE_SIZE];
702 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
704 /* Hash (x2) the Unicode version of the secret (== password). */
705 ascii2unicode(secret, secret_len, unicodePassword);
706 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
707 NTPasswordHash(PasswordHash, sizeof(PasswordHash),
710 GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
711 rchallenge, username, authResponse);
718 * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
721 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
723 u_char unicodePassword[MAX_NT_PASSWORD * 2];
724 u_char PasswordHash[MD4_SIGNATURE_SIZE];
725 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
727 /* Hash (x2) the Unicode version of the secret (== password). */
728 ascii2unicode(secret, secret_len, unicodePassword);
729 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
730 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
732 mppe_set_chapv1(rchallenge, PasswordHashHash);
736 * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
739 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
741 u_char unicodePassword[MAX_NT_PASSWORD * 2];
742 u_char PasswordHash[MD4_SIGNATURE_SIZE];
743 u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
744 /* Hash (x2) the Unicode version of the secret (== password). */
745 ascii2unicode(secret, secret_len, unicodePassword);
746 NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
747 NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
748 mppe_set_chapv2(PasswordHashHash, NTResponse, IsServer);
755 ChapMS(u_char *rchallenge, char *secret, int secret_len,
756 unsigned char *response)
758 BZERO(response, MS_CHAP_RESPONSE_LEN);
760 ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
763 ChapMS_LANMan(rchallenge, secret, secret_len,
764 &response[MS_CHAP_LANMANRESP]);
766 /* preferred method is set by option */
767 response[MS_CHAP_USENT] = !ms_lanman;
769 response[MS_CHAP_USENT] = 1;
773 Set_Start_Key(rchallenge, secret, secret_len);
779 * If PeerChallenge is NULL, one is generated and the PeerChallenge
780 * field of response is filled in. Call this way when generating a response.
781 * If PeerChallenge is supplied, it is copied into the PeerChallenge field.
782 * Call this way when verifying a response (or debugging).
783 * Do not call with PeerChallenge = response.
785 * The PeerChallenge field of response is then used for calculation of the
786 * Authenticator Response.
789 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
790 char *user, char *secret, int secret_len, unsigned char *response,
791 u_char authResponse[], int authenticator)
794 u_char *p = &response[MS_CHAP2_PEER_CHALLENGE];
797 BZERO(response, MS_CHAP2_RESPONSE_LEN);
799 /* Generate the Peer-Challenge if requested, or copy it if supplied. */
801 for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++)
802 *p++ = (u_char) (drand48() * 0xff);
804 BCOPY(PeerChallenge, &response[MS_CHAP2_PEER_CHALLENGE],
805 MS_CHAP2_PEER_CHAL_LEN);
807 /* Generate the NT-Response */
808 ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
809 secret, secret_len, &response[MS_CHAP2_NTRESP]);
811 /* Generate the Authenticator Response. */
812 GenerateAuthenticatorResponsePlain(secret, secret_len,
813 &response[MS_CHAP2_NTRESP],
814 &response[MS_CHAP2_PEER_CHALLENGE],
815 rchallenge, user, authResponse);
818 SetMasterKeys(secret, secret_len,
819 &response[MS_CHAP2_NTRESP], authenticator);
824 static struct chap_digest_type chapms_digest = {
825 CHAP_MICROSOFT, /* code */
826 chapms_generate_challenge,
827 chapms_verify_response,
828 chapms_make_response,
829 NULL, /* check_success */
830 chapms_handle_failure,
833 static struct chap_digest_type chapms2_digest = {
834 CHAP_MICROSOFT_V2, /* code */
835 chapms2_generate_challenge,
836 chapms2_verify_response,
837 chapms2_make_response,
838 chapms2_check_success,
839 chapms_handle_failure,
845 chap_register_digest(&chapms_digest);
846 chap_register_digest(&chapms2_digest);
847 add_options(chapms_option_list);