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