source: rtems/cpukit/pppd/chap_ms.c @ 4bf1801

4.104.114.84.95
Last change on this file since 4bf1801 was d0950ad, checked in by Joel Sherrill <joel.sherrill@…>, on 11/30/99 at 22:12:50

Added port of ppp-2.3.5 from Tomasz Domin <dot@…> of ComArch? SA.
Tomasz only tested this on the mpc823.

The official site for the original source for this PPP implementation is:

ftp://cs.anu.edu.au/pub/software/ppp

NOTE: As of 11/30/1999, the current version of this source is 2.3.10.

  • Property mode set to 100644
File size: 9.0 KB
Line 
1/*
2 * chap_ms.c - Microsoft MS-CHAP compatible implementation.
3 *
4 * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
5 * http://www.strataware.com/
6 *
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms are permitted
10 * provided that the above copyright notice and this paragraph are
11 * duplicated in all such forms and that any documentation,
12 * advertising materials, and other materials related to such
13 * distribution and use acknowledge that the software was developed
14 * by Eric Rosenquist.  The name of the author may not be used to
15 * endorse or promote products derived from this software without
16 * specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 */
22
23/*
24 * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
25 *
26 *   Implemented LANManager type password response to MS-CHAP challenges.
27 *   Now pppd provides both NT style and LANMan style blocks, and the
28 *   prefered is set by option "ms-lanman". Default is to use NT.
29 *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
30 *
31 *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
32 */
33
34#ifndef lint
35/* static char rcsid[] = "$Id$"; */
36#endif
37
38#ifdef CHAPMS
39
40#include <stdio.h>
41#include <string.h>
42#include <ctype.h>
43#include <sys/types.h>
44#include <sys/time.h>
45#include <syslog.h>
46#include <unistd.h>
47#ifdef HAVE_CRYPT_H
48#include <crypt.h>
49#endif
50
51#include "pppd.h"
52#include "chap.h"
53#include "chap_ms.h"
54#include "md4.h"
55
56#ifndef USE_CRYPT
57#include <des.h>
58#endif
59
60typedef struct {
61    u_char LANManResp[24];
62    u_char NTResp[24];
63    u_char UseNT;               /* If 1, ignore the LANMan response field */
64} MS_ChapResponse;
65/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
66   in case this struct gets padded. */
67
68
69static void     ChallengeResponse __P((u_char *, u_char *, u_char *));
70static void     DesEncrypt __P((u_char *, u_char *, u_char *));
71static void     MakeKey __P((u_char *, u_char *));
72static u_char   Get7Bits __P((u_char *, int));
73static void     ChapMS_NT __P((char *, int, char *, int, MS_ChapResponse *));
74#ifdef MSLANMAN
75static void     ChapMS_LANMan __P((char *, int, char *, int, MS_ChapResponse *));
76#endif
77
78#ifdef USE_CRYPT
79static void     Expand __P((u_char *, u_char *));
80static void     Collapse __P((u_char *, u_char *));
81#endif
82
83static void
84ChallengeResponse(challenge, pwHash, response)
85    u_char *challenge;  /* IN   8 octets */
86    u_char *pwHash;     /* IN  16 octets */
87    u_char *response;   /* OUT 24 octets */
88{
89    char    ZPasswordHash[21];
90
91    BZERO(ZPasswordHash, sizeof(ZPasswordHash));
92    BCOPY(pwHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
93
94#if 0
95    log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);
96#endif
97
98    DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
99    DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
100    DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
101
102#if 0
103    log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);
104#endif
105}
106
107
108#ifdef USE_CRYPT
109static void
110DesEncrypt(clear, key, cipher)
111    u_char *clear;      /* IN  8 octets */
112    u_char *key;        /* IN  7 octets */
113    u_char *cipher;     /* OUT 8 octets */
114{
115    u_char des_key[8];
116    u_char crypt_key[66];
117    u_char des_input[66];
118
119    MakeKey(key, des_key);
120
121    Expand(des_key, crypt_key);
122    setkey(crypt_key);
123
124#if 0
125    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X",
126               clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
127#endif
128
129    Expand(clear, des_input);
130    encrypt(des_input, 0);
131    Collapse(des_input, cipher);
132
133#if 0
134    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X",
135               cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
136#endif
137}
138
139#else /* USE_CRYPT */
140
141static void
142DesEncrypt(clear, key, cipher)
143    u_char *clear;      /* IN  8 octets */
144    u_char *key;        /* IN  7 octets */
145    u_char *cipher;     /* OUT 8 octets */
146{
147    des_cblock          des_key;
148    des_key_schedule    key_schedule;
149
150    MakeKey(key, des_key);
151
152    des_set_key(&des_key, key_schedule);
153
154#if 0
155    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X",
156               clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
157#endif
158
159    des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
160
161#if 0
162    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X",
163               cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
164#endif
165}
166
167#endif /* USE_CRYPT */
168
169
170static u_char Get7Bits(input, startBit)
171    u_char *input;
172    int startBit;
173{
174    register unsigned int       word;
175
176    word  = (unsigned)input[startBit / 8] << 8;
177    word |= (unsigned)input[startBit / 8 + 1];
178
179    word >>= 15 - (startBit % 8 + 7);
180
181    return word & 0xFE;
182}
183
184#ifdef USE_CRYPT
185
186/* in == 8-byte string (expanded version of the 56-bit key)
187 * out == 64-byte string where each byte is either 1 or 0
188 * Note that the low-order "bit" is always ignored by by setkey()
189 */
190static void Expand(in, out)
191    u_char *in;
192    u_char *out;
193{
194        int j, c;
195        int i;
196
197        for(i = 0; i < 64; in++){
198                c = *in;
199                for(j = 7; j >= 0; j--)
200                        *out++ = (c >> j) & 01;
201                i += 8;
202        }
203}
204
205/* The inverse of Expand
206 */
207static void Collapse(in, out)
208    u_char *in;
209    u_char *out;
210{
211        int j;
212        int i;
213        unsigned int c;
214
215        for (i = 0; i < 64; i += 8, out++) {
216            c = 0;
217            for (j = 7; j >= 0; j--, in++)
218                c |= *in << j;
219            *out = c & 0xff;
220        }
221}
222#endif
223
224static void MakeKey(key, des_key)
225    u_char *key;        /* IN  56 bit DES key missing parity bits */
226    u_char *des_key;    /* OUT 64 bit DES key with parity bits added */
227{
228    des_key[0] = Get7Bits(key,  0);
229    des_key[1] = Get7Bits(key,  7);
230    des_key[2] = Get7Bits(key, 14);
231    des_key[3] = Get7Bits(key, 21);
232    des_key[4] = Get7Bits(key, 28);
233    des_key[5] = Get7Bits(key, 35);
234    des_key[6] = Get7Bits(key, 42);
235    des_key[7] = Get7Bits(key, 49);
236
237#ifndef USE_CRYPT
238    des_set_odd_parity((des_cblock *)des_key);
239#endif
240
241#if 0
242    CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X",
243               key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
244    CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X",
245               des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
246#endif
247}
248
249static void
250ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, response)
251    char *rchallenge;
252    int rchallenge_len;
253    char *secret;
254    int secret_len;
255    MS_ChapResponse    *response;
256{
257    int                 i;
258    MD4_CTX             md4Context;
259    u_char              hash[MD4_SIGNATURE_SIZE];
260    u_char              unicodePassword[MAX_NT_PASSWORD * 2];
261
262    /* Initialize the Unicode version of the secret (== password). */
263    /* This implicitly supports 8-bit ISO8859/1 characters. */
264    BZERO(unicodePassword, sizeof(unicodePassword));
265    for (i = 0; i < secret_len; i++)
266        unicodePassword[i * 2] = (u_char)secret[i];
267
268    MD4Init(&md4Context);
269    MD4Update(&md4Context, unicodePassword, secret_len * 2 * 8);        /* Unicode is 2 bytes/char, *8 for bit count */
270
271    MD4Final(hash, &md4Context);        /* Tell MD4 we're done */
272
273    ChallengeResponse(rchallenge, hash, response->NTResp);
274}
275
276#ifdef MSLANMAN
277static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
278
279static void
280ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, response)
281    char *rchallenge;
282    int rchallenge_len;
283    char *secret;
284    int secret_len;
285    MS_ChapResponse     *response;
286{
287    int                 i;
288    u_char              UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
289    u_char              PasswordHash[MD4_SIGNATURE_SIZE];
290
291    /* LANMan password is case insensitive */
292    BZERO(UcasePassword, sizeof(UcasePassword));
293    for (i = 0; i < secret_len; i++)
294       UcasePassword[i] = (u_char)toupper(secret[i]);
295    DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
296    DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
297    ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
298}
299#endif
300
301void
302ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
303    chap_state *cstate;
304    char *rchallenge;
305    int rchallenge_len;
306    char *secret;
307    int secret_len;
308{
309    MS_ChapResponse     response;
310#ifdef MSLANMAN
311    extern int ms_lanman;
312#endif
313
314#if 0
315    CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
316#endif
317    BZERO(&response, sizeof(response));
318
319    /* Calculate both always */
320    ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
321
322#ifdef MSLANMAN
323    ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
324
325    /* prefered method is set by option  */
326    response.UseNT = !ms_lanman;
327#else
328    response.UseNT = 1;
329#endif
330
331    BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
332    cstate->resp_length = MS_CHAP_RESPONSE_LEN;
333}
334
335#endif /* CHAPMS */
Note: See TracBrowser for help on using the repository browser.