]> git.ozlabs.org Git - ppp.git/blob - pppd/chap_ms.c
69b2982412d1b54a507ff981e5c534d6a996bcb6
[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.28 2003/01/10 07:12:36 fcusack Exp $"
78
79 #ifdef CHAPMS
80
81 #include <stdio.h>
82 #include <stdlib.h>
83 #include <string.h>
84 #include <ctype.h>
85 #include <sys/types.h>
86 #include <sys/time.h>
87 #include <unistd.h>
88
89 #include "pppd.h"
90 #include "chap.h"
91 #include "chap_ms.h"
92 #include "md4.h"
93 #include "sha1.h"
94 #include "pppcrypt.h"
95
96 static const char rcsid[] = RCSID;
97
98
99 static void     ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
100 static void     ascii2unicode __P((char[], int, u_char[]));
101 static void     NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
102 static void     ChallengeResponse __P((u_char *, u_char *, u_char[24]));
103 static void     ChapMS_NT __P((u_char *, char *, int, u_char[24]));
104 static void     ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
105                                 u_char[24]));
106 static void     GenerateAuthenticatorResponse __P((char*, int, u_char[24],
107                                                    u_char[16], u_char *,
108                                                    char *, u_char[41]));
109 #ifdef MSLANMAN
110 static void     ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
111 #endif
112
113 #ifdef MPPE
114 static void     Set_Start_Key __P((u_char *, char *, int));
115 static void     SetMasterKeys __P((char *, int, u_char[24], int));
116 #endif
117
118 extern double drand48 __P((void));
119
120 #ifdef 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 MPPE
126 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
127 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
128 int mppe_keys_set = 0;          /* Have the MPPE keys been set? */
129
130 #include "fsm.h"                /* Need to poke MPPE options */
131 #include "ccp.h"
132 #include <net/ppp-comp.h>
133 #endif
134
135 static void
136 ChallengeResponse(u_char *challenge,
137                   u_char PasswordHash[MD4_SIGNATURE_SIZE],
138                   u_char response[24])
139 {
140     u_char    ZPasswordHash[21];
141
142     BZERO(ZPasswordHash, sizeof(ZPasswordHash));
143     BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
144
145 #if 0
146     dbglog("ChallengeResponse - ZPasswordHash %.*B",
147            sizeof(ZPasswordHash), ZPasswordHash);
148 #endif
149
150     (void) DesSetkey(ZPasswordHash + 0);
151     DesEncrypt(challenge, response + 0);
152     (void) DesSetkey(ZPasswordHash + 7);
153     DesEncrypt(challenge, response + 8);
154     (void) DesSetkey(ZPasswordHash + 14);
155     DesEncrypt(challenge, response + 16);
156
157 #if 0
158     dbglog("ChallengeResponse - response %.24B", response);
159 #endif
160 }
161
162 static void
163 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
164               char *username, u_char Challenge[8])
165     
166 {
167     SHA1_CTX    sha1Context;
168     u_char      sha1Hash[SHA1_SIGNATURE_SIZE];
169     char        *user;
170
171     /* remove domain from "domain\username" */
172     if ((user = strrchr(username, '\\')) != NULL)
173         ++user;
174     else
175         user = username;
176
177     SHA1_Init(&sha1Context);
178     SHA1_Update(&sha1Context, PeerChallenge, 16);
179     SHA1_Update(&sha1Context, rchallenge, 16);
180     SHA1_Update(&sha1Context, user, strlen(user));
181     SHA1_Final(sha1Hash, &sha1Context);
182
183     BCOPY(sha1Hash, Challenge, 8);
184 }
185
186 /*
187  * Convert the ASCII version of the password to Unicode.
188  * This implicitly supports 8-bit ISO8859/1 characters.
189  * This gives us the little-endian representation, which
190  * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
191  * is machine-dependent.)
192  */
193 static void
194 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
195 {
196     int i;
197
198     BZERO(unicode, ascii_len * 2);
199     for (i = 0; i < ascii_len; i++)
200         unicode[i * 2] = (u_char) ascii[i];
201 }
202
203 static void
204 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
205 {
206 #ifdef __NetBSD__
207     /* NetBSD uses the libc md4 routines which take bytes instead of bits */
208     int                 mdlen = secret_len;
209 #else
210     int                 mdlen = secret_len * 8;
211 #endif
212     MD4_CTX             md4Context;
213
214     MD4Init(&md4Context);
215     MD4Update(&md4Context, secret, mdlen);
216     MD4Final(hash, &md4Context);
217
218 }
219
220 static void
221 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
222           u_char NTResponse[24])
223 {
224     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
225     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
226
227     /* Hash the Unicode version of the secret (== password). */
228     ascii2unicode(secret, secret_len, unicodePassword);
229     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
230
231     ChallengeResponse(rchallenge, PasswordHash, NTResponse);
232 }
233
234 static void
235 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
236            char *secret, int secret_len, u_char NTResponse[24])
237 {
238     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
239     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
240     u_char      Challenge[8];
241
242     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
243
244     /* Hash the Unicode version of the secret (== password). */
245     ascii2unicode(secret, secret_len, unicodePassword);
246     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
247
248     ChallengeResponse(Challenge, PasswordHash, NTResponse);
249 }
250
251 #ifdef MSLANMAN
252 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
253
254 static void
255 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
256               MS_ChapResponse *response)
257 {
258     int                 i;
259     u_char              UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
260     u_char              PasswordHash[MD4_SIGNATURE_SIZE];
261
262     /* LANMan password is case insensitive */
263     BZERO(UcasePassword, sizeof(UcasePassword));
264     for (i = 0; i < secret_len; i++)
265        UcasePassword[i] = (u_char)toupper(secret[i]);
266     (void) DesSetkey(UcasePassword + 0);
267     DesEncrypt( StdText, PasswordHash + 0 );
268     (void) DesSetkey(UcasePassword + 7);
269     DesEncrypt( StdText, PasswordHash + 8 );
270     ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
271 }
272 #endif
273
274
275 static void
276 GenerateAuthenticatorResponse(char *secret, int secret_len,
277                               u_char NTResponse[24], u_char PeerChallenge[16],
278                               u_char *rchallenge, char *username,
279                               u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
280 {
281     /*
282      * "Magic" constants used in response generation, from RFC 2759.
283      */
284     u_char Magic1[39] = /* "Magic server to client signing constant" */
285         { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
286           0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
287           0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
288           0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
289     u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
290         { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
291           0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
292           0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
293           0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
294           0x6E };
295
296     int         i;
297     SHA1_CTX    sha1Context;
298     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
299     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
300     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
301     u_char      Digest[SHA1_SIGNATURE_SIZE];
302     u_char      Challenge[8];
303
304     /* Hash (x2) the Unicode version of the secret (== password). */
305     ascii2unicode(secret, secret_len, unicodePassword);
306     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
307     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
308
309     SHA1_Init(&sha1Context);
310     SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
311     SHA1_Update(&sha1Context, NTResponse, 24);
312     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
313     SHA1_Final(Digest, &sha1Context);
314
315     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
316
317     SHA1_Init(&sha1Context);
318     SHA1_Update(&sha1Context, Digest, sizeof(Digest));
319     SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
320     SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
321     SHA1_Final(Digest, &sha1Context);
322
323     /* Convert to ASCII hex string. */
324     for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
325         sprintf(&authResponse[i * 2], "%02X", Digest[i]);
326 }
327
328
329 #ifdef MPPE
330 /*
331  * Set mppe_xxxx_key from the NTPasswordHashHash.
332  * RFC 2548 (RADIUS support) requires us to export this function (ugh).
333  */
334 void
335 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
336 {
337     SHA1_CTX    sha1Context;
338     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
339
340     SHA1_Init(&sha1Context);
341     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
342     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
343     SHA1_Update(&sha1Context, rchallenge, 8);
344     SHA1_Final(Digest, &sha1Context);
345
346     /* Same key in both directions. */
347     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
348     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
349 }
350
351 /*
352  * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
353  */
354 static void
355 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
356 {
357     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
358     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
359     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
360
361     /* Hash (x2) the Unicode version of the secret (== password). */
362     ascii2unicode(secret, secret_len, unicodePassword);
363     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
364     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
365
366     mppe_set_keys(rchallenge, PasswordHashHash);
367 }
368
369 /*
370  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
371  */
372 static void
373 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
374 {
375     SHA1_CTX    sha1Context;
376     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
377     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
378     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
379     u_char      MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
380     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
381
382     u_char SHApad1[40] =
383         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
384           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
386           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
387     u_char SHApad2[40] =
388         { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
389           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
390           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
391           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
392
393     /* "This is the MPPE Master Key" */
394     u_char Magic1[27] =
395         { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
396           0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
397           0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
398     /* "On the client side, this is the send key; "
399        "on the server side, it is the receive key." */
400     u_char Magic2[84] =
401         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
402           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
403           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
404           0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
405           0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
406           0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
407           0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
408           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
409           0x6b, 0x65, 0x79, 0x2e };
410     /* "On the client side, this is the receive key; "
411        "on the server side, it is the send key." */
412     u_char Magic3[84] =
413         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
414           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
415           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
416           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
417           0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
418           0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
419           0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
420           0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
421           0x6b, 0x65, 0x79, 0x2e };
422     u_char *s;
423
424     /* Hash (x2) the Unicode version of the secret (== password). */
425     ascii2unicode(secret, secret_len, unicodePassword);
426     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
427     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
428
429     SHA1_Init(&sha1Context);
430     SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
431     SHA1_Update(&sha1Context, NTResponse, 24);
432     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
433     SHA1_Final(MasterKey, &sha1Context);
434
435     /*
436      * generate send key
437      */
438     if (IsServer)
439         s = Magic3;
440     else
441         s = Magic2;
442     SHA1_Init(&sha1Context);
443     SHA1_Update(&sha1Context, MasterKey, 16);
444     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
445     SHA1_Update(&sha1Context, s, 84);
446     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
447     SHA1_Final(Digest, &sha1Context);
448
449     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
450
451     /*
452      * generate recv key
453      */
454     if (IsServer)
455         s = Magic2;
456     else
457         s = Magic3;
458     SHA1_Init(&sha1Context);
459     SHA1_Update(&sha1Context, MasterKey, 16);
460     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
461     SHA1_Update(&sha1Context, s, 84);
462     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
463     SHA1_Final(Digest, &sha1Context);
464
465     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
466 }
467
468 #endif /* MPPE */
469
470
471 void
472 ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len,
473        MS_ChapResponse *response)
474 {
475 #if 0
476     CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
477 #endif
478     BZERO(response, sizeof(*response));
479
480     ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
481
482 #ifdef MSLANMAN
483     ChapMS_LANMan(rchallenge, secret, secret_len, response);
484
485     /* preferred method is set by option  */
486     response->UseNT[0] = !ms_lanman;
487 #else
488     response->UseNT[0] = 1;
489 #endif
490
491     cstate->resp_length = MS_CHAP_RESPONSE_LEN;
492
493 #ifdef MPPE
494     Set_Start_Key(rchallenge, secret, secret_len);
495     mppe_keys_set = 1;
496 #endif
497 }
498
499
500 /*
501  * If PeerChallenge is NULL, one is generated and response->PeerChallenge
502  * is filled in.  Call this way when generating a response.
503  * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
504  * Call this way when verifying a response (or debugging).
505  * Do not call with PeerChallenge = response->PeerChallenge.
506  *
507  * response->PeerChallenge is then used for calculation of the
508  * Authenticator Response.
509  */
510 void
511 ChapMS2(chap_state *cstate, u_char *rchallenge, u_char *PeerChallenge,
512         char *user, char *secret, int secret_len, MS_Chap2Response *response,
513         u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1], int authenticator)
514 {
515     /* ARGSUSED */
516     u_char *p = response->PeerChallenge;
517     int i;
518
519     BZERO(response, sizeof(*response));
520
521     /* Generate the Peer-Challenge if requested, or copy it if supplied. */
522     if (!PeerChallenge)
523         for (i = 0; i < sizeof(response->PeerChallenge); i++)
524             *p++ = (u_char) (drand48() * 0xff);
525     else
526         BCOPY(PeerChallenge, response->PeerChallenge,
527               sizeof(response->PeerChallenge));
528
529     /* Generate the NT-Response */
530     ChapMS2_NT(rchallenge, response->PeerChallenge, user,
531                secret, secret_len, response->NTResp);
532
533     /* Generate the Authenticator Response. */
534     GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
535                                   response->PeerChallenge, rchallenge,
536                                   user, authResponse);
537
538     cstate->resp_length = MS_CHAP2_RESPONSE_LEN;
539
540 #ifdef MPPE
541     SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
542     mppe_keys_set = 1;
543 #endif
544 }
545
546 #ifdef MPPE
547 /*
548  * Set MPPE options from plugins.
549  */
550 void
551 set_mppe_enc_types(int policy, int types)
552 {
553     /* Early exit for unknown policies. */
554     if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
555         policy != MPPE_ENC_POL_ENC_REQUIRED)
556         return;
557
558     /* Don't modify MPPE if it's optional and wasn't already configured. */
559     if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
560         return;
561
562     /*
563      * Disable undesirable encryption types.  Note that we don't ENABLE
564      * any encryption types, to avoid overriding manual configuration.
565      */
566     switch(types) {
567         case MPPE_ENC_TYPES_RC4_40:
568             ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;   /* disable 128-bit */
569             break;
570         case MPPE_ENC_TYPES_RC4_128:
571             ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;    /* disable 40-bit */
572             break;
573         default:
574             break;
575     }
576 }
577 #endif /* MPPE */
578
579 #endif /* CHAPMS */