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