]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ppp/chap_ms.c
Bmake bits for Gcc 3.1.
[FreeBSD/FreeBSD.git] / usr.sbin / ppp / chap_ms.c
1 /*-
2  * Copyright (c) 1997        Gabor Kincses <gabor@acm.org>
3  *               1997 - 2001 Brian Somers <brian@Awfulhak.org>
4  *          based on work by Eric Rosenquist
5  *                           Strata Software Limited.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 #include <ctype.h>
33 #ifdef __FreeBSD__
34 #include <openssl/des.h>
35 #include <sha.h>
36 #else
37 #include <sys/types.h>
38 #include <stdlib.h>
39 #include <des.h>
40 #include <openssl/sha.h>
41 #endif
42 #include <md4.h>
43 #include <string.h>
44
45 #include "chap_ms.h"
46
47 /*
48  * Documentation & specifications:
49  *
50  * MS-CHAP (CHAP80)     rfc2433
51  * MS-CHAP-V2 (CHAP81)  rfc2759
52  * MPPE key management  draft-ietf-pppext-mppe-keys-02.txt
53  */
54
55 static char SHA1_Pad1[40] =
56   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
60
61 static char SHA1_Pad2[40] =
62   {0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
63    0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
64    0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
65    0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2};
66
67 /* unused, for documentation only */
68 /* only NTResp is filled in for FreeBSD */
69 struct MS_ChapResponse {
70     u_char LANManResp[24];
71     u_char NTResp[24];
72     u_char UseNT;       /* If 1, ignore the LANMan response field */
73 };
74
75 static u_char
76 Get7Bits(u_char *input, int startBit)
77 {
78     register unsigned int       word;
79
80     word  = (unsigned)input[startBit / 8] << 8;
81     word |= (unsigned)input[startBit / 8 + 1];
82
83     word >>= 15 - (startBit % 8 + 7);
84
85     return word & 0xFE;
86 }
87
88 /* IN  56 bit DES key missing parity bits
89    OUT 64 bit DES key with parity bits added */
90 static void
91 MakeKey(u_char *key, u_char *des_key)
92 {
93     des_key[0] = Get7Bits(key,  0);
94     des_key[1] = Get7Bits(key,  7);
95     des_key[2] = Get7Bits(key, 14);
96     des_key[3] = Get7Bits(key, 21);
97     des_key[4] = Get7Bits(key, 28);
98     des_key[5] = Get7Bits(key, 35);
99     des_key[6] = Get7Bits(key, 42);
100     des_key[7] = Get7Bits(key, 49);
101
102     des_set_odd_parity((des_cblock *)des_key);
103 }
104
105 static void /* IN 8 octets IN 7 octest OUT 8 octets */
106 DesEncrypt(u_char *clear, u_char *key, u_char *cipher)
107 {
108     des_cblock          des_key;
109     des_key_schedule    key_schedule;
110
111     MakeKey(key, des_key);
112     des_set_key(&des_key, key_schedule);
113     des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
114 }
115
116 static void      /* IN 8 octets      IN 16 octets     OUT 24 octets */
117 ChallengeResponse(u_char *challenge, u_char *pwHash, u_char *response)
118 {
119     char    ZPasswordHash[21];
120
121     memset(ZPasswordHash, '\0', sizeof ZPasswordHash);
122     memcpy(ZPasswordHash, pwHash, 16);
123
124     DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
125     DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
126     DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
127 }
128
129 void
130 NtPasswordHash(char *key, int keylen, char *hash)
131
132   MD4_CTX MD4context;
133
134   MD4Init(&MD4context);
135   MD4Update(&MD4context, key, keylen);
136   MD4Final(hash, &MD4context);
137 }
138
139 void
140 HashNtPasswordHash(char *hash, char *hashhash)
141
142   MD4_CTX MD4context;
143
144   MD4Init(&MD4context);
145   MD4Update(&MD4context, hash, 16);
146   MD4Final(hashhash, &MD4context);
147 }
148
149 void
150 ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge,
151               char *UserName, int UserNameLen, char *Challenge)
152 {
153   SHA_CTX Context;
154   char Digest[SHA_DIGEST_LENGTH];
155   char *Name;
156
157   Name = strrchr(UserName, '\\');
158   if(NULL == Name) 
159     Name = UserName;
160   else
161     Name++;
162
163   SHA1_Init(&Context);
164
165   SHA1_Update(&Context, PeerChallenge, 16); 
166   SHA1_Update(&Context, AuthenticatorChallenge, 16);
167   SHA1_Update(&Context, Name, strlen(Name));
168
169   SHA1_Final(Digest, &Context);
170   memcpy(Challenge, Digest, 8);
171 }
172
173 void
174 GenerateNTResponse(char *AuthenticatorChallenge, char *PeerChallenge,
175                    char *UserName, int UserNameLen, char *Password,
176                    int PasswordLen, char *Response)
177 {
178   char Challenge[8];
179   char PasswordHash[16];
180
181   ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen,
182                 Challenge);
183   NtPasswordHash(Password, PasswordLen, PasswordHash);
184   ChallengeResponse(Challenge, PasswordHash, Response);
185 }
186
187 #ifndef __FreeBSD__
188 #define LENGTH 20
189 static char *
190 SHA1_End(SHA_CTX *ctx, char *buf)
191 {
192     int i;
193     unsigned char digest[LENGTH];
194     static const char hex[]="0123456789abcdef";
195
196     if (!buf)
197         buf = malloc(2*LENGTH + 1);
198     if (!buf)
199         return 0;
200     SHA1_Final(digest, ctx);
201     for (i = 0; i < LENGTH; i++) {
202         buf[i+i] = hex[digest[i] >> 4];
203         buf[i+i+1] = hex[digest[i] & 0x0f];
204     }
205     buf[i+i] = '\0';
206     return buf;
207 }
208 #endif
209
210 void
211 GenerateAuthenticatorResponse(char *Password, int PasswordLen,
212                               char *NTResponse, char *PeerChallenge,
213                               char *AuthenticatorChallenge, char *UserName,
214                               int UserNameLen, char *AuthenticatorResponse)
215 {
216   SHA_CTX Context;
217   char PasswordHash[16];
218   char PasswordHashHash[16];
219   char Challenge[8];
220   u_char Digest[SHA_DIGEST_LENGTH];
221   int i;
222
223       /*
224        * "Magic" constants used in response generation
225        */
226   char Magic1[39] =
227          {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
228           0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
229           0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
230           0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
231
232
233   char Magic2[41] =
234          {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
235           0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
236           0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
237           0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
238           0x6E};
239       /*
240        * Hash the password with MD4
241        */
242   NtPasswordHash(Password, PasswordLen, PasswordHash);
243       /*
244        * Now hash the hash
245        */
246   HashNtPasswordHash(PasswordHash, PasswordHashHash);
247
248   SHA1_Init(&Context);
249   SHA1_Update(&Context, PasswordHashHash, 16);
250   SHA1_Update(&Context, NTResponse, 24);
251   SHA1_Update(&Context, Magic1, 39);
252   SHA1_Final(Digest, &Context);
253   ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen, 
254                 Challenge);
255   SHA1_Init(&Context);
256   SHA1_Update(&Context, Digest, 20);
257   SHA1_Update(&Context, Challenge, 8);
258   SHA1_Update(&Context, Magic2, 41);
259
260       /*
261        * Encode the value of 'Digest' as "S=" followed by
262        * 40 ASCII hexadecimal digits and return it in
263        * AuthenticatorResponse.
264        * For example,
265        *   "S=0123456789ABCDEF0123456789ABCDEF01234567"
266        */
267   AuthenticatorResponse[0] = 'S';
268   AuthenticatorResponse[1] = '=';
269   SHA1_End(&Context, AuthenticatorResponse + 2);
270   for (i=2; i<42; i++)
271     AuthenticatorResponse[i] = toupper(AuthenticatorResponse[i]);
272
273 }
274  
275 void
276 GetMasterKey(char *PasswordHashHash, char *NTResponse, char *MasterKey)
277 {
278   char Digest[SHA_DIGEST_LENGTH];
279   SHA_CTX Context;
280   static char Magic1[27] =
281       {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
282        0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
283        0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79};
284
285   SHA1_Init(&Context);
286   SHA1_Update(&Context, PasswordHashHash, 16);
287   SHA1_Update(&Context, NTResponse, 24);
288   SHA1_Update(&Context, Magic1, 27);
289   SHA1_Final(Digest, &Context);
290   memcpy(MasterKey, Digest, 16);
291 }
292
293 void
294 GetAsymetricStartKey(char *MasterKey, char *SessionKey, int SessionKeyLength,
295                      int IsSend, int IsServer)
296 {
297   char Digest[SHA_DIGEST_LENGTH];
298   SHA_CTX Context;
299   char *s;
300
301   static char Magic2[84] =
302       {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
303        0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
304        0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
305        0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
306        0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
307        0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
308        0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
309        0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
310        0x6b, 0x65, 0x79, 0x2e};
311
312   static char Magic3[84] =
313       {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
314        0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
315        0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
316        0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
317        0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
318        0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
319        0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
320        0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
321        0x6b, 0x65, 0x79, 0x2e};
322
323   if (IsSend) {
324      if (IsServer) {
325         s = Magic3;
326      } else {
327         s = Magic2;
328      }
329   } else {
330      if (IsServer) {
331         s = Magic2;
332      } else {
333         s = Magic3;
334      }
335   }
336
337   SHA1_Init(&Context);
338   SHA1_Update(&Context, MasterKey, 16);
339   SHA1_Update(&Context, SHA1_Pad1, 40);
340   SHA1_Update(&Context, s, 84);
341   SHA1_Update(&Context, SHA1_Pad2, 40);
342   SHA1_Final(Digest, &Context);
343
344   memcpy(SessionKey, Digest, SessionKeyLength);
345 }
346
347 void
348 GetNewKeyFromSHA(char *StartKey, char *SessionKey, long SessionKeyLength,
349                  char *InterimKey)
350 {
351   SHA_CTX Context;
352   char Digest[SHA_DIGEST_LENGTH];
353
354   SHA1_Init(&Context);
355   SHA1_Update(&Context, StartKey, SessionKeyLength);
356   SHA1_Update(&Context, SHA1_Pad1, 40);
357   SHA1_Update(&Context, SessionKey, SessionKeyLength);
358   SHA1_Update(&Context, SHA1_Pad2, 40);
359   SHA1_Final(Digest, &Context);
360
361   memcpy(InterimKey, Digest, SessionKeyLength);
362 }
363
364 #if 0
365 static void
366 Get_Key(char *InitialSessionKey, char *CurrentSessionKey,
367         int LengthOfDesiredKey)
368 {
369   SHA_CTX Context;
370   char Digest[SHA_DIGEST_LENGTH];
371
372   SHA1_Init(&Context);
373   SHA1_Update(&Context, InitialSessionKey, LengthOfDesiredKey);
374   SHA1_Update(&Context, SHA1_Pad1, 40);
375   SHA1_Update(&Context, CurrentSessionKey, LengthOfDesiredKey);
376   SHA1_Update(&Context, SHA1_Pad2, 40);
377   SHA1_Final(Digest, &Context);
378
379   memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey);
380 }
381 #endif
382
383 /* passwordHash 16-bytes MD4 hashed password
384    challenge    8-bytes peer CHAP challenge
385    since passwordHash is in a 24-byte buffer, response is written in there */
386 void
387 mschap_NT(char *passwordHash, char *challenge)
388 {
389     u_char response[24];
390
391     ChallengeResponse(challenge, passwordHash, response);
392     memcpy(passwordHash, response, 24);
393     passwordHash[24] = 1;               /* NT-style response */
394 }
395
396 void
397 mschap_LANMan(char *digest, char *challenge, char *secret)
398 {
399   static u_char salt[] = "KGS!@#$%";    /* RASAPI32.dll */
400   char SECRET[14], *ptr, *end;
401   u_char hash[16];
402
403   end = SECRET + sizeof SECRET;
404   for (ptr = SECRET; *secret && ptr < end; ptr++, secret++)
405     *ptr = toupper(*secret);
406   if (ptr < end)
407     memset(ptr, '\0', end - ptr);
408
409   DesEncrypt(salt, SECRET, hash);
410   DesEncrypt(salt, SECRET + 7, hash + 8);
411
412   ChallengeResponse(challenge, hash, digest);
413 }