]> git.ozlabs.org Git - ppp.git/blob - pppd/chap_ms.c
ChapMS_LANMan(): update for new definition MS_ChapResponse/ChallengeResponse().
[ppp.git] / pppd / chap_ms.c
1 /*
2  * chap_ms.c - Microsoft MS-CHAP compatible implementation.
3  *
4  * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
5  * http://www.strataware.com/
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms are permitted
10  * provided that the above copyright notice and this paragraph are
11  * duplicated in all such forms and that any documentation,
12  * advertising materials, and other materials related to such
13  * distribution and use acknowledge that the software was developed
14  * by Eric Rosenquist.  The name of the author may not be used to
15  * endorse or promote products derived from this software without
16  * specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21  */
22
23 /*
24  * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
25  *
26  *   Implemented LANManager type password response to MS-CHAP challenges.
27  *   Now pppd provides both NT style and LANMan style blocks, and the
28  *   prefered is set by option "ms-lanman". Default is to use NT.
29  *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
30  *
31  *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
32  */
33
34 /*
35  * Modifications by Frank Cusack, frank@google.com, March 2002.
36  *
37  *   Implemented MS-CHAPv2 functionality, heavily based on sample
38  *   implementation in RFC 2759.  Implemented MPPE functionality,
39  *   heavily based on sample implementation in RFC 3079.
40  *   Copyright (c) 2002 Google, Inc.
41  */
42
43 #define RCSID   "$Id: chap_ms.c,v 1.24 2002/11/13 12:26:03 fcusack Exp $"
44
45 #ifdef CHAPMS
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <ctype.h>
51 #include <sys/types.h>
52 #include <sys/time.h>
53 #include <unistd.h>
54
55 #include "pppd.h"
56 #include "chap.h"
57 #include "chap_ms.h"
58 #include "md4.h"
59 #include "sha1.h"
60 #include "pppcrypt.h"
61
62 static const char rcsid[] = RCSID;
63
64
65 static void     ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
66 static void     ascii2unicode __P((char[], int, u_char[]));
67 static void     NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
68 static void     ChallengeResponse __P((u_char *, u_char *, u_char[24]));
69 static void     ChapMS_NT __P((u_char *, char *, int, u_char[24]));
70 static void     ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
71                                 u_char[24]));
72 static void     GenerateAuthenticatorResponse __P((char*, int, u_char[24],
73                                                    u_char[16], u_char *,
74                                                    char *, u_char[41]));
75 #ifdef MSLANMAN
76 static void     ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
77 #endif
78
79 #ifdef MPPE
80 static void     Set_Start_Key __P((u_char *, char *, int));
81 static void     SetMasterKeys __P((char *, int, u_char[24], int));
82 #endif
83
84 extern double drand48 __P((void));
85
86 #ifdef MSLANMAN
87 bool    ms_lanman = 0;          /* Use LanMan password instead of NT */
88                                 /* Has meaning only with MS-CHAP challenges */
89 #endif
90
91 #ifdef MPPE
92 u_char mppe_send_key[MPPE_MAX_KEY_LEN];
93 u_char mppe_recv_key[MPPE_MAX_KEY_LEN];
94 #endif
95
96 static void
97 ChallengeResponse(u_char *challenge,
98                   u_char PasswordHash[MD4_SIGNATURE_SIZE],
99                   u_char response[24])
100 {
101     u_char    ZPasswordHash[21];
102
103     BZERO(ZPasswordHash, sizeof(ZPasswordHash));
104     BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
105
106 #if 0
107     dbglog("ChallengeResponse - ZPasswordHash %.*B",
108            sizeof(ZPasswordHash), ZPasswordHash);
109 #endif
110
111     (void) DesSetkey(ZPasswordHash + 0);
112     DesEncrypt(challenge, response + 0);
113     (void) DesSetkey(ZPasswordHash + 7);
114     DesEncrypt(challenge, response + 8);
115     (void) DesSetkey(ZPasswordHash + 14);
116     DesEncrypt(challenge, response + 16);
117
118 #if 0
119     dbglog("ChallengeResponse - response %.24B", response);
120 #endif
121 }
122
123 static void
124 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
125               char *username, u_char Challenge[8])
126     
127 {
128     SHA1_CTX    sha1Context;
129     u_char      sha1Hash[SHA1_SIGNATURE_SIZE];
130     char        *user;
131
132     /* remove domain from "domain\username" */
133     if ((user = strrchr(username, '\\')) != NULL)
134         ++user;
135     else
136         user = username;
137
138     SHA1_Init(&sha1Context);
139     SHA1_Update(&sha1Context, PeerChallenge, 16);
140     SHA1_Update(&sha1Context, rchallenge, 16);
141     SHA1_Update(&sha1Context, user, strlen(user));
142     SHA1_Final(sha1Hash, &sha1Context);
143
144     BCOPY(sha1Hash, Challenge, 8);
145 }
146
147 /*
148  * Convert the ASCII version of the password to Unicode.
149  * This implicitly supports 8-bit ISO8859/1 characters.
150  * This gives us the little-endian representation, which
151  * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
152  * is machine-dependent.)
153  */
154 static void
155 ascii2unicode(char ascii[], int ascii_len, u_char unicode[])
156 {
157     int i;
158
159     BZERO(unicode, ascii_len * 2);
160     for (i = 0; i < ascii_len; i++)
161         unicode[i * 2] = (u_char) ascii[i];
162 }
163
164 static void
165 NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE])
166 {
167 #ifdef __NetBSD__
168     /* NetBSD uses the libc md4 routines which take bytes instead of bits */
169     int                 mdlen = secret_len;
170 #else
171     int                 mdlen = secret_len * 8;
172 #endif
173     MD4_CTX             md4Context;
174
175     MD4Init(&md4Context);
176     MD4Update(&md4Context, secret, mdlen);
177     MD4Final(hash, &md4Context);
178
179 }
180
181 static void
182 ChapMS_NT(u_char *rchallenge, char *secret, int secret_len,
183           u_char NTResponse[24])
184 {
185     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
186     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
187
188     /* Hash the Unicode version of the secret (== password). */
189     ascii2unicode(secret, secret_len, unicodePassword);
190     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
191
192     ChallengeResponse(rchallenge, PasswordHash, NTResponse);
193 }
194
195 static void
196 ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username,
197            char *secret, int secret_len, u_char NTResponse[24])
198 {
199     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
200     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
201     u_char      Challenge[8];
202
203     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
204
205     /* Hash the Unicode version of the secret (== password). */
206     ascii2unicode(secret, secret_len, unicodePassword);
207     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
208
209     ChallengeResponse(Challenge, PasswordHash, NTResponse);
210 }
211
212 #ifdef MSLANMAN
213 static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
214
215 static void
216 ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
217               MS_ChapResponse *response)
218 {
219     int                 i;
220     u_char              UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
221     u_char              PasswordHash[MD4_SIGNATURE_SIZE];
222
223     /* LANMan password is case insensitive */
224     BZERO(UcasePassword, sizeof(UcasePassword));
225     for (i = 0; i < secret_len; i++)
226        UcasePassword[i] = (u_char)toupper(secret[i]);
227     (void) DesSetkey(UcasePassword + 0);
228     DesEncrypt( StdText, PasswordHash + 0 );
229     (void) DesSetkey(UcasePassword + 7);
230     DesEncrypt( StdText, PasswordHash + 8 );
231     ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
232 }
233 #endif
234
235
236 static void
237 GenerateAuthenticatorResponse(char *secret, int secret_len,
238                               u_char NTResponse[24], u_char PeerChallenge[16],
239                               u_char *rchallenge, char *username,
240                               u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
241 {
242     /*
243      * "Magic" constants used in response generation, from RFC 2759.
244      */
245     u_char Magic1[39] = /* "Magic server to client signing constant" */
246         { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
247           0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
248           0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
249           0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
250     u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
251         { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
252           0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
253           0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
254           0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
255           0x6E };
256
257     int         i;
258     SHA1_CTX    sha1Context;
259     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
260     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
261     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
262     u_char      Digest[SHA1_SIGNATURE_SIZE];
263     u_char      Challenge[8];
264
265     /* Hash (x2) the Unicode version of the secret (== password). */
266     ascii2unicode(secret, secret_len, unicodePassword);
267     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
268     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
269
270     SHA1_Init(&sha1Context);
271     SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
272     SHA1_Update(&sha1Context, NTResponse, 24);
273     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
274     SHA1_Final(Digest, &sha1Context);
275
276     ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
277
278     SHA1_Init(&sha1Context);
279     SHA1_Update(&sha1Context, Digest, sizeof(Digest));
280     SHA1_Update(&sha1Context, Challenge, sizeof(Challenge));
281     SHA1_Update(&sha1Context, Magic2, sizeof(Magic2));
282     SHA1_Final(Digest, &sha1Context);
283
284     /* Convert to ASCII hex string. */
285     for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++)
286         sprintf(&authResponse[i * 2], "%02X", Digest[i]);
287 }
288
289
290 #ifdef MPPE
291 /*
292  * Set mppe_xxxx_key from the NTPasswordHashHash.
293  * RFC 2548 (RADIUS support) requires us to export this function (ugh).
294  */
295 void
296 mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
297 {
298     SHA1_CTX    sha1Context;
299     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
300
301     SHA1_Init(&sha1Context);
302     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
303     SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
304     SHA1_Update(&sha1Context, rchallenge, 8);
305     SHA1_Final(Digest, &sha1Context);
306
307     /* Same key in both directions. */
308     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
309     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
310 }
311
312 /*
313  * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
314  */
315 static void
316 Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
317 {
318     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
319     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
320     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
321
322     /* Hash (x2) the Unicode version of the secret (== password). */
323     ascii2unicode(secret, secret_len, unicodePassword);
324     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
325     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
326
327     mppe_set_keys(rchallenge, PasswordHashHash);
328 }
329
330 /*
331  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
332  */
333 static void
334 SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
335 {
336     SHA1_CTX    sha1Context;
337     u_char      unicodePassword[MAX_NT_PASSWORD * 2];
338     u_char      PasswordHash[MD4_SIGNATURE_SIZE];
339     u_char      PasswordHashHash[MD4_SIGNATURE_SIZE];
340     u_char      MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
341     u_char      Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
342
343     u_char SHApad1[40] =
344         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
348     u_char SHApad2[40] =
349         { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
350           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
351           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
352           0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
353
354     /* "This is the MPPE Master Key" */
355     u_char Magic1[27] =
356         { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
357           0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
358           0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
359     /* "On the client side, this is the send key; "
360        "on the server side, it is the receive key." */
361     u_char Magic2[84] =
362         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
363           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
364           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
365           0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
366           0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
367           0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
368           0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
369           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
370           0x6b, 0x65, 0x79, 0x2e };
371     /* "On the client side, this is the receive key; "
372        "on the server side, it is the send key." */
373     u_char Magic3[84] =
374         { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
375           0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
376           0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
377           0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
378           0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
379           0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
380           0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
381           0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
382           0x6b, 0x65, 0x79, 0x2e };
383     u_char *s;
384
385     /* Hash (x2) the Unicode version of the secret (== password). */
386     ascii2unicode(secret, secret_len, unicodePassword);
387     NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
388     NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
389
390     SHA1_Init(&sha1Context);
391     SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
392     SHA1_Update(&sha1Context, NTResponse, 24);
393     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
394     SHA1_Final(MasterKey, &sha1Context);
395
396     /*
397      * generate send key
398      */
399     if (IsServer)
400         s = Magic3;
401     else
402         s = Magic2;
403     SHA1_Init(&sha1Context);
404     SHA1_Update(&sha1Context, MasterKey, 16);
405     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
406     SHA1_Update(&sha1Context, s, 84);
407     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
408     SHA1_Final(Digest, &sha1Context);
409
410     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
411
412     /*
413      * generate recv key
414      */
415     if (IsServer)
416         s = Magic2;
417     else
418         s = Magic3;
419     SHA1_Init(&sha1Context);
420     SHA1_Update(&sha1Context, MasterKey, 16);
421     SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1));
422     SHA1_Update(&sha1Context, s, 84);
423     SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2));
424     SHA1_Final(Digest, &sha1Context);
425
426     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
427 }
428
429 #endif /* MPPE */
430
431
432 void
433 ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len,
434        MS_ChapResponse *response)
435 {
436 #if 0
437     CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
438 #endif
439     BZERO(response, sizeof(*response));
440
441     ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
442
443 #ifdef MSLANMAN
444     ChapMS_LANMan(rchallenge, secret, secret_len, response);
445
446     /* preferred method is set by option  */
447     response->UseNT[0] = !ms_lanman;
448 #else
449     response->UseNT[0] = 1;
450 #endif
451
452     cstate->resp_length = MS_CHAP_RESPONSE_LEN;
453
454 #ifdef MPPE
455     Set_Start_Key(rchallenge, secret, secret_len);
456 #endif
457 }
458
459
460 /*
461  * If PeerChallenge is NULL, one is generated and response->PeerChallenge
462  * is filled in.  Call this way when generating a response.
463  * If PeerChallenge is supplied, it is copied into response->PeerChallenge.
464  * Call this way when verifying a response (or debugging).
465  * Do not call with PeerChallenge = response->PeerChallenge.
466  *
467  * response->PeerChallenge is then used for calculation of the
468  * Authenticator Response.
469  */
470 void
471 ChapMS2(chap_state *cstate, u_char *rchallenge, u_char *PeerChallenge,
472         char *user, char *secret, int secret_len, MS_Chap2Response *response,
473         u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1], int authenticator)
474 {
475     /* ARGSUSED */
476     u_char *p = response->PeerChallenge;
477     int i;
478
479     BZERO(response, sizeof(*response));
480
481     /* Generate the Peer-Challenge if requested, or copy it if supplied. */
482     if (!PeerChallenge)
483         for (i = 0; i < sizeof(response->PeerChallenge); i++)
484             *p++ = (u_char) (drand48() * 0xff);
485     else
486         BCOPY(PeerChallenge, response->PeerChallenge,
487               sizeof(response->PeerChallenge));
488
489     /* Generate the NT-Response */
490     ChapMS2_NT(rchallenge, response->PeerChallenge, user,
491                secret, secret_len, response->NTResp);
492
493     /* Generate the Authenticator Response. */
494     GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
495                                   response->PeerChallenge, rchallenge,
496                                   user, authResponse);
497
498     cstate->resp_length = MS_CHAP2_RESPONSE_LEN;
499
500 #ifdef MPPE
501     SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
502 #endif
503 }
504
505
506 #endif /* CHAPMS */