#define RCSID "$Id: chap_ms.c,v 1.2 2002/03/13 22:44:31 callie Exp $"
#ifdef CHAPMS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
#include "pppd.h"
#include "chap.h"
#include "chap_ms.h"
#include "openssl/sha.h"
#include "fsm.h"
#include "lcp.h"
#ifdef MPPE
#include "mppe.h"
#endif
#include "extra_crypto.h"
static const char rcsid[] = RCSID;
typedef struct {
u_char LANManResp[24];
u_char NTResp[24];
u_char UseNT;
} MS_ChapResponse;
typedef struct {
u_char PeerChallenge[16];
u_char Reserved[8];
u_char NTResp[24];
u_char Flags;
} MS_ChapResponse_v2;
static void ChallengeResponse __P((u_char *, u_char *, u_char *));
static void ChapMS_NT __P((char *, int, char *, int, MS_ChapResponse *));
#ifdef MSLANMAN
static void ChapMS_LANMan __P((char *, int, char *, int, MS_ChapResponse *));
#endif
#ifdef MSLANMAN
bool ms_lanman = 0;
#endif
static void
ChallengeResponse(challenge, pwHash, response)
u_char *challenge;
u_char *pwHash;
u_char *response;
{
char ZPasswordHash[21];
BZERO(ZPasswordHash, sizeof(ZPasswordHash));
BCOPY(pwHash, 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);
#if 0
dbglog("ChallengeResponse - response %.24B", response);
#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;
{
u_char hash[MD4_SIGNATURE_SIZE];
NtPasswordHash(secret, secret_len, hash);
ChallengeResponse(rchallenge, hash, response->NTResp);
}
#ifdef MSLANMAN
static void
ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, response)
char *rchallenge;
int rchallenge_len;
char *secret;
int secret_len;
MS_ChapResponse *response;
{
u_char PasswordHash[MD4_SIGNATURE_SIZE];
LmPasswordHash(secret, secret_len, PasswordHash);
ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
}
#endif
void
ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
chap_state *cstate;
char *rchallenge;
int rchallenge_len;
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));
ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
#ifdef MSLANMAN
ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
response.UseNT = !ms_lanman;
#else
response.UseNT = 1;
#endif
#ifdef MPPE
mppe_gen_master_key(secret, secret_len, rchallenge);
#endif
BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
cstate->resp_length = MS_CHAP_RESPONSE_LEN;
}
int
ChapMS_Resp(cstate, secret, secret_len, remmd)
chap_state *cstate;
char *secret;
int secret_len;
u_char *remmd;
{
MS_ChapResponse local;
MS_ChapResponse *response = (MS_ChapResponse *)remmd;
int i;
BZERO(&local, sizeof(response));
if(response->UseNT)
{
ChapMS_NT(cstate->challenge,cstate->chal_len, secret, secret_len, &local);
i = memcmp(local.NTResp, response->NTResp, sizeof(local.NTResp));
#ifdef MPPE
if(i == 0)
mppe_gen_master_key(secret, secret_len, cstate->challenge);
#endif
return(i);
}
#ifdef MSLANMAN
ChapMS_LANMan(cstate->challenge, cstate->chal_len, secret, secret_len,
&local);
if(memcmp(local.LANManResp, response->LANManResp,
sizeof(local.LANManResp)) == 0) {
#ifdef MPPE
mppe_gen_master_key(secret, secret_len, cstate->challenge);
#endif
return(0);
}
#endif
return(1);
}
void
ChallengeHash(PeerChallenge, AuthenticatorChallenge, UserName, Challenge)
char *PeerChallenge;
char *AuthenticatorChallenge;
char *UserName;
char *Challenge;
{
SHA_CTX Context;
u_char Digest[SHA_DIGEST_LENGTH];
char *username;
if((username = strrchr(UserName, '\\')) != (char *)NULL)
++username;
else
username = UserName;
SHA1_Init(&Context);
SHA1_Update(&Context, PeerChallenge, 16);
SHA1_Update(&Context, AuthenticatorChallenge, 16);
SHA1_Update(&Context, username, strlen(username));
SHA1_Final(Digest, &Context);
BCOPY(Digest, Challenge, 8);
}
void
ChapMS_v2(cstate, AuthenticatorChallenge, AuthenticatorChallengeLen, Password, PasswordLen)
chap_state *cstate;
char *AuthenticatorChallenge;
int AuthenticatorChallengeLen;
char *Password;
int PasswordLen;
{
u_char Challenge[8];
u_char PasswordHash[MD4_SIGNATURE_SIZE];
MS_ChapResponse_v2 response;
BZERO(&response, sizeof(response));
ChapGenChallenge(cstate);
BCOPY(cstate->challenge, response.PeerChallenge,
sizeof(response.PeerChallenge));
ChallengeHash(response.PeerChallenge, AuthenticatorChallenge,
cstate->resp_name, Challenge);
NtPasswordHash(Password, PasswordLen, PasswordHash);
ChallengeResponse(Challenge, PasswordHash, response.NTResp);
BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
cstate->resp_length = MS_CHAP_RESPONSE_LEN;
#ifdef MPPE
mppe_gen_master_key_v2(Password, PasswordLen, response.NTResp, 0);
#endif
}
int
ChapMS_v2_Resp(cstate, Password, PasswordLen, remmd, UserName)
chap_state *cstate;
char *Password;
int PasswordLen;
u_char *remmd;
char *UserName;
{
u_char Challenge[8];
u_char PasswordHash[MD4_SIGNATURE_SIZE];
MS_ChapResponse_v2 response, response1;
int i;
BCOPY(remmd, &response, MS_CHAP_RESPONSE_LEN);
ChallengeHash(response.PeerChallenge,cstate->challenge,UserName,Challenge);
NtPasswordHash(Password, PasswordLen, PasswordHash);
ChallengeResponse(Challenge, PasswordHash, response1.NTResp);
i = memcmp(response.NTResp, response1.NTResp, sizeof(response.NTResp));
#ifdef MPPE
if(i == 0)
mppe_gen_master_key_v2(Password, PasswordLen, response1.NTResp, 1);
#endif
return(i);
}
void
ChapMS_v2_Auth(cstate, Password, PasswordLen, remmd, UserName)
chap_state *cstate;
char *Password;
int PasswordLen;
u_char *remmd;
char *UserName;
{
u_char PasswordHash[MD4_SIGNATURE_SIZE];
u_char PasswordHashHash[MD4_SIGNATURE_SIZE];
u_char Challenge[8];
static char Magic1[] = "Magic server to client signing constant";
static char Magic2[] = "Pad to make it do more than one iteration";
SHA_CTX Context;
u_char Digest[SHA_DIGEST_LENGTH];
MS_ChapResponse_v2 *response = (MS_ChapResponse_v2 *)remmd;
char StrResponse[SHA_DIGEST_LENGTH * 2 + 3], *s;
int i;
static char HexDigs[] = "0123456789ABCDEF";
NtPasswordHash(Password, PasswordLen, PasswordHash);
md4(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
SHA1_Init(&Context);
SHA1_Update(&Context, PasswordHashHash, 16);
SHA1_Update(&Context, response->NTResp, 24);
SHA1_Update(&Context, Magic1, sizeof(Magic1) - 1);
SHA1_Final(Digest, &Context);
ChallengeHash(response->PeerChallenge,cstate->challenge,UserName,Challenge);
SHA1_Init(&Context);
SHA1_Update(&Context, Digest, SHA_DIGEST_LENGTH);
SHA1_Update(&Context, Challenge, 8);
SHA1_Update(&Context, Magic2, sizeof(Magic2) - 1);
SHA1_Final(Digest, &Context);
s = strcpy(StrResponse, "S=");
s += strlen(s);
for(i = 0; i < SHA_DIGEST_LENGTH; ++i) {
*s++ = HexDigs[Digest[i] >> 4];
*s++ = HexDigs[Digest[i] & 0x0F];
}
*s = '\0';
BCOPY(StrResponse, cstate->response, sizeof(StrResponse));
cstate->resp_length = sizeof(StrResponse) - 1;
}
int
reqchapms(char **argv)
{
lcp_wantoptions[0].neg_chap = 1;
lcp_wantoptions[0].use_chapms = 1;
auth_required = 1;
return 1;
}
int
nochapms(char **argv)
{
lcp_wantoptions[0].use_chapms = 0;
return 1;
}
int
reqchapms_v2(char **argv)
{
lcp_wantoptions[0].neg_chap = 1;
lcp_wantoptions[0].use_chapms_v2 = 1;
auth_required = 1;
return 1;
}
int
nochapms_v2(char **argv)
{
lcp_wantoptions[0].use_chapms_v2 = 0;
return 1;
}
#endif