Initial import from FreeBSD RELENG_4:
[dragonfly.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: src/usr.sbin/ppp/chap_ms.c,v 1.9.2.6 2002/09/01 02:12:23 brian Exp $
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 void
154 ChallengeHash(char *PeerChallenge, char *AuthenticatorChallenge,
155               char *UserName, int UserNameLen, 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, int UserNameLen, char *Password,
180                    int PasswordLen, char *Response)
181 {
182   char Challenge[8];
183   char PasswordHash[16];
184
185   ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen,
186                 Challenge);
187   NtPasswordHash(Password, PasswordLen, PasswordHash);
188   ChallengeResponse(Challenge, PasswordHash, Response);
189 }
190
191 #ifndef __FreeBSD__
192 #define LENGTH 20
193 static char *
194 SHA1_End(SHA_CTX *ctx, char *buf)
195 {
196     int i;
197     unsigned char digest[LENGTH];
198     static const char hex[]="0123456789abcdef";
199
200     if (!buf)
201         buf = malloc(2*LENGTH + 1);
202     if (!buf)
203         return 0;
204     SHA1_Final(digest, ctx);
205     for (i = 0; i < LENGTH; i++) {
206         buf[i+i] = hex[digest[i] >> 4];
207         buf[i+i+1] = hex[digest[i] & 0x0f];
208     }
209     buf[i+i] = '\0';
210     return buf;
211 }
212 #endif
213
214 void
215 GenerateAuthenticatorResponse(char *Password, int PasswordLen,
216                               char *NTResponse, char *PeerChallenge,
217                               char *AuthenticatorChallenge, char *UserName,
218                               int UserNameLen, char *AuthenticatorResponse)
219 {
220   SHA_CTX Context;
221   char PasswordHash[16];
222   char PasswordHashHash[16];
223   char Challenge[8];
224   u_char Digest[SHA_DIGEST_LENGTH];
225   int i;
226
227       /*
228        * "Magic" constants used in response generation
229        */
230   char Magic1[39] =
231          {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
232           0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
233           0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
234           0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
235
236
237   char Magic2[41] =
238          {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
239           0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
240           0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
241           0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
242           0x6E};
243       /*
244        * Hash the password with MD4
245        */
246   NtPasswordHash(Password, PasswordLen, PasswordHash);
247       /*
248        * Now hash the hash
249        */
250   HashNtPasswordHash(PasswordHash, PasswordHashHash);
251
252   SHA1_Init(&Context);
253   SHA1_Update(&Context, PasswordHashHash, 16);
254   SHA1_Update(&Context, NTResponse, 24);
255   SHA1_Update(&Context, Magic1, 39);
256   SHA1_Final(Digest, &Context);
257   ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, UserNameLen,
258                 Challenge);
259   SHA1_Init(&Context);
260   SHA1_Update(&Context, Digest, 20);
261   SHA1_Update(&Context, Challenge, 8);
262   SHA1_Update(&Context, Magic2, 41);
263
264       /*
265        * Encode the value of 'Digest' as "S=" followed by
266        * 40 ASCII hexadecimal digits and return it in
267        * AuthenticatorResponse.
268        * For example,
269        *   "S=0123456789ABCDEF0123456789ABCDEF01234567"
270        */
271   AuthenticatorResponse[0] = 'S';
272   AuthenticatorResponse[1] = '=';
273   SHA1_End(&Context, AuthenticatorResponse + 2);
274   for (i=2; i<42; i++)
275     AuthenticatorResponse[i] = toupper(AuthenticatorResponse[i]);
276
277 }
278
279 void
280 GetMasterKey(char *PasswordHashHash, char *NTResponse, char *MasterKey)
281 {
282   char Digest[SHA_DIGEST_LENGTH];
283   SHA_CTX Context;
284   static char Magic1[27] =
285       {0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
286        0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
287        0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79};
288
289   SHA1_Init(&Context);
290   SHA1_Update(&Context, PasswordHashHash, 16);
291   SHA1_Update(&Context, NTResponse, 24);
292   SHA1_Update(&Context, Magic1, 27);
293   SHA1_Final(Digest, &Context);
294   memcpy(MasterKey, Digest, 16);
295 }
296
297 void
298 GetAsymetricStartKey(char *MasterKey, char *SessionKey, int SessionKeyLength,
299                      int IsSend, int IsServer)
300 {
301   char Digest[SHA_DIGEST_LENGTH];
302   SHA_CTX Context;
303   char *s;
304
305   static char Magic2[84] =
306       {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
307        0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
308        0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
309        0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
310        0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
311        0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
312        0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
313        0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
314        0x6b, 0x65, 0x79, 0x2e};
315
316   static char Magic3[84] =
317       {0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
318        0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
319        0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
320        0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
321        0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
322        0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
323        0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
324        0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
325        0x6b, 0x65, 0x79, 0x2e};
326
327   if (IsSend) {
328      if (IsServer) {
329         s = Magic3;
330      } else {
331         s = Magic2;
332      }
333   } else {
334      if (IsServer) {
335         s = Magic2;
336      } else {
337         s = Magic3;
338      }
339   }
340
341   SHA1_Init(&Context);
342   SHA1_Update(&Context, MasterKey, 16);
343   SHA1_Update(&Context, SHA1_Pad1, 40);
344   SHA1_Update(&Context, s, 84);
345   SHA1_Update(&Context, SHA1_Pad2, 40);
346   SHA1_Final(Digest, &Context);
347
348   memcpy(SessionKey, Digest, SessionKeyLength);
349 }
350
351 void
352 GetNewKeyFromSHA(char *StartKey, char *SessionKey, long SessionKeyLength,
353                  char *InterimKey)
354 {
355   SHA_CTX Context;
356   char Digest[SHA_DIGEST_LENGTH];
357
358   SHA1_Init(&Context);
359   SHA1_Update(&Context, StartKey, SessionKeyLength);
360   SHA1_Update(&Context, SHA1_Pad1, 40);
361   SHA1_Update(&Context, SessionKey, SessionKeyLength);
362   SHA1_Update(&Context, SHA1_Pad2, 40);
363   SHA1_Final(Digest, &Context);
364
365   memcpy(InterimKey, Digest, SessionKeyLength);
366 }
367
368 #if 0
369 static void
370 Get_Key(char *InitialSessionKey, char *CurrentSessionKey,
371         int LengthOfDesiredKey)
372 {
373   SHA_CTX Context;
374   char Digest[SHA_DIGEST_LENGTH];
375
376   SHA1_Init(&Context);
377   SHA1_Update(&Context, InitialSessionKey, LengthOfDesiredKey);
378   SHA1_Update(&Context, SHA1_Pad1, 40);
379   SHA1_Update(&Context, CurrentSessionKey, LengthOfDesiredKey);
380   SHA1_Update(&Context, SHA1_Pad2, 40);
381   SHA1_Final(Digest, &Context);
382
383   memcpy(CurrentSessionKey, Digest, LengthOfDesiredKey);
384 }
385 #endif
386
387 /* passwordHash 16-bytes MD4 hashed password
388    challenge    8-bytes peer CHAP challenge
389    since passwordHash is in a 24-byte buffer, response is written in there */
390 void
391 mschap_NT(char *passwordHash, char *challenge)
392 {
393     u_char response[24];
394
395     ChallengeResponse(challenge, passwordHash, response);
396     memcpy(passwordHash, response, 24);
397     passwordHash[24] = 1;               /* NT-style response */
398 }
399
400 void
401 mschap_LANMan(char *digest, char *challenge, char *secret)
402 {
403   static u_char salt[] = "KGS!@#$%";    /* RASAPI32.dll */
404   char SECRET[14], *ptr, *end;
405   u_char hash[16];
406
407   end = SECRET + sizeof SECRET;
408   for (ptr = SECRET; *secret && ptr < end; ptr++, secret++)
409     *ptr = toupper(*secret);
410   if (ptr < end)
411     memset(ptr, '\0', end - ptr);
412
413   DesEncrypt(salt, SECRET, hash);
414   DesEncrypt(salt, SECRET + 7, hash + 8);
415
416   ChallengeResponse(challenge, hash, digest);
417 }