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