OSDN Git Service

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