X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fchap_ms.c;h=0f627fb5aedc8f5ac99428b7cd9ce0c89452890e;hp=114b951a40d936161cacde8904fcc0392a6db961;hb=f79e0204d1134667d049c14f2c2ab38c9cb6a81a;hpb=4e3c66a04c0b86108858081d434bc45983471990 diff --git a/pppd/chap_ms.c b/pppd/chap_ms.c index 114b951..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.11 1998/11/24 19:30:38 christos 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 @@ -43,7 +50,6 @@ static char rcsid[] = "$Id: chap_ms.c,v 1.11 1998/11/24 19:30:38 christos Exp $" #include #include #include -#include #include #ifdef HAVE_CRYPT_H #include @@ -53,27 +59,30 @@ static char rcsid[] = "$Id: chap_ms.c,v 1.11 1998/11/24 19:30:38 christos 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 @@ -81,42 +90,51 @@ 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 - log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG); + 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 - log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG); + dbglog("ChallengeResponse - response %.24B", response); #endif } #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]; @@ -128,8 +146,7 @@ DesEncrypt(clear, key, cipher) setkey(crypt_key); #if 0 - CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X", - clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7])); + CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear)); #endif Expand(clear, des_input); @@ -137,18 +154,14 @@ DesEncrypt(clear, key, cipher) Collapse(des_input, cipher); #if 0 - CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X", - cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7])); + CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher)); #endif } #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; @@ -158,24 +171,20 @@ DesEncrypt(clear, key, cipher) des_set_key(&des_key, key_schedule); #if 0 - CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X", - clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7])); + CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear)); #endif des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1); #if 0 - CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X", - cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7])); + CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher)); #endif } #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; @@ -193,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; @@ -210,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; @@ -227,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); @@ -245,50 +248,107 @@ static void MakeKey(key, des_key) #endif #if 0 - CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X", - key[0], key[1], key[2], key[3], key[4], key[5], key[6])); - CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X", - des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7])); + CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %.7B", key)); + CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %.8B", 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]) + { - int i; - MD4_CTX md4Context; - u_char hash[MD4_SIGNATURE_SIZE]; - u_char unicodePassword[MAX_NT_PASSWORD * 2]; + 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); +} - /* 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]; +/* + * 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]) +{ +#ifdef __NetBSD__ + /* NetBSD uses the libc md4 routines which take bytes instead of bits */ + int mdlen = secret_len; +#else + int mdlen = secret_len * 8; +#endif + MD4_CTX md4Context; MD4Init(&md4Context); - MD4Update(&md4Context, unicodePassword, secret_len * 2); + MD4Update(&md4Context, secret, mdlen); + MD4Final(hash, &md4Context); + +} + +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]; + + /* 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); - MD4Final(hash, &md4Context); /* Tell MD4 we're done */ + /* Hash the Unicode version of the secret (== password). */ + ascii2unicode(secret, secret_len, unicodePassword); + NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); - ChallengeResponse(rchallenge, hash, response->NTResp); + 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]) +{ + 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) { - MS_ChapResponse response; + 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 - BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN); - cstate->resp_length = MS_CHAP_RESPONSE_LEN; +#ifdef MPPE + Set_Start_Key(rchallenge, secret, secret_len); +#endif } + +/* + * 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 */