X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fchap_ms.c;h=0f627fb5aedc8f5ac99428b7cd9ce0c89452890e;hp=b7404638cf30d2485eb32e286d033c2120eee234;hb=f79e0204d1134667d049c14f2c2ab38c9cb6a81a;hpb=7a4dc0ff500aaa176a41965d8d4ad15a97a70904 diff --git a/pppd/chap_ms.c b/pppd/chap_ms.c index b740463..0f627fb 100644 --- a/pppd/chap_ms.c +++ b/pppd/chap_ms.c @@ -31,9 +31,16 @@ * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80 */ -#ifndef lint -static char rcsid[] = "$Id: chap_ms.c,v 1.13 1999/03/16 03:15:14 paulus Exp $"; -#endif +/* + * Modifications by Frank Cusack, frank@google.com, March 2002. + * + * Implemented MS-CHAPv2 functionality, heavily based on sample + * implementation in RFC 2759. Implemented MPPE functionality, + * heavily based on sample implementation in RFC 3079. + * Copyright (c) 2002 Google, Inc. + */ + +#define RCSID "$Id: chap_ms.c,v 1.20 2002/04/02 14:15:07 dfs Exp $" #ifdef CHAPMS @@ -52,27 +59,30 @@ static char rcsid[] = "$Id: chap_ms.c,v 1.13 1999/03/16 03:15:14 paulus Exp $"; #include "chap.h" #include "chap_ms.h" #include "md4.h" +#include "sha1.h" #ifndef USE_CRYPT #include #endif -typedef struct { - u_char LANManResp[24]; - u_char NTResp[24]; - u_char UseNT; /* If 1, ignore the LANMan response field */ -} MS_ChapResponse; -/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse), - in case this struct gets padded. */ +static const char rcsid[] = RCSID; -static void ChallengeResponse __P((u_char *, u_char *, u_char *)); -static void DesEncrypt __P((u_char *, u_char *, u_char *)); +static void ChallengeHash __P((u_char[16], u_char *, char *, u_char[8])); +static void ascii2unicode __P((char[], int, u_char[])); +static void NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE])); +static void ChallengeResponse __P((u_char *, u_char *, u_char[24])); +static void DesEncrypt __P((u_char *, u_char *, u_char[8])); static void MakeKey __P((u_char *, u_char *)); static u_char Get7Bits __P((u_char *, int)); -static void ChapMS_NT __P((char *, int, char *, int, MS_ChapResponse *)); +static void ChapMS_NT __P((u_char *, char *, int, u_char[24])); +static void ChapMS2_NT __P((char *, u_char[16], char *, char *, int, + u_char[24])); +static void GenerateAuthenticatorResponse __P((char*, int, u_char[24], + u_char[16], u_char *, + char *, u_char[41])); #ifdef MSLANMAN -static void ChapMS_LANMan __P((char *, int, char *, int, MS_ChapResponse *)); +static void ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *)); #endif #ifdef USE_CRYPT @@ -80,30 +90,41 @@ static void Expand __P((u_char *, u_char *)); static void Collapse __P((u_char *, u_char *)); #endif +#ifdef MPPE +static void Set_Start_Key __P((u_char *, char *, int)); +static void SetMasterKeys __P((char *, int, u_char[24], int)); +#endif + +extern double drand48 __P((void)); + #ifdef MSLANMAN bool ms_lanman = 0; /* Use LanMan password instead of NT */ /* Has meaning only with MS-CHAP challenges */ #endif +#ifdef MPPE +u_char mppe_send_key[MPPE_MAX_KEY_LEN]; +u_char mppe_recv_key[MPPE_MAX_KEY_LEN]; +#endif + static void -ChallengeResponse(challenge, pwHash, response) - u_char *challenge; /* IN 8 octets */ - u_char *pwHash; /* IN 16 octets */ - u_char *response; /* OUT 24 octets */ +ChallengeResponse(u_char *challenge, + u_char PasswordHash[MD4_SIGNATURE_SIZE], + u_char response[24]) { char ZPasswordHash[21]; BZERO(ZPasswordHash, sizeof(ZPasswordHash)); - BCOPY(pwHash, ZPasswordHash, MD4_SIGNATURE_SIZE); + BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE); #if 0 dbglog("ChallengeResponse - ZPasswordHash %.*B", sizeof(ZPasswordHash), ZPasswordHash); #endif - DesEncrypt(challenge, ZPasswordHash + 0, response + 0); - DesEncrypt(challenge, ZPasswordHash + 7, response + 8); - DesEncrypt(challenge, ZPasswordHash + 14, response + 16); + DesEncrypt(challenge, ZPasswordHash + 0, &response[0]); + DesEncrypt(challenge, ZPasswordHash + 7, &response[8]); + DesEncrypt(challenge, ZPasswordHash + 14, &response[16]); #if 0 dbglog("ChallengeResponse - response %.24B", response); @@ -113,10 +134,7 @@ ChallengeResponse(challenge, pwHash, response) #ifdef USE_CRYPT static void -DesEncrypt(clear, key, cipher) - u_char *clear; /* IN 8 octets */ - u_char *key; /* IN 7 octets */ - u_char *cipher; /* OUT 8 octets */ +DesEncrypt(u_char *clear, u_char *key, u_char cipher[8]) { u_char des_key[8]; u_char crypt_key[66]; @@ -143,10 +161,7 @@ DesEncrypt(clear, key, cipher) #else /* USE_CRYPT */ static void -DesEncrypt(clear, key, cipher) - u_char *clear; /* IN 8 octets */ - u_char *key; /* IN 7 octets */ - u_char *cipher; /* OUT 8 octets */ +DesEncrypt(u_char *clear, u_char *key, u_char cipher[8]) { des_cblock des_key; des_key_schedule key_schedule; @@ -169,9 +184,7 @@ DesEncrypt(clear, key, cipher) #endif /* USE_CRYPT */ -static u_char Get7Bits(input, startBit) - u_char *input; - int startBit; +static u_char Get7Bits(u_char *input, int startBit) { register unsigned int word; @@ -189,9 +202,7 @@ static u_char Get7Bits(input, startBit) * out == 64-byte string where each byte is either 1 or 0 * Note that the low-order "bit" is always ignored by by setkey() */ -static void Expand(in, out) - u_char *in; - u_char *out; +static void Expand(u_char *in, u_char *out) { int j, c; int i; @@ -206,9 +217,7 @@ static void Expand(in, out) /* The inverse of Expand */ -static void Collapse(in, out) - u_char *in; - u_char *out; +static void Collapse(u_char *in, u_char *out) { int j; int i; @@ -223,9 +232,7 @@ static void Collapse(in, out) } #endif -static void MakeKey(key, des_key) - u_char *key; /* IN 56 bit DES key missing parity bits */ - u_char *des_key; /* OUT 64 bit DES key with parity bits added */ +static void MakeKey(u_char *key, u_char *des_key) { des_key[0] = Get7Bits(key, 0); des_key[1] = Get7Bits(key, 7); @@ -246,49 +253,102 @@ static void MakeKey(key, des_key) #endif } + static void -ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, response) - char *rchallenge; - int rchallenge_len; - char *secret; - int secret_len; - MS_ChapResponse *response; +ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge, + char *username, u_char Challenge[8]) + +{ + SHA1_CTX sha1Context; + u_char sha1Hash[SHA1_SIGNATURE_SIZE]; + char *user; + + /* remove domain from "domain\username" */ + if ((user = strrchr(username, '\\')) != NULL) + ++user; + else + user = username; + + SHA1_Init(&sha1Context); + SHA1_Update(&sha1Context, PeerChallenge, 16); + SHA1_Update(&sha1Context, rchallenge, 16); + SHA1_Update(&sha1Context, user, strlen(user)); + SHA1_Final(sha1Hash, &sha1Context); + + BCOPY(sha1Hash, Challenge, 8); +} + +/* + * Convert the ASCII version of the password to Unicode. + * This implicitly supports 8-bit ISO8859/1 characters. + * This gives us the little-endian representation, which + * is assumed by all M$ CHAP RFCs. (Unicode byte ordering + * is machine-dependent.) + */ +static void +ascii2unicode(char ascii[], int ascii_len, u_char unicode[]) +{ + int i; + + BZERO(unicode, ascii_len * 2); + for (i = 0; i < ascii_len; i++) + unicode[i * 2] = (u_char) ascii[i]; +} + +static void +NTPasswordHash(char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE]) { - int i; #ifdef __NetBSD__ /* NetBSD uses the libc md4 routines which take bytes instead of bits */ - int mdlen = secret_len * 2; + int mdlen = secret_len; #else - int mdlen = secret_len * 2 * 8; + int mdlen = secret_len * 8; #endif MD4_CTX md4Context; - u_char hash[MD4_SIGNATURE_SIZE]; - u_char unicodePassword[MAX_NT_PASSWORD * 2]; - - /* Initialize the Unicode version of the secret (== password). */ - /* This implicitly supports 8-bit ISO8859/1 characters. */ - BZERO(unicodePassword, sizeof(unicodePassword)); - for (i = 0; i < secret_len; i++) - unicodePassword[i * 2] = (u_char)secret[i]; MD4Init(&md4Context); - MD4Update(&md4Context, unicodePassword, mdlen); + MD4Update(&md4Context, secret, mdlen); + MD4Final(hash, &md4Context); + +} - MD4Final(hash, &md4Context); /* Tell MD4 we're done */ +static void +ChapMS_NT(u_char *rchallenge, char *secret, int secret_len, + u_char NTResponse[24]) +{ + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; - ChallengeResponse(rchallenge, hash, response->NTResp); + /* Hash the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + + ChallengeResponse(rchallenge, PasswordHash, NTResponse); +} + +static void +ChapMS2_NT(char *rchallenge, u_char PeerChallenge[16], char *username, + char *secret, int secret_len, u_char NTResponse[24]) +{ + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char Challenge[8]; + + ChallengeHash(PeerChallenge, rchallenge, username, Challenge); + + /* Hash the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + + ChallengeResponse(Challenge, PasswordHash, NTResponse); } #ifdef MSLANMAN static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ static void -ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, response) - char *rchallenge; - int rchallenge_len; - char *secret; - int secret_len; - MS_ChapResponse *response; +ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len, + u_char LMResponse[24]) { int i; u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ @@ -300,39 +360,275 @@ ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, response) UcasePassword[i] = (u_char)toupper(secret[i]); DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 ); DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 ); - ChallengeResponse(rchallenge, PasswordHash, response->LANManResp); + ChallengeResponse(rchallenge, PasswordHash, LMResponse); } #endif + +static void +GenerateAuthenticatorResponse(char *secret, int secret_len, + u_char NTResponse[24], u_char PeerChallenge[16], + u_char *rchallenge, char *username, + u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) +{ + /* + * "Magic" constants used in response generation, from RFC 2759. + */ + u_char Magic1[39] = /* "Magic server to client signing constant" */ + { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, + 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, + 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; + u_char Magic2[41] = /* "Pad to make it do more than one iteration" */ + { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, + 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, + 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, + 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, + 0x6E }; + + int i; + SHA1_CTX sha1Context; + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; + u_char Digest[SHA1_SIGNATURE_SIZE]; + u_char Challenge[8]; + + /* Hash (x2) the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); + + SHA1_Init(&sha1Context); + SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash)); + SHA1_Update(&sha1Context, NTResponse, 24); + SHA1_Update(&sha1Context, Magic1, sizeof(Magic1)); + SHA1_Final(Digest, &sha1Context); + + ChallengeHash(PeerChallenge, rchallenge, username, Challenge); + + SHA1_Init(&sha1Context); + SHA1_Update(&sha1Context, Digest, sizeof(Digest)); + SHA1_Update(&sha1Context, Challenge, sizeof(Challenge)); + SHA1_Update(&sha1Context, Magic2, sizeof(Magic2)); + SHA1_Final(Digest, &sha1Context); + + /* Convert to ASCII hex string. */ + for (i = 0; i < MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++) + sprintf(&authResponse[i * 2], "%02X", Digest[i]); +} + + +#ifdef MPPE +/* + * Set mppe_xxxx_key from the NTPasswordHashHash. + * RFC 2548 (RADIUS support) requires us to export this function (ugh). + */ void -ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len) - chap_state *cstate; - char *rchallenge; - int rchallenge_len; - char *secret; - int secret_len; +mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE]) { - MS_ChapResponse response; + SHA1_CTX sha1Context; + u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ + + SHA1_Init(&sha1Context); + SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); + SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); + SHA1_Update(&sha1Context, rchallenge, 8); + SHA1_Final(Digest, &sha1Context); + + /* Same key in both directions. */ + BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); + BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); +} +/* + * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079) + */ +static void +Set_Start_Key(u_char *rchallenge, char *secret, int secret_len) +{ + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; + + /* Hash (x2) the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); + + mppe_set_keys(rchallenge, PasswordHashHash); +} + +/* + * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) + */ +static void +SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer) +{ + SHA1_CTX sha1Context; + u_char unicodePassword[MAX_NT_PASSWORD * 2]; + u_char PasswordHash[MD4_SIGNATURE_SIZE]; + u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; + u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ + u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ + + u_char SHApad1[40] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + u_char SHApad2[40] = + { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 }; + + /* "This is the MPPE Master Key" */ + u_char Magic1[27] = + { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, + 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 }; + /* "On the client side, this is the send key; " + "on the server side, it is the receive key." */ + u_char Magic2[84] = + { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, + 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, + 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, + 0x6b, 0x65, 0x79, 0x2e }; + /* "On the client side, this is the receive key; " + "on the server side, it is the send key." */ + u_char Magic3[84] = + { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, + 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, + 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, + 0x6b, 0x65, 0x79, 0x2e }; + u_char *s; + + /* Hash (x2) the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); + NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); + + SHA1_Init(&sha1Context); + SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash)); + SHA1_Update(&sha1Context, NTResponse, 24); + SHA1_Update(&sha1Context, Magic1, sizeof(Magic1)); + SHA1_Final(MasterKey, &sha1Context); + + /* + * generate send key + */ + if (IsServer) + s = Magic3; + else + s = Magic2; + SHA1_Init(&sha1Context); + SHA1_Update(&sha1Context, MasterKey, 16); + SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1)); + SHA1_Update(&sha1Context, s, 84); + SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2)); + SHA1_Final(Digest, &sha1Context); + + BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key)); + + /* + * generate recv key + */ + if (IsServer) + s = Magic2; + else + s = Magic3; + SHA1_Init(&sha1Context); + SHA1_Update(&sha1Context, MasterKey, 16); + SHA1_Update(&sha1Context, SHApad1, sizeof(SHApad1)); + SHA1_Update(&sha1Context, s, 84); + SHA1_Update(&sha1Context, SHApad2, sizeof(SHApad2)); + SHA1_Final(Digest, &sha1Context); + + BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key)); +} + +#endif /* MPPE */ + + +void +ChapMS(chap_state *cstate, u_char *rchallenge, char *secret, int secret_len, + MS_ChapResponse *response) +{ #if 0 CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret)); #endif - BZERO(&response, sizeof(response)); + BZERO(response, sizeof(*response)); /* Calculate both always */ - ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response); + ChapMS_NT(rchallenge, secret, secret_len, response->NTResp); #ifdef MSLANMAN - ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response); + ChapMS_LANMan(rchallenge, secret, secret_len, response); /* prefered method is set by option */ - response.UseNT = !ms_lanman; + response->UseNT[0] = !ms_lanman; #else - response.UseNT = 1; + response->UseNT[0] = 1; +#endif + +#ifdef MPPE + Set_Start_Key(rchallenge, secret, secret_len); #endif +} + - BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN); - cstate->resp_length = MS_CHAP_RESPONSE_LEN; +/* + * If PeerChallenge is NULL, one is generated and response->PeerChallenge + * is filled in. Call this way when generating a response. + * If PeerChallenge is supplied, it is copied into response->PeerChallenge. + * Call this way when verifying a response (or debugging). + * Do not call with PeerChallenge = response->PeerChallenge. + * + * response->PeerChallenge is then used for calculation of the + * Authenticator Response. + */ +void +ChapMS2(chap_state *cstate, u_char *rchallenge, u_char *PeerChallenge, + char *user, char *secret, int secret_len, MS_Chap2Response *response, + u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1], int authenticator) +{ + /* ARGSUSED */ + u_char *p = response->PeerChallenge; + int i; + + BZERO(response, sizeof(*response)); + + /* Generate the Peer-Challenge if requested, or copy it if supplied. */ + if (!PeerChallenge) + for (i = 0; i < sizeof(response->PeerChallenge); i++) + *p++ = (u_char) (drand48() * 0xff); + else + BCOPY(PeerChallenge, response->PeerChallenge, + sizeof(response->PeerChallenge)); + + /* Generate the NT-Response */ + ChapMS2_NT(rchallenge, response->PeerChallenge, user, + secret, secret_len, response->NTResp); + + /* Generate the Authenticator Response. */ + GenerateAuthenticatorResponse(secret, secret_len, response->NTResp, + response->PeerChallenge, rchallenge, + user, authResponse); +#ifdef MPPE + SetMasterKeys(secret, secret_len, response->NTResp, authenticator); +#endif } + #endif /* CHAPMS */