Permalink
Browse files

Make early protocol auth mechanism generic, and add SRP

Adds everything needed for SRP (and everything works too),
but still deactivated, as protocol v25 init packets aren't final yet.
Can be activated by changing the LATEST_PROTOCOL_VERSION header to 25
inside networkprotocol.h.
  • Loading branch information...
1 parent 181f7ba commit 82e35edff52d88dcd64a9bfc9d2c4c93f1341b78 @est31 est31 committed Apr 12, 2015
@@ -208,13 +208,15 @@ LOCAL_SRC_FILES := \
jni/src/version.cpp \
jni/src/voxel.cpp \
jni/src/voxelalgorithms.cpp \
+ jni/src/util/auth.cpp \
jni/src/util/base64.cpp \
jni/src/util/directiontables.cpp \
jni/src/util/numeric.cpp \
jni/src/util/pointedthing.cpp \
jni/src/util/serialize.cpp \
jni/src/util/sha1.cpp \
jni/src/util/string.cpp \
+ jni/src/util/srp.cpp \
jni/src/util/timetaker.cpp \
jni/src/unittest/test.cpp \
jni/src/unittest/test_collision.cpp \
@@ -243,6 +245,8 @@ LOCAL_SRC_FILES := \
jni/src/client/clientlauncher.cpp \
jni/src/client/tile.cpp
+# intentionally kept out (we already build openssl itself): jni/src/util/sha256.c
+
# Network
LOCAL_SRC_FILES += \
jni/src/network/connection.cpp \
View
@@ -22,10 +22,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <sstream>
#include <IFileSystem.h>
#include "jthread/jmutexautolock.h"
+#include "util/auth.h"
#include "util/directiontables.h"
#include "util/pointedthing.h"
#include "util/serialize.h"
#include "util/string.h"
+#include "util/srp.h"
#include "client.h"
#include "network/clientopcodes.h"
#include "filesys.h"
@@ -255,6 +257,8 @@ Client::Client(
m_highlighted_pos(0,0,0),
m_map_seed(0),
m_password(password),
+ m_chosen_auth_mech(AUTH_MECHANISM_NONE),
+ m_auth_data(NULL),
m_access_denied(false),
m_itemdef_received(false),
m_nodedef_received(false),
@@ -404,10 +408,13 @@ void Client::step(float dtime)
memset(pName, 0, PLAYERNAME_SIZE * sizeof(char));
memset(pPassword, 0, PASSWORD_SIZE * sizeof(char));
+ std::string hashed_password = translatePassword(myplayer->getName(), m_password);
snprintf(pName, PLAYERNAME_SIZE, "%s", myplayer->getName());
- snprintf(pPassword, PASSWORD_SIZE, "%s", m_password.c_str());
+ snprintf(pPassword, PASSWORD_SIZE, "%s", hashed_password.c_str());
sendLegacyInit(pName, pPassword);
+ if (LATEST_PROTOCOL_VERSION >= 25)
+ sendInit(myplayer->getName());
}
// Not connected, return
@@ -943,6 +950,39 @@ void Client::interact(u8 action, const PointedThing& pointed)
Send(&pkt);
}
+void Client::deleteAuthData()
+{
+ if (!m_auth_data)
+ return;
+
+ switch (m_chosen_auth_mech) {
+ case AUTH_MECHANISM_FIRST_SRP:
+ break;
+ case AUTH_MECHANISM_SRP:
+ case AUTH_MECHANISM_LEGACY_PASSWORD:
+ srp_user_delete((SRPUser *) m_auth_data);
+ m_auth_data = NULL;
+ break;
+ case AUTH_MECHANISM_NONE:
+ break;
+ }
+}
+
+
+AuthMechanism Client::choseAuthMech(const u32 mechs)
+{
+ if (mechs & AUTH_MECHANISM_SRP)
+ return AUTH_MECHANISM_SRP;
+
+ if (mechs & AUTH_MECHANISM_FIRST_SRP)
+ return AUTH_MECHANISM_FIRST_SRP;
+
+ if (mechs & AUTH_MECHANISM_LEGACY_PASSWORD)
+ return AUTH_MECHANISM_LEGACY_PASSWORD;
+
+ return AUTH_MECHANISM_NONE;
+}
+
void Client::sendLegacyInit(const char* playerName, const char* playerPassword)
{
NetworkPacket pkt(TOSERVER_INIT_LEGACY,
@@ -956,6 +996,70 @@ void Client::sendLegacyInit(const char* playerName, const char* playerPassword)
Send(&pkt);
}
+void Client::sendInit(const std::string &playerName)
+{
+ NetworkPacket pkt(TOSERVER_INIT, 1 + 2 + 2 + (1 + playerName.size()));
+
+ // TODO (later) actually send supported compression modes
+ pkt << (u8) SER_FMT_VER_HIGHEST_READ << (u8) 42;
+ pkt << (u16) CLIENT_PROTOCOL_VERSION_MIN << (u16) CLIENT_PROTOCOL_VERSION_MAX;
+ pkt << playerName;
+
+ Send(&pkt);
+}
+
+void Client::startAuth(AuthMechanism chosen_auth_mechanism)
+{
+ m_chosen_auth_mech = chosen_auth_mechanism;
+
+ switch (chosen_auth_mechanism) {
+ case AUTH_MECHANISM_FIRST_SRP: {
+ // send srp verifier to server
+ NetworkPacket resp_pkt(TOSERVER_FIRST_SRP, 0);
+ char *salt, *bytes_v;
+ std::size_t len_salt, len_v;
+ salt = NULL;
+ getSRPVerifier(getPlayerName(), m_password,
+ &salt, &len_salt, &bytes_v, &len_v);
+ resp_pkt
+ << std::string((char*)salt, len_salt)
+ << std::string((char*)bytes_v, len_v)
+ << (u8)((m_password == "") ? 1 : 0);
+ free(salt);
+ free(bytes_v);
+ Send(&resp_pkt);
+ break;
+ }
+ case AUTH_MECHANISM_SRP:
+ case AUTH_MECHANISM_LEGACY_PASSWORD: {
+ u8 based_on = 1;
+
+ if (chosen_auth_mechanism == AUTH_MECHANISM_LEGACY_PASSWORD) {
+ m_password = translatePassword(getPlayerName(), m_password);
+ based_on = 0;
+ }
+
+ std::string playername_u = lowercase(getPlayerName());
+ m_auth_data = srp_user_new(SRP_SHA256, SRP_NG_2048,
+ getPlayerName().c_str(), playername_u.c_str(),
+ (const unsigned char *) m_password.c_str(),
+ m_password.length(), NULL, NULL);
+ char *bytes_A = 0;
+ size_t len_A = 0;
+ srp_user_start_authentication((struct SRPUser *) m_auth_data,
+ NULL, NULL, 0, (unsigned char **) &bytes_A, &len_A);
+
+ NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_A, 0);
+ resp_pkt << std::string(bytes_A, len_A) << based_on;
+ free(bytes_A);
+ Send(&resp_pkt);
+ break;
+ }
+ case AUTH_MECHANISM_NONE:
+ break; // not handled in this method
+ }
+}
+
void Client::sendDeletedBlocks(std::vector<v3s16> &blocks)
{
NetworkPacket pkt(TOSERVER_DELETEDBLOCKS, 1 + sizeof(v3s16) * blocks.size());
@@ -1066,24 +1170,30 @@ void Client::sendChangePassword(const std::string &oldpassword,
const std::string &newpassword)
{
Player *player = m_env.getLocalPlayer();
- if(player == NULL)
+ if (player == NULL)
return;
std::string playername = player->getName();
- std::string oldpwd = translatePassword(playername, oldpassword);
- std::string newpwd = translatePassword(playername, newpassword);
+ if (m_proto_ver >= 25) {
+ // get into sudo mode and then send new password to server
+ m_password = oldpassword;
+ m_new_password = newpassword;
+ startAuth(choseAuthMech(m_sudo_auth_methods));
+ } else {
+ std::string oldpwd = translatePassword(playername, oldpassword);
+ std::string newpwd = translatePassword(playername, newpassword);
- NetworkPacket pkt(TOSERVER_PASSWORD_LEGACY, 2 * PASSWORD_SIZE);
+ NetworkPacket pkt(TOSERVER_PASSWORD_LEGACY, 2 * PASSWORD_SIZE);
- for(u8 i = 0; i < PASSWORD_SIZE; i++) {
- pkt << (u8) (i < oldpwd.length() ? oldpwd[i] : 0);
- }
+ for (u8 i = 0; i < PASSWORD_SIZE; i++) {
+ pkt << (u8) (i < oldpwd.length() ? oldpwd[i] : 0);
+ }
- for(u8 i = 0; i < PASSWORD_SIZE; i++) {
- pkt << (u8) (i < newpwd.length() ? newpwd[i] : 0);
+ for (u8 i = 0; i < PASSWORD_SIZE; i++) {
+ pkt << (u8) (i < newpwd.length() ? newpwd[i] : 0);
+ }
+ Send(&pkt);
}
-
- Send(&pkt);
}
View
@@ -351,6 +351,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
void handleCommand_Deprecated(NetworkPacket* pkt);
void handleCommand_Hello(NetworkPacket* pkt);
void handleCommand_AuthAccept(NetworkPacket* pkt);
+ void handleCommand_AcceptSudoMode(NetworkPacket* pkt);
+ void handleCommand_DenySudoMode(NetworkPacket* pkt);
void handleCommand_InitLegacy(NetworkPacket* pkt);
void handleCommand_AccessDenied(NetworkPacket* pkt);
void handleCommand_RemoveNode(NetworkPacket* pkt);
@@ -391,6 +393,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
void handleCommand_OverrideDayNightRatio(NetworkPacket* pkt);
void handleCommand_LocalPlayerAnimations(NetworkPacket* pkt);
void handleCommand_EyeOffset(NetworkPacket* pkt);
+ void handleCommand_SrpBytesSandB(NetworkPacket* pkt);
void ProcessData(NetworkPacket *pkt);
@@ -542,11 +545,21 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
// Send the item number 'item' as player item to the server
void sendPlayerItem(u16 item);
+ void deleteAuthData();
+ // helper method shared with clientpackethandler
+ static AuthMechanism choseAuthMech(const u32 mechs);
+
void sendLegacyInit(const char* playerName, const char* playerPassword);
+ void sendInit(const std::string &playerName);
+ void startAuth(AuthMechanism chosen_auth_mechanism);
void sendDeletedBlocks(std::vector<v3s16> &blocks);
void sendGotBlocks(v3s16 block);
void sendRemovedSounds(std::vector<s32> &soundList);
+ // Helper function
+ inline std::string getPlayerName()
+ { return m_env.getLocalPlayer()->getName(); }
+
float m_packetcounter_timer;
float m_connection_reinit_timer;
float m_avg_rtt_timer;
@@ -569,6 +582,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
IrrlichtDevice *m_device;
// Server serialization version
u8 m_server_ser_ver;
+ // Used version of the protocol with server
+ u8 m_proto_ver;
u16 m_playeritem;
bool m_inventory_updated;
Inventory *m_inventory_from_server;
@@ -584,9 +599,23 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
//s32 m_daynight_i;
//u32 m_daynight_ratio;
std::queue<std::wstring> m_chat_queue;
+
+ // The authentication methods we can use to enter sudo mode (=change password)
+ u32 m_sudo_auth_methods;
+
// The seed returned by the server in TOCLIENT_INIT is stored here
u64 m_map_seed;
+
+ // Auth data
+ std::string m_playername;
std::string m_password;
+ // If set, this will be sent (and cleared) upon a TOCLIENT_ACCEPT_SUDO_MODE
+ std::string m_new_password;
+ // Usable by auth mechanisms.
+ AuthMechanism m_chosen_auth_mech;
+ void * m_auth_data;
+
+
bool m_access_denied;
std::string m_access_denied_reason;
std::queue<ClientEvent> m_client_event_queue;
@@ -392,7 +392,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
else
playername = menudata.name;
- password = translatePassword(playername, menudata.password);
+ password = menudata.password;
g_settings->set("name", playername);
View
@@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "emerge.h"
#include "serverobject.h" // TODO this is used for cleanup of only
#include "log.h"
+#include "util/srp.h"
const char *ClientInterface::statenames[] = {
"Invalid",
@@ -427,10 +428,12 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
//intentionally do nothing
break;
case CS_Created:
- switch(event)
- {
- case CSE_Init:
- m_state = CS_InitSent;
+ switch (event) {
+ case CSE_Hello:
+ m_state = CS_HelloSent;
+ break;
+ case CSE_InitLegacy:
+ m_state = CS_AwaitingInit2;
break;
case CSE_Disconnect:
m_state = CS_Disconnecting;
@@ -447,7 +450,32 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
case CS_Denied:
/* don't do anything if in denied state */
break;
- case CS_InitSent:
+ case CS_HelloSent:
+ switch(event)
+ {
+ case CSE_AuthAccept:
+ m_state = CS_AwaitingInit2;
+ if ((chosen_mech == AUTH_MECHANISM_SRP)
+ || (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
+ srp_verifier_delete((SRPVerifier *) auth_data);
+ chosen_mech = AUTH_MECHANISM_NONE;
+ break;
+ case CSE_Disconnect:
+ m_state = CS_Disconnecting;
+ break;
+ case CSE_SetDenied:
+ m_state = CS_Denied;
+ if ((chosen_mech == AUTH_MECHANISM_SRP)
+ || (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
+ srp_verifier_delete((SRPVerifier *) auth_data);
+ chosen_mech = AUTH_MECHANISM_NONE;
+ break;
+ default:
+ myerror << "HelloSent: Invalid client state transition! " << event;
+ throw ClientStateError(myerror.str());
+ }
+ break;
+ case CS_AwaitingInit2:
switch(event)
{
case CSE_GotInit2:
@@ -514,13 +542,38 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
case CSE_Disconnect:
m_state = CS_Disconnecting;
break;
+ case CSE_SudoSuccess:
+ m_state = CS_SudoMode;
+ if ((chosen_mech == AUTH_MECHANISM_SRP)
+ || (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
+ srp_verifier_delete((SRPVerifier *) auth_data);
+ chosen_mech = AUTH_MECHANISM_NONE;
+ break;
/* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
default:
myerror << "Active: Invalid client state transition! " << event;
throw ClientStateError(myerror.str());
break;
}
break;
+ case CS_SudoMode:
+ switch(event)
+ {
+ case CSE_SetDenied:
+ m_state = CS_Denied;
+ break;
+ case CSE_Disconnect:
+ m_state = CS_Disconnecting;
+ break;
+ case CSE_SudoLeave:
+ m_state = CS_Active;
+ break;
+ default:
+ myerror << "Active: Invalid client state transition! " << event;
+ throw ClientStateError(myerror.str());
+ break;
+ }
+ break;
case CS_Disconnecting:
/* we are already disconnecting */
break;
Oops, something went wrong.

0 comments on commit 82e35ed

Please sign in to comment.