]> git.ozlabs.org Git - ppp.git/blob - pppd/chap_ms.c
pppoe-discovery: add options to tune discovery timeout and attempts
[ppp.git] / pppd / chap_ms.c
1 /*
2  * chap_ms.c - Microsoft MS-CHAP compatible implementation.
3  *
4  * Copyright (c) 1995 Eric Rosenquist.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
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
16  *    distribution.
17  *
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.
21  *
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.
29  */
30
31 /*
32  * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
33  *
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.
38  *
39  *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
40  */
41
42 /*
43  * Modifications by Frank Cusack, frank@google.com, March 2002.
44  *
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.
48  *
49  * Copyright (c) 2002 Google, Inc.  All rights reserved.
50  *
51  * Redistribution and use in source and binary forms, with or without
52  * modification, are permitted provided that the following conditions
53  * are met:
54  *
55  * 1. Redistributions of source code must retain the above copyright
56  *    notice, this list of conditions and the following disclaimer.
57  *
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
61  *    distribution.
62  *
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.
66  *
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.
74  *
75  */
76
77 #define RCSID   "$Id: chap_ms.c,v 1.38 2007/12/01 20:10:51 carlsonj Exp $"
78
79 #ifdef CHAPMS
80
81 #include <stdio.h>
82 #include <stdlib.h>
83 #include <string.h>
84 #include <ctype.h>
85 #include <sys/types.h>
86 #include <sys/time.h>
87 #include <unistd.h>
88
89 #include "pppd.h"
90 #include "chap-new.h"
91 #include "chap_ms.h"
92 #include "md4.h"
93 #include "sha1.h"
94 #include "pppcrypt.h"
95 #include "magic.h"
96
97 static const char rcsid[] = RCSID;
98
99
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,
105                                 u_char[24]));
106 static void     GenerateAuthenticatorResponsePlain
107                         __P((char*, int, u_char[24], u_char[16], u_char *,
108                              char *, u_char[41]));
109 #ifdef MSLANMAN
110 static void     ChapMS_LANMan __P((u_char *, char *, int, u_char *));
111 #endif
112
113 #ifdef MPPE
114 static void     Set_Start_Key __P((u_char *, char *, int));
115 static void     SetMasterKeys __P((char *, int, u_char[24], int));
116 #endif
117
118 #ifdef MSLANMAN
119 bool    ms_lanman = 0;          /* Use LanMan password instead of NT */
120                                 /* Has meaning only with MS-CHAP challenges */
121 #endif
122
123 #ifdef MPPE
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? */
127
128 #ifdef DEBUGMPPEKEY
129 /* For MPPE debug */
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;
134 #endif
135
136 #include "fsm.h"                /* Need to poke MPPE options */
137 #include "ccp.h"
138 #include <net/ppp-comp.h>
139 #endif
140
141 /*
142  * Command-line options.
143  */
144 static option_t chapms_option_list[] = {
145 #ifdef MSLANMAN
146         { "ms-lanman", o_bool, &ms_lanman,
147           "Use LanMan passwd when using MS-CHAP", 1 },
148 #endif
149 #ifdef DEBUGMPPEKEY
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" },
154 #endif
155         { NULL }
156 };
157
158 /*
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
162  * at challenge[1].
163  */
164 static void
165 chapms_generate_challenge(unsigned char *challenge)
166 {
167         *challenge++ = 8;
168 #ifdef DEBUGMPPEKEY
169         if (mschap_challenge && strlen(mschap_challenge) == 8)
170                 memcpy(challenge, mschap_challenge, 8);
171         else
172 #endif
173                 random_bytes(challenge, 8);
174 }
175
176 static void
177 chapms2_generate_challenge(unsigned char *challenge)
178 {
179         *challenge++ = 16;
180 #ifdef DEBUGMPPEKEY
181         if (mschap_challenge && strlen(mschap_challenge) == 16)
182                 memcpy(challenge, mschap_challenge, 16);
183         else
184 #endif
185                 random_bytes(challenge, 16);
186 }
187
188 static int
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)
193 {
194         unsigned char md[MS_CHAP_RESPONSE_LEN];
195         int diff;
196         int challenge_len, response_len;
197
198         challenge_len = *challenge++;   /* skip length, is 8 */
199         response_len = *response++;
200         if (response_len != MS_CHAP_RESPONSE_LEN)
201                 goto bad;
202
203 #ifndef MSLANMAN
204         if (!response[MS_CHAP_USENT]) {
205                 /* Should really propagate this into the error packet. */
206                 notice("Peer request for LANMAN auth not supported");
207                 goto bad;
208         }
209 #endif
210
211         /* Generate the expected response. */
212         ChapMS(challenge, (char *)secret, secret_len, md);
213
214 #ifdef MSLANMAN
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);
219         else
220 #endif
221                 diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP],
222                               MS_CHAP_NTRESP_LEN);
223
224         if (diff == 0) {
225                 slprintf(message, message_space, "Access granted");
226                 return 1;
227         }
228
229  bad:
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);
233         return 0;
234 }
235
236 static int
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)
241 {
242         unsigned char md[MS_CHAP2_RESPONSE_LEN];
243         char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
244         int challenge_len, response_len;
245
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 */
250
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);
255
256         /* compare MDs and send the appropriate status */
257         /*
258          * Per RFC 2759, success message must be formatted as
259          *     "S=<auth_string> M=<message>"
260          * where
261          *     <auth_string> is the Authenticator Response (mutual auth)
262          *     <message> is a text message
263          *
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.
272          *
273          * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
274          * help debugging this.
275          */
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);
280                 else
281                         slprintf(message, message_space, "S=%s M=%s",
282                                  saresponse, "Access granted");
283                 return 1;
284         }
285
286  bad:
287         /*
288          * Failure message must be formatted as
289          *     "E=e R=r C=c V=v M=m"
290          * where
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
295          *     m = text message
296          *
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.
300          *
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).
304          *
305          * Basically, this whole bit is useless code, even the small
306          * implementation here is only because of overspecification.
307          */
308         slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
309                  challenge_len, challenge, "Access denied");
310         return 0;
311 }
312
313 static void
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)
317 {
318         challenge++;    /* skip length, should be 8 */
319         *response++ = MS_CHAP_RESPONSE_LEN;
320         ChapMS(challenge, secret, secret_len, response);
321 }
322
323 struct chapms2_response_cache_entry {
324         int id;
325         unsigned char challenge[16];
326         unsigned char response[MS_CHAP2_RESPONSE_LEN];
327         unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH];
328 };
329
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;
335
336 static void
337 chapms2_add_to_response_cache(int id, unsigned char *challenge,
338                               unsigned char *response,
339                               unsigned char *auth_response)
340 {
341         int i = chapms2_response_cache_next_index;
342
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);
354 }
355
356 static struct chapms2_response_cache_entry*
357 chapms2_find_in_response_cache(int id, unsigned char *challenge,
358                       unsigned char *auth_response)
359 {
360         int i;
361
362         for (i = 0; i < chapms2_response_cache_size; i++) {
363                 if (id == chapms2_response_cache[i].id
364                     && (!challenge
365                         || memcmp(challenge,
366                                   chapms2_response_cache[i].challenge,
367                                   16) == 0)
368                     && (!auth_response
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];
374                 }
375         }
376         return NULL;  /* not found */
377 }
378
379 static void
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)
383 {
384         const struct chapms2_response_cache_entry *cache_entry;
385         unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH+1];
386
387         challenge++;    /* skip length, should be 16 */
388         *response++ = MS_CHAP2_RESPONSE_LEN;
389         cache_entry = chapms2_find_in_response_cache(id, challenge, NULL);
390         if (cache_entry) {
391                 memcpy(response, cache_entry->response, MS_CHAP2_RESPONSE_LEN);
392                 return;
393         }
394         ChapMS2(challenge,
395 #ifdef DEBUGMPPEKEY
396                 mschap2_peer_challenge,
397 #else
398                 NULL,
399 #endif
400                 our_name, secret, secret_len, response, auth_response,
401                 MS_CHAP2_AUTHENTICATEE);
402         chapms2_add_to_response_cache(id, challenge, response, auth_response);
403 }
404
405 static int
406 chapms2_check_success(int id, unsigned char *msg, int len)
407 {
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.");
412                 return 0;
413         }
414         msg += 2;
415         len -= 2;
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.");
420                 return 0;
421         }
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 */
427         } else if (len) {
428                 /* Packet has extra text which does not begin " M=" */
429                 error("MS-CHAPv2 Success packet is badly formed.");
430                 return 0;
431         }
432         return 1;
433 }
434
435 static void
436 chapms_handle_failure(unsigned char *inp, int len)
437 {
438         int err;
439         char *p, *msg;
440
441         /* We want a null-terminated string for strxxx(). */
442         msg = malloc(len + 1);
443         if (!msg) {
444                 notice("Out of memory in chapms_handle_failure");
445                 return;
446         }
447         BCOPY(inp, msg, len);
448         msg[len] = 0;
449         p = msg;
450
451         /*
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.
456          */
457         if (!strncmp(p, "E=", 2))
458                 err = strtol(p+2, NULL, 10); /* Remember the error code. */
459         else
460                 goto print_msg; /* Message is badly formatted. */
461
462         if (len && ((p = strstr(p, " M=")) != NULL)) {
463                 /* M=<message> field found. */
464                 p += 3;
465         } else {
466                 /* No M=<message>; use the error code. */
467                 switch (err) {
468                 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
469                         p = "E=646 Restricted logon hours";
470                         break;
471
472                 case MS_CHAP_ERROR_ACCT_DISABLED:
473                         p = "E=647 Account disabled";
474                         break;
475
476                 case MS_CHAP_ERROR_PASSWD_EXPIRED:
477                         p = "E=648 Password expired";
478                         break;
479
480                 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
481                         p = "E=649 No dialin permission";
482                         break;
483
484                 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
485                         p = "E=691 Authentication failure";
486                         break;
487
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";
491                         break;
492
493                 default:
494                         free(msg);
495                         error("Unknown MS-CHAP authentication failure: %.*v",
496                               len, inp);
497                         return;
498                 }
499         }
500 print_msg:
501         if (p != NULL)
502                 error("MS-CHAP authentication failed: %v", p);
503         free(msg);
504 }
505
506 static void
507 ChallengeResponse(u_char *challenge,
508                   u_char PasswordHash[MD4_SIGNATURE_SIZE],
509                   u_char response[24])
510 {
511     u_char    ZPasswordHash[21];
512
513     BZERO(ZPasswordHash, sizeof(ZPasswordHash));
514     BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
515
516 #if 0
517     dbglog("ChallengeResponse - ZPasswordHash %.*B",
518            sizeof(ZPasswordHash), ZPasswordHash);
519 #endif
520
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);
527
528 #if 0
529     dbglog("ChallengeResponse - response %.24B", response);
530 #endif
531 }
532
533 void
534 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
535               char *username, u_char Challenge[8])
536     
537 {
538     SHA1_CTX    sha1Context;
539     u_char      sha1Hash[SHA1_SIGNATURE_SIZE];
540     char        *user;
541
542     /* remove domain from "domain\username" */
543     if ((user = strrchr(username, '\\')) != NULL)
544         ++user;
545     else
546         user = username;
547
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);
553
554     BCOPY(sha1Hash, Challenge, 8);
555 }
556
557 /*
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.)
563  */
564 static void
565 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
566 {
567     int i;
568
569     BZERO(unicode, ascii_len * 2);
570     for (i = 0; i < ascii_len; i++)
571         unicode[i * 2] = (u_char) ascii[i];
572 }
573
574 static void
575 NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
576 {
577 #ifdef __NetBSD__
578     /* NetBSD uses the libc md4 routines which take bytes instead of bits */
579     int                 mdlen = secret_len;
580 #else
581     int                 mdlen = secret_len * 8;
582 #endif
583     MD4_CTX             md4Context;
584
585     MD4Init(&md4Context);
586     /* MD4Update can take at most 64 bytes at a time */
587     while (mdlen > 512) {
588         MD4Update(&md4Context, secret, 512);
589         secret += 64;
590         mdlen -= 512;
591     }
592     MD4Update(&md4Context, secret, mdlen);
593     MD4Final(hash, &md4Context);
594
595 }
596
597 static void
598 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
599           u_char NTResponse[24])
600 {
601     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
602     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
603
604     /* Hash the Unicode version of the secret (== password). */
605     ascii2unicode(secret, secret_len, unicodePassword);
606     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
607
608     ChallengeResponse(rchallenge, PasswordHash, NTResponse);
609 }
610
611 static void
612 ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username,
613            char *secret, int secret_len, u_char NTResponse[24])
614 {
615     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
616     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
617     u_char      Challenge[8];
618
619     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
620
621     /* Hash the Unicode version of the secret (== password). */
622     ascii2unicode(secret, secret_len, unicodePassword);
623     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
624
625     ChallengeResponse(Challenge, PasswordHash, NTResponse);
626 }
627
628 #ifdef MSLANMAN
629 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
630
631 static void
632 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
633               unsigned char *response)
634 {
635     int                 i;
636     u_char              UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
637     u_char              PasswordHash[MD4_SIGNATURE_SIZE];
638
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]);
648 }
649 #endif
650
651
652 void
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])
657 {
658     /*
659      * "Magic" constants used in response generation, from RFC 2759.
660      */
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,
671           0x6E };
672
673     int         i;
674     SHA1_CTX    sha1Context;
675     u_char      Digest[SHA1_SIGNATURE_SIZE];
676     u_char      Challenge[8];
677
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);
683
684     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
685
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);
691
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]);
695 }
696
697
698 static void
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])
704 {
705     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
706     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
707     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
708
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),
713                    PasswordHashHash);
714
715     GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
716                                   rchallenge, username, authResponse);
717 }
718
719
720 #ifdef MPPE
721 /*
722  * Set mppe_xxxx_key from the NTPasswordHashHash.
723  * RFC 2548 (RADIUS support) requires us to export this function (ugh).
724  */
725 void
726 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
727 {
728     SHA1_CTX    sha1Context;
729     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
730
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);
736
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));
740
741     mppe_keys_set = 1;
742 }
743
744 /*
745  * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
746  */
747 static void
748 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
749 {
750     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
751     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
752     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
753
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);
758
759     mppe_set_keys(rchallenge, PasswordHashHash);
760 }
761
762 /*
763  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
764  *
765  * This helper function used in the Winbind module, which gets the
766  * NTHashHash from the server.
767  */
768 void
769 mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
770                u_char NTResponse[24], int IsServer)
771 {
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 */
775
776     u_char SHApad1[40] =
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 };
781     u_char SHApad2[40] =
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 };
786
787     /* "This is the MPPE Master Key" */
788     u_char Magic1[27] =
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." */
794     u_char Magic2[84] =
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." */
806     u_char Magic3[84] =
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 };
816     u_char *s;
817
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);
823
824     /*
825      * generate send key
826      */
827     if (IsServer)
828         s = Magic3;
829     else
830         s = Magic2;
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);
837
838     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
839
840     /*
841      * generate recv key
842      */
843     if (IsServer)
844         s = Magic2;
845     else
846         s = Magic3;
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);
853
854     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
855
856     mppe_keys_set = 1;
857 }
858
859 /*
860  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
861  */
862 static void
863 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
864 {
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);
873 }
874
875 #endif /* MPPE */
876
877
878 void
879 ChapMS(u_char *rchallenge, char *secret, int secret_len,
880        unsigned char *response)
881 {
882     BZERO(response, MS_CHAP_RESPONSE_LEN);
883
884     ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
885
886 #ifdef MSLANMAN
887     ChapMS_LANMan(rchallenge, secret, secret_len,
888                   &response[MS_CHAP_LANMANRESP]);
889
890     /* preferred method is set by option  */
891     response[MS_CHAP_USENT] = !ms_lanman;
892 #else
893     response[MS_CHAP_USENT] = 1;
894 #endif
895
896 #ifdef MPPE
897     Set_Start_Key(rchallenge, secret, secret_len);
898 #endif
899 }
900
901
902 /*
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.
908  *
909  * The PeerChallenge field of response is then used for calculation of the
910  * Authenticator Response.
911  */
912 void
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)
916 {
917     /* ARGSUSED */
918     u_char *p = &response[MS_CHAP2_PEER_CHALLENGE];
919     int i;
920
921     BZERO(response, MS_CHAP2_RESPONSE_LEN);
922
923     /* Generate the Peer-Challenge if requested, or copy it if supplied. */
924     if (!PeerChallenge)
925         for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++)
926             *p++ = (u_char) (drand48() * 0xff);
927     else
928         BCOPY(PeerChallenge, &response[MS_CHAP2_PEER_CHALLENGE],
929               MS_CHAP2_PEER_CHAL_LEN);
930
931     /* Generate the NT-Response */
932     ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
933                secret, secret_len, &response[MS_CHAP2_NTRESP]);
934
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);
940
941 #ifdef MPPE
942     SetMasterKeys(secret, secret_len,
943                   &response[MS_CHAP2_NTRESP], authenticator);
944 #endif
945 }
946
947 #ifdef MPPE
948 /*
949  * Set MPPE options from plugins.
950  */
951 void
952 set_mppe_enc_types(int policy, int types)
953 {
954     /* Early exit for unknown policies. */
955     if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
956         policy != MPPE_ENC_POL_ENC_REQUIRED)
957         return;
958
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)
961         return;
962
963     /*
964      * Disable undesirable encryption types.  Note that we don't ENABLE
965      * any encryption types, to avoid overriding manual configuration.
966      */
967     switch(types) {
968         case MPPE_ENC_TYPES_RC4_40:
969             ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;   /* disable 128-bit */
970             break;
971         case MPPE_ENC_TYPES_RC4_128:
972             ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;    /* disable 40-bit */
973             break;
974         default:
975             break;
976     }
977 }
978 #endif /* MPPE */
979
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,
987 };
988
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,
996 };
997
998 void
999 chapms_init(void)
1000 {
1001         chap_register_digest(&chapms_digest);
1002         chap_register_digest(&chapms2_digest);
1003         add_options(chapms_option_list);
1004 }
1005
1006 #endif /* CHAPMS */