xref: /freebsd/usr.sbin/ppp/chap_ms.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1  /*-
2   * SPDX-License-Identifier: BSD-2-Clause
3   *
4   * Copyright (c) 1997        Gabor Kincses <gabor@acm.org>
5   *               1997 - 2001 Brian Somers <brian@Awfulhak.org>
6   *          based on work by Eric Rosenquist
7   *                           Strata Software Limited.
8   * All rights reserved.
9   *
10   * Redistribution and use in source and binary forms, with or without
11   * modification, are permitted provided that the following conditions
12   * are met:
13   * 1. Redistributions of source code must retain the above copyright
14   *    notice, this list of conditions and the following disclaimer.
15   * 2. Redistributions in binary form must reproduce the above copyright
16   *    notice, this list of conditions and the following disclaimer in the
17   *    documentation and/or other materials provided with the distribution.
18   *
19   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29   * SUCH DAMAGE.
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
Get7Bits(u_char * input,int startBit)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
MakeKey(u_char * key,u_char * des_key)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 */
DesEncrypt(u_char * clear,u_char * key,u_char * cipher)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 */
ChallengeResponse(u_char * challenge,u_char * pwHash,u_char * response)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
NtPasswordHash(char * key,int keylen,char * hash)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
HashNtPasswordHash(char * hash,char * hashhash)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
ChallengeHash(char * PeerChallenge,char * AuthenticatorChallenge,char * UserName,char * Challenge)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
GenerateNTResponse(char * AuthenticatorChallenge,char * PeerChallenge,char * UserName,char * Password,int PasswordLen,char * Response)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 *
SHA1_End(SHA_CTX * ctx,char * buf)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
GenerateAuthenticatorResponse(char * Password,int PasswordLen,char * NTResponse,char * PeerChallenge,char * AuthenticatorChallenge,char * UserName,char * AuthenticatorResponse)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
GetMasterKey(char * PasswordHashHash,char * NTResponse,char * MasterKey)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
GetAsymetricStartKey(char * MasterKey,char * SessionKey,int SessionKeyLength,int IsSend,int IsServer)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
GetNewKeyFromSHA(char * StartKey,char * SessionKey,long SessionKeyLength,char * InterimKey)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
mschap_NT(char * passwordHash,char * challenge)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
mschap_LANMan(char * digest,char * challenge,char * secret)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  }
416