Merge pull request #945 from notlesh/key_manager_cleanup

Key manager cleanup (post 0.6-rc1)
pull/949/head^2
Stephen Shelton 5 years ago committed by GitHub
commit 68a604070b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -12,51 +12,53 @@
/// curl callback /// curl callback
static size_t static size_t
curl_RecvIdentKey(char *ptr, size_t, size_t nmemb, void *userdata) curl_RecvIdentKey(char* ptr, size_t, size_t nmemb, void* userdata)
{ {
for(size_t idx = 0; idx < nmemb; idx++) for(size_t idx = 0; idx < nmemb; idx++)
static_cast< std::vector< char > * >(userdata)->push_back(ptr[idx]); static_cast< std::vector< char >* >(userdata)->push_back(ptr[idx]);
return nmemb; return nmemb;
} }
namespace llarp namespace llarp
{ {
KeyManager::KeyManager() KeyManager::KeyManager() : m_initialized(false), m_needBackup(false)
: m_initialized(false)
{ {
} }
bool bool
KeyManager::initialize(const llarp::Config& config, bool genIfAbsent) KeyManager::initialize(const llarp::Config& config, bool genIfAbsent)
{ {
if (m_initialized) if(m_initialized)
return false; return false;
m_rcPath = config.router.ourRcFile(); m_rcPath = config.router.ourRcFile();
m_idKeyPath = config.router.identKeyfile(); m_idKeyPath = config.router.identKeyfile();
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_usingLokid = config.lokid.whitelistRouters;
m_lokidRPCAddr = config.lokid.lokidRPCAddr; m_lokidRPCAddr = config.lokid.lokidRPCAddr;
m_lokidRPCUser = config.lokid.lokidRPCUser; m_lokidRPCUser = config.lokid.lokidRPCUser;
m_lokidRPCPassword = config.lokid.lokidRPCPassword; 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)
{ {
LogError("Could not read RouterContact at path ", m_rcPath); LogError("Could not read RouterContact at path ", m_rcPath);
return false; return false;
} }
// we need to back up keys if our self.signed doesn't appear to have a
// valid signature
m_needBackup = (not rc.VerifySignature());
// if our RC file can't be verified, assume it is out of date (e.g. uses // if our RC file can't be verified, assume it is out of date (e.g. uses
// older encryption) and needs to be regenerated. before doing so, backup // older encryption) and needs to be regenerated. before doing so, backup
// files that will be overwritten // files that will be overwritten
if (exists and not rc.VerifySignature()) if(exists and m_needBackup)
{ {
if (! genIfAbsent) if(!genIfAbsent)
{ {
LogError("Our RouterContact ", m_rcPath, " is invalid or out of date"); LogError("Our RouterContact ", m_rcPath, " is invalid or out of date");
return false; return false;
@ -64,126 +66,114 @@ namespace llarp
else else
{ {
LogWarn("Our RouterContact ", m_rcPath, LogWarn("Our RouterContact ", m_rcPath,
" seems out of date, backing up and regenerating private keys"); " seems out of date, backing up and regenerating private keys");
if (! backupKeyFilesByMoving()) if(!backupKeyFilesByMoving())
{ {
LogError("Could not mv some key files, please ensure key files" LogError(
"Could not mv some key files, please ensure key files"
" are backed up if needed and remove"); " are backed up if needed and remove");
return false; return false;
} }
} }
} }
if (not m_usingLokid) if(not m_usingLokid)
{ {
// load identity key or create if needed // load identity key or create if needed
auto identityKeygen = [](llarp::SecretKey& key) auto identityKeygen = [](llarp::SecretKey& key) {
{
// TODO: handle generating from service node seed // TODO: handle generating from service node seed
llarp::CryptoManager::instance()->identity_keygen(key); llarp::CryptoManager::instance()->identity_keygen(key);
}; };
if (not loadOrCreateKey(m_idKeyPath, m_idKey, identityKeygen)) if(not loadOrCreateKey(m_idKeyPath, identityKey, identityKeygen))
return false; return false;
} }
else else
{ {
if (not loadIdentityFromLokid()) if(not loadIdentityFromLokid())
return false; return false;
} }
// load encryption key // load encryption key
auto encryptionKeygen = [](llarp::SecretKey& key) auto encryptionKeygen = [](llarp::SecretKey& key) {
{
llarp::CryptoManager::instance()->encryption_keygen(key); llarp::CryptoManager::instance()->encryption_keygen(key);
}; };
if (not loadOrCreateKey(m_encKeyPath, m_encKey, encryptionKeygen)) if(not loadOrCreateKey(m_encKeyPath, encryptionKey, encryptionKeygen))
return false; return false;
// TODO: transport key (currently done in LinkLayer) // TODO: transport key (currently done in LinkLayer)
auto transportKeygen = [](llarp::SecretKey& key) auto transportKeygen = [](llarp::SecretKey& key) {
{
key.Zero(); key.Zero();
CryptoManager::instance()->encryption_keygen(key); CryptoManager::instance()->encryption_keygen(key);
}; };
if (not loadOrCreateKey(m_transportKeyPath, m_transportKey, transportKeygen)) if(not loadOrCreateKey(m_transportKeyPath, transportKey, transportKeygen))
return false; return false;
m_initialized = true; m_initialized = true;
return true; return true;
} }
const llarp::SecretKey&
KeyManager::getIdentityKey() const
{
return m_idKey;
}
const llarp::SecretKey&
KeyManager::getEncryptionKey() const
{
return m_encKey;
}
const llarp::SecretKey&
KeyManager::getTransportKey() const
{
return m_transportKey;
}
bool bool
KeyManager::backupKeyFilesByMoving() const KeyManager::backupFileByMoving(const std::string& filepath)
{ {
auto findFreeBackupFilename = [](const fs::path& filepath) { auto findFreeBackupFilename = [](const fs::path& filepath) {
for (int i=0; i<9; i++) for(int i = 0; i < 9; i++)
{ {
std::string ext("." + std::to_string(i) + ".bak"); std::string ext("." + std::to_string(i) + ".bak");
fs::path newPath = filepath; fs::path newPath = filepath;
newPath += ext; newPath += ext;
if (not fs::exists(newPath)) if(not fs::exists(newPath))
return newPath; return newPath;
} }
return fs::path(); return fs::path();
}; };
std::vector<std::string> files = { std::error_code ec;
m_rcPath, bool exists = fs::exists(filepath, ec);
m_idKeyPath, if(ec)
m_encKeyPath, {
m_transportKeyPath LogError("Could not determine status of file ", filepath, ": ",
}; ec.message());
return false;
}
for (auto& filepath : files) if(not exists)
{ {
std::error_code ec; LogInfo("File ", filepath, " doesn't exist; no backup needed");
bool exists = fs::exists(filepath, ec); return true;
if (ec) }
{
LogError("Could not determine status of file ", filepath, ": ", ec.message());
return false;
}
if (not exists) fs::path newFilepath = findFreeBackupFilename(filepath);
{ if(newFilepath.empty())
LogInfo("File ", filepath, " doesn't exist; no backup needed"); {
continue; LogWarn("Could not find an appropriate backup filename for", filepath);
} return false;
}
fs::path newFilepath = findFreeBackupFilename(filepath); LogInfo("Backing up (moving) key file ", filepath, " to ", newFilepath,
if (newFilepath.empty()) "...");
{
LogWarn("Could not find an appropriate backup filename for", filepath); fs::rename(filepath, newFilepath, ec);
return false; if(ec)
} {
LogError("Failed to move key file ", ec.message());
return false;
}
LogInfo("Backing up (moving) key file ", filepath, " to ", newFilepath, "..."); return true;
}
fs::rename(filepath, newFilepath, ec); bool
if (ec) { KeyManager::backupKeyFilesByMoving() const
LogError("Failed to move key file ", ec.message()); {
std::vector< std::string > files = {m_rcPath, m_idKeyPath, m_encKeyPath,
m_transportKeyPath};
for(auto& filepath : files)
{
if(not backupFileByMoving(filepath))
return false; return false;
}
} }
return true; return true;
@ -191,15 +181,14 @@ namespace llarp
bool bool
KeyManager::loadOrCreateKey( KeyManager::loadOrCreateKey(
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)
{ {
fs::path path(filepath); fs::path path(filepath);
std::error_code ec; std::error_code ec;
if (! fs::exists(path, ec)) if(!fs::exists(path, ec))
{ {
if (ec) if(ec)
{ {
LogError("Error checking key", filepath, ec.message()); LogError("Error checking key", filepath, ec.message());
return false; return false;
@ -208,7 +197,7 @@ namespace llarp
LogInfo("Generating new key", filepath); LogInfo("Generating new key", filepath);
keygen(key); keygen(key);
if (! key.SaveToFile(filepath.c_str())) if(!key.SaveToFile(filepath.c_str()))
{ {
LogError("Failed to save new key"); LogError("Failed to save new key");
return false; return false;
@ -222,7 +211,7 @@ namespace llarp
bool bool
KeyManager::loadIdentityFromLokid() KeyManager::loadIdentityFromLokid()
{ {
CURL *curl = curl_easy_init(); CURL* curl = curl_easy_init();
if(curl) if(curl)
{ {
bool ret = false; bool ret = false;
@ -233,7 +222,7 @@ namespace llarp
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY); curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
const auto auth = m_lokidRPCUser + ":" + m_lokidRPCPassword; const auto auth = m_lokidRPCUser + ":" + m_lokidRPCPassword;
curl_easy_setopt(curl, CURLOPT_USERPWD, auth.c_str()); curl_easy_setopt(curl, CURLOPT_USERPWD, auth.c_str());
curl_slist *list = nullptr; curl_slist* list = nullptr;
list = curl_slist_append(list, "Content-Type: application/json"); list = curl_slist_append(list, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
@ -266,7 +255,7 @@ namespace llarp
continue; continue;
const auto k = const auto k =
(*itr)["service_node_ed25519_privkey"].get< std::string >(); (*itr)["service_node_ed25519_privkey"].get< std::string >();
if(k.size() != (m_idKey.size() * 2)) if(k.size() != (identityKey.size() * 2))
{ {
if(k.empty()) if(k.empty())
{ {
@ -278,9 +267,9 @@ namespace llarp
} }
return false; return false;
} }
if(not HexDecode(k.c_str(), m_idKey.data(), m_idKey.size())) if(not HexDecode(k.c_str(), identityKey.data(), identityKey.size()))
continue; continue;
if(CryptoManager::instance()->check_identity_privkey(m_idKey)) if(CryptoManager::instance()->check_identity_privkey(identityKey))
{ {
ret = true; ret = true;
} }
@ -289,7 +278,7 @@ namespace llarp
LogError("lokid gave bogus identity key"); LogError("lokid gave bogus identity key");
} }
} }
catch(nlohmann::json::exception &ex) catch(nlohmann::json::exception& ex)
{ {
LogError("Bad response from lokid: ", ex.what()); LogError("Bad response from lokid: ", ex.what());
} }
@ -300,7 +289,8 @@ namespace llarp
} }
if(ret) if(ret)
{ {
LogInfo("Got Identity Keys from lokid: ", RouterID(seckey_topublic(m_idKey))); LogInfo("Got Identity Keys from lokid: ",
RouterID(seckey_topublic(identityKey)));
break; break;
} }
else else

@ -8,53 +8,46 @@
namespace llarp namespace llarp
{ {
/// KeyManager manages the cryptographic keys stored on disk for the local
/// KeyManager manages the cryptographic keys stored on disk for the local node. /// node. This includes private keys as well as the self-signed router contact
/// This includes private keys as well as the self-signed router contact file /// file (e.g. "self.signed").
/// (e.g. "self.signed").
/// ///
/// Keys are either read from disk if they exist and are valid (see below) or are /// Keys are either read from disk if they exist and are valid (see below) or
/// generated and written to disk. /// are generated and written to disk.
/// ///
/// In addition, the KeyManager detects when the keys obsolete (e.g. as a result /// In addition, the KeyManager detects when the keys obsolete (e.g. as a
/// of a software upgrade) and backs up existing keys before writing out new ones. /// result of a software upgrade) and backs up existing keys before writing
/// out new ones.
struct KeyManager {
struct KeyManager
{
/// Utility function to backup a file by moving it. Attempts to find a new
/// filename based on the original that doesn't exist, then moves it. The
/// pattern used is originalFile.N.bak where N is the lowest integer
/// matching a filename that doesn't exist.
///
/// @param filepath is the name of the original file to backup.
/// @return true if the file could be moved or didn't exist, false otherwise
static bool
backupFileByMoving(const std::string& filepath);
/// Constructor /// Constructor
KeyManager(); KeyManager();
/// Initializes keys using the provided config, loading from disk and/or lokid /// Initializes keys using the provided config, loading from disk and/or
/// via HTTP request. /// lokid 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 /// 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
initialize(const llarp::Config& config, bool genIfAbsent); initialize(const llarp::Config& config, bool genIfAbsent);
/// Obtain the identity key (e.g. ~/.lokinet/identity.private)
///
/// @return a reference to the identity key
const llarp::SecretKey&
getIdentityKey() const;
/// Obtain the encryption key (e.g. ~/.lokinet/encryption.private)
///
/// @return a reference to the encryption key
const llarp::SecretKey&
getEncryptionKey() const;
/// Obtain the transport key (e.g. ~/.lokinet/transport.private)
///
/// @return a reference to the transport key
const llarp::SecretKey&
getTransportKey() const;
/// Obtain the self-signed RouterContact /// Obtain the self-signed RouterContact
/// ///
/// @param rc (out) will be modified to contian the RouterContact /// @param rc (out) will be modified to contian the RouterContact
@ -62,23 +55,30 @@ namespace llarp
bool bool
getRouterContact(llarp::RouterContact& rc) const; getRouterContact(llarp::RouterContact& rc) const;
private: /// Return whether or not we need to backup keys as we load them
bool
needBackup() const
{
return m_needBackup;
}
llarp::SecretKey identityKey;
llarp::SecretKey encryptionKey;
llarp::SecretKey transportKey;
private:
std::string m_rcPath; std::string m_rcPath;
std::string m_idKeyPath; std::string m_idKeyPath;
std::string m_encKeyPath; std::string m_encKeyPath;
std::string m_transportKeyPath; std::string m_transportKeyPath;
std::atomic_bool m_initialized; std::atomic_bool m_initialized;
std::atomic_bool m_needBackup;
bool m_usingLokid = false; bool m_usingLokid = false;
std::string m_lokidRPCAddr = "127.0.0.1:22023"; std::string m_lokidRPCAddr = "127.0.0.1:22023";
std::string m_lokidRPCUser; std::string m_lokidRPCUser;
std::string m_lokidRPCPassword; std::string m_lokidRPCPassword;
llarp::SecretKey m_idKey;
llarp::SecretKey m_encKey;
llarp::SecretKey m_transportKey;
/// Backup each key file (by copying, e.g. foo -> foo.bak) /// Backup each key file (by copying, e.g. foo -> foo.bak)
bool bool
backupKeyFilesByMoving() const; backupKeyFilesByMoving() const;
@ -87,10 +87,8 @@ namespace llarp
/// ///
/// @param keygen is a function that will generate the key if needed /// @param keygen is a function that will generate the key if needed
static bool static bool
loadOrCreateKey( loadOrCreateKey(const std::string& filepath, llarp::SecretKey& key,
const std::string& filepath, std::function< void(llarp::SecretKey& key) > keygen);
llarp::SecretKey& key,
std::function<void(llarp::SecretKey& key)> keygen);
/// Requests the identity key from lokid via HTTP (curl) /// Requests the identity key from lokid via HTTP (curl)
bool bool

@ -27,7 +27,7 @@ namespace llarp
return false; return false;
if(!BEncodeMaybeVerifyVersion("V", version, LLARP_PROTO_VERSION, read, k, if(!BEncodeMaybeVerifyVersion("V", version, LLARP_PROTO_VERSION, read, k,
val)) val))
return false; return false;
return read; return read;

@ -71,8 +71,8 @@ namespace llarp
return bencode_read_integer(val, &txid); return bencode_read_integer(val, &txid);
} }
bool read = false; bool read = false;
if(!BEncodeMaybeVerifyVersion("V", version, LLARP_PROTO_VERSION, read, key, if(!BEncodeMaybeVerifyVersion("V", version, LLARP_PROTO_VERSION, read,
val)) key, val))
return false; return false;
return read; return read;

@ -143,8 +143,8 @@ tun_ev_loop(void* unused)
while(true) while(true)
{ {
alert = alert = GetQueuedCompletionStatus(tun_event_queue, &size, &listener, &ovl,
GetQueuedCompletionStatus(tun_event_queue, &size, &listener, &ovl, EV_TICK_INTERVAL); EV_TICK_INTERVAL);
if(!alert) if(!alert)
{ {

@ -9,7 +9,7 @@ namespace llarp
namespace iwp namespace iwp
{ {
LinkLayer_ptr LinkLayer_ptr
NewInboundLink(std::shared_ptr<KeyManager> keyManager, GetRCFunc getrc, NewInboundLink(std::shared_ptr< KeyManager > keyManager, GetRCFunc getrc,
LinkMessageHandler h, SignBufferFunc sign, LinkMessageHandler h, SignBufferFunc sign,
SessionEstablishedHandler est, SessionEstablishedHandler est,
SessionRenegotiateHandler reneg, TimeoutHandler timeout, SessionRenegotiateHandler reneg, TimeoutHandler timeout,
@ -21,7 +21,7 @@ namespace llarp
} }
LinkLayer_ptr LinkLayer_ptr
NewOutboundLink(std::shared_ptr<KeyManager> keyManager, GetRCFunc getrc, NewOutboundLink(std::shared_ptr< KeyManager > keyManager, GetRCFunc getrc,
LinkMessageHandler h, SignBufferFunc sign, LinkMessageHandler h, SignBufferFunc sign,
SessionEstablishedHandler est, SessionEstablishedHandler est,
SessionRenegotiateHandler reneg, TimeoutHandler timeout, SessionRenegotiateHandler reneg, TimeoutHandler timeout,

@ -11,13 +11,13 @@ namespace llarp
namespace iwp namespace iwp
{ {
LinkLayer_ptr LinkLayer_ptr
NewInboundLink(std::shared_ptr<KeyManager> keyManager, GetRCFunc getrc, NewInboundLink(std::shared_ptr< KeyManager > keyManager, GetRCFunc getrc,
LinkMessageHandler h, SignBufferFunc sign, LinkMessageHandler h, SignBufferFunc sign,
SessionEstablishedHandler est, SessionEstablishedHandler est,
SessionRenegotiateHandler reneg, TimeoutHandler timeout, SessionRenegotiateHandler reneg, TimeoutHandler timeout,
SessionClosedHandler closed, PumpDoneHandler pumpDone); SessionClosedHandler closed, PumpDoneHandler pumpDone);
LinkLayer_ptr LinkLayer_ptr
NewOutboundLink(std::shared_ptr<KeyManager> keyManager, GetRCFunc getrc, NewOutboundLink(std::shared_ptr< KeyManager > keyManager, GetRCFunc getrc,
LinkMessageHandler h, SignBufferFunc sign, LinkMessageHandler h, SignBufferFunc sign,
SessionEstablishedHandler est, SessionEstablishedHandler est,
SessionRenegotiateHandler reneg, TimeoutHandler timeout, SessionRenegotiateHandler reneg, TimeoutHandler timeout,

@ -8,14 +8,14 @@ namespace llarp
{ {
namespace iwp namespace iwp
{ {
LinkLayer::LinkLayer(std::shared_ptr<KeyManager> keyManager, GetRCFunc getrc, LinkLayer::LinkLayer(std::shared_ptr< KeyManager > keyManager,
LinkMessageHandler h, SignBufferFunc sign, GetRCFunc getrc, LinkMessageHandler h,
SessionEstablishedHandler est, SignBufferFunc sign, SessionEstablishedHandler est,
SessionRenegotiateHandler reneg, SessionRenegotiateHandler reneg,
TimeoutHandler timeout, SessionClosedHandler closed, TimeoutHandler timeout, SessionClosedHandler closed,
PumpDoneHandler pumpDone, bool allowInbound) PumpDoneHandler pumpDone, bool allowInbound)
: ILinkLayer(keyManager, getrc, h, sign, est, reneg, timeout, : ILinkLayer(keyManager, getrc, h, sign, est, reneg, timeout, closed,
closed, pumpDone) pumpDone)
, permitInbound{allowInbound} , permitInbound{allowInbound}
{ {
} }

@ -17,7 +17,7 @@ namespace llarp
{ {
struct LinkLayer final : public ILinkLayer struct LinkLayer final : public ILinkLayer
{ {
LinkLayer(std::shared_ptr<KeyManager> keyManager, GetRCFunc getrc, LinkLayer(std::shared_ptr< KeyManager > keyManager, GetRCFunc getrc,
LinkMessageHandler h, SignBufferFunc sign, LinkMessageHandler h, SignBufferFunc sign,
SessionEstablishedHandler est, SessionRenegotiateHandler reneg, SessionEstablishedHandler est, SessionRenegotiateHandler reneg,
TimeoutHandler timeout, SessionClosedHandler closed, TimeoutHandler timeout, SessionClosedHandler closed,
@ -29,7 +29,6 @@ namespace llarp
NewOutboundSession(const RouterContact &rc, NewOutboundSession(const RouterContact &rc,
const AddressInfo &ai) override; const AddressInfo &ai) override;
const char * const char *
Name() const override; Name() const override;

@ -22,9 +22,9 @@ namespace llarp
}; };
using Factory = std::function< LinkLayer_ptr( using Factory = std::function< LinkLayer_ptr(
std::shared_ptr<KeyManager>, GetRCFunc, LinkMessageHandler, SignBufferFunc, std::shared_ptr< KeyManager >, GetRCFunc, LinkMessageHandler,
SessionEstablishedHandler, SessionRenegotiateHandler, TimeoutHandler, SignBufferFunc, SessionEstablishedHandler, SessionRenegotiateHandler,
SessionClosedHandler, PumpDoneHandler) >; TimeoutHandler, SessionClosedHandler, PumpDoneHandler) >;
/// get link type by name string /// get link type by name string
/// if invalid returns eLinkUnspec /// if invalid returns eLinkUnspec

@ -26,8 +26,8 @@ namespace llarp
, SessionClosed(std::move(closed)) , SessionClosed(std::move(closed))
, SessionRenegotiate(std::move(reneg)) , SessionRenegotiate(std::move(reneg))
, PumpDone(std::move(pumpDone)) , PumpDone(std::move(pumpDone))
, m_RouterEncSecret(keyManager->getEncryptionKey()) , m_RouterEncSecret(keyManager->encryptionKey)
, m_SecretKey(keyManager->getTransportKey()) , m_SecretKey(keyManager->transportKey)
{ {
} }

@ -42,7 +42,7 @@ namespace llarp
if(!BEncodeMaybeReadDictEntry("p", pathid, read, key, buf)) if(!BEncodeMaybeReadDictEntry("p", pathid, read, key, buf))
return false; return false;
if(!BEncodeMaybeVerifyVersion("v", version, LLARP_PROTO_VERSION, read, key, if(!BEncodeMaybeVerifyVersion("v", version, LLARP_PROTO_VERSION, read, key,
buf)) buf))
return false; return false;
if(!BEncodeMaybeReadDictEntry("x", X, read, key, buf)) if(!BEncodeMaybeReadDictEntry("x", X, read, key, buf))
return false; return false;
@ -98,7 +98,7 @@ namespace llarp
if(!BEncodeMaybeReadDictEntry("p", pathid, read, key, buf)) if(!BEncodeMaybeReadDictEntry("p", pathid, read, key, buf))
return false; return false;
if(!BEncodeMaybeVerifyVersion("v", version, LLARP_PROTO_VERSION, read, key, if(!BEncodeMaybeVerifyVersion("v", version, LLARP_PROTO_VERSION, read, key,
buf)) buf))
return false; return false;
if(!BEncodeMaybeReadDictEntry("x", X, read, key, buf)) if(!BEncodeMaybeReadDictEntry("x", X, read, key, buf))
return false; return false;

@ -27,7 +27,7 @@ namespace llarp
} }
bool read = false; bool read = false;
if(!BEncodeMaybeVerifyVersion("v", version, LLARP_PROTO_VERSION, read, key, if(!BEncodeMaybeVerifyVersion("v", version, LLARP_PROTO_VERSION, read, key,
buf)) buf))
return false; return false;
return read; return read;
@ -135,7 +135,7 @@ namespace llarp
return nextRC->BDecode(buffer); return nextRC->BDecode(buffer);
} }
if(!BEncodeMaybeVerifyVersion("v", version, LLARP_PROTO_VERSION, read, *key, if(!BEncodeMaybeVerifyVersion("v", version, LLARP_PROTO_VERSION, read, *key,
buffer)) buffer))
return false; return false;
if(*key == "w") if(*key == "w")
{ {

@ -76,8 +76,8 @@ namespace llarp
} }
else if(key == "v") else if(key == "v")
{ {
if(!BEncodeMaybeVerifyVersion("v", version, LLARP_PROTO_VERSION, read, key, if(!BEncodeMaybeVerifyVersion("v", version, LLARP_PROTO_VERSION, read,
buf)) key, buf))
{ {
return false; return false;
} }
@ -263,7 +263,7 @@ namespace llarp
if(!BEncodeMaybeReadDictInt("s", status, read, *key, buffer)) if(!BEncodeMaybeReadDictInt("s", status, read, *key, buffer))
return false; return false;
if(!BEncodeMaybeVerifyVersion("v", version, LLARP_PROTO_VERSION, read, *key, if(!BEncodeMaybeVerifyVersion("v", version, LLARP_PROTO_VERSION, read, *key,
buffer)) buffer))
return false; return false;
return read; return read;

@ -1,6 +1,8 @@
#ifndef LLARP_ABSTRACT_ROUTER_HPP #ifndef LLARP_ABSTRACT_ROUTER_HPP
#define LLARP_ABSTRACT_ROUTER_HPP #define LLARP_ABSTRACT_ROUTER_HPP
#include <config/key_manager.hpp>
#include <memory>
#include <util/types.hpp> #include <util/types.hpp>
#include <util/status.hpp> #include <util/status.hpp>
#include <router/i_outbound_message_handler.hpp> #include <router/i_outbound_message_handler.hpp>
@ -84,6 +86,9 @@ namespace llarp
virtual exit::Context & virtual exit::Context &
exitContext() = 0; exitContext() = 0;
virtual std::shared_ptr< KeyManager >
keyManager() const = 0;
virtual const SecretKey & virtual const SecretKey &
identity() const = 0; identity() const = 0;

@ -49,7 +49,7 @@ namespace llarp
, inbound_link_msg_parser(this) , inbound_link_msg_parser(this)
, _hiddenServiceContext(this) , _hiddenServiceContext(this)
{ {
m_keyManager = std::make_shared<KeyManager>(); m_keyManager = std::make_shared< KeyManager >();
// set rational defaults // set rational defaults
this->ip4addr.sin_family = AF_INET; this->ip4addr.sin_family = AF_INET;
@ -195,7 +195,6 @@ namespace llarp
bool bool
Router::EnsureIdentity() Router::EnsureIdentity()
{ {
if(whitelistRouters) if(whitelistRouters)
{ {
#if defined(ANDROID) || defined(IOS) #if defined(ANDROID) || defined(IOS)
@ -209,12 +208,12 @@ namespace llarp
#endif #endif
} }
_identity = m_keyManager->getIdentityKey(); _identity = m_keyManager->identityKey;
_encryption = m_keyManager->getEncryptionKey(); _encryption = m_keyManager->encryptionKey;
if (_identity.IsZero()) if(_identity.IsZero())
return false; return false;
if (_encryption.IsZero()) if(_encryption.IsZero())
return false; return false;
return true; return true;
@ -231,7 +230,7 @@ namespace llarp
} }
_nodedb = nodedb; _nodedb = nodedb;
if (not m_keyManager->initialize(*conf, true)) if(not m_keyManager->initialize(*conf, true))
return false; return false;
if(!FromConfig(conf)) if(!FromConfig(conf))
@ -524,8 +523,7 @@ namespace llarp
util::memFn(&IOutboundSessionMaker::OnConnectTimeout, util::memFn(&IOutboundSessionMaker::OnConnectTimeout,
&_outboundSessionMaker), &_outboundSessionMaker),
util::memFn(&AbstractRouter::SessionClosed, this), util::memFn(&AbstractRouter::SessionClosed, this),
util::memFn(&AbstractRouter::PumpLL, this) util::memFn(&AbstractRouter::PumpLL, this));
);
const auto &key = std::get< LinksConfig::Interface >(serverConfig); const auto &key = std::get< LinksConfig::Interface >(serverConfig);
int af = std::get< LinksConfig::AddressFamily >(serverConfig); int af = std::get< LinksConfig::AddressFamily >(serverConfig);
@ -1161,8 +1159,7 @@ namespace llarp
util::memFn(&IOutboundSessionMaker::OnConnectTimeout, util::memFn(&IOutboundSessionMaker::OnConnectTimeout,
&_outboundSessionMaker), &_outboundSessionMaker),
util::memFn(&AbstractRouter::SessionClosed, this), util::memFn(&AbstractRouter::SessionClosed, this),
util::memFn(&AbstractRouter::PumpLL, this) util::memFn(&AbstractRouter::PumpLL, this));
);
if(!link) if(!link)
return false; return false;

@ -127,6 +127,12 @@ namespace llarp
return _exitContext; return _exitContext;
} }
std::shared_ptr< KeyManager >
keyManager() const
{
return m_keyManager;
}
const SecretKey & const SecretKey &
identity() const override identity() const override
{ {
@ -461,7 +467,7 @@ namespace llarp
llarp_time_t m_LastStatsReport = 0; llarp_time_t m_LastStatsReport = 0;
std::shared_ptr<llarp::KeyManager> m_keyManager; std::shared_ptr< llarp::KeyManager > m_keyManager;
bool bool
ShouldReportStats(llarp_time_t now) const; ShouldReportStats(llarp_time_t now) const;

@ -453,7 +453,8 @@ namespace llarp
const auto& keyfile = m_state->m_Keyfile; const auto& keyfile = m_state->m_Keyfile;
if(!keyfile.empty()) if(!keyfile.empty())
{ {
if(!m_Identity.EnsureKeys(keyfile)) if(!m_Identity.EnsureKeys(keyfile,
Router()->keyManager()->needBackup()))
{ {
LogError("Can't ensure keyfile [", keyfile, "]"); LogError("Can't ensure keyfile [", keyfile, "]");
return false; return false;

@ -78,13 +78,27 @@ namespace llarp
} }
bool bool
Identity::EnsureKeys(const std::string& fname) Identity::EnsureKeys(const std::string& fname, bool needBackup)
{ {
std::array< byte_t, 4096 > tmp; std::array< byte_t, 4096 > tmp;
llarp_buffer_t buf(tmp); llarp_buffer_t buf(tmp);
std::error_code ec; std::error_code ec;
bool exists = fs::exists(fname, ec);
if(ec)
{
LogError("Could not query file status for ", fname);
return false;
}
if(exists and needBackup)
{
KeyManager::backupFileByMoving(fname);
exists = false;
}
// check for file // check for file
if(!fs::exists(fname, ec)) if(!exists)
{ {
// regen and encode // regen and encode
RegenerateKeys(); RegenerateKeys();

@ -1,8 +1,10 @@
#ifndef LLARP_SERVICE_IDENTITY_HPP #ifndef LLARP_SERVICE_IDENTITY_HPP
#define LLARP_SERVICE_IDENTITY_HPP #define LLARP_SERVICE_IDENTITY_HPP
#include <config/key_manager.hpp>
#include <constants/proto.hpp> #include <constants/proto.hpp>
#include <crypto/types.hpp> #include <crypto/types.hpp>
#include <memory>
#include <service/info.hpp> #include <service/info.hpp>
#include <service/intro_set.hpp> #include <service/intro_set.hpp>
#include <service/vanity.hpp> #include <service/vanity.hpp>
@ -33,8 +35,9 @@ namespace llarp
bool bool
BEncode(llarp_buffer_t* buf) const; BEncode(llarp_buffer_t* buf) const;
/// @param needBackup determines whether existing keys will be cycled
bool bool
EnsureKeys(const std::string& fpath); EnsureKeys(const std::string& fpath, bool needBackup);
bool bool
KeyExchange(path_dh_func dh, SharedSecret& sharedkey, KeyExchange(path_dh_func dh, SharedSecret& sharedkey,

@ -163,8 +163,8 @@ namespace llarp
return false; return false;
if(!BEncodeMaybeReadDictEntry("T", T, read, key, val)) if(!BEncodeMaybeReadDictEntry("T", T, read, key, val))
return false; return false;
if(!BEncodeMaybeVerifyVersion("V", version, LLARP_PROTO_VERSION, read, key, if(!BEncodeMaybeVerifyVersion("V", version, LLARP_PROTO_VERSION, read,
val)) key, val))
return false; return false;
if(!BEncodeMaybeReadDictEntry("Z", Z, read, key, val)) if(!BEncodeMaybeReadDictEntry("Z", Z, read, key, val))
return false; return false;

@ -139,9 +139,10 @@ bencode_discard(llarp_buffer_t* buf)
} }
bool bool
bencode_write_uint64_entry(llarp_buffer_t* buff, const void* name, size_t sz, uint64_t i) bencode_write_uint64_entry(llarp_buffer_t* buff, const void* name, size_t sz,
uint64_t i)
{ {
if (! bencode_write_bytestring(buff, name, sz)) if(!bencode_write_bytestring(buff, name, sz))
return false; return false;
return bencode_write_uint64(buff, i); return bencode_write_uint64(buff, i);

@ -31,7 +31,8 @@ bencode_write_uint64(llarp_buffer_t* buff, uint64_t i);
/// Write a dictionary entry with a uint64_t value /// Write a dictionary entry with a uint64_t value
bool bool
bencode_write_uint64_entry(llarp_buffer_t* buff, const void* name, size_t sz, uint64_t i); bencode_write_uint64_entry(llarp_buffer_t* buff, const void* name, size_t sz,
uint64_t i);
bool bool
bencode_start_list(llarp_buffer_t* buff); bencode_start_list(llarp_buffer_t* buff);

@ -104,8 +104,8 @@ namespace llarp
template < typename Item_t > template < typename Item_t >
bool bool
BEncodeMaybeVerifyVersion(const char* k, Item_t& item, uint64_t expect, BEncodeMaybeVerifyVersion(const char* k, Item_t& item, uint64_t expect,
bool& read, const llarp_buffer_t& key, bool& read, const llarp_buffer_t& key,
llarp_buffer_t* buf) llarp_buffer_t* buf)
{ {
if(key == k) if(key == k)
{ {

@ -3,6 +3,7 @@
#include <iwp/iwp.hpp> #include <iwp/iwp.hpp>
#include <llarp_test.hpp> #include <llarp_test.hpp>
#include <iwp/iwp.hpp> #include <iwp/iwp.hpp>
#include <memory>
#include <messages/link_intro.hpp> #include <messages/link_intro.hpp>
#include <messages/discard.hpp> #include <messages/discard.hpp>
@ -17,23 +18,35 @@ using namespace ::testing;
struct LinkLayerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium > struct LinkLayerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium >
{ {
static constexpr uint16_t AlicePort = 5000; static constexpr uint16_t AlicePort = 41163;
static constexpr uint16_t BobPort = 6000; static constexpr uint16_t BobPort = 8088;
struct Context struct Context
{ {
Context() Context()
{ {
keyManager = std::make_shared<KeyManager>();
SecretKey signingKey;
CryptoManager::instance()->identity_keygen(signingKey); CryptoManager::instance()->identity_keygen(signingKey);
keyManager->identityKey = signingKey;
SecretKey encryptionKey;
CryptoManager::instance()->encryption_keygen(encryptionKey); CryptoManager::instance()->encryption_keygen(encryptionKey);
keyManager->encryptionKey = encryptionKey;
SecretKey transportKey;
CryptoManager::instance()->encryption_keygen(transportKey);
keyManager->transportKey = transportKey;
rc.pubkey = signingKey.toPublic(); rc.pubkey = signingKey.toPublic();
rc.enckey = encryptionKey.toPublic(); rc.enckey = encryptionKey.toPublic();
} }
std::shared_ptr<thread::ThreadPool> worker; std::shared_ptr<thread::ThreadPool> worker;
SecretKey signingKey; std::shared_ptr<KeyManager> keyManager;
SecretKey encryptionKey;
RouterContact rc; RouterContact rc;
@ -64,15 +77,6 @@ struct LinkLayerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium >
return rc.pubkey; return rc.pubkey;
} }
/// regenerate rc and rotate onion key
bool
Regen()
{
CryptoManager::instance()->encryption_keygen(encryptionKey);
rc.enckey = seckey_topublic(encryptionKey);
return rc.Sign(signingKey);
}
std::shared_ptr< ILinkLayer > link; std::shared_ptr< ILinkLayer > link;
static std::string static std::string
@ -93,12 +97,15 @@ struct LinkLayerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium >
return false; return false;
if(!link->Configure(loop, localLoopBack(), AF_INET, port)) if(!link->Configure(loop, localLoopBack(), AF_INET, port))
return false; return false;
// if(!link->GenEphemeralKeys()) TODO: reimplement GenEphemeralKeys /*
* TODO: ephemeral key management
if(!link->GenEphemeralKeys())
return false; return false;
*/
rc.addrs.emplace_back(); rc.addrs.emplace_back();
if(!link->GetOurAddressInfo(rc.addrs[0])) if(!link->GetOurAddressInfo(rc.addrs[0]))
return false; return false;
if(!rc.Sign(signingKey)) if(!rc.Sign(keyManager->identityKey))
return false; return false;
return link->Start(logic, worker); return link->Start(logic, worker);
} }
@ -188,9 +195,6 @@ TEST_F(LinkLayerTest, TestIWP)
#ifdef WIN32 #ifdef WIN32
GTEST_SKIP(); GTEST_SKIP();
#else #else
/*
* TODO: use KeyManager
*
auto sendDiscardMessage = [](ILinkSession* s, auto callback) -> bool { auto sendDiscardMessage = [](ILinkSession* s, auto callback) -> bool {
// send discard message in reply to complete unit test // send discard message in reply to complete unit test
std::vector< byte_t> tmp(32); std::vector< byte_t> tmp(32);
@ -201,8 +205,13 @@ TEST_F(LinkLayerTest, TestIWP)
return s->SendMessageBuffer(std::move(tmp), callback); return s->SendMessageBuffer(std::move(tmp), callback);
}; };
Alice.link = iwp::NewInboundLink( Alice.link = iwp::NewInboundLink(
Alice.encryptionKey, // KeyManager
Alice.keyManager,
// GetRCFunc
[&]() -> const RouterContact& { return Alice.GetRC(); }, [&]() -> const RouterContact& { return Alice.GetRC(); },
// LinkMessageHandler
[&](ILinkSession* s, const llarp_buffer_t& buf) -> bool { [&](ILinkSession* s, const llarp_buffer_t& buf) -> bool {
llarp_buffer_t copy(buf.base, buf.sz); llarp_buffer_t copy(buf.base, buf.sz);
if(not Alice.gotLIM) if(not Alice.gotLIM)
@ -215,9 +224,13 @@ TEST_F(LinkLayerTest, TestIWP)
} }
return Alice.gotLIM; return Alice.gotLIM;
}, },
// SignBufferFunc
[&](Signature& sig, const llarp_buffer_t& buf) -> bool { [&](Signature& sig, const llarp_buffer_t& buf) -> bool {
return m_crypto.sign(sig, Alice.signingKey, buf); return m_crypto.sign(sig, Alice.keyManager->identityKey, buf);
}, },
// SessionEstablishedHandler
[&](ILinkSession* s) -> bool { [&](ILinkSession* s) -> bool {
const auto rc = s->GetRemoteRC(); const auto rc = s->GetRemoteRC();
if(rc.pubkey != Bob.GetRC().pubkey) if(rc.pubkey != Bob.GetRC().pubkey)
@ -231,20 +244,33 @@ TEST_F(LinkLayerTest, TestIWP)
}); });
return true; return true;
}, },
// SessionRenegotiateHandler
[&](RouterContact, RouterContact) -> bool { return true; }, [&](RouterContact, RouterContact) -> bool { return true; },
// TimeoutHandler
[&](ILinkSession* session) { [&](ILinkSession* session) {
ASSERT_FALSE(session->IsEstablished()); ASSERT_FALSE(session->IsEstablished());
Stop(); Stop();
}, },
// SessionClosedHandler
[&](RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); }, [&](RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); },
[]() {})
; // PumpDoneHandler
[]() {}
);
Bob.link = iwp::NewInboundLink( Bob.link = iwp::NewInboundLink(
Bob.encryptionKey, [&]() -> const RouterContact& { return Bob.GetRC(); }, // KeyManager
Bob.keyManager,
// GetRCFunc
[&]() -> const RouterContact& { return Bob.GetRC(); },
// LinkMessageHandler
[&](ILinkSession* s, const llarp_buffer_t& buf) -> bool { [&](ILinkSession* s, const llarp_buffer_t& buf) -> bool {
llarp_buffer_t copy(buf.base, buf.sz); llarp_buffer_t copy(buf.base, buf.sz);
@ -266,9 +292,12 @@ TEST_F(LinkLayerTest, TestIWP)
return false; return false;
}, },
// SignBufferFunc
[&](Signature& sig, const llarp_buffer_t& buf) -> bool { [&](Signature& sig, const llarp_buffer_t& buf) -> bool {
return m_crypto.sign(sig, Bob.signingKey, buf); return m_crypto.sign(sig, Bob.keyManager->identityKey, buf);
}, },
//SessionEstablishedHandler
[&](ILinkSession* s) -> bool { [&](ILinkSession* s) -> bool {
if(s->GetRemoteRC().pubkey != Alice.GetRC().pubkey) if(s->GetRemoteRC().pubkey != Alice.GetRC().pubkey)
return false; return false;
@ -277,13 +306,21 @@ TEST_F(LinkLayerTest, TestIWP)
return true; return true;
}, },
// SessionRenegotiateHandler
[&](RouterContact newrc, RouterContact oldrc) -> bool { [&](RouterContact newrc, RouterContact oldrc) -> bool {
return newrc.pubkey == oldrc.pubkey; return newrc.pubkey == oldrc.pubkey;
}, },
// TimeoutHandler
[&](ILinkSession* session) { ASSERT_FALSE(session->IsEstablished()); }, [&](ILinkSession* session) { ASSERT_FALSE(session->IsEstablished()); },
// SessionClosedHandler
[&](RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); }, [&](RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); },
[]() {})
; // PumpDoneHandler
[]() {}
);
ASSERT_TRUE(Alice.Start(m_logic, netLoop, AlicePort)); ASSERT_TRUE(Alice.Start(m_logic, netLoop, AlicePort));
ASSERT_TRUE(Bob.Start(m_logic, netLoop, BobPort)); ASSERT_TRUE(Bob.Start(m_logic, netLoop, BobPort));
@ -294,7 +331,5 @@ TEST_F(LinkLayerTest, TestIWP)
ASSERT_TRUE(Alice.IsGucci()); ASSERT_TRUE(Alice.IsGucci());
ASSERT_TRUE(Bob.IsGucci()); ASSERT_TRUE(Bob.IsGucci());
ASSERT_TRUE(success); ASSERT_TRUE(success);
*/
ASSERT_TRUE(false); // FIXME, see above
#endif #endif
}; };

@ -83,13 +83,13 @@ TEST_F(ServiceIdentityTest, EnsureKeys)
.WillOnce(WithArg< 0 >(FillArg< PQKeyPair >(0x03))); .WillOnce(WithArg< 0 >(FillArg< PQKeyPair >(0x03)));
service::Identity identity; service::Identity identity;
ASSERT_TRUE(identity.EnsureKeys(p.string())); ASSERT_TRUE(identity.EnsureKeys(p.string(), false));
ASSERT_TRUE(fs::exists(fs::status(p))); ASSERT_TRUE(fs::exists(fs::status(p)));
// Verify what is on disk is what is what was generated // Verify what is on disk is what is what was generated
service::Identity other; service::Identity other;
// No need to set more mocks, as we shouldn't need to re-keygen // No need to set more mocks, as we shouldn't need to re-keygen
ASSERT_TRUE(other.EnsureKeys(p.string())); ASSERT_TRUE(other.EnsureKeys(p.string(), false));
ASSERT_EQ(identity, other); ASSERT_EQ(identity, other);
} }
@ -103,7 +103,7 @@ TEST_F(ServiceIdentityTest, EnsureKeysDir)
ASSERT_TRUE(fs::create_directory(p, code)) << code; ASSERT_TRUE(fs::create_directory(p, code)) << code;
service::Identity identity; service::Identity identity;
ASSERT_FALSE(identity.EnsureKeys(p.string())); ASSERT_FALSE(identity.EnsureKeys(p.string(), false));
} }
TEST_F(ServiceIdentityTest, EnsureKeysBrokenFile) TEST_F(ServiceIdentityTest, EnsureKeysBrokenFile)
@ -120,5 +120,5 @@ TEST_F(ServiceIdentityTest, EnsureKeysBrokenFile)
file.close(); file.close();
service::Identity identity; service::Identity identity;
ASSERT_FALSE(identity.EnsureKeys(p.string())); ASSERT_FALSE(identity.EnsureKeys(p.string(), false));
} }

Loading…
Cancel
Save