Move lokid key API request to KeyManager

pull/937/head
Stephen Shelton 5 years ago
parent 49e248bfc1
commit af2259db5f

@ -6,6 +6,19 @@
#include "crypto/crypto.hpp" #include "crypto/crypto.hpp"
#include "crypto/types.hpp" #include "crypto/types.hpp"
#ifndef _WIN32
#include <curl/curl.h>
#endif
/// curl callback
static size_t
curl_RecvIdentKey(char *ptr, size_t, size_t nmemb, void *userdata)
{
for(size_t idx = 0; idx < nmemb; idx++)
static_cast< std::vector< char > * >(userdata)->push_back(ptr[idx]);
return nmemb;
}
namespace llarp namespace llarp
{ {
KeyManager::KeyManager() KeyManager::KeyManager()
@ -14,7 +27,7 @@ namespace llarp
} }
bool bool
KeyManager::initializeFromDisk(const llarp::Config& config, bool genIfAbsent) KeyManager::initialize(const llarp::Config& config, bool genIfAbsent)
{ {
if (m_initialized) if (m_initialized)
return false; return false;
@ -24,6 +37,12 @@ namespace llarp
m_encKeyPath = config.router.encryptionKeyfile(); m_encKeyPath = config.router.encryptionKeyfile();
m_transportKeyPath = config.router.transportKeyfile(); m_transportKeyPath = config.router.transportKeyfile();
m_usingLokid = config.lokid.whitelistRouters;
m_lokidRPCAddr = config.lokid.lokidRPCAddr;
m_lokidRPCUser = config.lokid.lokidRPCUser;
m_lokidRPCPassword = config.lokid.lokidRPCPassword;
RouterContact rc; RouterContact rc;
bool exists = rc.Read(m_rcPath.c_str()); bool exists = rc.Read(m_rcPath.c_str());
if (not exists and not genIfAbsent) if (not exists and not genIfAbsent)
@ -56,14 +75,22 @@ namespace llarp
} }
} }
// load identity key or create if needed if (not m_usingLokid)
auto identityKeygen = [](llarp::SecretKey& key)
{ {
// TODO: handle generating from service node seed // load identity key or create if needed
llarp::CryptoManager::instance()->identity_keygen(key); auto identityKeygen = [](llarp::SecretKey& key)
}; {
if (not loadOrCreateKey(m_idKeyPath, m_idKey, identityKeygen)) // TODO: handle generating from service node seed
return false; llarp::CryptoManager::instance()->identity_keygen(key);
};
if (not loadOrCreateKey(m_idKeyPath, m_idKey, identityKeygen))
return false;
}
else
{
if (not loadIdentityFromLokid())
return false;
}
// load encryption key // load encryption key
auto encryptionKeygen = [](llarp::SecretKey& key) auto encryptionKeygen = [](llarp::SecretKey& key)
@ -202,4 +229,104 @@ namespace llarp
return key.LoadFromFile(filepath.c_str()); return key.LoadFromFile(filepath.c_str());
} }
bool
KeyManager::loadIdentityFromLokid()
{
CURL *curl = curl_easy_init();
if(curl)
{
bool ret = false;
std::stringstream ss;
ss << "http://" << m_lokidRPCAddr << "/json_rpc";
const auto url = ss.str();
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
const auto auth = m_lokidRPCUser + ":" + m_lokidRPCPassword;
curl_easy_setopt(curl, CURLOPT_USERPWD, auth.c_str());
curl_slist *list = nullptr;
list = curl_slist_append(list, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
nlohmann::json request = {{"id", "0"},
{"jsonrpc", "2.0"},
{"method", "get_service_node_privkey"}};
const auto data = request.dump();
std::vector< char > resp;
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_RecvIdentKey);
do
{
resp.clear();
LogInfo("Getting Identity Keys from lokid...");
if(curl_easy_perform(curl) == CURLE_OK)
{
try
{
auto j = nlohmann::json::parse(resp);
if(not j.is_object())
continue;
const auto itr = j.find("result");
if(itr == j.end())
continue;
if(not itr->is_object())
continue;
const auto k =
(*itr)["service_node_ed25519_privkey"].get< std::string >();
if(k.size() != (m_idKey.size() * 2))
{
if(k.empty())
{
LogError("lokid gave no identity key");
}
else
{
LogError("lokid gave invalid identity key");
}
return false;
}
if(not HexDecode(k.c_str(), m_idKey.data(), m_idKey.size()))
continue;
if(CryptoManager::instance()->check_identity_privkey(m_idKey))
{
ret = true;
}
else
{
LogError("lokid gave bogus identity key");
}
}
catch(nlohmann::json::exception &ex)
{
LogError("Bad response from lokid: ", ex.what());
}
}
else
{
LogError("failed to get identity keys");
}
if(ret)
{
LogInfo("Got Identity Keys from lokid: ", RouterID(seckey_topublic(m_idKey)));
break;
}
else
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
} while(true);
curl_easy_cleanup(curl);
curl_slist_free_all(list);
return ret;
}
else
{
LogError("failed to init curl");
return false;
}
}
} // namespace llarp } // namespace llarp

@ -24,17 +24,18 @@ namespace llarp
/// Constructor /// Constructor
KeyManager(); KeyManager();
/// Initializes from disk. This reads enough from disk to understand the current /// Initializes keys using the provided config, loading from disk and/or lokid
/// state of the stored keys. /// via HTTP request.
/// ///
/// NOTE: Must be called prior to obtaining any keys. /// NOTE: Must be called prior to obtaining any keys.
/// NOTE: blocks on I/O
/// ///
/// @param config should be a prepared config object /// @param config should be a prepared config object
/// @param genIfAbsent determines whether or not we will create files if they /// @param genIfAbsent determines whether or not we will create files if they
/// do not exist. /// do not exist.
/// @return true on success, false otherwise /// @return true on success, false otherwise
bool bool
initializeFromDisk(const llarp::Config& config, bool genIfAbsent); initialize(const llarp::Config& config, bool genIfAbsent);
/// Obtain the identity key (e.g. ~/.lokinet/identity.private) /// Obtain the identity key (e.g. ~/.lokinet/identity.private)
/// ///
@ -69,6 +70,11 @@ namespace llarp
std::string m_transportKeyPath; std::string m_transportKeyPath;
std::atomic_bool m_initialized; std::atomic_bool m_initialized;
bool m_usingLokid = false;
std::string m_lokidRPCAddr = "127.0.0.1:22023";
std::string m_lokidRPCUser;
std::string m_lokidRPCPassword;
llarp::RouterContact m_rc; llarp::RouterContact m_rc;
llarp::SecretKey m_idKey; llarp::SecretKey m_idKey;
llarp::SecretKey m_encKey; llarp::SecretKey m_encKey;
@ -86,6 +92,10 @@ namespace llarp
const std::string& filepath, const std::string& filepath,
llarp::SecretKey& key, llarp::SecretKey& key,
std::function<void(llarp::SecretKey& key)> keygen); std::function<void(llarp::SecretKey& key)> keygen);
/// Requests the identity key from lokid via HTTP (curl)
bool
loadIdentityFromLokid();
}; };
} // namespace llarp } // namespace llarp

@ -31,26 +31,8 @@
#include <utility> #include <utility>
#if defined(ANDROID) || defined(IOS) #if defined(ANDROID) || defined(IOS)
#include <unistd.h> #include <unistd.h>
#else
#if defined(_WIN32)
#else
#include <curl/curl.h>
#endif
#endif #endif
bool
llarp_loadServiceNodeIdentityKey(const fs::path &fpath,
llarp::SecretKey &secret)
{
std::string path = fpath.string();
llarp::IdentitySecret ident;
if(!ident.LoadFromFile(path.c_str()))
return false;
return llarp::CryptoManager::instance()->seed_to_secretkey(secret, ident);
}
namespace llarp namespace llarp
{ {
Router::Router(std::shared_ptr< llarp::thread::ThreadPool > _tp, Router::Router(std::shared_ptr< llarp::thread::ThreadPool > _tp,
@ -210,27 +192,10 @@ namespace llarp
LogError(rcfile, " contains invalid RC"); LogError(rcfile, " contains invalid RC");
} }
static size_t
RecvIdentKey(char *ptr, size_t, size_t nmemb, void *userdata)
{
for(size_t idx = 0; idx < nmemb; idx++)
static_cast< std::vector< char > * >(userdata)->push_back(ptr[idx]);
return nmemb;
}
bool bool
Router::EnsureIdentity() Router::EnsureIdentity()
{ {
// TODO: handle loading SN identity instead
_identity = m_keyManager->getIdentityKey();
_encryption = m_keyManager->getEncryptionKey();
if (_identity.IsZero())
return false;
if (_encryption.IsZero())
return false;
if(whitelistRouters) if(whitelistRouters)
{ {
#if defined(ANDROID) || defined(IOS) #if defined(ANDROID) || defined(IOS)
@ -240,111 +205,17 @@ namespace llarp
#if defined(_WIN32) #if defined(_WIN32)
LogError("running a service node on windows is not possible."); LogError("running a service node on windows is not possible.");
return false; return false;
#else
CURL *curl = curl_easy_init();
if(curl)
{
bool ret = false;
std::stringstream ss;
ss << "http://" << lokidRPCAddr << "/json_rpc";
const auto url = ss.str();
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
const auto auth = lokidRPCUser + ":" + lokidRPCPassword;
curl_easy_setopt(curl, CURLOPT_USERPWD, auth.c_str());
curl_slist *list = nullptr;
list = curl_slist_append(list, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
nlohmann::json request = {{"id", "0"},
{"jsonrpc", "2.0"},
{"method", "get_service_node_privkey"}};
const auto data = request.dump();
std::vector< char > resp;
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &RecvIdentKey);
do
{
resp.clear();
LogInfo("Getting Identity Keys from lokid...");
if(curl_easy_perform(curl) == CURLE_OK)
{
try
{
auto j = nlohmann::json::parse(resp);
if(not j.is_object())
continue;
const auto itr = j.find("result");
if(itr == j.end())
continue;
if(not itr->is_object())
continue;
const auto k =
(*itr)["service_node_ed25519_privkey"].get< std::string >();
if(k.size() != (_identity.size() * 2))
{
if(k.empty())
{
LogError("lokid gave no identity key");
}
else
{
LogError("lokid gave invalid identity key");
}
return false;
}
if(not HexDecode(k.c_str(), _identity.data(), _identity.size()))
continue;
if(CryptoManager::instance()->check_identity_privkey(_identity))
{
ret = true;
}
else
{
LogError("lokid gave bogus identity key");
}
}
catch(nlohmann::json::exception &ex)
{
LogError("Bad response from lokid: ", ex.what());
}
}
else
{
LogError("failed to get identity keys");
}
if(ret)
{
LogInfo("Got Identity Keys from lokid: ", RouterID(pubkey()));
break;
}
else
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
} while(true);
curl_easy_cleanup(curl);
curl_slist_free_all(list);
return ret;
}
else
{
LogError("failed to init curl");
return false;
}
#endif #endif
#endif #endif
} }
if(usingSNSeed) _identity = m_keyManager->getIdentityKey();
{ _encryption = m_keyManager->getEncryptionKey();
LogError("FIXME: load identity key from SNode seed");
if (_identity.IsZero())
return false;
if (_encryption.IsZero())
return false; return false;
}
return true; return true;
} }
@ -366,7 +237,7 @@ namespace llarp
if(!InitOutboundLinks()) if(!InitOutboundLinks())
return false; return false;
if (not m_keyManager->initializeFromDisk(*conf, true)) if (not m_keyManager->initialize(*conf, true))
return false; return false;
return EnsureIdentity(); return EnsureIdentity();

@ -46,10 +46,6 @@ namespace llarp
struct Config; struct Config;
} // namespace llarp } // namespace llarp
bool
llarp_loadServiceNodeIdentityKey(const fs::path &fpath,
llarp::SecretKey &secretkey);
namespace llarp namespace llarp
{ {
struct Router final : public AbstractRouter struct Router final : public AbstractRouter

Loading…
Cancel
Save