Client token authentication implementation

The game internally obtains a auth token from Origin. On connect to a gameserver, it will send it to the masterserver. The master server will create a JWT token and send this back to the client. The client stores this token in 3 userinfo cvars (token, sig1, sig2). the sig1 and sig2 cvars are there to compensate for the truncation caused by sending the cvar, as each cvar string length could be up to 255 (byte max). The server verifies this token (the signature, timestamp, expiry); if they are valid, the has successfully authenticated and will connect.
This commit is contained in:
Kawe Mazidjatari 2023-10-15 10:40:46 +02:00
parent 6b344ad52f
commit 59fab7ac93
15 changed files with 403 additions and 28 deletions

View File

@ -15,6 +15,7 @@
#ifndef DEDICATED #ifndef DEDICATED
#include "engine/client/cl_rcon.h" #include "engine/client/cl_rcon.h"
#include "engine/client/cdll_engine_int.h" #include "engine/client/cdll_engine_int.h"
#include "engine/client/clientstate.h"
#endif // !DEDICATED #endif // !DEDICATED
#include "engine/client/client.h" #include "engine/client/client.h"
#include "engine/net.h" #include "engine/net.h"
@ -808,7 +809,8 @@ SIG_GetAdr_f
*/ */
void SIG_GetAdr_f(const CCommand& args) void SIG_GetAdr_f(const CCommand& args)
{ {
DetourAddress(); if (!IsCert() && !IsRetail())
DetourAddress();
} }
/* /*
@ -1458,13 +1460,16 @@ CC_CreateFakePlayer_f
#ifndef CLIENT_DLL #ifndef CLIENT_DLL
void CC_CreateFakePlayer_f(const CCommand& args) void CC_CreateFakePlayer_f(const CCommand& args)
{ {
if (!g_pServer->IsActive())
return;
if (args.ArgC() < 3) if (args.ArgC() < 3)
{ {
Msg(eDLL_T::SERVER, "usage 'sv_addbot': name(string) teamid(int)\n"); Msg(eDLL_T::SERVER, "usage 'sv_addbot': name(string) teamid(int)\n");
return; return;
} }
int numPlayers = g_pServer->GetNumClients(); const int numPlayers = g_pServer->GetNumClients();
// Already at max, don't create. // Already at max, don't create.
if (numPlayers >= g_ServerGlobalVariables->m_nMaxClients) if (numPlayers >= g_ServerGlobalVariables->m_nMaxClients)
@ -1473,7 +1478,7 @@ void CC_CreateFakePlayer_f(const CCommand& args)
const char* playerName = args.Arg(1); const char* playerName = args.Arg(1);
int teamNum = atoi(args.Arg(2)); int teamNum = atoi(args.Arg(2));
int maxTeams = int(g_pServer->GetMaxTeams()) + 1; const int maxTeams = int(g_pServer->GetMaxTeams()) + 1;
// Clamp team count, going above the limit will // Clamp team count, going above the limit will
// cause a crash. Going below 0 means that the // cause a crash. Going below 0 means that the
@ -1483,9 +1488,44 @@ void CC_CreateFakePlayer_f(const CCommand& args)
g_pEngineServer->LockNetworkStringTables(true); g_pEngineServer->LockNetworkStringTables(true);
edict_t nHandle = g_pEngineServer->CreateFakeClient(playerName, teamNum); const edict_t nHandle = g_pEngineServer->CreateFakeClient(playerName, teamNum);
g_pServerGameClients->ClientFullyConnect(nHandle, false); g_pServerGameClients->ClientFullyConnect(nHandle, false);
g_pEngineServer->LockNetworkStringTables(false); g_pEngineServer->LockNetworkStringTables(false);
} }
#endif // !CLIENT_DLL #endif // !CLIENT_DLL
/*
=====================
Cmd_Exec_f
executes a cfg file
=====================
*/
void Cmd_Exec_f(const CCommand& args)
{
#ifndef DEDICATED
// Prevent users from running neo strafe commands and other quick hacks.
// TODO: when reBar becomes a thing, we should verify this function and
// flag users that patch them out.
if (!ThreadInServerFrameThread() && (!sv_cheats->GetBool() && g_pClientState->IsActive()))
{
DevWarning(eDLL_T::ENGINE, "Client is simulating and %s = false; dropped exec command: %s\n",
sv_cheats->GetName(), args.ArgS());
return;
}
#endif // !DEDICATED
_Cmd_Exec_f(args);
}
void VCallback::Attach() const
{
DetourAttach(&_Cmd_Exec_f, &Cmd_Exec_f);
}
void VCallback::Detach() const
{
DetourDetach(&_Cmd_Exec_f, &Cmd_Exec_f);
}

View File

@ -7,6 +7,9 @@ inline bool(*SetupGamemode)(const char* pszPlayList);
inline CMemory p_DownloadPlaylists_f; inline CMemory p_DownloadPlaylists_f;
inline void(*_DownloadPlaylists_f)(void); inline void(*_DownloadPlaylists_f)(void);
inline CMemory p_Cmd_Exec_f;
inline void(*_Cmd_Exec_f)(const CCommand& args);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
void MP_GameMode_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue); void MP_GameMode_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue);
void MP_HostName_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue); void MP_HostName_Changed_f(IConVar* pConVar, const char* pOldString, float flOldValue);
@ -87,18 +90,21 @@ class VCallback : public IDetour
{ {
LogFunAdr("SetupGamemode", p_SetupGamemode.GetPtr()); LogFunAdr("SetupGamemode", p_SetupGamemode.GetPtr());
LogFunAdr("DownloadPlaylist_f", p_DownloadPlaylists_f.GetPtr()); LogFunAdr("DownloadPlaylist_f", p_DownloadPlaylists_f.GetPtr());
LogFunAdr("Cmd_Exec_f", p_Cmd_Exec_f.GetPtr());
} }
virtual void GetFun(void) const virtual void GetFun(void) const
{ {
p_SetupGamemode = g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 48 8B D9 48 C7 C0 ?? ?? ?? ??"); p_SetupGamemode = g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 48 8B D9 48 C7 C0 ?? ?? ?? ??");
p_DownloadPlaylists_f = g_GameDll.FindPatternSIMD("33 C9 C6 05 ?? ?? ?? ?? ?? E9 ?? ?? ?? ??"); p_DownloadPlaylists_f = g_GameDll.FindPatternSIMD("33 C9 C6 05 ?? ?? ?? ?? ?? E9 ?? ?? ?? ??");
p_Cmd_Exec_f = g_GameDll.FindPatternSIMD("40 55 53 48 8D AC 24 ?? ?? ?? ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B D9");
SetupGamemode = p_SetupGamemode.RCast<bool(*)(const char*)>(); /*40 53 48 83 EC 20 48 8B D9 48 C7 C0 ?? ?? ?? ??*/ SetupGamemode = p_SetupGamemode.RCast<bool(*)(const char*)>();
_DownloadPlaylists_f = p_DownloadPlaylists_f.RCast<void(*)(void)>(); /*33 C9 C6 05 ?? ?? ?? ?? ?? E9 ?? ?? ?? ??*/ _DownloadPlaylists_f = p_DownloadPlaylists_f.RCast<void(*)(void)>();
_Cmd_Exec_f = p_Cmd_Exec_f.RCast<void(*)(const CCommand& args)>();
} }
virtual void GetVar(void) const { } virtual void GetVar(void) const { }
virtual void GetCon(void) const { } virtual void GetCon(void) const { }
virtual void Attach(void) const { } virtual void Attach(void) const;
virtual void Detach(void) const { } virtual void Detach(void) const;
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -195,6 +195,10 @@ ConVar* cl_threaded_bone_setup = nullptr;
ConVar* cl_language = nullptr; ConVar* cl_language = nullptr;
ConVar* cl_onlineAuthToken = nullptr;
ConVar* cl_onlineAuthTokenSignature1 = nullptr;
ConVar* cl_onlineAuthTokenSignature2 = nullptr;
ConVar* con_drawnotify = nullptr; ConVar* con_drawnotify = nullptr;
ConVar* con_notifylines = nullptr; ConVar* con_notifylines = nullptr;
ConVar* con_notifytime = nullptr; ConVar* con_notifytime = nullptr;
@ -403,6 +407,10 @@ void ConVar_StaticInit(void)
cl_materialinfo_offset_x = ConVar::StaticCreate("cl_materialinfo_offset_x", "0" , FCVAR_DEVELOPMENTONLY, "X offset for material debug info overlay.", false, 0.f, false, 0.f, nullptr, nullptr); cl_materialinfo_offset_x = ConVar::StaticCreate("cl_materialinfo_offset_x", "0" , FCVAR_DEVELOPMENTONLY, "X offset for material debug info overlay.", false, 0.f, false, 0.f, nullptr, nullptr);
cl_materialinfo_offset_y = ConVar::StaticCreate("cl_materialinfo_offset_y", "420", FCVAR_DEVELOPMENTONLY, "Y offset for material debug info overlay.", false, 0.f, false, 0.f, nullptr, nullptr); cl_materialinfo_offset_y = ConVar::StaticCreate("cl_materialinfo_offset_y", "420", FCVAR_DEVELOPMENTONLY, "Y offset for material debug info overlay.", false, 0.f, false, 0.f, nullptr, nullptr);
cl_onlineAuthToken = ConVar::StaticCreate("cl_onlineAuthToken", "", FCVAR_HIDDEN | FCVAR_USERINFO | FCVAR_DONTRECORD | FCVAR_SERVER_CANNOT_QUERY | FCVAR_PLATFORM_SYSTEM, "", false, 0.f, false, 0.f, nullptr, nullptr);
cl_onlineAuthTokenSignature1 = ConVar::StaticCreate("cl_onlineAuthTokenSignature1", "", FCVAR_HIDDEN | FCVAR_USERINFO | FCVAR_DONTRECORD | FCVAR_SERVER_CANNOT_QUERY | FCVAR_PLATFORM_SYSTEM, "", false, 0.f, false, 0.f, nullptr, nullptr);
cl_onlineAuthTokenSignature2 = ConVar::StaticCreate("cl_onlineAuthTokenSignature2", "", FCVAR_HIDDEN | FCVAR_USERINFO | FCVAR_DONTRECORD | FCVAR_SERVER_CANNOT_QUERY | FCVAR_PLATFORM_SYSTEM, "", false, 0.f, false, 0.f, nullptr, nullptr);
con_drawnotify = ConVar::StaticCreate("con_drawnotify", "0", FCVAR_RELEASE, "Draws the RUI console to the hud.", false, 0.f, false, 0.f, nullptr, nullptr); con_drawnotify = ConVar::StaticCreate("con_drawnotify", "0", FCVAR_RELEASE, "Draws the RUI console to the hud.", false, 0.f, false, 0.f, nullptr, nullptr);
con_notifylines = ConVar::StaticCreate("con_notifylines" , "3" , FCVAR_MATERIAL_SYSTEM_THREAD, "Number of console lines to overlay for debugging.", true, 1.f, false, 0.f, nullptr, nullptr); con_notifylines = ConVar::StaticCreate("con_notifylines" , "3" , FCVAR_MATERIAL_SYSTEM_THREAD, "Number of console lines to overlay for debugging.", true, 1.f, false, 0.f, nullptr, nullptr);
con_notifytime = ConVar::StaticCreate("con_notifytime" , "6" , FCVAR_MATERIAL_SYSTEM_THREAD, "How long to display recent console text to the upper part of the game window.", false, 1.f, false, 50.f, nullptr, nullptr); con_notifytime = ConVar::StaticCreate("con_notifytime" , "6" , FCVAR_MATERIAL_SYSTEM_THREAD, "How long to display recent console text to the upper part of the game window.", false, 1.f, false, 50.f, nullptr, nullptr);
@ -473,7 +481,7 @@ void ConVar_StaticInit(void)
net_processTimeBudget = ConVar::StaticCreate("net_processTimeBudget" ,"200" , FCVAR_RELEASE , "Net message process time budget in milliseconds (removing netchannel if exceeded).", true, 0.f, false, 0.f, nullptr, "0 = disabled"); net_processTimeBudget = ConVar::StaticCreate("net_processTimeBudget" ,"200" , FCVAR_RELEASE , "Net message process time budget in milliseconds (removing netchannel if exceeded).", true, 0.f, false, 0.f, nullptr, "0 = disabled");
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// NETWORKSYSTEM | // NETWORKSYSTEM |
pylon_matchmaking_hostname = ConVar::StaticCreate("pylon_matchmaking_hostname", "ms.r5reloaded.com", FCVAR_RELEASE, "Holds the pylon matchmaking hostname.", false, 0.f, false, 0.f, &MP_HostName_Changed_f, nullptr); pylon_matchmaking_hostname = ConVar::StaticCreate("pylon_matchmaking_hostname", "ms-dev.r5reloaded.com", FCVAR_RELEASE, "Holds the pylon matchmaking hostname.", false, 0.f, false, 0.f, &MP_HostName_Changed_f, nullptr);
pylon_host_update_interval = ConVar::StaticCreate("pylon_host_update_interval", "5" , FCVAR_RELEASE, "Length of time in seconds between each status update interval to master server.", true, 5.f, false, 0.f, nullptr, nullptr); pylon_host_update_interval = ConVar::StaticCreate("pylon_host_update_interval", "5" , FCVAR_RELEASE, "Length of time in seconds between each status update interval to master server.", true, 5.f, false, 0.f, nullptr, nullptr);
pylon_showdebuginfo = ConVar::StaticCreate("pylon_showdebuginfo" , "0" , FCVAR_RELEASE, "Shows debug output for pylon.", false, 0.f, false, 0.f, nullptr, nullptr); pylon_showdebuginfo = ConVar::StaticCreate("pylon_showdebuginfo" , "0" , FCVAR_RELEASE, "Shows debug output for pylon.", false, 0.f, false, 0.f, nullptr, nullptr);
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -737,7 +745,8 @@ void ConCommand_StaticInit(void)
ConCommand::StaticCreate("net_generatekey", "Generates and sets a random base64 net key.", nullptr, FCVAR_RELEASE, NET_GenerateKey_f, nullptr); ConCommand::StaticCreate("net_generatekey", "Generates and sets a random base64 net key.", nullptr, FCVAR_RELEASE, NET_GenerateKey_f, nullptr);
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// TIER0 | // TIER0 |
ConCommand::StaticCreate("sig_getadr", "Logs the sigscan results to the console.", nullptr, FCVAR_DEVELOPMENTONLY | FCVAR_HIDDEN, SIG_GetAdr_f, nullptr); if (!IsCert() && !IsRetail())
ConCommand::StaticCreate("sig_getadr", "Logs the sigscan results to the console.", nullptr, FCVAR_DEVELOPMENTONLY | FCVAR_HIDDEN, SIG_GetAdr_f, nullptr);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -185,6 +185,11 @@ extern ConVar* cl_threaded_bone_setup;
extern ConVar* cl_language; extern ConVar* cl_language;
extern ConVar* cl_onlineAuthToken;
extern ConVar* cl_onlineAuthTokenSignature1;
extern ConVar* cl_onlineAuthTokenSignature2;
extern ConVar* con_drawnotify; extern ConVar* con_drawnotify;
extern ConVar* con_notifylines; extern ConVar* con_notifylines;
extern ConVar* con_notifytime; extern ConVar* con_notifytime;

View File

@ -103,6 +103,15 @@ target_link_libraries( ${PROJECT_NAME} PRIVATE
) )
endif() endif()
if( NOT ${PROJECT_NAME} STREQUAL "client" )
target_link_libraries( ${PROJECT_NAME} PRIVATE
"libmbedcrypto"
"libmbedtls"
"libmbedx509"
"libjwt"
)
endif()
# Determine the compiler definitions and link libraries per project. # Determine the compiler definitions and link libraries per project.
if( ${PROJECT_NAME} STREQUAL "gamesdk" ) if( ${PROJECT_NAME} STREQUAL "gamesdk" )
end_sources() end_sources()

View File

@ -11,8 +11,12 @@
#include "core/stdafx.h" #include "core/stdafx.h"
#include "tier1/cvar.h" #include "tier1/cvar.h"
#include "tier1/strtools.h" #include "tier1/strtools.h"
#include "mathlib/sha256.h"
#include "engine/server/server.h" #include "engine/server/server.h"
#include "engine/client/client.h" #include "engine/client/client.h"
#ifndef CLIENT_DLL
#include "jwt/include/decode.h"
#endif
// Absolute max string cmd length, any character past this will be NULLED. // Absolute max string cmd length, any character past this will be NULLED.
#define STRINGCMD_MAX_LEN 512 #define STRINGCMD_MAX_LEN 512
@ -37,22 +41,156 @@ void CClient::VClear(CClient* pClient)
pClient->Clear(); pClient->Clear();
} }
static const char JWT_PUBLIC_KEY[] =
"-----BEGIN PUBLIC KEY-----\n"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2/335exIZ6LE8pYi6e50\n"
"7tH19tXaeeEJVF5XXpTCXpndXIIWVimvg6xQ381eajySDw93wvG1DzW3U/6LHzyt\n"
"Q++N8w7N+FwnXyoDUD5Y8hheTZv6jjLoYT8ZtsMl20k9UosrbFBTMUhgmIT2dVth\n"
"LH+rT9ohpUNwQXHJvTOs9eY74GyfFw93+32LANBPZ8b+S8S3oZnKFVeCxRkYKsV0\n"
"b34POHVBbXNw6Kt163gR5zaiCfJJtRto9AA7MV2t9pfy8CChs3uJ+Xn7QVHD5cqt\n"
"Msg9MBac2Pvs2j+8wJ/igAVL5L81z3FXVt04id59TfPMUbYhRfY8pk7FB0MCigOH\n"
"dwIDAQAB\n"
"-----END PUBLIC KEY-----\n";
bool CClient::Authenticate(const char* const playerName, char* const reasonBuf, const size_t reasonBufLen)
{
#ifndef CLIENT_DLL
// don't bother checking origin auth on bots or local clients
if (IsFakeClient() || GetNetChan()->GetRemoteAddress().IsLoopback())
return true;
#define FORMAT_ERROR_REASON(fmt, ...) V_snprintf(reasonBuf, reasonBufLen, fmt, ##__VA_ARGS__);
KeyValues* cl_onlineAuthTokenKv = this->m_ConVars->FindKey("cl_onlineAuthToken");
KeyValues* cl_onlineAuthTokenSignature1Kv = this->m_ConVars->FindKey("cl_onlineAuthTokenSignature1");
KeyValues* cl_onlineAuthTokenSignature2Kv = this->m_ConVars->FindKey("cl_onlineAuthTokenSignature2");
if (!cl_onlineAuthTokenKv || !cl_onlineAuthTokenSignature1Kv)
{
FORMAT_ERROR_REASON("Missing token");
return false;
}
const char* onlineAuthToken = cl_onlineAuthTokenKv->GetString();
const char* onlineAuthTokenSignature1 = cl_onlineAuthTokenSignature1Kv->GetString();
const char* onlineAuthTokenSignature2 = cl_onlineAuthTokenSignature2Kv->GetString();
const std::string fullToken = Format("%s.%s%s", onlineAuthToken, onlineAuthTokenSignature1, onlineAuthTokenSignature2);
struct l8w8jwt_decoding_params params;
l8w8jwt_decoding_params_init(&params);
params.alg = L8W8JWT_ALG_RS256;
params.jwt = (char*)fullToken.c_str();
params.jwt_length = fullToken.length();
params.verification_key = (unsigned char*)JWT_PUBLIC_KEY;
params.verification_key_length = strlen(JWT_PUBLIC_KEY);
params.validate_exp = 1;
params.exp_tolerance_seconds = 1;
params.validate_iat = 1;
params.iat_tolerance_seconds = 30;
l8w8jwt_claim* claims = nullptr;
size_t numClaims = 0;
enum l8w8jwt_validation_result validation_result;
const int r = l8w8jwt_decode(&params, &validation_result, &claims, &numClaims);
if (r != L8W8JWT_SUCCESS)
{
FORMAT_ERROR_REASON("Code %i", r);
return false;
}
if (validation_result != L8W8JWT_VALID)
{
char reasonBuffer[256];
l8w8jwt_get_validation_result_desc(validation_result, reasonBuffer, sizeof(reasonBuffer));
FORMAT_ERROR_REASON("%s", reasonBuffer);
return false;
}
bool foundSessionId = false;
for (size_t i = 0; i < numClaims; ++i)
{
// session id
if (!strcmp(claims[i].key, "sessionId"))
{
const char* const sessionId = claims[i].value;
const std::string newId = Format(
"%lld-%s-%s",
this->m_DataBlock.userData,
playerName,
g_pMasterServer->GetHostIP().c_str()
);
DevMsg(eDLL_T::SERVER, "%s: newId=%s\n", __FUNCTION__, newId.c_str());
const std::string hashedNewId = sha256(newId);
if (hashedNewId.compare(sessionId) != 0)
{
FORMAT_ERROR_REASON("Token is not authorized for the connecting client");
return false;
}
foundSessionId = true;
}
}
if (!foundSessionId)
{
FORMAT_ERROR_REASON("No session ID");
return false;
}
#undef REJECT_CONNECTION
#endif // !CLIENT_DLL
return true;
}
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
// Purpose: connect new client // Purpose: connect new client
// Input : *szName - // Input : *szName -
// *pNetChannel - // *pNetChannel -
// bFakePlayer - // bFakePlayer -
// *a5 - // *conVars -
// *szMessage - // *szMessage -
// nMessageSize - // nMessageSize -
// Output : true if connection was successful, false otherwise // Output : true if connection was successful, false otherwise
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
bool CClient::Connect(const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize) bool CClient::Connect(const char* szName, void* pNetChannel, bool bFakePlayer,
CUtlVector<NET_SetConVar::cvar_t>* conVars, char* szMessage, int nMessageSize)
{ {
#ifndef CLIENT_DLL #ifndef CLIENT_DLL
g_ServerPlayer[GetUserID()].Reset(); // Reset ServerPlayer slot. g_ServerPlayer[GetUserID()].Reset(); // Reset ServerPlayer slot.
#endif
if (!v_CClient_Connect(this, szName, pNetChannel, bFakePlayer, conVars, szMessage, nMessageSize))
return false;
#ifndef CLIENT_DLL
#define REJECT_CONNECTION(fmt, ...) V_snprintf(szMessage, nMessageSize, fmt, ##__VA_ARGS__);
char authFailReason[512];
if (!Authenticate(szName, authFailReason, sizeof(authFailReason)))
{
REJECT_CONNECTION("Failed to verify authentication token [%s]", authFailReason);
return false;
}
#undef REJECT_CONNECTION
#endif // !CLIENT_DLL #endif // !CLIENT_DLL
return v_CClient_Connect(this, szName, pNetChannel, bFakePlayer, a5, szMessage, nMessageSize);
return true;
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
@ -66,9 +204,10 @@ bool CClient::Connect(const char* szName, void* pNetChannel, bool bFakePlayer, v
// nMessageSize - // nMessageSize -
// Output : true if connection was successful, false otherwise // Output : true if connection was successful, false otherwise
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
bool CClient::VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize) bool CClient::VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer,
CUtlVector<NET_SetConVar::cvar_t>* conVars, char* szMessage, int nMessageSize)
{ {
return pClient->Connect(szName, pNetChannel, bFakePlayer, a5, szMessage, nMessageSize);; return pClient->Connect(szName, pNetChannel, bFakePlayer, conVars, szMessage, nMessageSize);;
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
@ -258,8 +397,8 @@ bool CClient::VProcessStringCmd(CClient* pClient, NET_StringCmd* pMsg)
bool CClient::VProcessSetConVar(CClient* pClient, NET_SetConVar* pMsg) bool CClient::VProcessSetConVar(CClient* pClient, NET_SetConVar* pMsg)
{ {
#ifndef CLIENT_DLL #ifndef CLIENT_DLL
CClient* pAdj = AdjustShiftedThisPointer(pClient); CClient* const pAdj = AdjustShiftedThisPointer(pClient);
ServerPlayer_t* pSlot = &g_ServerPlayer[pAdj->GetUserID()]; ServerPlayer_t* const pSlot = &g_ServerPlayer[pAdj->GetUserID()];
// This loop never exceeds 255 iterations, NET_SetConVar::ReadFromBuffer(...) // This loop never exceeds 255 iterations, NET_SetConVar::ReadFromBuffer(...)
// reads and inserts up to 255 entries in the vector (reads a byte for size). // reads and inserts up to 255 entries in the vector (reads a byte for size).
@ -297,6 +436,7 @@ bool CClient::VProcessSetConVar(CClient* pClient, NET_SetConVar* pMsg)
continue; continue;
} }
// Add ConVar to list and set string.
pAdj->m_ConVars->SetString(name, value); pAdj->m_ConVars->SetString(name, value);
DevMsg(eDLL_T::SERVER, "UserInfo update from \"%s\": %s = %s\n", pAdj->GetClientName(), name, value); DevMsg(eDLL_T::SERVER, "UserInfo update from \"%s\": %s = %s\n", pAdj->GetClientName(), name, value);
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "vpc/keyvalues.h" #include "vpc/keyvalues.h"
#include "common/protocol.h" #include "common/protocol.h"
#include "engine/net.h"
#include "engine/net_chan.h" #include "engine/net_chan.h"
#include "public/edict.h" #include "public/edict.h"
#include "engine/server/datablock_sender.h" #include "engine/server/datablock_sender.h"
@ -93,13 +94,18 @@ public:
inline bool IsHumanPlayer(void) const { if (!IsConnected() || IsFakeClient()) { return false; } return true; } inline bool IsHumanPlayer(void) const { if (!IsConnected() || IsFakeClient()) { return false; } return true; }
bool SendNetMsgEx(CNetMessage* pMsg, char bLocal, bool bForceReliable, bool bVoice); bool SendNetMsgEx(CNetMessage* pMsg, char bLocal, bool bForceReliable, bool bVoice);
bool Connect(const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize);
bool Authenticate(const char* const playerName, char* const reasonBuf, const size_t reasonBufLen);
bool Connect(const char* szName, void* pNetChannel, bool bFakePlayer,
CUtlVector<NET_SetConVar::cvar_t>* conVars, char* szMessage, int nMessageSize);
void Disconnect(const Reputation_t nRepLvl, const char* szReason, ...); void Disconnect(const Reputation_t nRepLvl, const char* szReason, ...);
static bool VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize);
void Clear(void); void Clear(void);
public: // Hook statics: public: // Hook statics:
static void VClear(CClient* pClient); static void VClear(CClient* pClient);
static bool VConnect(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer,
CUtlVector<NET_SetConVar::cvar_t>* conVars, char* szMessage, int nMessageSize);
static void VActivatePlayer(CClient* pClient); static void VActivatePlayer(CClient* pClient);
static void* VSendSnapshot(CClient* pClient, CClientFrame* pFrame, int nTick, int nTickAck); static void* VSendSnapshot(CClient* pClient, CClientFrame* pFrame, int nTick, int nTickAck);
static bool VSendNetMsgEx(CClient* pClient, CNetMessage* pMsg, char bLocal, bool bForceReliable, bool bVoice); static bool VSendNetMsgEx(CClient* pClient, CNetMessage* pMsg, char bLocal, bool bForceReliable, bool bVoice);
@ -204,7 +210,7 @@ static_assert(sizeof(CClient) == 0x4A4C0);
/* ==== CBASECLIENT ===================================================================================================================================================== */ /* ==== CBASECLIENT ===================================================================================================================================================== */
inline CMemory p_CClient_Connect; inline CMemory p_CClient_Connect;
inline bool(*v_CClient_Connect)(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, void* a5, char* szMessage, int nMessageSize); inline bool(*v_CClient_Connect)(CClient* pClient, const char* szName, void* pNetChannel, bool bFakePlayer, CUtlVector<NET_SetConVar::cvar_t>* conVars, char* szMessage, int nMessageSize);
inline CMemory p_CClient_Disconnect; inline CMemory p_CClient_Disconnect;
inline bool(*v_CClient_Disconnect)(CClient* pClient, const Reputation_t nRepLvl, const char* szReason, ...); inline bool(*v_CClient_Disconnect)(CClient* pClient, const Reputation_t nRepLvl, const char* szReason, ...);
@ -269,7 +275,7 @@ class VClient : public IDetour
p_CClient_ProcessSetConVar = g_GameDll.FindPatternSIMD("48 83 EC 28 48 83 C2 20"); p_CClient_ProcessSetConVar = g_GameDll.FindPatternSIMD("48 83 EC 28 48 83 C2 20");
p_CClient_SetSignonState = g_GameDll.FindPatternSIMD("48 8B C4 48 89 58 10 48 89 70 18 57 48 81 EC ?? ?? ?? ?? 0F 29 70 E8 8B F2"); p_CClient_SetSignonState = g_GameDll.FindPatternSIMD("48 8B C4 48 89 58 10 48 89 70 18 57 48 81 EC ?? ?? ?? ?? 0F 29 70 E8 8B F2");
v_CClient_Connect = p_CClient_Connect.RCast<bool (*)(CClient*, const char*, void*, bool, void*, char*, int)>(); v_CClient_Connect = p_CClient_Connect.RCast<bool (*)(CClient*, const char*, void*, bool, CUtlVector<NET_SetConVar::cvar_t>*, char*, int)>();
v_CClient_Disconnect = p_CClient_Disconnect.RCast<bool (*)(CClient*, const Reputation_t, const char*, ...)>(); v_CClient_Disconnect = p_CClient_Disconnect.RCast<bool (*)(CClient*, const Reputation_t, const char*, ...)>();
v_CClient_Clear = p_CClient_Clear.RCast<void (*)(CClient*)>(); v_CClient_Clear = p_CClient_Clear.RCast<void (*)(CClient*)>();
v_CClient_ActivatePlayer = p_CClient_ActivatePlayer.RCast<void (*)(CClient* pClient)>(); v_CClient_ActivatePlayer = p_CClient_ActivatePlayer.RCast<void (*)(CClient* pClient)>();

View File

@ -16,6 +16,7 @@
#include "common/callback.h" #include "common/callback.h"
#include "cdll_engine_int.h" #include "cdll_engine_int.h"
#include "vgui/vgui_baseui_interface.h" #include "vgui/vgui_baseui_interface.h"
#include <ebisusdk/EbisuSDK.h>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -163,16 +164,76 @@ bool CClientState::VProcessServerTick(CClientState* pClientState, SVC_ServerTick
} }
} }
bool CClientState::Authenticate(connectparams_t* connectParams) const
{
string msToken; // token returned by the masterserver authorising the client to play online
string message; // message returned by the masterserver about the result of the auth
// verify that the client is not lying about their account identity
// code is immediately discarded upon verification
const bool ret = g_pMasterServer->AuthForConnection(*g_NucleusID, connectParams->netAdr, g_OriginAuthCode, msToken, message);
if (!ret)
{
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to authenticate for online play: %s\n", message.c_str());
return false;
}
// get full token
const char* token = msToken.c_str();
// get a pointer to the delimiter that begins the token's signature
const char* tokenSignatureDelim = strrchr(token, '.');
if (!tokenSignatureDelim)
{
Error(eDLL_T::ENGINE, NO_ERROR, "Failed to authenticate for online play: %s\n", "Invalid token returned by MS");
return false;
}
// replace the delimiter with a null char so the first cvar only takes the header and payload data
*(char*)tokenSignatureDelim = '\0';
const size_t sigLength = strlen(tokenSignatureDelim) - 1;
cl_onlineAuthToken->SetValue(token);
if (sigLength > 0)
{
// get a pointer to the first part of the token signature to store in cl_onlineAuthTokenSignature1
const char* tokenSignaturePart1 = tokenSignatureDelim + 1;
cl_onlineAuthTokenSignature1->SetValue(tokenSignaturePart1);
if (sigLength > 255)
{
// get a pointer to the rest of the token signature to store in cl_onlineAuthTokenSignature2
const char* tokenSignaturePart2 = tokenSignaturePart1 + 255;
cl_onlineAuthTokenSignature2->SetValue(tokenSignaturePart2);
}
}
return true;
}
void CClientState::VConnect(CClientState* thisptr, connectparams_t* connectParams)
{
thisptr->Authenticate(connectParams);
CClientState__Connect(thisptr, connectParams);
}
void VClientState::Attach() const void VClientState::Attach() const
{ {
DetourAttach(&CClientState__ConnectionClosing, &CClientState::VConnectionClosing); DetourAttach(&CClientState__ConnectionClosing, &CClientState::VConnectionClosing);
DetourAttach(&CClientState__ProcessServerTick, &CClientState::VProcessServerTick); DetourAttach(&CClientState__ProcessServerTick, &CClientState::VProcessServerTick);
DetourAttach(&CClientState__Connect, &CClientState::VConnect);
} }
void VClientState::Detach() const void VClientState::Detach() const
{ {
DetourDetach(&CClientState__ConnectionClosing, &CClientState::VConnectionClosing); DetourDetach(&CClientState__ConnectionClosing, &CClientState::VConnectionClosing);
DetourDetach(&CClientState__ProcessServerTick, &CClientState::VProcessServerTick); DetourDetach(&CClientState__ProcessServerTick, &CClientState::VProcessServerTick);
DetourDetach(&CClientState__Connect, &CClientState::VConnect);
} }
///////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////

View File

@ -11,6 +11,16 @@
#include "engine/packed_entity.h" #include "engine/packed_entity.h"
#include "datablock_receiver.h" #include "datablock_receiver.h"
struct connectparams_t
{
const char* netAdr;
const char* netKey;
int unkReconnect;
int unk;
bool challengeRequest;
bool asSpectator_MAYBE;
};
class CClientSnapshotManager : public IClientSnapshotManager class CClientSnapshotManager : public IClientSnapshotManager
{ {
public: public:
@ -27,6 +37,7 @@ class CClientState : CS_INetChannelHandler, IConnectionlessPacketHandler, IServe
public: // Hook statics. public: // Hook statics.
static void VConnectionClosing(CClientState* thisptr, const char* szReason); static void VConnectionClosing(CClientState* thisptr, const char* szReason);
static bool VProcessServerTick(CClientState* thisptr, SVC_ServerTick* msg); static bool VProcessServerTick(CClientState* thisptr, SVC_ServerTick* msg);
static void VConnect(CClientState* thisptr, connectparams_t* connectParams);
public: public:
bool IsPaused() const; bool IsPaused() const;
@ -46,6 +57,8 @@ public:
float GetFrameTime(void) const; float GetFrameTime(void) const;
bool Authenticate(connectparams_t* connectParams) const;
int m_Socket; int m_Socket;
int _padding_maybe; int _padding_maybe;
CNetChan* m_NetChannel; CNetChan* m_NetChannel;
@ -199,6 +212,9 @@ extern CClientState** g_pClientState_Shifted; // Shifted by 0x10 forward!
inline CMemory p_CClientState__RunFrame; inline CMemory p_CClientState__RunFrame;
inline void(*CClientState__RunFrame)(CClientState* thisptr); inline void(*CClientState__RunFrame)(CClientState* thisptr);
inline CMemory p_CClientState__Connect;
inline void(*CClientState__Connect)(CClientState* thisptr, connectparams_t* connectParams);
inline CMemory p_CClientState__Disconnect; inline CMemory p_CClientState__Disconnect;
inline void(*CClientState__Disconnect)(CClientState* thisptr, bool bSendTrackingContext); inline void(*CClientState__Disconnect)(CClientState* thisptr, bool bSendTrackingContext);
@ -214,6 +230,7 @@ class VClientState : public IDetour
virtual void GetAdr(void) const virtual void GetAdr(void) const
{ {
LogFunAdr("CClientState::RunFrame", p_CClientState__RunFrame.GetPtr()); LogFunAdr("CClientState::RunFrame", p_CClientState__RunFrame.GetPtr());
LogFunAdr("CClientState::Connect", p_CClientState__Connect.GetPtr());
LogFunAdr("CClientState::Disconnect", p_CClientState__Disconnect.GetPtr()); LogFunAdr("CClientState::Disconnect", p_CClientState__Disconnect.GetPtr());
LogFunAdr("CClientState::ConnectionClosing", p_CClientState__ConnectionClosing.GetPtr()); LogFunAdr("CClientState::ConnectionClosing", p_CClientState__ConnectionClosing.GetPtr());
LogFunAdr("CClientState::ProcessServerTick", p_CClientState__ProcessServerTick.GetPtr()); LogFunAdr("CClientState::ProcessServerTick", p_CClientState__ProcessServerTick.GetPtr());
@ -234,7 +251,11 @@ class VClientState : public IDetour
#endif #endif
p_CClientState__ProcessServerTick = g_GameDll.FindPatternSIMD("40 57 48 83 EC 20 83 B9 ?? ?? ?? ?? ?? 48 8B F9 7C 66"); p_CClientState__ProcessServerTick = g_GameDll.FindPatternSIMD("40 57 48 83 EC 20 83 B9 ?? ?? ?? ?? ?? 48 8B F9 7C 66");
p_CClientState__Connect = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 81 EC ?? ?? ?? ?? 48 8B 32");
CClientState__RunFrame = p_CClientState__RunFrame.RCast<void(*)(CClientState*)>(); CClientState__RunFrame = p_CClientState__RunFrame.RCast<void(*)(CClientState*)>();
CClientState__Connect = p_CClientState__Connect.RCast<void(*)(CClientState*, connectparams_t*)>();
CClientState__Disconnect = p_CClientState__Disconnect.RCast<void(*)(CClientState*, bool)>(); CClientState__Disconnect = p_CClientState__Disconnect.RCast<void(*)(CClientState*, bool)>();
CClientState__ConnectionClosing = p_CClientState__ConnectionClosing.RCast<void(*)(CClientState*, const char*)>(); CClientState__ConnectionClosing = p_CClientState__ConnectionClosing.RCast<void(*)(CClientState*, const char*)>();
CClientState__ProcessServerTick = p_CClientState__ProcessServerTick.RCast<bool(*)(CClientState*, SVC_ServerTick*)>(); CClientState__ProcessServerTick = p_CClientState__ProcessServerTick.RCast<bool(*)(CClientState*, SVC_ServerTick*)>();

View File

@ -69,8 +69,9 @@ bool HostState_KeepAlive(const NetGameServer_t& netGameServer)
string errorMsg; string errorMsg;
string hostToken; string hostToken;
string hostIp;
const bool result = g_pMasterServer->PostServerHost(errorMsg, hostToken, netGameServer); const bool result = g_pMasterServer->PostServerHost(errorMsg, hostToken, hostIp, netGameServer);
if (!result) if (!result)
{ {
if (!errorMsg.empty() && g_pMasterServer->GetCurrentError().compare(errorMsg) != NULL) if (!errorMsg.empty() && g_pMasterServer->GetCurrentError().compare(errorMsg) != NULL)
@ -90,6 +91,9 @@ bool HostState_KeepAlive(const NetGameServer_t& netGameServer)
} }
} }
if (hostIp.length() != 0)
g_pMasterServer->SetHostIP(hostIp);
return result; return result;
} }
#endif // !CLIENT_DLL #endif // !CLIENT_DLL

View File

@ -46,8 +46,8 @@ protected:
struct ServerDataBlock struct ServerDataBlock
{ {
char SnapshotBuffer[295312]; // this might be wrong !!! char blockBuffer[295312]; // this might be wrong !!!
void* pUnkBlockStruct; void* userData;
char gapC0008[56]; char gapC0008[56];
ServerDataBlockSender sender; ServerDataBlockSender sender;
}; };

View File

@ -778,13 +778,18 @@ void CBrowser::SendHostingPostRequest(const NetGameServer_t& gameServer)
#ifndef CLIENT_DLL #ifndef CLIENT_DLL
string svHostRequestMessage; string svHostRequestMessage;
string svHostToken; string svHostToken;
bool result = g_pMasterServer->PostServerHost(svHostRequestMessage, svHostToken, gameServer); string svHostIp;
bool result = g_pMasterServer->PostServerHost(svHostRequestMessage, svHostToken, svHostIp, gameServer);
std::lock_guard<std::mutex> l(m_Mutex); std::lock_guard<std::mutex> l(m_Mutex);
m_svHostRequestMessage = svHostRequestMessage; m_svHostRequestMessage = svHostRequestMessage;
m_svHostToken = svHostToken; m_svHostToken = svHostToken;
if(svHostIp.length() != 0)
g_pMasterServer->SetHostIP(svHostIp);
if (result) if (result)
{ {
m_HostRequestMessageColor = ImVec4(0.00f, 1.00f, 0.00f, 1.00f); m_HostRequestMessageColor = ImVec4(0.00f, 1.00f, 0.00f, 1.00f);

View File

@ -169,7 +169,7 @@ bool CPylon::GetServerByToken(NetGameServer_t& outGameServer,
// &netGameServer - // &netGameServer -
// Output : Returns true on success, false on failure. // Output : Returns true on success, false on failure.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool CPylon::PostServerHost(string& outMessage, string& outToken, const NetGameServer_t& netGameServer) const bool CPylon::PostServerHost(string& outMessage, string& outToken, string& outHostIp, const NetGameServer_t& netGameServer) const
{ {
rapidjson::Document requestJson; rapidjson::Document requestJson;
requestJson.SetObject(); requestJson.SetObject();
@ -210,6 +210,13 @@ bool CPylon::PostServerHost(string& outMessage, string& outToken, const NetGameS
outToken = responseJson["token"].GetString(); outToken = responseJson["token"].GetString();
} }
if (responseJson.HasMember("ip") && responseJson["ip"].IsString() &&
responseJson.HasMember("port") && responseJson["port"].IsInt())
{
outHostIp = Format("[%s]:%i",
responseJson["ip"].GetString(), responseJson["port"].GetInt());
}
return true; return true;
} }
@ -304,6 +311,35 @@ bool CPylon::CheckForBan(const string& ipAddress, const uint64_t nucleusId, cons
return false; return false;
} }
bool CPylon::AuthForConnection(const uint64_t nucleusId, const char* ipAddress, const char* authCode, string& outToken, string& outMessage) const
{
rapidjson::Document requestJson;
requestJson.SetObject();
rapidjson::Document::AllocatorType& allocator = requestJson.GetAllocator();
requestJson.AddMember("id", nucleusId, allocator);
requestJson.AddMember("ip", rapidjson::Value(ipAddress, allocator), allocator);
requestJson.AddMember("code", rapidjson::Value(authCode, allocator), allocator);
rapidjson::Document responseJson;
CURLINFO status;
if (!SendRequest("/client/authenticate", requestJson, responseJson, outMessage, status, "origin auth error"))
{
return false;
}
if (responseJson.HasMember("token") && responseJson["token"].IsString())
{
outToken = responseJson["token"].GetString();
return true;
}
return false;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Sends request to Pylon Master Server. // Purpose: Sends request to Pylon Master Server.
// Input : *endpoint - // Input : *endpoint -

View File

@ -11,11 +11,13 @@ public:
vector<NetGameServer_t> GetServerList(string& outMessage) const; vector<NetGameServer_t> GetServerList(string& outMessage) const;
bool GetServerByToken(NetGameServer_t& slOutServer, string& outMessage, const string& svToken) const; bool GetServerByToken(NetGameServer_t& slOutServer, string& outMessage, const string& svToken) const;
bool PostServerHost(string& outMessage, string& svOutToken, const NetGameServer_t& netGameServer) const; bool PostServerHost(string& outMessage, string& svOutToken, string& outHostIp, const NetGameServer_t& netGameServer) const;
bool GetBannedList(const CBanSystem::BannedList_t& inBannedVec, CBanSystem::BannedList_t& outBannedVec) const; bool GetBannedList(const CBanSystem::BannedList_t& inBannedVec, CBanSystem::BannedList_t& outBannedVec) const;
bool CheckForBan(const string& ipAddress, const uint64_t nucleusId, const string& personaName, string& outReason) const; bool CheckForBan(const string& ipAddress, const uint64_t nucleusId, const string& personaName, string& outReason) const;
bool AuthForConnection(const uint64_t nucleusId, const char* ipAddress, const char* authCode, string& outToken, string& outMessage) const;
void ExtractError(const rapidjson::Document& resultBody, string& outMessage, CURLINFO status, const char* errorText = nullptr) const; void ExtractError(const rapidjson::Document& resultBody, string& outMessage, CURLINFO status, const char* errorText = nullptr) const;
void ExtractError(const string& response, string& outMessage, CURLINFO status, const char* messageText = nullptr) const; void ExtractError(const string& response, string& outMessage, CURLINFO status, const char* messageText = nullptr) const;
@ -26,14 +28,19 @@ public:
inline const string& GetCurrentToken() const { return m_Token; } inline const string& GetCurrentToken() const { return m_Token; }
inline const string& GetCurrentError() const { return m_ErrorMsg; } inline const string& GetCurrentError() const { return m_ErrorMsg; }
inline const string& GetHostIP() const { return m_HostIP; };
inline void SetCurrentToken(const string& token) { m_Token = token; } inline void SetCurrentToken(const string& token) { m_Token = token; }
inline void SetCurrentError(const string& error) { m_ErrorMsg = error; } inline void SetCurrentError(const string& error) { m_ErrorMsg = error; }
inline void SetHostIP(const string& ip) { m_HostIP = ip; };
inline void SetLanguage(const char* lang) { m_Language = lang; }; inline void SetLanguage(const char* lang) { m_Language = lang; };
private: private:
string m_Token; string m_Token;
string m_ErrorMsg; string m_ErrorMsg;
string m_HostIP;
string m_Language; string m_Language;
}; };
extern CPylon* g_pMasterServer; extern CPylon* g_pMasterServer;

View File

@ -34,6 +34,7 @@ extern "C" {
#include <time.h> #include <time.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#ifndef L8W8JWT_MAX_KEY_SIZE #ifndef L8W8JWT_MAX_KEY_SIZE
#define L8W8JWT_MAX_KEY_SIZE 8192 #define L8W8JWT_MAX_KEY_SIZE 8192
@ -94,6 +95,31 @@ enum l8w8jwt_validation_result {
L8W8JWT_TYP_FAILURE = (unsigned)1 << (unsigned)8 L8W8JWT_TYP_FAILURE = (unsigned)1 << (unsigned)8
}; };
static void l8w8jwt_get_validation_result_desc(enum l8w8jwt_validation_result res, char* out_buffer, size_t buffer_size)
{
#define JWT_OUTPUT_MSG(msg) snprintf(out_buffer, buffer_size, "%s", msg)
#define JWT_FLAG_STATUS(flag, msg) if(res & flag) { JWT_OUTPUT_MSG(msg); return; }
if (res == L8W8JWT_VALID)
{
JWT_OUTPUT_MSG("Success");
return;
}
JWT_FLAG_STATUS(L8W8JWT_ISS_FAILURE, "Issuer claim is invalid");
JWT_FLAG_STATUS(L8W8JWT_SUB_FAILURE, "Subject claim is invalid");
JWT_FLAG_STATUS(L8W8JWT_AUD_FAILURE, "Audience claim is invalid");
JWT_FLAG_STATUS(L8W8JWT_JTI_FAILURE, "JWT ID claim is invalid");
JWT_FLAG_STATUS(L8W8JWT_EXP_FAILURE, "Token has expired");
JWT_FLAG_STATUS(L8W8JWT_NBF_FAILURE, "Token is not yet valid");
JWT_FLAG_STATUS(L8W8JWT_IAT_FAILURE, "Token has not been issued yet");
JWT_FLAG_STATUS(L8W8JWT_SIGNATURE_VERIFICATION_FAILURE, "Token signature is invalid");
JWT_FLAG_STATUS(L8W8JWT_TYP_FAILURE, "Token type is invalid");
#undef JWT_OUTPUT_MSG
#undef JWT_FLAG_STATUS
}
/** /**
* Struct containing the parameters to use for decoding and validating a JWT. * Struct containing the parameters to use for decoding and validating a JWT.
*/ */