]> git.ozlabs.org Git - ppp.git/blob - pppd/chap_ms.c
Update DFS's legal name and email address to correct values. (#381)
[ppp.git] / pppd / chap_ms.c
1 /*
2  * chap_ms.c - Microsoft MS-CHAP compatible implementation.
3  *
4  * Copyright (c) 1995 Eric Rosenquist.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * 3. The name(s) of the authors of this software must not be used to
19  *    endorse or promote products derived from this software without
20  *    prior written permission.
21  *
22  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
23  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
24  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
26  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
28  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29  */
30
31 /*
32  * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
33  *
34  *   Implemented LANManager type password response to MS-CHAP challenges.
35  *   Now pppd provides both NT style and LANMan style blocks, and the
36  *   prefered is set by option "ms-lanman". Default is to use NT.
37  *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
38  *
39  *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
40  */
41
42 /*
43  * Modifications by Frank Cusack, frank@google.com, March 2002.
44  *
45  *   Implemented MS-CHAPv2 functionality, heavily based on sample
46  *   implementation in RFC 2759.  Implemented MPPE functionality,
47  *   heavily based on sample implementation in RFC 3079.
48  *
49  * Copyright (c) 2002 Google, Inc.  All rights reserved.
50  *
51  * Redistribution and use in source and binary forms, with or without
52  * modification, are permitted provided that the following conditions
53  * are met:
54  *
55  * 1. Redistributions of source code must retain the above copyright
56  *    notice, this list of conditions and the following disclaimer.
57  *
58  * 2. Redistributions in binary form must reproduce the above copyright
59  *    notice, this list of conditions and the following disclaimer in
60  *    the documentation and/or other materials provided with the
61  *    distribution.
62  *
63  * 3. The name(s) of the authors of this software must not be used to
64  *    endorse or promote products derived from this software without
65  *    prior written permission.
66  *
67  * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
68  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
69  * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
70  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
71  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
72  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
73  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
74  *
75  */
76
77 #define RCSID   "$Id: chap_ms.c,v 1.38 2007/12/01 20:10:51 carlsonj Exp $"
78
79 #ifdef HAVE_CONFIG_H
80 #include "config.h"
81 #endif
82
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <string.h>
86 #include <ctype.h>
87 #include <sys/types.h>
88 #include <sys/time.h>
89 #include <unistd.h>
90 #if defined(SOL2)
91 #include <net/ppp-comp.h>
92 #else
93 #include <linux/ppp-comp.h>
94 #endif
95
96 #include "pppd.h"
97 #include "chap-new.h"
98 #include "chap_ms.h"
99 #include "magic.h"
100 #include "mppe.h"
101 #include "ppp-crypto.h"
102 #include "pppcrypt.h"
103
104 #ifdef UNIT_TEST
105 #undef PPP_WITH_MPPE
106 #endif
107
108 static void     ascii2unicode (char[], int, u_char[]);
109 static void     NTPasswordHash (u_char *, int, unsigned char *);
110 static int      ChallengeResponse (u_char *, u_char *, u_char*);
111 static void     ChapMS_NT (u_char *, char *, int, u_char[24]);
112 static void     ChapMS2_NT (u_char *, u_char[16], char *, char *, int,
113                                 u_char[24]);
114 static void     GenerateAuthenticatorResponsePlain
115                         (char*, int, u_char[24], u_char[16], u_char *,
116                          char *, u_char[41]);
117 #ifdef PPP_WITH_MSLANMAN
118 static void     ChapMS_LANMan (u_char *, char *, int, u_char *);
119 #endif
120
121 #ifdef PPP_WITH_MSLANMAN
122 bool    ms_lanman = 0;          /* Use LanMan password instead of NT */
123                                 /* Has meaning only with MS-CHAP challenges */
124 #endif
125
126 #ifdef PPP_WITH_MPPE
127 #ifdef DEBUGMPPEKEY
128 /* For MPPE debug */
129 /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
130 static char *mschap_challenge = NULL;
131 /* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
132 static char *mschap2_peer_challenge = NULL;
133 #endif
134
135 #include "fsm.h"                /* Need to poke MPPE options */
136 #include "ccp.h"
137 #endif
138
139 /*
140  * Command-line options.
141  */
142 static option_t chapms_option_list[] = {
143 #ifdef PPP_WITH_MSLANMAN
144         { "ms-lanman", o_bool, &ms_lanman,
145           "Use LanMan passwd when using MS-CHAP", 1 },
146 #endif
147 #ifdef DEBUGMPPEKEY
148         { "mschap-challenge", o_string, &mschap_challenge,
149           "specify CHAP challenge" },
150         { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
151           "specify CHAP peer challenge" },
152 #endif
153         { NULL }
154 };
155
156 /*
157  * chapms_generate_challenge - generate a challenge for MS-CHAP.
158  * For MS-CHAP the challenge length is fixed at 8 bytes.
159  * The length goes in challenge[0] and the actual challenge starts
160  * at challenge[1].
161  */
162 static void
163 chapms_generate_challenge(unsigned char *challenge)
164 {
165         *challenge++ = 8;
166 #ifdef DEBUGMPPEKEY
167         if (mschap_challenge && strlen(mschap_challenge) == 8)
168                 memcpy(challenge, mschap_challenge, 8);
169         else
170 #endif
171                 random_bytes(challenge, 8);
172 }
173
174 static void
175 chapms2_generate_challenge(unsigned char *challenge)
176 {
177         *challenge++ = 16;
178 #ifdef DEBUGMPPEKEY
179         if (mschap_challenge && strlen(mschap_challenge) == 16)
180                 memcpy(challenge, mschap_challenge, 16);
181         else
182 #endif
183                 random_bytes(challenge, 16);
184 }
185
186 static int
187 chapms_verify_response(int id, char *name,
188                        unsigned char *secret, int secret_len,
189                        unsigned char *challenge, unsigned char *response,
190                        char *message, int message_space)
191 {
192         unsigned char md[MS_CHAP_RESPONSE_LEN];
193         int diff;
194         int challenge_len, response_len;
195
196         challenge_len = *challenge++;   /* skip length, is 8 */
197         response_len = *response++;
198         if (response_len != MS_CHAP_RESPONSE_LEN)
199                 goto bad;
200
201 #ifndef PPP_WITH_MSLANMAN
202         if (!response[MS_CHAP_USENT]) {
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, (char *)secret, secret_len, md);
211
212 #ifdef PPP_WITH_MSLANMAN
213         /* Determine which part of response to verify against */
214         if (!response[MS_CHAP_USENT])
215                 diff = memcmp(&response[MS_CHAP_LANMANRESP],
216                               &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN);
217         else
218 #endif
219                 diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP],
220                               MS_CHAP_NTRESP_LEN);
221
222         if (diff == 0) {
223                 slprintf(message, message_space, "Access granted");
224                 return 1;
225         }
226
227  bad:
228         /* See comments below for MS-CHAP V2 */
229         slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
230                  challenge_len, challenge);
231         return 0;
232 }
233
234 static int
235 chapms2_verify_response(int id, char *name,
236                         unsigned char *secret, int secret_len,
237                         unsigned char *challenge, unsigned char *response,
238                         char *message, int message_space)
239 {
240         unsigned char md[MS_CHAP2_RESPONSE_LEN];
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         /* Generate the expected response and our mutual auth. */
250         ChapMS2(challenge, &response[MS_CHAP2_PEER_CHALLENGE], name,
251                 (char *)secret, secret_len, md,
252                 (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
253
254         /* compare MDs and send the appropriate status */
255         /*
256          * Per RFC 2759, success message must be formatted as
257          *     "S=<auth_string> M=<message>"
258          * where
259          *     <auth_string> is the Authenticator Response (mutual auth)
260          *     <message> is a text message
261          *
262          * However, some versions of Windows (win98 tested) do not know
263          * about the M=<message> part (required per RFC 2759) and flag
264          * it as an error (reported incorrectly as an encryption error
265          * to the user).  Since the RFC requires it, and it can be
266          * useful information, we supply it if the peer is a conforming
267          * system.  Luckily (?), win98 sets the Flags field to 0x04
268          * (contrary to RFC requirements) so we can use that to
269          * distinguish between conforming and non-conforming systems.
270          *
271          * Special thanks to Alex Swiridov <say@real.kharkov.ua> for
272          * help debugging this.
273          */
274         if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP],
275                    MS_CHAP2_NTRESP_LEN) == 0) {
276                 if (response[MS_CHAP2_FLAGS])
277                         slprintf(message, message_space, "S=%s", saresponse);
278                 else
279                         slprintf(message, message_space, "S=%s M=%s",
280                                  saresponse, "Access granted");
281                 return 1;
282         }
283
284  bad:
285         /*
286          * Failure message must be formatted as
287          *     "E=e R=r C=c V=v M=m"
288          * where
289          *     e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
290          *     r = retry (we use 1, ok to retry)
291          *     c = challenge to use for next response, we reuse previous
292          *     v = Change Password version supported, we use 0
293          *     m = text message
294          *
295          * The M=m part is only for MS-CHAPv2.  Neither win2k nor
296          * win98 (others untested) display the message to the user anyway.
297          * They also both ignore the E=e code.
298          *
299          * Note that it's safe to reuse the same challenge as we don't
300          * actually accept another response based on the error message
301          * (and no clients try to resend a response anyway).
302          *
303          * Basically, this whole bit is useless code, even the small
304          * implementation here is only because of overspecification.
305          */
306         slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
307                  challenge_len, challenge, "Access denied");
308         return 0;
309 }
310
311 static void
312 chapms_make_response(unsigned char *response, int id, char *our_name,
313                      unsigned char *challenge, char *secret, int secret_len,
314                      unsigned char *private)
315 {
316         challenge++;    /* skip length, should be 8 */
317         *response++ = MS_CHAP_RESPONSE_LEN;
318         ChapMS(challenge, secret, secret_len, response);
319 }
320
321 struct chapms2_response_cache_entry {
322         int id;
323         unsigned char challenge[16];
324         unsigned char response[MS_CHAP2_RESPONSE_LEN];
325         unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH];
326 };
327
328 #define CHAPMS2_MAX_RESPONSE_CACHE_SIZE 10
329 static struct chapms2_response_cache_entry
330     chapms2_response_cache[CHAPMS2_MAX_RESPONSE_CACHE_SIZE];
331 static int chapms2_response_cache_next_index = 0;
332 static int chapms2_response_cache_size = 0;
333
334 static void
335 chapms2_add_to_response_cache(int id, unsigned char *challenge,
336                               unsigned char *response,
337                               unsigned char *auth_response)
338 {
339         int i = chapms2_response_cache_next_index;
340
341         chapms2_response_cache[i].id = id;
342         memcpy(chapms2_response_cache[i].challenge, challenge, 16);
343         memcpy(chapms2_response_cache[i].response, response,
344                MS_CHAP2_RESPONSE_LEN);
345         memcpy(chapms2_response_cache[i].auth_response,
346                auth_response, MS_AUTH_RESPONSE_LENGTH);
347         chapms2_response_cache_next_index =
348                 (i + 1) % CHAPMS2_MAX_RESPONSE_CACHE_SIZE;
349         if (chapms2_response_cache_next_index > chapms2_response_cache_size)
350                 chapms2_response_cache_size = chapms2_response_cache_next_index;
351         dbglog("added response cache entry %d", i);
352 }
353
354 static struct chapms2_response_cache_entry*
355 chapms2_find_in_response_cache(int id, unsigned char *challenge,
356                       unsigned char *auth_response)
357 {
358         int i;
359
360         for (i = 0; i < chapms2_response_cache_size; i++) {
361                 if (id == chapms2_response_cache[i].id
362                     && (!challenge
363                         || memcmp(challenge,
364                                   chapms2_response_cache[i].challenge,
365                                   16) == 0)
366                     && (!auth_response
367                         || memcmp(auth_response,
368                                   chapms2_response_cache[i].auth_response,
369                                   MS_AUTH_RESPONSE_LENGTH) == 0)) {
370                         dbglog("response found in cache (entry %d)", i);
371                         return &chapms2_response_cache[i];
372                 }
373         }
374         return NULL;  /* not found */
375 }
376
377 static void
378 chapms2_make_response(unsigned char *response, int id, char *our_name,
379                       unsigned char *challenge, char *secret, int secret_len,
380                       unsigned char *private)
381 {
382         const struct chapms2_response_cache_entry *cache_entry;
383         unsigned char auth_response[MS_AUTH_RESPONSE_LENGTH+1];
384
385         challenge++;    /* skip length, should be 16 */
386         *response++ = MS_CHAP2_RESPONSE_LEN;
387         cache_entry = chapms2_find_in_response_cache(id, challenge, NULL);
388         if (cache_entry) {
389                 memcpy(response, cache_entry->response, MS_CHAP2_RESPONSE_LEN);
390                 return;
391         }
392         ChapMS2(challenge,
393 #ifdef DEBUGMPPEKEY
394                 mschap2_peer_challenge,
395 #else
396                 NULL,
397 #endif
398                 our_name, secret, secret_len, response, auth_response,
399                 MS_CHAP2_AUTHENTICATEE);
400         chapms2_add_to_response_cache(id, challenge, response, auth_response);
401 }
402
403 static int
404 chapms2_check_success(int id, unsigned char *msg, int len)
405 {
406         if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
407             strncmp((char *)msg, "S=", 2) != 0) {
408                 /* Packet does not start with "S=" */
409                 error("MS-CHAPv2 Success packet is badly formed.");
410                 return 0;
411         }
412         msg += 2;
413         len -= 2;
414         if (len < MS_AUTH_RESPONSE_LENGTH
415             || !chapms2_find_in_response_cache(id, NULL /* challenge */, msg)) {
416                 /* Authenticator Response did not match expected. */
417                 error("MS-CHAPv2 mutual authentication failed.");
418                 return 0;
419         }
420         /* Authenticator Response matches. */
421         msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
422         len -= MS_AUTH_RESPONSE_LENGTH;
423         if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
424                 msg += 3; /* Eat the delimiter */
425         } else  if ((len >= 2) && !strncmp((char *)msg, "M=", 2)) {
426                 msg += 2; /* Eat the delimiter */
427         } else if (len) {
428                 /* Packet has extra text which does not begin " M=" */
429                 error("MS-CHAPv2 Success packet is badly formed.");
430                 return 0;
431         }
432         return 1;
433 }
434
435 static void
436 chapms_handle_failure(unsigned char *inp, int len)
437 {
438         int err;
439         char *p, *msg;
440
441         /* We want a null-terminated string for strxxx(). */
442         msg = malloc(len + 1);
443         if (!msg) {
444                 notice("Out of memory in chapms_handle_failure");
445                 return;
446         }
447         BCOPY(inp, msg, len);
448         msg[len] = 0;
449         p = msg;
450
451         /*
452          * Deal with MS-CHAP formatted failure messages; just print the
453          * M=<message> part (if any).  For MS-CHAP we're not really supposed
454          * to use M=<message>, but it shouldn't hurt.  See
455          * chapms[2]_verify_response.
456          */
457         if (!strncmp(p, "E=", 2))
458                 err = strtol(p+2, NULL, 10); /* Remember the error code. */
459         else
460                 goto print_msg; /* Message is badly formatted. */
461
462         if (len && ((p = strstr(p, " M=")) != NULL)) {
463                 /* M=<message> field found. */
464                 p += 3;
465         } else {
466                 /* No M=<message>; use the error code. */
467                 switch (err) {
468                 case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
469                         p = "E=646 Restricted logon hours";
470                         break;
471
472                 case MS_CHAP_ERROR_ACCT_DISABLED:
473                         p = "E=647 Account disabled";
474                         break;
475
476                 case MS_CHAP_ERROR_PASSWD_EXPIRED:
477                         p = "E=648 Password expired";
478                         break;
479
480                 case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
481                         p = "E=649 No dialin permission";
482                         break;
483
484                 case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
485                         p = "E=691 Authentication failure";
486                         break;
487
488                 case MS_CHAP_ERROR_CHANGING_PASSWORD:
489                         /* Should never see this, we don't support Change Password. */
490                         p = "E=709 Error changing password";
491                         break;
492
493                 default:
494                         free(msg);
495                         error("Unknown MS-CHAP authentication failure: %.*v",
496                               len, inp);
497                         return;
498                 }
499         }
500 print_msg:
501         if (p != NULL)
502                 error("MS-CHAP authentication failed: %v", p);
503         free(msg);
504 }
505
506 static int
507 ChallengeResponse(u_char *challenge,
508                   u_char *PasswordHash,
509                   u_char *response)
510 {
511     u_char ZPasswordHash[21];
512     PPP_CIPHER_CTX *ctx;
513
514     BZERO(ZPasswordHash, sizeof(ZPasswordHash));
515     BCOPY(PasswordHash, ZPasswordHash, MD4_DIGEST_LENGTH);
516
517 #if 0
518     dbglog("ChallengeResponse - ZPasswordHash %.*B",
519            sizeof(ZPasswordHash), ZPasswordHash);
520 #endif
521
522     if (DesEncrypt(challenge, ZPasswordHash + 0,  response + 0) &&
523         DesEncrypt(challenge, ZPasswordHash + 7,  response + 8) &&
524         DesEncrypt(challenge, ZPasswordHash + 14, response + 16))
525         return 1;
526
527 #if 0
528     dbglog("ChallengeResponse - response %.24B", response);
529 #endif
530     return 0;
531 }
532
533 void
534 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
535               char *username, u_char Challenge[8])
536     
537 {
538     PPP_MD_CTX* ctx;
539     u_char      hash[SHA_DIGEST_LENGTH];
540     int     hash_len;
541     char        *user;
542
543     /* remove domain from "domain\username" */
544     if ((user = strrchr(username, '\\')) != NULL)
545         ++user;
546     else
547         user = username;
548     
549     ctx = PPP_MD_CTX_new();
550     if (ctx != NULL) {
551
552         if (PPP_DigestInit(ctx, PPP_sha1())) {
553
554             if (PPP_DigestUpdate(ctx, PeerChallenge, 16)) {
555
556                 if (PPP_DigestUpdate(ctx, rchallenge, 16)) {
557
558                     if (PPP_DigestUpdate(ctx, user, strlen(user))) {
559                         
560                         hash_len = SHA_DIGEST_LENGTH;
561                         if (PPP_DigestFinal(ctx, hash, &hash_len)) {
562
563                             BCOPY(hash, Challenge, 8);
564                         }
565                     }
566                 }
567             }
568         }
569
570         PPP_MD_CTX_free(ctx);
571     }
572 }
573
574 /*
575  * Convert the ASCII version of the password to Unicode.
576  * This implicitly supports 8-bit ISO8859/1 characters.
577  * This gives us the little-endian representation, which
578  * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
579  * is machine-dependent.)
580  */
581 static void
582 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
583 {
584     int i;
585
586     BZERO(unicode, ascii_len * 2);
587     for (i = 0; i < ascii_len; i++)
588         unicode[i * 2] = (u_char) ascii[i];
589 }
590
591 static void
592 NTPasswordHash(u_char *secret, int secret_len, unsigned char* hash)
593 {
594     PPP_MD_CTX* ctx = PPP_MD_CTX_new();
595     if (ctx != NULL) {
596
597         if (PPP_DigestInit(ctx, PPP_md4())) {
598
599             if (PPP_DigestUpdate(ctx, secret, secret_len)) {
600
601                 int hash_len = MD4_DIGEST_LENGTH;
602                 PPP_DigestFinal(ctx, hash, &hash_len);
603             }
604         }
605         
606         PPP_MD_CTX_free(ctx);
607     }
608 }
609
610 static void
611 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
612           u_char NTResponse[24])
613 {
614     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
615     u_char      PasswordHash[MD4_DIGEST_LENGTH];
616
617     /* Hash the Unicode version of the secret (== password). */
618     ascii2unicode(secret, secret_len, unicodePassword);
619     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
620
621     ChallengeResponse(rchallenge, PasswordHash, NTResponse);
622 }
623
624 static void
625 ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username,
626            char *secret, int secret_len, u_char NTResponse[24])
627 {
628     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
629     u_char      PasswordHash[MD4_DIGEST_LENGTH];
630     u_char      Challenge[8];
631
632     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
633
634     /* Hash the Unicode version of the secret (== password). */
635     ascii2unicode(secret, secret_len, unicodePassword);
636     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
637
638     ChallengeResponse(Challenge, PasswordHash, NTResponse);
639 }
640
641 #ifdef PPP_WITH_MSLANMAN
642 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
643
644 static void
645 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
646               unsigned char *response)
647 {
648     int                 i;
649     u_char              UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
650     u_char              PasswordHash[MD4_DIGEST_LENGTH];
651
652     /* LANMan password is case insensitive */
653     BZERO(UcasePassword, sizeof(UcasePassword));
654     for (i = 0; i < secret_len; i++)
655        UcasePassword[i] = (u_char)toupper(secret[i]);
656     (void) DesSetkey(UcasePassword + 0);
657     DesEncrypt( StdText, PasswordHash + 0 );
658     (void) DesSetkey(UcasePassword + 7);
659     DesEncrypt( StdText, PasswordHash + 8 );
660     ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]);
661 }
662 #endif
663
664
665 void
666 GenerateAuthenticatorResponse(unsigned char* PasswordHashHash,
667                               unsigned char *NTResponse, unsigned char *PeerChallenge,
668                               unsigned char *rchallenge, char *username,
669                               unsigned char *authResponse)
670 {
671     /*
672      * "Magic" constants used in response generation, from RFC 2759.
673      */
674     u_char Magic1[39] = /* "Magic server to client signing constant" */
675         { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
676           0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
677           0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
678           0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
679     u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
680         { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
681           0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
682           0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
683           0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
684           0x6E };
685
686     int         i;
687     PPP_MD_CTX *ctx;
688     u_char      Digest[SHA_DIGEST_LENGTH];
689     int     hash_len;
690     u_char      Challenge[8];
691
692     ctx = PPP_MD_CTX_new();
693     if (ctx != NULL) {
694
695         if (PPP_DigestInit(ctx, PPP_sha1())) {
696
697             if (PPP_DigestUpdate(ctx, PasswordHashHash, MD4_DIGEST_LENGTH)) {
698
699                 if (PPP_DigestUpdate(ctx, NTResponse, 24)) {
700
701                     if (PPP_DigestUpdate(ctx, Magic1, sizeof(Magic1))) {
702                         
703                         hash_len = sizeof(Digest);
704                         PPP_DigestFinal(ctx, Digest, &hash_len);
705                     }
706                 }
707             }
708         }
709         PPP_MD_CTX_free(ctx);
710     }
711     
712     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
713
714     ctx = PPP_MD_CTX_new();
715     if (ctx != NULL) {
716
717         if (PPP_DigestInit(ctx, PPP_sha1())) {
718
719             if (PPP_DigestUpdate(ctx, Digest, sizeof(Digest))) {
720
721                 if (PPP_DigestUpdate(ctx, Challenge, sizeof(Challenge))) {
722
723                     if (PPP_DigestUpdate(ctx, Magic2, sizeof(Magic2))) {
724                         
725                         hash_len = sizeof(Digest);
726                         PPP_DigestFinal(ctx, Digest, &hash_len);
727                     }
728                 }
729             }
730         }
731
732         PPP_MD_CTX_free(ctx);
733     }
734
735     /* Convert to ASCII hex string. */
736     for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++) {
737         sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
738     }
739 }
740
741
742 static void
743 GenerateAuthenticatorResponsePlain
744                 (char *secret, int secret_len,
745                  u_char NTResponse[24], u_char PeerChallenge[16],
746                  u_char *rchallenge, char *username,
747                  u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
748 {
749     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
750     u_char      PasswordHash[MD4_DIGEST_LENGTH];
751     u_char      PasswordHashHash[MD4_DIGEST_LENGTH];
752
753     /* Hash (x2) the Unicode version of the secret (== password). */
754     ascii2unicode(secret, secret_len, unicodePassword);
755     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
756     NTPasswordHash(PasswordHash, sizeof(PasswordHash),
757                    PasswordHashHash);
758
759     GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
760                                   rchallenge, username, authResponse);
761 }
762
763
764 #ifdef PPP_WITH_MPPE
765
766 /*
767  * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
768  */
769 static void
770 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
771 {
772     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
773     u_char      PasswordHash[MD4_DIGEST_LENGTH];
774     u_char      PasswordHashHash[MD4_DIGEST_LENGTH];
775
776     /* Hash (x2) the Unicode version of the secret (== password). */
777     ascii2unicode(secret, secret_len, unicodePassword);
778     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
779     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
780
781     mppe_set_chapv1(rchallenge, PasswordHashHash);
782 }
783
784 /*
785  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
786  */
787 static void
788 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
789 {
790     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
791     u_char      PasswordHash[MD4_DIGEST_LENGTH];
792     u_char      PasswordHashHash[MD4_DIGEST_LENGTH];
793     /* Hash (x2) the Unicode version of the secret (== password). */
794     ascii2unicode(secret, secret_len, unicodePassword);
795     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
796     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
797     mppe_set_chapv2(PasswordHashHash, NTResponse, IsServer);
798 }
799
800 #endif /* PPP_WITH_MPPE */
801
802
803 void
804 ChapMS(u_char *rchallenge, char *secret, int secret_len,
805        unsigned char *response)
806 {
807     BZERO(response, MS_CHAP_RESPONSE_LEN);
808
809     ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
810
811 #ifdef PPP_WITH_MSLANMAN
812     ChapMS_LANMan(rchallenge, secret, secret_len,
813                   &response[MS_CHAP_LANMANRESP]);
814
815     /* preferred method is set by option  */
816     response[MS_CHAP_USENT] = !ms_lanman;
817 #else
818     response[MS_CHAP_USENT] = 1;
819 #endif
820
821 #ifdef PPP_WITH_MPPE
822     Set_Start_Key(rchallenge, secret, secret_len);
823 #endif
824 }
825
826
827 /*
828  * If PeerChallenge is NULL, one is generated and the PeerChallenge
829  * field of response is filled in.  Call this way when generating a response.
830  * If PeerChallenge is supplied, it is copied into the PeerChallenge field.
831  * Call this way when verifying a response (or debugging).
832  * Do not call with PeerChallenge = response.
833  *
834  * The PeerChallenge field of response is then used for calculation of the
835  * Authenticator Response.
836  */
837 void
838 ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
839         char *user, char *secret, int secret_len, unsigned char *response,
840         u_char authResponse[], int authenticator)
841 {
842     /* ARGSUSED */
843     u_char *p = &response[MS_CHAP2_PEER_CHALLENGE];
844     int i;
845
846     BZERO(response, MS_CHAP2_RESPONSE_LEN);
847
848     /* Generate the Peer-Challenge if requested, or copy it if supplied. */
849     if (!PeerChallenge)
850         for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++)
851             *p++ = (u_char) (drand48() * 0xff);
852     else
853         BCOPY(PeerChallenge, &response[MS_CHAP2_PEER_CHALLENGE],
854               MS_CHAP2_PEER_CHAL_LEN);
855
856     /* Generate the NT-Response */
857     ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
858                secret, secret_len, &response[MS_CHAP2_NTRESP]);
859
860     /* Generate the Authenticator Response. */
861     GenerateAuthenticatorResponsePlain(secret, secret_len,
862                                        &response[MS_CHAP2_NTRESP],
863                                        &response[MS_CHAP2_PEER_CHALLENGE],
864                                        rchallenge, user, authResponse);
865
866 #ifdef PPP_WITH_MPPE
867     SetMasterKeys(secret, secret_len,
868                   &response[MS_CHAP2_NTRESP], authenticator);
869 #endif
870 }
871
872
873 static struct chap_digest_type chapms_digest = {
874         CHAP_MICROSOFT,         /* code */
875         chapms_generate_challenge,
876         chapms_verify_response,
877         chapms_make_response,
878         NULL,                   /* check_success */
879         chapms_handle_failure,
880 };
881
882 static struct chap_digest_type chapms2_digest = {
883         CHAP_MICROSOFT_V2,      /* code */
884         chapms2_generate_challenge,
885         chapms2_verify_response,
886         chapms2_make_response,
887         chapms2_check_success,
888         chapms_handle_failure,
889 };
890
891 #ifndef UNIT_TEST
892 void
893 chapms_init(void)
894 {
895         chap_register_digest(&chapms_digest);
896         chap_register_digest(&chapms2_digest);
897         add_options(chapms_option_list);
898 }
899 #else
900
901 #include <time.h>
902
903 int debug = 1;
904 int error_count = 0;
905 int unsuccess = 0;
906
907 void random_bytes(unsigned char *bytes, int len)
908 {
909     int i = 0;
910     srand(time(NULL));
911     while (i < len) {
912         bytes[i++] = (unsigned char) rand();
913     }
914 }
915
916
917 int test_chap_v1(void) {
918     char *secret = "MyPw";
919
920     unsigned char challenge[8] = {
921         0x10, 0x2D, 0xB5, 0xDF, 0x08, 0x5D, 0x30, 0x41
922     };
923     unsigned char response[MS_CHAP_RESPONSE_LEN] = {
924     };
925     unsigned char result[MS_CHAP_RESPONSE_LEN] = {
926         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
927         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
928         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
929
930         0x4E, 0x9D, 0x3C, 0x8F, 0x9C, 0xFD, 0x38, 0x5D,
931         0x5B, 0xF4, 0xD3, 0x24, 0x67, 0x91, 0x95, 0x6C,
932         0xA4, 0xC3, 0x51, 0xAB, 0x40, 0x9A, 0x3D, 0x61,
933
934         0x01
935     };
936
937     ChapMS(challenge, secret, strlen(secret), response);
938     return memcmp(response, result, MS_CHAP_RESPONSE_LEN);
939 }
940
941 int test_chap_v2(void) {
942     char *secret = "clientPass";
943     char *name = "User";
944
945     char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
946     char *saresult = "407A5589115FD0D6209F510FE9C04566932CDA56";
947
948     unsigned char authenticator[16] = {
949         0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
950         0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
951     };
952     unsigned char peerchallenge[16] = {
953         0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
954         0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
955     };
956     unsigned char result[MS_CHAP_NTRESP_LEN] = {
957         0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
958         0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
959         0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
960     };
961
962     unsigned char response[MS_CHAP2_RESPONSE_LEN] = {
963     };
964
965         ChapMS2(authenticator, peerchallenge, name,
966                 secret, strlen(secret), response,
967                 (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
968
969     return memcmp(&response[MS_CHAP2_NTRESP], result, MS_CHAP2_NTRESP_LEN) ||
970         strncmp(saresponse, saresult, MS_AUTH_RESPONSE_LENGTH);
971 }
972
973 int main(int argc, char *argv[]) {
974     
975     PPP_crypto_init();
976
977     if (test_chap_v1()) {
978         printf("CHAPv1 failed\n");
979         return -1;
980     }
981
982     if (test_chap_v2()) {
983         printf("CHAPv2 failed\n");
984         return -1;
985     }
986
987     PPP_crypto_deinit();
988
989     printf("Success\n");
990     return 0;
991 }
992
993 #endif  /* UNIT_TEST */
994