]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/net/lwip_tcpip/v2_0/src/netif/ppp/chpms.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / net / lwip_tcpip / v2_0 / src / netif / ppp / chpms.c
1 /*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/
2 /*****************************************************************************
3 * chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file.
4 *
5 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
6 * Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved.
7 *
8 * The authors hereby grant permission to use, copy, modify, distribute,
9 * and license this software and its documentation for any purpose, provided
10 * that existing copyright notices are retained in all copies and that this
11 * notice and the following disclaimer are included verbatim in any 
12 * distributions. No written agreement, license, or royalty fee is required
13 * for any of the authorized uses.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
18 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 ******************************************************************************
27 * REVISION HISTORY
28 *
29 * 03-01-01 Marc Boucher <marc@mbsi.ca>
30 *   Ported to lwIP.
31 * 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
32 *       Original based on BSD chap_ms.c.
33 *****************************************************************************/
34 /*
35  * chap_ms.c - Microsoft MS-CHAP compatible implementation.
36  *
37  * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
38  * http://www.strataware.com/
39  *
40  * All rights reserved.
41  *
42  * Redistribution and use in source and binary forms are permitted
43  * provided that the above copyright notice and this paragraph are
44  * duplicated in all such forms and that any documentation,
45  * advertising materials, and other materials related to such
46  * distribution and use acknowledge that the software was developed
47  * by Eric Rosenquist.  The name of the author may not be used to
48  * endorse or promote products derived from this software without
49  * specific prior written permission.
50  *
51  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
52  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
53  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
54  */
55
56 /*
57  * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
58  *
59  *   Implemented LANManager type password response to MS-CHAP challenges.
60  *   Now pppd provides both NT style and LANMan style blocks, and the
61  *   prefered is set by option "ms-lanman". Default is to use NT.
62  *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
63  *
64  *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
65  */
66
67 #define USE_CRYPT
68
69
70 #include "ppp.h"
71
72 #if MSCHAP_SUPPORT > 0
73
74 #include "md4.h"
75 #ifndef USE_CRYPT
76 #include "des.h"
77 #endif
78 #include "chap.h"
79 #include "chpms.h"
80 #include "pppdebug.h"
81
82
83 /*************************/
84 /*** LOCAL DEFINITIONS ***/
85 /*************************/
86
87
88 /************************/
89 /*** LOCAL DATA TYPES ***/
90 /************************/
91 typedef struct {
92     u_char LANManResp[24];
93     u_char NTResp[24];
94     u_char UseNT;               /* If 1, ignore the LANMan response field */
95 } MS_ChapResponse;
96 /* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
97    in case this struct gets padded. */
98
99
100
101 /***********************************/
102 /*** LOCAL FUNCTION DECLARATIONS ***/
103 /***********************************/
104
105 /* XXX Don't know what to do with these. */
106 extern void setkey(const char *);
107 extern void encrypt(char *, int);
108
109 static void     DesEncrypt (u_char *, u_char *, u_char *);
110 static void     MakeKey (u_char *, u_char *);
111
112 #ifdef USE_CRYPT
113 static void     Expand (u_char *, u_char *);
114 static void     Collapse (u_char *, u_char *);
115 #endif
116
117 static void ChallengeResponse(
118         u_char *challenge,      /* IN   8 octets */
119         u_char *pwHash,         /* IN  16 octets */
120         u_char *response        /* OUT 24 octets */
121 );
122 static void ChapMS_NT(
123         char *rchallenge,
124         int rchallenge_len,
125         char *secret,
126         int secret_len,
127         MS_ChapResponse *response
128 );
129 static u_char Get7Bits(
130         u_char *input,
131         int startBit
132 );
133
134
135 /***********************************/
136 /*** PUBLIC FUNCTION DEFINITIONS ***/
137 /***********************************/
138 void ChapMS(
139         chap_state *cstate,
140         char *rchallenge,
141         int rchallenge_len,
142         char *secret,
143         int secret_len
144 )
145 {
146         MS_ChapResponse response;
147 #ifdef MSLANMAN
148         extern int ms_lanman;
149 #endif
150         
151 #if 0
152         CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'\n", secret_len, secret));
153 #endif
154         BZERO(&response, sizeof(response));
155         
156         /* Calculate both always */
157         ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
158         
159 #ifdef MSLANMAN
160         ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
161         
162         /* prefered method is set by option  */
163         response.UseNT = !ms_lanman;
164 #else
165         response.UseNT = 1;
166 #endif
167         
168         BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
169         cstate->resp_length = MS_CHAP_RESPONSE_LEN;
170 }
171
172
173 /**********************************/
174 /*** LOCAL FUNCTION DEFINITIONS ***/
175 /**********************************/
176 static void ChallengeResponse(
177         u_char *challenge,      /* IN   8 octets */
178         u_char *pwHash,         /* IN  16 octets */
179         u_char *response        /* OUT 24 octets */
180 )
181 {
182         char    ZPasswordHash[21];
183         
184         BZERO(ZPasswordHash, sizeof(ZPasswordHash));
185         BCOPY(pwHash, ZPasswordHash, 16);
186         
187 #if 0
188         log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);
189 #endif
190         
191         DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
192         DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
193         DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
194         
195 #if 0
196         log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);
197 #endif
198 }
199
200
201 #ifdef USE_CRYPT
202 static void DesEncrypt(
203         u_char *clear,  /* IN  8 octets */
204         u_char *key,    /* IN  7 octets */
205         u_char *cipher  /* OUT 8 octets */
206 )
207 {
208         u_char des_key[8];
209         u_char crypt_key[66];
210         u_char des_input[66];
211         
212         MakeKey(key, des_key);
213         
214         Expand(des_key, crypt_key);
215         setkey(crypt_key);
216         
217 #if 0
218         CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
219                clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
220 #endif
221         
222         Expand(clear, des_input);
223         encrypt(des_input, 0);
224         Collapse(des_input, cipher);
225         
226 #if 0
227         CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
228                cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
229 #endif
230 }
231
232 #else /* USE_CRYPT */
233
234 static void DesEncrypt(
235         u_char *clear,  /* IN  8 octets */
236         u_char *key,    /* IN  7 octets */
237         u_char *cipher  /* OUT 8 octets */
238 )
239 {
240         des_cblock              des_key;
241         des_key_schedule        key_schedule;
242         
243         MakeKey(key, des_key);
244         
245         des_set_key(&des_key, key_schedule);
246         
247 #if 0
248         CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
249                clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
250 #endif
251         
252         des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
253         
254 #if 0
255         CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
256                cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
257 #endif
258 }
259
260 #endif /* USE_CRYPT */
261
262
263 static u_char Get7Bits(
264         u_char *input,
265         int startBit
266 )
267 {
268         register unsigned int   word;
269         
270         word  = (unsigned)input[startBit / 8] << 8;
271         word |= (unsigned)input[startBit / 8 + 1];
272         
273         word >>= 15 - (startBit % 8 + 7);
274         
275         return word & 0xFE;
276 }
277
278 #ifdef USE_CRYPT
279
280 /* in == 8-byte string (expanded version of the 56-bit key)
281  * out == 64-byte string where each byte is either 1 or 0
282  * Note that the low-order "bit" is always ignored by by setkey()
283  */
284 static void Expand(u_char *in, u_char *out)
285 {
286         int j, c;
287         int i;
288         
289         for(i = 0; i < 64; in++){
290                 c = *in;
291                 for(j = 7; j >= 0; j--)
292                         *out++ = (c >> j) & 01;
293                 i += 8;
294         }
295 }
296
297 /* The inverse of Expand
298  */
299 static void Collapse(u_char *in, u_char *out)
300 {
301         int j;
302         int i;
303         unsigned int c;
304         
305         for (i = 0; i < 64; i += 8, out++) {
306                 c = 0;
307                 for (j = 7; j >= 0; j--, in++)
308                         c |= *in << j;
309                 *out = c & 0xff;
310         }
311 }
312 #endif
313
314 static void MakeKey(
315         u_char *key,            /* IN  56 bit DES key missing parity bits */
316         u_char *des_key         /* OUT 64 bit DES key with parity bits added */
317 )
318 {
319         des_key[0] = Get7Bits(key,  0);
320         des_key[1] = Get7Bits(key,  7);
321         des_key[2] = Get7Bits(key, 14);
322         des_key[3] = Get7Bits(key, 21);
323         des_key[4] = Get7Bits(key, 28);
324         des_key[5] = Get7Bits(key, 35);
325         des_key[6] = Get7Bits(key, 42);
326         des_key[7] = Get7Bits(key, 49);
327         
328 #ifndef USE_CRYPT
329         des_set_odd_parity((des_cblock *)des_key);
330 #endif
331         
332 #if 0
333         CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",
334                key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
335         CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
336                des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
337 #endif
338 }
339
340 static void ChapMS_NT(
341         char *rchallenge,
342         int rchallenge_len,
343         char *secret,
344         int secret_len,
345         MS_ChapResponse *response
346 )
347 {
348         int                     i;
349         MDstruct        md4Context;
350         u_char          unicodePassword[MAX_NT_PASSWORD * 2];
351         static int      low_byte_first = -1;
352         
353         /* Initialize the Unicode version of the secret (== password). */
354         /* This implicitly supports 8-bit ISO8859/1 characters. */
355         BZERO(unicodePassword, sizeof(unicodePassword));
356         for (i = 0; i < secret_len; i++)
357                 unicodePassword[i * 2] = (u_char)secret[i];
358         
359         MDbegin(&md4Context);
360         MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8);     /* Unicode is 2 bytes/char, *8 for bit count */
361         
362         if (low_byte_first == -1)
363                 low_byte_first = (htons((unsigned short int)1) != 1);
364         if (low_byte_first == 0)
365                 MDreverse((u_long *)&md4Context);  /*  sfb 961105 */
366         
367         MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */
368         
369         ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp);
370 }
371
372 #ifdef MSLANMAN
373 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
374
375 static ChapMS_LANMan(
376         char *rchallenge,
377         int rchallenge_len,
378         char *secret,
379         int secret_len,
380         MS_ChapResponse *response
381 )
382 {
383         int                     i;
384         u_char          UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
385         u_char          PasswordHash[16];
386         
387         /* LANMan password is case insensitive */
388         BZERO(UcasePassword, sizeof(UcasePassword));
389         for (i = 0; i < secret_len; i++)
390                 UcasePassword[i] = (u_char)toupper(secret[i]);
391         DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
392         DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
393         ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
394 }
395 #endif
396
397 #endif /* MSCHAP_SUPPORT */
398