1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-11-23 01:49:53 +03:00

Implement EAP-MSCHAPv2

This commit is contained in:
domosekai 2021-07-08 14:26:31 +00:00
parent a2f30c8aad
commit 22a9231c33
2 changed files with 156 additions and 31 deletions

View File

@ -267,6 +267,22 @@ void PPPThread(THREAD *thread, void *param)
break; break;
} }
break; break;
case PPP_EAP_TYPE_MSCHAPV2:
// Sending challenge
p->Eap_PacketId = p->NextId;
lcp = BuildMSCHAP2ChallengePacket(p);
BUF *b = BuildLCPData(lcp);
lcpEap = BuildEAPPacketEx(PPP_EAP_CODE_REQUEST, p->Eap_PacketId, PPP_EAP_TYPE_MSCHAPV2, b->Size);
eapPacket = lcpEap->Data;
Copy(eapPacket->Data, b->Buf, b->Size);
Free(b);
PPPSetStatus(p, PPP_STATUS_AUTHENTICATING);
if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_EAP, lcpEap))
{
PPPSetStatus(p, PPP_STATUS_FAIL);
WHERE;
}
break;
case PPP_EAP_TYPE_IDENTITY: case PPP_EAP_TYPE_IDENTITY:
default: // We treat the unspecified protocol as the IDENTITY protocol default: // We treat the unspecified protocol as the IDENTITY protocol
p->Eap_Protocol = PPP_EAP_TYPE_IDENTITY; p->Eap_Protocol = PPP_EAP_TYPE_IDENTITY;
@ -1011,9 +1027,13 @@ bool PPPProcessLCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req
// Process CHAP responses // Process CHAP responses
bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req) bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req)
{
return PPPProcessCHAPResponsePacketEx(p, pp, req, pp->Lcp, false);
}
bool PPPProcessCHAPResponsePacketEx(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req, PPP_LCP *chap, bool eap)
{ {
PPP_LCP *lcp; PPP_LCP *lcp;
if (pp->Lcp->Code == PPP_CHAP_CODE_RESPONSE) if (chap->Code == PPP_CHAP_CODE_RESPONSE)
{ {
bool ok = false; bool ok = false;
if (p->PPPStatus != PPP_STATUS_AUTHENTICATING && !p->AuthOk) if (p->PPPStatus != PPP_STATUS_AUTHENTICATING && !p->AuthOk)
@ -1023,7 +1043,7 @@ bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *re
WHERE; WHERE;
return false; return false;
} }
if (p->AuthProtocol != PPP_PROTOCOL_CHAP) if (p->AuthProtocol != PPP_PROTOCOL_CHAP && !eap)
{ {
Debug("Receiving CHAP packet when auth protocol set to 0x%x\n", p->AuthProtocol); Debug("Receiving CHAP packet when auth protocol set to 0x%x\n", p->AuthProtocol);
PPPLog(p, "LP_NEXT_PROTOCOL_IS_NOT_PAP", pp->Protocol); PPPLog(p, "LP_NEXT_PROTOCOL_IS_NOT_PAP", pp->Protocol);
@ -1031,10 +1051,10 @@ bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *re
return false; return false;
} }
ok = PPPParseMSCHAP2ResponsePacket(p, pp); ok = PPPParseMSCHAP2ResponsePacketEx(p, chap);
// If we got only first packet of double CHAP then send second challenge // If we got only first packet of double CHAP then send second challenge
if (ok && p->MsChapV2_UseDoubleMsChapV2 && p->EapClient != NULL && p->Ipc == NULL) if (ok && p->MsChapV2_UseDoubleMsChapV2 && p->EapClient != NULL && p->Ipc == NULL && !eap)
{ {
lcp = BuildMSCHAP2ChallengePacket(p); lcp = BuildMSCHAP2ChallengePacket(p);
if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_CHAP, lcp)) if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_CHAP, lcp))
@ -1050,7 +1070,6 @@ bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *re
char hex[MAX_SIZE]; char hex[MAX_SIZE];
char ret_str[MAX_SIZE]; char ret_str[MAX_SIZE];
BUF *lcp_ret_data = NewBuf(); BUF *lcp_ret_data = NewBuf();
PPP_PACKET *res = ZeroMalloc(sizeof(PPP_PACKET));
BinToStr(hex, sizeof(hex), p->MsChapV2_ServerResponse, 20); BinToStr(hex, sizeof(hex), p->MsChapV2_ServerResponse, 20);
Format(ret_str, sizeof(ret_str), Format(ret_str, sizeof(ret_str),
@ -1067,19 +1086,39 @@ bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *re
FreeBuf(lcp_ret_data); FreeBuf(lcp_ret_data);
} }
res->Lcp = lcp; if (!eap)
res->IsControl = true;
res->Protocol = PPP_PROTOCOL_CHAP;
if (!PPPSendPacketAndFree(p, res))
{ {
PPPSetStatus(p, PPP_STATUS_FAIL); PPP_PACKET *res = ZeroMalloc(sizeof(PPP_PACKET));
WHERE; res->Lcp = lcp;
return false; res->IsControl = true;
res->Protocol = PPP_PROTOCOL_CHAP;
if (!PPPSendPacketAndFree(p, res))
{
PPPSetStatus(p, PPP_STATUS_FAIL);
WHERE;
return false;
}
PPPSetStatus(p, PPP_STATUS_AUTH_SUCCESS);
}
else
{
BUF *b = BuildLCPData(lcp);
p->Eap_PacketId = p->NextId++;
lcp = BuildEAPPacketEx(PPP_EAP_CODE_REQUEST, p->Eap_PacketId, PPP_EAP_TYPE_MSCHAPV2, b->Size);
PPP_EAP *eapPacket = lcp->Data;
Copy(eapPacket->Data, b->Buf, b->Size);
Free(b);
if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_EAP, lcp))
{
PPPSetStatus(p, PPP_STATUS_FAIL);
WHERE;
return false;
}
} }
p->AuthOk = true; p->AuthOk = true;
PPPSetStatus(p, PPP_STATUS_AUTH_SUCCESS);
} }
// We failed MSCHAPv2 auth // We failed MSCHAPv2 auth
else else
@ -1087,7 +1126,6 @@ bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *re
char hex[MAX_SIZE]; char hex[MAX_SIZE];
char ret_str[MAX_SIZE]; char ret_str[MAX_SIZE];
BUF *lcp_ret_data = NewBuf(); BUF *lcp_ret_data = NewBuf();
PPP_PACKET *res = ZeroMalloc(sizeof(PPP_PACKET));
BinToStr(hex, sizeof(hex), p->MsChapV2_ServerChallenge, 16); BinToStr(hex, sizeof(hex), p->MsChapV2_ServerChallenge, 16);
@ -1105,19 +1143,39 @@ bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *re
FreeBuf(lcp_ret_data); FreeBuf(lcp_ret_data);
} }
res->Lcp = lcp; if (!eap)
res->IsControl = true;
res->Protocol = PPP_PROTOCOL_CHAP;
if (!PPPSendPacketAndFree(p, res))
{ {
PPPSetStatus(p, PPP_STATUS_FAIL); PPP_PACKET *res = ZeroMalloc(sizeof(PPP_PACKET));
WHERE; res->Lcp = lcp;
return false; res->IsControl = true;
res->Protocol = PPP_PROTOCOL_CHAP;
if (!PPPSendPacketAndFree(p, res))
{
PPPSetStatus(p, PPP_STATUS_FAIL);
WHERE;
return false;
}
PPPSetStatus(p, PPP_STATUS_AUTH_FAIL);
}
else
{
BUF *b = BuildLCPData(lcp);
p->Eap_PacketId = p->NextId++;
lcp = BuildEAPPacketEx(PPP_EAP_CODE_REQUEST, p->Eap_PacketId, PPP_EAP_TYPE_MSCHAPV2, b->Size);
PPP_EAP *eapPacket = lcp->Data;
Copy(eapPacket->Data, b->Buf, b->Size);
Free(b);
if (!PPPSendAndRetransmitRequest(p, PPP_PROTOCOL_EAP, lcp))
{
PPPSetStatus(p, PPP_STATUS_FAIL);
WHERE;
return false;
}
} }
PPPLog(p, "LP_CHAP_FAILED"); PPPLog(p, "LP_CHAP_FAILED");
PPPSetStatus(p, PPP_STATUS_AUTH_FAIL);
} }
return ok; return ok;
@ -1219,8 +1277,14 @@ bool PPPProcessEAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req
// Basically this is just an acknoweldgment that the notification was accepted by the client. Nothing to do here... // Basically this is just an acknoweldgment that the notification was accepted by the client. Nothing to do here...
break; break;
case PPP_EAP_TYPE_NAK: case PPP_EAP_TYPE_NAK:
/// TODO: implement alternative EAP protocol selection based on received NAK if (p->Eap_Protocol == PPP_EAP_TYPE_TLS)
// For now just fallback to auth protocol selection to try to select MSCHAP or PAP {
// Propose EAP-MSCHAPv2
p->Eap_Protocol = PPP_EAP_TYPE_MSCHAPV2;
PPPSetStatus(p, PPP_STATUS_BEFORE_AUTH);
break;
}
// Fallback to auth protocol selection to try to select MSCHAP or PAP
Debug("Got a EAP_NAK, abandoning EAP protocol\n"); Debug("Got a EAP_NAK, abandoning EAP protocol\n");
PPPRejectUnsupportedPacketEx(p, pp, true); PPPRejectUnsupportedPacketEx(p, pp, true);
PPPSetStatus(p, PPP_STATUS_CONNECTED); PPPSetStatus(p, PPP_STATUS_CONNECTED);
@ -1239,6 +1303,51 @@ bool PPPProcessEAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req
case PPP_EAP_TYPE_TLS: case PPP_EAP_TYPE_TLS:
PPPProcessEAPTlsResponse(p, eap_packet, eap_datasize); PPPProcessEAPTlsResponse(p, eap_packet, eap_datasize);
break; break;
case PPP_EAP_TYPE_MSCHAPV2:
if (p->PPPStatus != PPP_STATUS_AUTHENTICATING)
{
Debug("Received EAP-MSCHAPv2 response not during authentication\n");
break;
}
if (eap_datasize == 1)
{
// Success or failure response
PPP_PACKET *pack = ZeroMalloc(sizeof(PPP_PACKET));
pack->IsControl = true;
pack->Protocol = PPP_PROTOCOL_EAP;
if (p->AuthOk)
{
PPPSetStatus(p, PPP_STATUS_AUTH_SUCCESS);
pack->Lcp = NewPPPLCP(PPP_EAP_CODE_SUCCESS, p->Eap_PacketId);
}
else
{
PPPSetStatus(p, PPP_STATUS_AUTH_FAIL);
pack->Lcp = NewPPPLCP(PPP_EAP_CODE_FAILURE, p->Eap_PacketId);
}
if (!PPPSendPacketAndFree(p, pack))
{
PPPSetStatus(p, PPP_STATUS_FAIL);
WHERE;
}
}
else
{
// CHAP response
PPP_LCP *chap = PPPParseLCP(PPP_PROTOCOL_CHAP, eap_packet->Data, eap_datasize);
if (chap == NULL)
{
Debug("Received an invalid EAP-MSCHAPv2 packet\n");
PPPSetStatus(p, PPP_STATUS_FAIL);
WHERE;
break;
}
PPPProcessCHAPResponsePacketEx(p, pp, req, chap, true);
FreePPPLCP(chap);
}
break;
default: default:
Debug("We got an unexpected EAP response packet! Ignoring...\n"); Debug("We got an unexpected EAP response packet! Ignoring...\n");
break; break;
@ -2686,6 +2795,15 @@ PPP_LCP *PPPParseLCP(USHORT protocol, void *data, UINT size)
goto LABEL_ERROR; goto LABEL_ERROR;
} }
len = READ_USHORT(buf); len = READ_USHORT(buf);
// Fix bad endianness
if (len > size)
{
USHORT len1 = Swap16(len);
if (len1 <= size)
{
len = len1;
}
}
if (len < 4) if (len < 4)
{ {
goto LABEL_ERROR; goto LABEL_ERROR;
@ -2761,6 +2879,10 @@ LABEL_ERROR:
// Analyse MS CHAP v2 Response packet // Analyse MS CHAP v2 Response packet
bool PPPParseMSCHAP2ResponsePacket(PPP_SESSION *p, PPP_PACKET *pp) bool PPPParseMSCHAP2ResponsePacket(PPP_SESSION *p, PPP_PACKET *pp)
{
return PPPParseMSCHAP2ResponsePacketEx(p, pp->Lcp);
}
bool PPPParseMSCHAP2ResponsePacketEx(PPP_SESSION *p, PPP_LCP *lcp)
{ {
bool ok = false; bool ok = false;
@ -2783,18 +2905,18 @@ bool PPPParseMSCHAP2ResponsePacket(PPP_SESSION *p, PPP_PACKET *pp)
UINT error_code; UINT error_code;
UINT64 eap_client_ptr = (UINT64)p->EapClient; UINT64 eap_client_ptr = (UINT64)p->EapClient;
if (pp->Lcp != NULL && pp->Lcp->DataSize >= 51) if (lcp != NULL && lcp->DataSize >= 51)
{ {
BUF *b; BUF *b;
if (pp->Lcp->Id != p->MsChapV2_PacketId) if (lcp->Id != p->MsChapV2_PacketId)
{ {
Debug("Got incorrect LCP PacketId! Should be 0x%x, got 0x%x\n", p->MsChapV2_PacketId, pp->Lcp->Id); Debug("Got incorrect LCP PacketId! Should be 0x%x, got 0x%x\n", p->MsChapV2_PacketId, lcp->Id);
p->MsChapV2_PacketId = pp->Lcp->Id; p->MsChapV2_PacketId = lcp->Id;
} }
b = NewBuf(); b = NewBuf();
WriteBuf(b, pp->Lcp->Data, pp->Lcp->DataSize); WriteBuf(b, lcp->Data, lcp->DataSize);
SeekBuf(b, 0, 0); SeekBuf(b, 0, 0);
if (ReadBufChar(b) == 49) if (ReadBufChar(b) == 49)

View File

@ -111,6 +111,7 @@
#define PPP_EAP_TYPE_NOTIFICATION 2 #define PPP_EAP_TYPE_NOTIFICATION 2
#define PPP_EAP_TYPE_NAK 3 #define PPP_EAP_TYPE_NAK 3
#define PPP_EAP_TYPE_TLS 13 #define PPP_EAP_TYPE_TLS 13
#define PPP_EAP_TYPE_MSCHAPV2 26
// EAP-TLS Flags // EAP-TLS Flags
#define PPP_EAP_TLS_FLAG_NONE 0 #define PPP_EAP_TLS_FLAG_NONE 0
@ -336,6 +337,7 @@ bool PPPSendEchoRequest(PPP_SESSION *p);
bool PPPProcessResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req); bool PPPProcessResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req);
bool PPPProcessLCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req); bool PPPProcessLCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req);
bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req); bool PPPProcessCHAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req);
bool PPPProcessCHAPResponsePacketEx(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req, PPP_LCP *chap, bool eap);
bool PPPProcessIPCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req); bool PPPProcessIPCPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req);
bool PPPProcessEAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req); bool PPPProcessEAPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req);
bool PPPProcessIPv6CPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req); bool PPPProcessIPv6CPResponsePacket(PPP_SESSION *p, PPP_PACKET *pp, PPP_PACKET *req);
@ -376,6 +378,7 @@ PPP_OPTION *NewPPPOption(UCHAR type, void *data, UINT size);
PPP_PACKET *ParsePPPPacket(void *data, UINT size); PPP_PACKET *ParsePPPPacket(void *data, UINT size);
PPP_LCP *PPPParseLCP(USHORT protocol, void *data, UINT size); PPP_LCP *PPPParseLCP(USHORT protocol, void *data, UINT size);
bool PPPParseMSCHAP2ResponsePacket(PPP_SESSION *p, PPP_PACKET *req); bool PPPParseMSCHAP2ResponsePacket(PPP_SESSION *p, PPP_PACKET *req);
bool PPPParseMSCHAP2ResponsePacketEx(PPP_SESSION *p, PPP_LCP *lcp);
// Packet building utilities // Packet building utilities
BUF *BuildPPPPacketData(PPP_PACKET *pp); BUF *BuildPPPPacketData(PPP_PACKET *pp);
BUF *BuildLCPData(PPP_LCP *c); BUF *BuildLCPData(PPP_LCP *c);