t2-scripts/t2csri/serverSideClans.cs

204 lines
6.5 KiB
C#
Raw Normal View History

// Tribes 2 Unofficial Authentication System
// http://www.tribesnext.com/
// Written by Electricutioner/Thyth
// Copyright 2008 by Electricutioner/Thyth and the Tribes 2 Community System Reengineering Intitiative
// Version 1.0: 2009-02-13
// A little bit of development theory:
// -The Apotheosis DLL contains 3 RSA public keys. One for authentication, one for updates,
// and one for delegation. The delegation key forms the root of the community system trust heirarchy.
// -The delegated-community-enhancement server issues time limited community certificates, which
// annotate the bare account certificates. The annotations include current name, current clan, current tag
// and current clan membership so that getAuthInfo() provides all relevant information. These certificates
// are time limited to enforce the "current" status of the annotations.
// -Since game servers don't communicate with centralized systems (except for listing), the client is
// responsible for providing a signed community certificate, and if prompted, the client is also
// responsible for providing the authoratatively signed certificate from the relevant DCE. Thus, the
// server will accumilate a small cache of valid DCE certificates.
// DCE certificate format:
// DCEName DCENum IssuedEpoch ExpireEpoch 0 0 e n sig
// The two zeros are reserved for future use.
// Community certificate format:
// DCENum IssuedEpoch ExpireEpoch IssuedForGUID HexBlob Sig
// HexBlob format:
// (Follows same format as contents returned by getAuthInfo, but is hex encoded.)
// verify with the delegation RSA public key... hard coded in the executable
function t2csri_verify_deleg_signature(%sig)
{
%sig = strReplace(%sig, "\x27", "\\\x27");
rubyEval("tsEval '$temp=\"' + t2csri_verify_deleg_signature('" @ %sig @ "').to_s(16) + '\";'");
while (strLen($temp) < 40)
$temp = "0" @ $temp;
return $temp;
}
// allow the client to send in an unknown DCE certificate
function serverCmdt2csri_getDCEChunk(%client, %chunk)
{
// client can only send in one DCE
if (%client.t2csri_sentDCEDone)
return;
%client.t2csri_activeDCE = %client.t2csri_activeDCE @ %chunk;
if (strlen(%client.t2csri_activeDCE) > 20000)
{
%client.setDisconnectReason("DCE certificate is too long.");
%client.delete();
return;
}
}
// client finished sending their DCE. validate it
function serverCmdt2csri_finishedDCE(%client)
{
if (%client.t2csri_sentDCEDone)
return;
%dce = %client.t2csri_activeDCE;
if (getFieldCount(%dce) != 9)
{
%client.setDisconnectReason("DCE certificate format is invalid.");
%client.delete();
return;
}
%dceName = getField(%dce, 0);
%dceNum = getField(%dce, 1);
%dceIssued = getField(%dce, 2);
%dceExpire = getField(%dce, 3);
%dceE = getField(%dce, 6);
%dceN = getField(%dce, 7);
// check to see if we already have this certificate
if ($T2CSRI::DCEE[%dceNum] !$= "")
{
// we already have the cert... set the client as done
%client.t2csri_sentDCEDone = 1;
%client.t2csri_activeDCE = "";
return;
}
%dceSig = getField(%dce, 8);
%sigSha = t2csri_verify_deleg_signature(%dceSig);
%sumStr = %dceName @ "\t" @ %dceNum @ "\t" @ %dceIssued @ "\t" @ %dceExpire @ "\t";
%sumStr = %sumStr @ getField(%dce, 4) @ "\t" @ getField(%dce, 5) @ "\t" @ %dceE @ "\t" @ %dceN;
%calcSha = sha1sum(%sumStr);
if (%sigSha !$= %calcSha)
{
%client.setDisconnectReason("DCE is not signed by authoritative root.");
%client.delete();
return;
}
// passed signature check... now check to see if it has expired/issued time has arrived
%currentTime = currentEpochTime();
if (%currentTime < %dceIssued || %currentTime > %dceExpire)
{
%client.setDisconnectReason("DCE is not valid for the current time period.");
%client.delete();
return;
}
// passed time check... enter it into global data structure
$T2CSRI::DCEName[%dceNum] = %dceName;
$T2CSRI::DCEE[%dceNum] = %dceE;
$T2CSRI::DCEN[%dceNum] = %dceN;
// client has successfully sent a DCE
%client.t2csri_sentDCEDone = 1;
%client.t2csri_activeDCE = "";
// client was pending on a certificate signature check, do that now that we have the DCE cert
if (%client.t2csri_pendingDCE)
{
%client.t2csri_pendingDCE = 0;
serverCmdt2csri_comCertSendDone(%client);
}
}
// client sending community cert chunk
function serverCmdt2csri_sendCommunityCertChunk(%client, %chunk)
{
// client can only send in one community cert
if (%client.t2csri_sentComCertDone)
return;
%client.t2csri_comCert = %client.t2csri_comCert @ %chunk;
if (strlen(%client.t2csri_comCert) > 20000)
{
%client.setDisconnectReason("Community certificate is too long.");
%client.delete();
return;
}
}
// client has sent in a full community certificate... validate and parse it
function serverCmdt2csri_comCertSendDone(%client)
{
if (%client.t2csri_sentComCertDone)
return;
%comCert = %client.t2csri_comCert;
if (getFieldCount(%comCert) != 6)
{
%client.setDisconnectReason("Community certificate format is invalid.");
%client.delete();
return;
}
// parse
%dceNum = getField(%comCert, 0);
%issued = getField(%comCert, 1);
%expire = getField(%comCert, 2);
%guid = getField(%comCert, 3);
%blob = getField(%comCert, 4);
%sig = getField(%comCert, 5);
%sumStr = getFieldS(%comCert, 0, 4);
%calcSha = sha1Sum(%sumStr);
// find the correct DCE
%e = $T2CSRI::DCEE[%dceNum];
%n = $T2CSRI::DCEN[%dceNum];
// what if we don't have it? ask the client for a copy
if (%e $= "")
{
%client.t2csri_pendingDCE = 1;
commandToClient(%client, 't2csri_requestUnknownDCECert', %dceNum);
return;
}
// get the signature SHA1
rubyEval("tsEval '$temp = \"' + rsa_mod_exp('" @ %sig @ "'.to_i(16), '" @ %e @ "'.to_i(16), '" @ %n @ "'.to_i(16)).to_s(16) + '\";'");
while (strlen($temp) < 40)
$temp = "0" @ $temp;
%sigSha = $temp;
if (%sigSha !$= %calcSha)
{
%client.setDisconnectReason("Community cert is not signed by a known/valid DCE.");
%client.delete();
return;
}
// check expiration
%currentTime = currentEpochTime();
if (%currentTime > %expire)
{
%client.setDisconnectReason("Community cert has expired. Get a fresh one from the DCE.");
%client.delete();
return;
}
// valid cert... set the field for processing in the auth-phase code
%len = strlen(%blob);
for (%i = 0; %i < %len; %i += 2)
{
%decoded = %decoded @ collapseEscape("\\x" @ getSubStr(%blob, %i, 2));
}
%client.t2csri_comInfo = %decoded @ "\n";
%client.t2csri_sentComCertDone = 1;
}