]> git.ozlabs.org Git - ppp.git/blob - pppd/chap_ms.c
PPPoE updates: don't exit if discovery fails, cope with both
[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.30 2003/07/10 17:59:33 fcusack 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     ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
101 static void     ascii2unicode __P((char[], int, u_char[]));
102 static void     NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
103 static void     ChallengeResponse __P((u_char *, u_char *, u_char[24]));
104 static void     ChapMS_NT __P((u_char *, char *, int, u_char[24]));
105 static void     ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
106                                 u_char[24]));
107 static void     GenerateAuthenticatorResponse __P((char*, int, u_char[24],
108                                                    u_char[16], u_char *,
109                                                    char *, u_char[41]));
110 #ifdef MSLANMAN
111 static void     ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
112 #endif
113
114 #ifdef MPPE
115 static void     Set_Start_Key __P((u_char *, char *, int));
116 static void     SetMasterKeys __P((char *, int, u_char[24], int));
117 #endif
118
119 #ifdef MSLANMAN
120 bool    ms_lanman = 0;          /* Use LanMan password instead of NT */
121                                 /* Has meaning only with MS-CHAP challenges */
122 #endif
123
124 #ifdef MPPE
125 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
126 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
127 int mppe_keys_set = 0;          /* Have the MPPE keys been set? */
128
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
135 #include "fsm.h"                /* Need to poke MPPE options */
136 #include "ccp.h"
137 #include <net/ppp-comp.h>
138 #endif
139
140 /*
141  * Command-line options.
142  */
143 static option_t chapms_option_list[] = {
144 #ifdef MSLANMAN
145         { "ms-lanman", o_bool, &ms_lanman,
146           "Use LanMan passwd when using MS-CHAP", 1 },
147 #endif
148 #ifdef DEBUGMPPEKEY
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" },
153 #endif
154         { NULL }
155 };
156
157 /*
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
161  * at challenge[1].
162  */
163 static void
164 chapms_generate_challenge(unsigned char *challenge)
165 {
166         *challenge++ = 8;
167         if (mschap_challenge && strlen(mschap_challenge) == 8)
168                 memcpy(challenge, mschap_challenge, 8);
169         else
170                 random_bytes(challenge, 8);
171 }
172
173 static void
174 chapms2_generate_challenge(unsigned char *challenge)
175 {
176         *challenge++ = 16;
177         if (mschap_challenge && strlen(mschap_challenge) == 16)
178                 memcpy(challenge, mschap_challenge, 16);
179         else
180                 random_bytes(challenge, 16);
181 }
182
183 static int
184 chapms_verify_response(int id, char *name,
185                        unsigned char *secret, int secret_len,
186                        unsigned char *challenge, unsigned char *response,
187                        char *message, int message_space)
188 {
189         MS_ChapResponse *rmd;
190         MS_ChapResponse md;
191         int diff;
192         int challenge_len, response_len;
193
194         challenge_len = *challenge++;   /* skip length, is 8 */
195         response_len = *response++;
196         if (response_len != MS_CHAP_RESPONSE_LEN)
197                 goto bad;
198
199         rmd = (MS_ChapResponse *) response;
200
201 #ifndef MSLANMAN
202         if (!rmd->UseNT[0]) {
203                 /* Should really propagate this into the error packet. */
204                 notice("Peer request for LANMAN auth not supported");
205                 goto bad;
206         }
207 #endif
208
209         /* Generate the expected response. */
210         ChapMS(challenge, secret, secret_len, &md);
211
212 #ifdef MSLANMAN
213         /* Determine which part of response to verify against */
214         if (!rmd->UseNT[0])
215                 diff = memcmp(&rmd->LANManResp, &md.LANManResp,
216                               sizeof(md.LANManResp));
217         else
218 #endif
219                 diff = memcmp(&rmd->NTResp, &md.NTResp, sizeof(md.NTResp));
220
221         if (diff == 0) {
222                 slprintf(message, message_space, "Access granted");
223                 return 1;
224         }
225
226  bad:
227         /* See comments below for MS-CHAP V2 */
228         slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
229                  challenge_len, challenge);
230         return 0;
231 }
232
233 static int
234 chapms2_verify_response(int id, char *name,
235                         unsigned char *secret, int secret_len,
236                         unsigned char *challenge, unsigned char *response,
237                         char *message, int message_space)
238 {
239         MS_Chap2Response *rmd;
240         MS_Chap2Response md;
241         char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
242         int challenge_len, response_len;
243
244         challenge_len = *challenge++;   /* skip length, is 16 */
245         response_len = *response++;
246         if (response_len != MS_CHAP2_RESPONSE_LEN)
247                 goto bad;       /* not even the right length */
248
249         rmd = (MS_Chap2Response *) response;
250
251         /* Generate the expected response and our mutual auth. */
252         ChapMS2(challenge, rmd->PeerChallenge, name,
253                 secret, secret_len, &md,
254                 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.NTResp, rmd->NTResp, sizeof(md.NTResp)) == 0) {
277                 if (rmd->Flags[0])
278                         slprintf(message, message_space, "S=%s", saresponse);
279                 else
280                         slprintf(message, message_space, "S=%s M=%s",
281                                  saresponse, "Access granted");
282                 return 1;
283         }
284
285  bad:
286         /*
287          * Failure message must be formatted as
288          *     "E=e R=r C=c V=v M=m"
289          * where
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
294          *     m = text message
295          *
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.
299          *
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).
303          *
304          * Basically, this whole bit is useless code, even the small
305          * implementation here is only because of overspecification.
306          */
307         slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
308                  challenge_len, challenge, "Access denied");
309         return 0;
310 }
311
312 static void
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)
316 {
317         challenge++;    /* skip length, should be 8 */
318         *response++ = MS_CHAP_RESPONSE_LEN;
319         ChapMS(challenge, secret, secret_len, (MS_ChapResponse *) response);
320 }
321
322 static void
323 chapms2_make_response(unsigned char *response, int id, char *our_name,
324                       unsigned char *challenge, char *secret, int secret_len,
325                       unsigned char *private)
326 {
327         challenge++;    /* skip length, should be 16 */
328         *response++ = MS_CHAP2_RESPONSE_LEN;
329         ChapMS2(challenge, mschap2_peer_challenge, our_name,
330                 secret, secret_len,
331                 (MS_Chap2Response *) response, private,
332                 MS_CHAP2_AUTHENTICATEE);
333 }
334
335 static int
336 chapms2_check_success(unsigned char *msg, int len, unsigned char *private)
337 {
338         if ((len < MS_AUTH_RESPONSE_LENGTH + 2) || strncmp(msg, "S=", 2)) {
339                 /* Packet does not start with "S=" */
340                 error("MS-CHAPv2 Success packet is badly formed.");
341                 return 0;
342         }
343         msg += 2;
344         len -= 2;
345         if (len < MS_AUTH_RESPONSE_LENGTH
346             || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {
347                 /* Authenticator Response did not match expected. */
348                 error("MS-CHAPv2 mutual authentication failed.");
349                 return 0;
350         }
351         /* Authenticator Response matches. */
352         msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
353         len -= MS_AUTH_RESPONSE_LENGTH;
354         if ((len >= 3) && !strncmp(msg, " M=", 3)) {
355                 msg += 3; /* Eat the delimiter */
356         } else if (len) {
357                 /* Packet has extra text which does not begin " M=" */
358                 error("MS-CHAPv2 Success packet is badly formed.");
359                 return 0;
360         }
361         return 1;
362 }
363
364 static void
365 chapms_handle_failure(unsigned char *inp, int len)
366 {
367         int err;
368         char *p, *msg;
369
370         /* We want a null-terminated string for strxxx(). */
371         msg = malloc(len + 1);
372         if (!msg) {
373                 notice("Out of memory in chapms_handle_failure");
374                 return;
375         }
376         BCOPY(inp, msg, len);
377         msg[len] = 0;
378         p = msg;
379
380         /*
381          * Deal with MS-CHAP formatted failure messages; just print the
382          * M=<message> part (if any).  For MS-CHAP we're not really supposed
383          * to use M=<message>, but it shouldn't hurt.  See
384          * chapms[2]_verify_response.
385          */
386         if (!strncmp(p, "E=", 2))
387                 err = strtol(p, NULL, 10); /* Remember the error code. */
388         else
389                 goto print_msg; /* Message is badly formatted. */
390
391         if (len && ((p = strstr(p, " M=")) != NULL)) {
392                 /* M=<message> field found. */
393                 p += 3;
394         } else {
395                 /* No M=<message>; use the error code. */
396                 switch (err) {
397                 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
398                         p = "E=646 Restricted logon hours";
399                         break;
400
401                 case MS_CHAP_ERROR_ACCT_DISABLED:
402                         p = "E=647 Account disabled";
403                         break;
404
405                 case MS_CHAP_ERROR_PASSWD_EXPIRED:
406                         p = "E=648 Password expired";
407                         break;
408
409                 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
410                         p = "E=649 No dialin permission";
411                         break;
412
413                 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
414                         p = "E=691 Authentication failure";
415                         break;
416
417                 case MS_CHAP_ERROR_CHANGING_PASSWORD:
418                         /* Should never see this, we don't support Change Password. */
419                         p = "E=709 Error changing password";
420                         break;
421
422                 default:
423                         free(msg);
424                         error("Unknown MS-CHAP authentication failure: %.*v",
425                               len, inp);
426                         return;
427                 }
428         }
429 print_msg:
430         if (p != NULL)
431                 error("MS-CHAP authentication failed: %v", p);
432         free(msg);
433 }
434
435 static void
436 ChallengeResponse(u_char *challenge,
437                   u_char PasswordHash[MD4_SIGNATURE_SIZE],
438                   u_char response[24])
439 {
440     u_char    ZPasswordHash[21];
441
442     BZERO(ZPasswordHash, sizeof(ZPasswordHash));
443     BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
444
445 #if 0
446     dbglog("ChallengeResponse - ZPasswordHash %.*B",
447            sizeof(ZPasswordHash), ZPasswordHash);
448 #endif
449
450     (void) DesSetkey(ZPasswordHash + 0);
451     DesEncrypt(challenge, response + 0);
452     (void) DesSetkey(ZPasswordHash + 7);
453     DesEncrypt(challenge, response + 8);
454     (void) DesSetkey(ZPasswordHash + 14);
455     DesEncrypt(challenge, response + 16);
456
457 #if 0
458     dbglog("ChallengeResponse - response %.24B", response);
459 #endif
460 }
461
462 static void
463 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
464               char *username, u_char Challenge[8])
465     
466 {
467     SHA1_CTX    sha1Context;
468     u_char      sha1Hash[SHA1_SIGNATURE_SIZE];
469     char        *user;
470
471     /* remove domain from "domain\username" */
472     if ((user = strrchr(username, '\\')) != NULL)
473         ++user;
474     else
475         user = username;
476
477     SHA1_Init(&sha1Context);
478     SHA1_Update(&sha1Context, PeerChallenge, 16);
479     SHA1_Update(&sha1Context, rchallenge, 16);
480     SHA1_Update(&sha1Context, user, strlen(user));
481     SHA1_Final(sha1Hash, &sha1Context);
482
483     BCOPY(sha1Hash, Challenge, 8);
484 }
485
486 /*
487  * Convert the ASCII version of the password to Unicode.
488  * This implicitly supports 8-bit ISO8859/1 characters.
489  * This gives us the little-endian representation, which
490  * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
491  * is machine-dependent.)
492  */
493 static void
494 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
495 {
496     int i;
497
498     BZERO(unicode, ascii_len * 2);
499     for (i = 0; i < ascii_len; i++)
500         unicode[i * 2] = (u_char) ascii[i];
501 }
502
503 static void
504 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
505 {
506 #ifdef __NetBSD__
507     /* NetBSD uses the libc md4 routines which take bytes instead of bits */
508     int                 mdlen = secret_len;
509 #else
510     int                 mdlen = secret_len * 8;
511 #endif
512     MD4_CTX             md4Context;
513
514     MD4Init(&md4Context);
515     MD4Update(&md4Context, secret, mdlen);
516     MD4Final(hash, &md4Context);
517
518 }
519
520 static void
521 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
522           u_char NTResponse[24])
523 {
524     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
525     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
526
527     /* Hash the Unicode version of the secret (== password). */
528     ascii2unicode(secret, secret_len, unicodePassword);
529     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
530
531     ChallengeResponse(rchallenge, PasswordHash, NTResponse);
532 }
533
534 static void
535 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
536            char *secret, int secret_len, u_char NTResponse[24])
537 {
538     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
539     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
540     u_char      Challenge[8];
541
542     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
543
544     /* Hash the Unicode version of the secret (== password). */
545     ascii2unicode(secret, secret_len, unicodePassword);
546     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
547
548     ChallengeResponse(Challenge, PasswordHash, NTResponse);
549 }
550
551 #ifdef MSLANMAN
552 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
553
554 static void
555 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
556               MS_ChapResponse *response)
557 {
558     int                 i;
559     u_char              UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
560     u_char              PasswordHash[MD4_SIGNATURE_SIZE];
561
562     /* LANMan password is case insensitive */
563     BZERO(UcasePassword, sizeof(UcasePassword));
564     for (i = 0; i < secret_len; i++)
565        UcasePassword[i] = (u_char)toupper(secret[i]);
566     (void) DesSetkey(UcasePassword + 0);
567     DesEncrypt( StdText, PasswordHash + 0 );
568     (void) DesSetkey(UcasePassword + 7);
569     DesEncrypt( StdText, PasswordHash + 8 );
570     ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
571 }
572 #endif
573
574
575 static void
576 GenerateAuthenticatorResponse(char *secret, int secret_len,
577                               u_char NTResponse[24], u_char PeerChallenge[16],
578                               u_char *rchallenge, char *username,
579                               u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
580 {
581     /*
582      * "Magic" constants used in response generation, from RFC 2759.
583      */
584     u_char Magic1[39] = /* "Magic server to client signing constant" */
585         { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
586           0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
587           0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
588           0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
589     u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
590         { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
591           0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
592           0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
593           0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
594           0x6E };
595
596     int         i;
597     SHA1_CTX    sha1Context;
598     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
599     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
600     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
601     u_char      Digest[SHA1_SIGNATURE_SIZE];
602     u_char      Challenge[8];
603
604     /* Hash (x2) the Unicode version of the secret (== password). */
605     ascii2unicode(secret, secret_len, unicodePassword);
606     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
607     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
608
609     SHA1_Init(&sha1Context);
610     SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
611     SHA1_Update(&sha1Context, NTResponse, 24);
612     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
613     SHA1_Final(Digest, &sha1Context);
614
615     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
616
617     SHA1_Init(&sha1Context);
618     SHA1_Update(&sha1Context, Digest, sizeof(Digest));
619     SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
620     SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
621     SHA1_Final(Digest, &sha1Context);
622
623     /* Convert to ASCII hex string. */
624     for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
625         sprintf(&authResponse[i * 2], "%02X", Digest[i]);
626 }
627
628
629 #ifdef MPPE
630 /*
631  * Set mppe_xxxx_key from the NTPasswordHashHash.
632  * RFC 2548 (RADIUS support) requires us to export this function (ugh).
633  */
634 void
635 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
636 {
637     SHA1_CTX    sha1Context;
638     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
639
640     SHA1_Init(&sha1Context);
641     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
642     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
643     SHA1_Update(&sha1Context, rchallenge, 8);
644     SHA1_Final(Digest, &sha1Context);
645
646     /* Same key in both directions. */
647     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
648     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
649 }
650
651 /*
652  * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
653  */
654 static void
655 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
656 {
657     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
658     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
659     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
660
661     /* Hash (x2) the Unicode version of the secret (== password). */
662     ascii2unicode(secret, secret_len, unicodePassword);
663     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
664     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
665
666     mppe_set_keys(rchallenge, PasswordHashHash);
667 }
668
669 /*
670  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
671  */
672 static void
673 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
674 {
675     SHA1_CTX    sha1Context;
676     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
677     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
678     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
679     u_char      MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
680     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
681
682     u_char SHApad1[40] =
683         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
685           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
686           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
687     u_char SHApad2[40] =
688         { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
689           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
690           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
691           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
692
693     /* "This is the MPPE Master Key" */
694     u_char Magic1[27] =
695         { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
696           0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
697           0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
698     /* "On the client side, this is the send key; "
699        "on the server side, it is the receive key." */
700     u_char Magic2[84] =
701         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
702           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
703           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
704           0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
705           0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
706           0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
707           0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
708           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
709           0x6b, 0x65, 0x79, 0x2e };
710     /* "On the client side, this is the receive key; "
711        "on the server side, it is the send key." */
712     u_char Magic3[84] =
713         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
714           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
715           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
716           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
717           0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
718           0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
719           0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
720           0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
721           0x6b, 0x65, 0x79, 0x2e };
722     u_char *s;
723
724     /* Hash (x2) the Unicode version of the secret (== password). */
725     ascii2unicode(secret, secret_len, unicodePassword);
726     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
727     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
728
729     SHA1_Init(&sha1Context);
730     SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
731     SHA1_Update(&sha1Context, NTResponse, 24);
732     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
733     SHA1_Final(MasterKey, &sha1Context);
734
735     /*
736      * generate send key
737      */
738     if (IsServer)
739         s = Magic3;
740     else
741         s = Magic2;
742     SHA1_Init(&sha1Context);
743     SHA1_Update(&sha1Context, MasterKey, 16);
744     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
745     SHA1_Update(&sha1Context, s, 84);
746     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
747     SHA1_Final(Digest, &sha1Context);
748
749     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
750
751     /*
752      * generate recv key
753      */
754     if (IsServer)
755         s = Magic2;
756     else
757         s = Magic3;
758     SHA1_Init(&sha1Context);
759     SHA1_Update(&sha1Context, MasterKey, 16);
760     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
761     SHA1_Update(&sha1Context, s, 84);
762     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
763     SHA1_Final(Digest, &sha1Context);
764
765     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
766 }
767
768 #endif /* MPPE */
769
770
771 void
772 ChapMS(u_char *rchallenge, char *secret, int secret_len,
773        MS_ChapResponse *response)
774 {
775 #if 0
776     CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
777 #endif
778     BZERO(response, sizeof(*response));
779
780     ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
781
782 #ifdef MSLANMAN
783     ChapMS_LANMan(rchallenge, secret, secret_len, response);
784
785     /* preferred method is set by option  */
786     response->UseNT[0] = !ms_lanman;
787 #else
788     response->UseNT[0] = 1;
789 #endif
790
791 #ifdef MPPE
792     Set_Start_Key(rchallenge, secret, secret_len);
793     mppe_keys_set = 1;
794 #endif
795 }
796
797
798 /*
799  * If PeerChallenge is NULL, one is generated and response->PeerChallenge
800  * is filled in.  Call this way when generating a response.
801  * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
802  * Call this way when verifying a response (or debugging).
803  * Do not call with PeerChallenge = response->PeerChallenge.
804  *
805  * response->PeerChallenge is then used for calculation of the
806  * Authenticator Response.
807  */
808 void
809 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
810         char *user, char *secret, int secret_len, MS_Chap2Response *response,
811         u_char authResponse[], int authenticator)
812 {
813     /* ARGSUSED */
814     u_char *p = response->PeerChallenge;
815     int i;
816
817     BZERO(response, sizeof(*response));
818
819     /* Generate the Peer-Challenge if requested, or copy it if supplied. */
820     if (!PeerChallenge)
821         for (i = 0; i < sizeof(response->PeerChallenge); i++)
822             *p++ = (u_char) (drand48() * 0xff);
823     else
824         BCOPY(PeerChallenge, response->PeerChallenge,
825               sizeof(response->PeerChallenge));
826
827     /* Generate the NT-Response */
828     ChapMS2_NT(rchallenge, response->PeerChallenge, user,
829                secret, secret_len, response->NTResp);
830
831     /* Generate the Authenticator Response. */
832     GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
833                                   response->PeerChallenge, rchallenge,
834                                   user, authResponse);
835
836 #ifdef MPPE
837     SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
838     mppe_keys_set = 1;
839 #endif
840 }
841
842 #ifdef MPPE
843 /*
844  * Set MPPE options from plugins.
845  */
846 void
847 set_mppe_enc_types(int policy, int types)
848 {
849     /* Early exit for unknown policies. */
850     if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
851         policy != MPPE_ENC_POL_ENC_REQUIRED)
852         return;
853
854     /* Don't modify MPPE if it's optional and wasn't already configured. */
855     if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
856         return;
857
858     /*
859      * Disable undesirable encryption types.  Note that we don't ENABLE
860      * any encryption types, to avoid overriding manual configuration.
861      */
862     switch(types) {
863         case MPPE_ENC_TYPES_RC4_40:
864             ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;   /* disable 128-bit */
865             break;
866         case MPPE_ENC_TYPES_RC4_128:
867             ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;    /* disable 40-bit */
868             break;
869         default:
870             break;
871     }
872 }
873 #endif /* MPPE */
874
875 static struct chap_digest_type chapms_digest = {
876         CHAP_MICROSOFT,         /* code */
877         chapms_generate_challenge,
878         chapms_verify_response,
879         chapms_make_response,
880         NULL,                   /* check_success */
881         chapms_handle_failure,
882 };
883
884 static struct chap_digest_type chapms2_digest = {
885         CHAP_MICROSOFT_V2,      /* code */
886         chapms2_generate_challenge,
887         chapms2_verify_response,
888         chapms2_make_response,
889         chapms2_check_success,
890         chapms_handle_failure,
891 };
892
893 void
894 chapms_init(void)
895 {
896         chap_register_digest(&chapms_digest);
897         chap_register_digest(&chapms2_digest);
898         add_options(chapms_option_list);
899 }
900
901 #endif /* CHAPMS */