blob: 01755ba39ca6e3afaeb58ca69870348a93da0ec8 [file] [log] [blame]
Travis Geiselbrecht1d0df692008-09-01 02:26:09 -07001/*** 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/************************/
91typedef 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. */
106extern void setkey(const char *);
107extern void encrypt(char *, int);
108
109static void DesEncrypt (u_char *, u_char *, u_char *);
110static void MakeKey (u_char *, u_char *);
111
112#ifdef USE_CRYPT
113static void Expand (u_char *, u_char *);
114static void Collapse (u_char *, u_char *);
115#endif
116
117static void ChallengeResponse(
118 u_char *challenge, /* IN 8 octets */
119 u_char *pwHash, /* IN 16 octets */
120 u_char *response /* OUT 24 octets */
121);
122static void ChapMS_NT(
123 char *rchallenge,
124 int rchallenge_len,
125 char *secret,
126 int secret_len,
127 MS_ChapResponse *response
128);
129static u_char Get7Bits(
130 u_char *input,
131 int startBit
132);
133
134
135/***********************************/
136/*** PUBLIC FUNCTION DEFINITIONS ***/
137/***********************************/
138void 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/**********************************/
176static 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
202static 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
234static 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
263static 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 */
284static 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 */
299static 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
314static 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
340static 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
373static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
374
375static 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