Skip to content

Commit

Permalink
Also check authhash
Browse files Browse the repository at this point in the history
  • Loading branch information
Skyedra committed Oct 9, 2024
1 parent 9aa8a28 commit 0c702b5
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 2 deletions.
7 changes: 7 additions & 0 deletions Robust.Shared/Network/AuthManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ internal interface IAuthManager
string? ServerPublicKey { get; set; }
string? UserPublicKey { get; set; }
string? UserJWT { get; set; }
string? SharedSecretBase64 { get; set; }

void LoadFromEnv();
}
Expand All @@ -22,6 +23,7 @@ internal sealed class AuthManager : IAuthManager
public string? ServerPublicKey { get; set; }
public string? UserPublicKey { get; set; }
public string? UserJWT { get; set; }
public string? SharedSecretBase64 { get; set; }

public void LoadFromEnv()
{
Expand All @@ -40,6 +42,11 @@ public void LoadFromEnv()
UserJWT = userJWT;
}

if (TryGetVar("ROBUST_SHARED_SECRET", out var sharedSecretBase64))
{
SharedSecretBase64 = sharedSecretBase64;
}

static bool TryGetVar(string var, [NotNullWhen(true)] out string? val)
{
val = Environment.GetEnvironmentVariable(var);
Expand Down
26 changes: 24 additions & 2 deletions Robust.Shared/Network/NetManager.ClientConnect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,30 @@ private async Task CCDoHandshake(NetPeerData peer, NetConnection connection, str
var encRequest = new MsgEncryptionRequest();
encRequest.ReadFromBuffer(response, _serializer);

var sharedSecret = new byte[SharedKeyLength];
RandomNumberGenerator.Fill(sharedSecret);
byte[] sharedSecret;

if (string.IsNullOrEmpty(_authManager.SharedSecretBase64))
{
// Generate new shared secret in robust client
sharedSecret = new byte[SharedKeyLength];
RandomNumberGenerator.Fill(sharedSecret); // In order for this to work, server must not be verifying JWT
}
else
{
// Use shared secret from launcher

// (Robust client does not have direct access to the user's private key for safety. The JWT needs to
// include the authhash to avoid a MITM. Thus, the launcher must generate the JWT and by extension
// the shared secret. Launcher will generate it and pass it to us in Base64 format.)
sharedSecret = System.Convert.FromBase64String(_authManager.SharedSecretBase64);

if (sharedSecret.Length != SharedKeyLength)
{
var msg = $"Invalid shared secret length from launcher. Expected {SharedKeyLength}, but was {sharedSecret.Length}.";
connection.Disconnect(msg);
throw new Exception(msg);
}
}

if (encrypt)
encryption = new NetEncryption(sharedSecret, isServer: false);
Expand Down
20 changes: 20 additions & 0 deletions Robust.Shared/Network/NetManager.ServerAuth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ private async void HandleHandshake(NetPeerData peer, NetConnection connection)
if (msgLogin.Encrypt)
encryption = new NetEncryption(sharedSecret, isServer: true);

var authHashBytes = MakeAuthHash(sharedSecret, CryptoPublicKey!);
var authHash = Base64Helpers.ConvertToBase64Url(authHashBytes);

// Validate the JWT
var userPublicKeyString = msgEncResponse.UserPublicKey ?? "";
var userJWTString = msgEncResponse.UserJWT ?? "";
Expand Down Expand Up @@ -219,6 +222,23 @@ private async void HandleHandshake(NetPeerData peer, NetConnection connection)
connection.Disconnect("JWT Validation Error\nJWT appears to be for another server.\nTry returning to launcher and reconnect.");
return;
}

// Also verify authhash matches.
// (This step helps deter a MITM/proxy attack, since even if traffic was proxied, it should also
// be encrypted.)
string authHashClaim = "";
var authHashClaimNode = jsonNode["authhash"];
if (authHashClaimNode == null)
{
connection.Disconnect("JWT Validation Error - No auth hash in JWT\n(Ensure you are using latest launcher version).");
return;
}
authHashClaim = (string) authHashClaimNode.GetValue<string>();
if (authHashClaim != authHash)
{
connection.Disconnect("JWT Validation Error - Wrong auth hash in JWT\n(Check server address is correct).");
return;
}
}

_logger.Verbose(
Expand Down

0 comments on commit 0c702b5

Please sign in to comment.