Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / lwip / 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 #include "lwip/opt.h"
70
71 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
72
73 #if MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
74
75 #include "ppp.h"
76 #include "pppdebug.h"
77
78 #include "md4.h"
79 #ifndef USE_CRYPT
80 #include "des.h"
81 #endif
82 #include "chap.h"
83 #include "chpms.h"
84
85
86 /*************************/
87 /*** LOCAL DEFINITIONS ***/
88 /*************************/
89
90
91 /************************/
92 /*** LOCAL DATA TYPES ***/
93 /************************/
94 typedef struct {
95     u_char LANManResp[24];
96     u_char NTResp[24];
97     u_char UseNT; /* If 1, ignore the LANMan response field */
98 } MS_ChapResponse;
99 /* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
100    in case this struct gets padded. */
101
102
103
104 /***********************************/
105 /*** LOCAL FUNCTION DECLARATIONS ***/
106 /***********************************/
107
108 /* XXX Don't know what to do with these. */
109 extern void setkey(const char *);
110 extern void encrypt(char *, int);
111
112 static void DesEncrypt (u_char *, u_char *, u_char *);
113 static void MakeKey (u_char *, u_char *);
114
115 #ifdef USE_CRYPT
116 static void Expand (u_char *, u_char *);
117 static void Collapse (u_char *, u_char *);
118 #endif
119
120 static void ChallengeResponse(
121   u_char *challenge, /* IN   8 octets */
122   u_char *pwHash,    /* IN  16 octets */
123   u_char *response   /* OUT 24 octets */
124 );
125 static void ChapMS_NT(
126   char *rchallenge,
127   int rchallenge_len,
128   char *secret,
129   int secret_len,
130   MS_ChapResponse *response
131 );
132 static u_char Get7Bits(
133   u_char *input,
134   int startBit
135 );
136
137
138 /***********************************/
139 /*** PUBLIC FUNCTION DEFINITIONS ***/
140 /***********************************/
141 void
142 ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len)
143 {
144   MS_ChapResponse response;
145 #ifdef MSLANMAN
146   extern int ms_lanman;
147 #endif
148
149 #if 0
150   CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'\n", secret_len, secret));
151 #endif
152   BZERO(&response, sizeof(response));
153
154   /* Calculate both always */
155   ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
156
157 #ifdef MSLANMAN
158   ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
159
160   /* prefered method is set by option  */
161   response.UseNT = !ms_lanman;
162 #else
163   response.UseNT = 1;
164 #endif
165
166   BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
167   cstate->resp_length = MS_CHAP_RESPONSE_LEN;
168 }
169
170
171 /**********************************/
172 /*** LOCAL FUNCTION DEFINITIONS ***/
173 /**********************************/
174 static void
175 ChallengeResponse( u_char *challenge, /* IN   8 octets */
176                    u_char *pwHash,    /* IN  16 octets */
177                    u_char *response   /* OUT 24 octets */)
178 {
179   char    ZPasswordHash[21];
180
181   BZERO(ZPasswordHash, sizeof(ZPasswordHash));
182   BCOPY(pwHash, ZPasswordHash, 16);
183
184 #if 0
185   log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);
186 #endif
187
188   DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
189   DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
190   DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
191
192 #if 0
193   log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);
194 #endif
195 }
196
197
198 #ifdef USE_CRYPT
199 static void
200 DesEncrypt( u_char *clear, /* IN  8 octets */
201             u_char *key,   /* IN  7 octets */
202             u_char *cipher /* OUT 8 octets */)
203 {
204   u_char des_key[8];
205   u_char crypt_key[66];
206   u_char des_input[66];
207
208   MakeKey(key, des_key);
209
210   Expand(des_key, crypt_key);
211   setkey(crypt_key);
212
213 #if 0
214   CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
215              clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
216 #endif
217
218   Expand(clear, des_input);
219   encrypt(des_input, 0);
220   Collapse(des_input, cipher);
221
222 #if 0
223   CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
224              cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
225 #endif
226 }
227
228 #else /* USE_CRYPT */
229
230 static void
231 DesEncrypt( u_char *clear, /* IN  8 octets */
232             u_char *key,   /* IN  7 octets */
233             u_char *cipher /* OUT 8 octets */)
234 {
235   des_cblock    des_key;
236   des_key_schedule  key_schedule;
237
238   MakeKey(key, des_key);
239
240   des_set_key(&des_key, key_schedule);
241
242 #if 0
243   CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",
244              clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
245 #endif
246
247   des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
248
249 #if 0
250   CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
251              cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
252 #endif
253 }
254
255 #endif /* USE_CRYPT */
256
257
258 static u_char
259 Get7Bits( u_char *input, int startBit)
260 {
261   register unsigned int  word;
262
263   word  = (unsigned)input[startBit / 8] << 8;
264   word |= (unsigned)input[startBit / 8 + 1];
265
266   word >>= 15 - (startBit % 8 + 7);
267
268   return word & 0xFE;
269 }
270
271 #ifdef USE_CRYPT
272
273 /* in == 8-byte string (expanded version of the 56-bit key)
274  * out == 64-byte string where each byte is either 1 or 0
275  * Note that the low-order "bit" is always ignored by by setkey()
276  */
277 static void
278 Expand(u_char *in, u_char *out)
279 {
280   int j, c;
281   int i;
282
283   for(i = 0; i < 64; in++){
284     c = *in;
285     for(j = 7; j >= 0; j--) {
286       *out++ = (c >> j) & 01;
287     }
288     i += 8;
289   }
290 }
291
292 /* The inverse of Expand
293  */
294 static void
295 Collapse(u_char *in, u_char *out)
296 {
297   int j;
298   int i;
299   unsigned int c;
300
301   for (i = 0; i < 64; i += 8, out++) {
302     c = 0;
303     for (j = 7; j >= 0; j--, in++) {
304       c |= *in << j;
305     }
306     *out = c & 0xff;
307   }
308 }
309 #endif
310
311 static void
312 MakeKey( u_char *key,    /* IN  56 bit DES key missing parity bits */
313          u_char *des_key /* OUT 64 bit DES key with parity bits added */)
314 {
315   des_key[0] = Get7Bits(key,  0);
316   des_key[1] = Get7Bits(key,  7);
317   des_key[2] = Get7Bits(key, 14);
318   des_key[3] = Get7Bits(key, 21);
319   des_key[4] = Get7Bits(key, 28);
320   des_key[5] = Get7Bits(key, 35);
321   des_key[6] = Get7Bits(key, 42);
322   des_key[7] = Get7Bits(key, 49);
323   
324 #ifndef USE_CRYPT
325   des_set_odd_parity((des_cblock *)des_key);
326 #endif
327   
328 #if 0
329   CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",
330              key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
331   CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",
332              des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
333 #endif
334 }
335
336 static void
337 ChapMS_NT( char *rchallenge,
338            int rchallenge_len,
339            char *secret,
340            int secret_len,
341            MS_ChapResponse *response)
342 {
343   int      i;
344   MDstruct  md4Context;
345   u_char    unicodePassword[MAX_NT_PASSWORD * 2];
346   static int  low_byte_first = -1;
347
348   /* Initialize the Unicode version of the secret (== password). */
349   /* This implicitly supports 8-bit ISO8859/1 characters. */
350   BZERO(unicodePassword, sizeof(unicodePassword));
351   for (i = 0; i < secret_len; i++) {
352     unicodePassword[i * 2] = (u_char)secret[i];
353   }
354   MDbegin(&md4Context);
355   MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8);  /* Unicode is 2 bytes/char, *8 for bit count */
356
357   if (low_byte_first == -1) {
358     low_byte_first = (htons((unsigned short int)1) != 1);
359   }
360   if (low_byte_first == 0) {
361     MDreverse((u_long *)&md4Context);  /*  sfb 961105 */
362   }
363
364   MDupdate(&md4Context, NULL, 0);  /* Tell MD4 we're done */
365
366   ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp);
367 }
368
369 #ifdef MSLANMAN
370 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
371
372 static void
373 ChapMS_LANMan( char *rchallenge,
374                int rchallenge_len,
375                char *secret,
376                int secret_len,
377                MS_ChapResponse  *response)
378 {
379   int      i;
380   u_char    UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
381   u_char    PasswordHash[16];
382   
383   /* LANMan password is case insensitive */
384   BZERO(UcasePassword, sizeof(UcasePassword));
385   for (i = 0; i < secret_len; i++) {
386     UcasePassword[i] = (u_char)toupper(secret[i]);
387   }
388   DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
389   DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
390   ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
391 }
392 #endif
393
394 #endif /* MSCHAP_SUPPORT */
395
396 #endif /* PPP_SUPPORT */