From af2259db5f75c991fb68d64dd04e6932bd4298e8 Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Tue, 3 Dec 2019 12:32:19 -0700 Subject: [PATCH] Move lokid key API request to KeyManager --- llarp/config/key_manager.cpp | 143 +++++++++++++++++++++++++++++++++-- llarp/config/key_manager.hpp | 16 +++- llarp/router/router.cpp | 143 ++--------------------------------- llarp/router/router.hpp | 4 - 4 files changed, 155 insertions(+), 151 deletions(-) diff --git a/llarp/config/key_manager.cpp b/llarp/config/key_manager.cpp index df686f0dd..803a7eedb 100644 --- a/llarp/config/key_manager.cpp +++ b/llarp/config/key_manager.cpp @@ -6,6 +6,19 @@ #include "crypto/crypto.hpp" #include "crypto/types.hpp" +#ifndef _WIN32 +#include +#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 { KeyManager::KeyManager() @@ -14,7 +27,7 @@ namespace llarp } bool - KeyManager::initializeFromDisk(const llarp::Config& config, bool genIfAbsent) + KeyManager::initialize(const llarp::Config& config, bool genIfAbsent) { if (m_initialized) return false; @@ -24,6 +37,12 @@ namespace llarp m_encKeyPath = config.router.encryptionKeyfile(); 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; bool exists = rc.Read(m_rcPath.c_str()); if (not exists and not genIfAbsent) @@ -56,14 +75,22 @@ namespace llarp } } - // load identity key or create if needed - auto identityKeygen = [](llarp::SecretKey& key) + if (not m_usingLokid) { - // TODO: handle generating from service node seed - llarp::CryptoManager::instance()->identity_keygen(key); - }; - if (not loadOrCreateKey(m_idKeyPath, m_idKey, identityKeygen)) - return false; + // load identity key or create if needed + auto identityKeygen = [](llarp::SecretKey& key) + { + // TODO: handle generating from service node seed + 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 auto encryptionKeygen = [](llarp::SecretKey& key) @@ -202,4 +229,104 @@ namespace llarp 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 diff --git a/llarp/config/key_manager.hpp b/llarp/config/key_manager.hpp index c6457eb28..d333358ed 100644 --- a/llarp/config/key_manager.hpp +++ b/llarp/config/key_manager.hpp @@ -24,17 +24,18 @@ namespace llarp /// Constructor KeyManager(); - /// Initializes from disk. This reads enough from disk to understand the current - /// state of the stored keys. + /// Initializes keys using the provided config, loading from disk and/or lokid + /// via HTTP request. /// /// NOTE: Must be called prior to obtaining any keys. + /// NOTE: blocks on I/O /// /// @param config should be a prepared config object /// @param genIfAbsent determines whether or not we will create files if they /// do not exist. /// @return true on success, false otherwise bool - initializeFromDisk(const llarp::Config& config, bool genIfAbsent); + initialize(const llarp::Config& config, bool genIfAbsent); /// Obtain the identity key (e.g. ~/.lokinet/identity.private) /// @@ -69,6 +70,11 @@ namespace llarp std::string m_transportKeyPath; 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::SecretKey m_idKey; llarp::SecretKey m_encKey; @@ -86,6 +92,10 @@ namespace llarp const std::string& filepath, llarp::SecretKey& key, std::function keygen); + + /// Requests the identity key from lokid via HTTP (curl) + bool + loadIdentityFromLokid(); }; } // namespace llarp diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 4bdad12cb..c6a9ee175 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -31,26 +31,8 @@ #include #if defined(ANDROID) || defined(IOS) #include -#else -#if defined(_WIN32) -#else -#include -#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 { Router::Router(std::shared_ptr< llarp::thread::ThreadPool > _tp, @@ -210,27 +192,10 @@ namespace llarp 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 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 defined(ANDROID) || defined(IOS) @@ -240,111 +205,17 @@ namespace llarp #if defined(_WIN32) LogError("running a service node on windows is not possible."); 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 } - if(usingSNSeed) - { - LogError("FIXME: load identity key from SNode seed"); + _identity = m_keyManager->getIdentityKey(); + _encryption = m_keyManager->getEncryptionKey(); + + if (_identity.IsZero()) + return false; + if (_encryption.IsZero()) return false; - } return true; } @@ -366,7 +237,7 @@ namespace llarp if(!InitOutboundLinks()) return false; - if (not m_keyManager->initializeFromDisk(*conf, true)) + if (not m_keyManager->initialize(*conf, true)) return false; return EnsureIdentity(); diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index 1fc8e59bd..1bdddb9b3 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -46,10 +46,6 @@ namespace llarp struct Config; } // namespace llarp -bool -llarp_loadServiceNodeIdentityKey(const fs::path &fpath, - llarp::SecretKey &secretkey); - namespace llarp { struct Router final : public AbstractRouter