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