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