mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2026-08-29 01:08:53 +00:00
i2pcontrol: harden authentication logic
This commit is contained in:
+33
-6
@@ -11,6 +11,8 @@
|
||||
#include <iomanip>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
// Use global placeholders from boost introduced when local_time.hpp is loaded
|
||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||
@@ -18,6 +20,7 @@
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "FS.h"
|
||||
#include "Base.h"
|
||||
#include "Log.h"
|
||||
#include "Config.h"
|
||||
#include "NetDb.hpp"
|
||||
@@ -278,7 +281,7 @@ namespace client
|
||||
{
|
||||
auto params = pt.get_child ("params");
|
||||
if (method != "Authenticate" &&
|
||||
!m_Tokens.count (params.get<std::string> ("Token", "")))
|
||||
!IsValidToken (params.get<std::string> ("Token", "")))
|
||||
{
|
||||
LogPrint (eLogWarning, "I2PControl: Invalid or missing token for method ", method);
|
||||
response << "{\"id\":null,\"error\":";
|
||||
@@ -352,18 +355,42 @@ namespace client
|
||||
{
|
||||
int api = params.get<int> ("API");
|
||||
auto password = params.get<std::string> ("Password");
|
||||
LogPrint (eLogDebug, "I2PControl: Authenticate API=", api, " Password=", password);
|
||||
if (password != m_Password) {
|
||||
LogPrint (eLogError, "I2PControl: Authenticate - Invalid password: ", password);
|
||||
LogPrint (eLogDebug, "I2PControl: Authenticate API=", api);
|
||||
bool isValid = password.size () == m_Password.size () &&
|
||||
CRYPTO_memcmp (password.data (), m_Password.data (), m_Password.size ()) == 0;
|
||||
if (!isValid) {
|
||||
LogPrint (eLogError, "I2PControl: Authenticate - Invalid password");
|
||||
return;
|
||||
}
|
||||
InsertParam (results, "API", api);
|
||||
results << ",";
|
||||
std::string token = boost::lexical_cast<std::string>(i2p::util::GetSecondsSinceEpoch ());
|
||||
m_Tokens.insert (token);
|
||||
uint8_t tokenBytes[32];
|
||||
RAND_bytes (tokenBytes, 32);
|
||||
std::string token = i2p::data::ByteStreamToBase64 (tokenBytes, 32);
|
||||
m_Tokens[token] = i2p::util::GetSecondsSinceEpoch () + I2P_CONTROL_TOKEN_LIFETIME;
|
||||
InsertParam (results, "Token", token);
|
||||
}
|
||||
|
||||
bool I2PControlService::IsValidToken (const std::string& token)
|
||||
{
|
||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
for (auto it = m_Tokens.begin (); it != m_Tokens.end ();)
|
||||
{
|
||||
if (ts > it->second)
|
||||
it = m_Tokens.erase (it); // expired
|
||||
else
|
||||
++it;
|
||||
}
|
||||
bool found = false;
|
||||
for (const auto& it: m_Tokens)
|
||||
{
|
||||
if (it.first.size () == token.size () &&
|
||||
CRYPTO_memcmp (it.first.data (), token.data (), token.size ()) == 0)
|
||||
found = true; // don't short-circuit; keep timing independent of match position
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
void I2PControlService::EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||
{
|
||||
auto echo = params.get<std::string> ("Echo");
|
||||
|
||||
+3
-1
@@ -29,6 +29,7 @@ namespace client
|
||||
const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024;
|
||||
typedef std::array<char, I2P_CONTROL_MAX_REQUEST_SIZE> I2PControlBuffer;
|
||||
|
||||
const uint64_t I2P_CONTROL_TOKEN_LIFETIME = 60*60; // 1 hour, in seconds
|
||||
const long I2P_CONTROL_CERTIFICATE_VALIDITY = 365*10; // 10 years
|
||||
const char I2P_CONTROL_CERTIFICATE_COMMON_NAME[] = "i2pd.i2pcontrol";
|
||||
const char I2P_CONTROL_CERTIFICATE_ORGANIZATION[] = "Purple I2P";
|
||||
@@ -95,7 +96,8 @@ namespace client
|
||||
#endif
|
||||
boost::asio::ssl::context m_SSLContext;
|
||||
boost::asio::steady_timer m_ShutdownTimer;
|
||||
std::set<std::string> m_Tokens;
|
||||
std::map<std::string, uint64_t> m_Tokens; // token -> expiration time in seconds since epoch
|
||||
bool IsValidToken (const std::string& token);
|
||||
|
||||
std::map<std::string, MethodHandler> m_MethodHandlers;
|
||||
std::map<std::string, I2PControlRequestHandler> m_I2PControlHandlers;
|
||||
|
||||
Reference in New Issue
Block a user