Merge remote-tracking branch 'origin/dev' into deb08-bionic

ubuntu/bionic
Jason Rhinelander 4 years ago
commit 259bf12a6f

@ -15,11 +15,11 @@ endif()
set(PROJECT_NAME lokinet)
project(${PROJECT_NAME}
VERSION 0.7.1
VERSION 0.8.0
DESCRIPTION "lokinet - IP packet onion router"
LANGUAGES C CXX)
set(RELEASE_MOTTO "I'll remember that..." CACHE STRING "Release motto")
set(RELEASE_MOTTO "Proof of soon" CACHE STRING "Release motto")
add_definitions(-DLLARP_VERSION_MAJOR=${lokinet_VERSION_MAJOR})
add_definitions(-DLLARP_VERSION_MINOR=${lokinet_VERSION_MINOR})

@ -0,0 +1 @@
*.private

@ -0,0 +1,35 @@
#!/usr/bin/env python3
"""
keygen tool for lokinet
"""
from argparse import ArgumentParser as AP
from base64 import b32encode
from nacl.signing import SigningKey
def base32z(data):
""" base32 z encode """
return b32encode(data).translate(
bytes.maketrans(
b'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
b'ybndrfg8ejkmcpqxot1uwisza345h769')).decode().rstrip('=')
def main():
"""
main function for keygen
"""
argparser = AP()
argparser.add_argument('--keyfile', type=str, required=True, help='place to put generated keys')
args = argparser.parse_args()
secret = SigningKey.generate()
with open(args.keyfile, 'wb') as wfile:
wfile.write(b'd1:s64:')
wfile.write(secret.encode())
wfile.write(secret.verify_key.encode())
wfile.write(b'e')
print("{}.loki".format(base32z(secret.verify_key.encode())))
if __name__ == '__main__':
main()

@ -0,0 +1,14 @@
# lokinet key generator
requires:
* python3.7 or higher
* pynacl
usage:
```bash
./keygen.py --keyfile somekeyfile.private
```
this will overwrite the keyfile with new keys

2
external/loki-mq vendored

@ -1 +1 @@
Subproject commit 0ac1d48bc8058bab4f10aeb3010343084f7a37d0
Subproject commit 53481cdfa9b0dc8d6dbbf04803401298754d7f44

@ -175,6 +175,7 @@ add_library(liblokinet
router/rc_lookup_handler.cpp
router/rc_gossiper.cpp
router/router.cpp
router/route_poker.cpp
router_contact.cpp
router_id.cpp
router_version.cpp

@ -559,7 +559,7 @@ namespace llarp
}
void
Config::Save() const
Config::Save()
{
m_Parser.Save();
}

@ -229,7 +229,7 @@ namespace llarp
generateBaseRouterConfig(fs::path defaultDataDir);
void
Save() const;
Save();
void
Override(std::string section, std::string key, std::string value);

@ -171,7 +171,7 @@ namespace llarp
}
void
ConfigParser::Save() const
ConfigParser::Save()
{
// if we have no overrides keep the config the same on disk
if (m_Overrides.empty())
@ -189,6 +189,7 @@ namespace llarp
ofs << key << "=" << value << std::endl;
}
}
m_Overrides.clear();
}
} // namespace llarp

@ -46,7 +46,7 @@ namespace llarp
/// save config and any overrides to the file it was loaded from
void
Save() const;
Save();
private:
bool

@ -623,9 +623,13 @@ namespace llarp
std::string
TunEndpoint::GetIfName() const
{
#ifdef _WIN32
return net::TruncateV6(GetIfAddr()).ToString();
#else
if (tunif)
return tunif->ifname;
return m_IfName;
#endif
}
bool

@ -154,6 +154,14 @@ namespace llarp
return m_ipAddress;
}
huint32_t
IpAddress::toIP() const
{
huint32_t ip;
ip.FromString(toHost());
return ip;
}
bool
IpAddress::operator<(const IpAddress& other) const
{

@ -6,6 +6,8 @@
#include <string_view>
#include <string>
#include <net/net_int.hpp>
namespace llarp
{
/// A struct that can represent either an IPv4 or IPv6 address. It is meant for representation
@ -121,6 +123,9 @@ namespace llarp
std::string
toHost() const;
huint32_t
toIP() const;
// TODO: other utility functions left over from Addr which may be useful
// IsBogon() const;
// isPrivate() const;

@ -32,6 +32,12 @@ namespace llarp
return all;
}
bool
Empty() const
{
return m_Entries.empty();
}
bool
ContainsValue(const Value_t& val) const
{

@ -370,25 +370,8 @@ namespace llarp::net
#endif
#elif _WIN32
ifname.back()++;
int ifindex = 0;
// find interface index for address
ForEachWIN32Interface([&ifindex, ifname = ifname](auto w32interface) {
in_addr interface_addr;
interface_addr.S_un.S_addr = (u_long)w32interface->dwForwardNextHop;
std::array<char, 128> interface_str{};
StringCchCopy(interface_str.data(), interface_str.size(), inet_ntoa(interface_addr));
std::string interface_name{interface_str.data()};
if (interface_name == ifname)
{
ifindex = w32interface->dwForwardIfIndex;
}
});
Execute(
RouteCommand() + " ADD 0.0.0.0 MASK 128.0.0.0 " + ifname + " IF "
+ std::to_string(ifindex));
Execute(
RouteCommand() + " ADD 128.0.0.0 MASK 128.0.0.0 " + ifname + " IF "
+ std::to_string(ifindex));
Execute(RouteCommand() + " ADD 0.0.0.0 MASK 128.0.0.0 " + ifname);
Execute(RouteCommand() + " ADD 128.0.0.0 MASK 128.0.0.0 " + ifname);
#elif __APPLE__
Execute("/sbin/route -n add -cloning -net 0.0.0.0 -netmask 128.0.0.0 -interface " + ifname);
Execute("/sbin/route -n add -cloning -net 128.0.0.0 -netmask 128.0.0.0 -interface " + ifname);

@ -80,7 +80,7 @@ namespace llarp
}
}
LogInfo("Updating ", staleStats.size(), " stats");
LogDebug("Updating ", staleStats.size(), " stats");
{
auto guard = m_storage->transaction_guard();
@ -96,7 +96,7 @@ namespace llarp
auto end = time_now_ms();
auto elapsed = end - start;
LogInfo("PeerDb flush took about ", elapsed, " seconds");
LogDebug("PeerDb flush took about ", elapsed, " seconds");
m_lastFlush.store(end);
}

@ -43,6 +43,7 @@ namespace llarp
struct IOutboundSessionMaker;
struct ILinkManager;
struct I_RCLookupHandler;
struct RoutePoker;
namespace exit
{
@ -156,6 +157,9 @@ namespace llarp
virtual ILinkManager&
linkManager() = 0;
virtual RoutePoker&
routePoker() = 0;
virtual I_RCLookupHandler&
rcLookupHandler() = 0;

@ -0,0 +1,80 @@
#include <router/route_poker.hpp>
#include <router/abstractrouter.hpp>
#include <net/route.hpp>
#include <service/context.hpp>
#include <unordered_set>
namespace llarp
{
void
RoutePoker::AddRoute(huint32_t ip)
{
if (m_CurrentGateway.h == 0)
return;
m_PokedRoutes.emplace(ip, m_CurrentGateway);
net::AddRoute(ip.ToString(), m_CurrentGateway.ToString());
}
void
RoutePoker::DelRoute(huint32_t ip)
{
const auto itr = m_PokedRoutes.find(ip);
if (itr == m_PokedRoutes.end())
return;
net::DelRoute(itr->first.ToString(), itr->second.ToString());
m_PokedRoutes.erase(itr);
}
RoutePoker::~RoutePoker()
{
for (const auto& [ip, gateway] : m_PokedRoutes)
net::DelRoute(ip.ToString(), gateway.ToString());
}
std::optional<huint32_t>
RoutePoker::GetDefaultGateway(const AbstractRouter& router) const
{
const auto ep = router.hiddenServiceContext().GetDefault();
const auto gateways = net::GetGatewaysNotOnInterface(ep->GetIfName());
huint32_t addr{};
if (not gateways.empty())
addr.FromString(gateways[0]);
return addr;
}
void
RoutePoker::Update(const AbstractRouter& router)
{
const auto maybe = GetDefaultGateway(router);
if (not maybe.has_value())
{
LogError("Network is down");
return;
}
const huint32_t gateway = *maybe;
if (m_CurrentGateway != gateway)
{
LogInfo("found default gateway: ", gateway);
// unpoke current routes
std::unordered_set<huint32_t> holes;
for (const auto& [ip, gw] : m_PokedRoutes)
{
// save hole
holes.emplace(ip);
// unpoke route
net::DelRoute(ip.ToString(), gw.ToString());
}
m_PokedRoutes.clear();
m_CurrentGateway = gateway;
for (const auto& ip : holes)
{
AddRoute(ip);
}
const auto ep = router.hiddenServiceContext().GetDefault();
net::AddDefaultRouteViaInterface(ep->GetIfName());
}
}
} // namespace llarp

@ -0,0 +1,31 @@
#pragma once
#include <unordered_map>
#include <string>
#include <net/net_int.hpp>
namespace llarp
{
struct AbstractRouter;
struct RoutePoker
{
void
AddRoute(huint32_t ip);
void
DelRoute(huint32_t ip);
~RoutePoker();
void
Update(const AbstractRouter& router);
private:
std::optional<huint32_t>
GetDefaultGateway(const AbstractRouter& router) const;
std::unordered_map<huint32_t, huint32_t> m_PokedRoutes;
huint32_t m_CurrentGateway;
};
} // namespace llarp

@ -333,10 +333,6 @@ namespace llarp
void
Router::Close()
{
for (const auto& [ip, gateway] : m_PokedRoutes)
{
net::DelRoute(ip, gateway);
}
if (_onDown)
_onDown();
LogInfo("closing router");
@ -770,45 +766,9 @@ namespace llarp
_linkManager.CheckPersistingSessions(now);
if (not IsServiceNode())
if (HasClientExit())
{
const auto gateway = GetDefaultGateway();
if (m_CurrentGateway != gateway)
{
// changed gateways
if (m_CurrentGateway.empty())
{
LogInfo("found default gateway: ", gateway);
}
else if (not gateway.empty())
{
LogInfo("default gateway changed from ", m_CurrentGateway, " to ", gateway);
}
else
{
LogError("Network is down");
}
// unpoke current routes
std::unordered_set<std::string> holes;
for (const auto& [ip, gw] : m_PokedRoutes)
{
// save hole
holes.emplace(ip);
// unpoke route
net::DelRoute(ip, gw);
}
m_PokedRoutes.clear();
if (not gateway.empty())
{
m_CurrentGateway = gateway;
for (const auto& ip : holes)
{
AddRoute(ip);
}
}
}
m_RoutePoker.Update(*this);
}
size_t connected = NumberOfConnectedRouters();
@ -860,7 +820,7 @@ namespace llarp
if (m_peerDb->shouldFlush(now))
{
LogWarn("Queing database flush...");
LogDebug("Queing database flush...");
QueueDiskIO([this]() { m_peerDb->flushDatabase(); });
}
}
@ -905,7 +865,7 @@ namespace llarp
RouterContact rc;
if (not nodedb()->Get(remote, rc))
return;
DelRoute(rc.addrs[0].toIpAddress().toHost());
m_RoutePoker.DelRoute(rc.addrs[0].toIpAddress().toIP());
}
void
@ -1269,31 +1229,13 @@ namespace llarp
return true;
}
std::string
Router::GetDefaultGateway() const
bool
Router::HasClientExit() const
{
if (IsServiceNode())
return false;
const auto ep = hiddenServiceContext().GetDefault();
const auto gateways = net::GetGatewaysNotOnInterface(ep->GetIfName());
if (gateways.empty())
return "";
return gateways[0];
}
void
Router::AddRoute(std::string ip)
{
m_PokedRoutes.emplace(ip, m_CurrentGateway);
net::AddRoute(ip, m_CurrentGateway);
}
void
Router::DelRoute(std::string ip)
{
const auto itr = m_PokedRoutes.find(ip);
if (itr == m_PokedRoutes.end())
return;
net::DelRoute(itr->first, itr->second);
m_PokedRoutes.erase(itr);
return ep and ep->HasExit();
}
bool
@ -1307,7 +1249,7 @@ namespace llarp
[&](llarp::RouterContact rc) {
if (IsServiceNode())
return;
AddRoute(rc.addrs[0].toIpAddress().toHost());
m_RoutePoker.AddRoute(rc.addrs[0].toIpAddress().toIP());
},
util::memFn(&Router::ConnectionEstablished, this),
util::memFn(&AbstractRouter::CheckRenegotiateValid, this),

@ -23,6 +23,7 @@
#include <router/outbound_session_maker.hpp>
#include <router/rc_gossiper.hpp>
#include <router/rc_lookup_handler.hpp>
#include <router/route_poker.hpp>
#include <routing/handler.hpp>
#include <routing/message_parser.hpp>
#include <rpc/lokid_rpc_client.hpp>
@ -260,17 +261,13 @@ namespace llarp
*/
}
std::string
GetDefaultGateway() const;
void
AddRoute(std::string ip);
void
DelRoute(std::string ip);
RoutePoker&
routePoker() override
{
return m_RoutePoker;
}
std::unordered_map<std::string, std::string> m_PokedRoutes;
std::string m_CurrentGateway;
RoutePoker m_RoutePoker;
void
PumpLL() override;
@ -403,6 +400,10 @@ namespace llarp
bool
SaveRC();
/// return true if we are a client with an exit configured
bool
HasClientExit() const;
const byte_t*
pubkey() const override
{

@ -10,6 +10,8 @@
#include <util/printer.hpp>
#include <util/time.hpp>
#include <lokimq/bt_serialize.h>
#include <fstream>
#include <util/fs.hpp>
@ -83,6 +85,29 @@ namespace llarp
bool
RouterContact::BEncode(llarp_buffer_t* buf) const
{
if (version == 0)
return BEncodeSignedSection(buf);
else if (version == 1)
{
// TODO: heapless serialization for this in lokimq's bt serialization.
if (not buf->writef("li1e%zu:", signature.size()))
return false;
if (not buf->write(signature.begin(), signature.end()))
return false;
if (not buf->write(signed_bt_dict.begin(), signed_bt_dict.end()))
return false;
if (not buf->writef("e"))
return false;
return true;
}
return false;
}
bool
RouterContact::BEncodeSignedSection(llarp_buffer_t* buf) const
{
/* write dict begin */
if (!bencode_start_dict(buf))
@ -150,11 +175,16 @@ namespace llarp
if (!BEncodeWriteList(exits.begin(), exits.end(), buf))
return false;
}
/* write signature */
if (!bencode_write_bytestring(buf, "z", 1))
return false;
if (!signature.BEncode(buf))
return false;
if (version == 0)
{
/* write signature */
if (!bencode_write_bytestring(buf, "z", 1))
return false;
if (!signature.BEncode(buf))
return false;
}
return bencode_end(buf);
}
@ -189,6 +219,80 @@ namespace llarp
return obj;
}
bool
RouterContact::BDecode(llarp_buffer_t* buf)
{
Clear();
if (*buf->cur == 'd') // old format
{
return DecodeVersion_0(buf);
}
else if (*buf->cur != 'l') // if not dict, should be new format and start with list
{
return false;
}
try
{
std::string_view buf_view(reinterpret_cast<char*>(buf->cur), buf->sz);
lokimq::bt_list_consumer btlist(buf_view);
uint64_t outer_version = btlist.consume_integer<uint64_t>();
if (outer_version == 1)
{
bool decode_result = DecodeVersion_1(btlist);
// advance the llarp_buffer_t since lokimq serialization is unaware of it.
buf->cur += btlist.current_buffer().data() - buf_view.data() + 1;
return decode_result;
}
else
{
llarp::LogWarn("Received RouterContact with unkown version (", outer_version, ")");
return false;
}
}
catch (const std::exception& e)
{
llarp::LogDebug("RouterContact::BDecode failed, reason: ", e.what());
}
return false;
}
bool
RouterContact::DecodeVersion_0(llarp_buffer_t* buf)
{
signed_bt_dict = std::string(reinterpret_cast<char*>(buf->cur), buf->sz);
return bencode_decode_dict(*this, buf);
}
bool
RouterContact::DecodeVersion_1(lokimq::bt_list_consumer& btlist)
{
auto signature_string = btlist.consume_string_view();
signed_bt_dict = btlist.consume_dict_data();
if (not btlist.is_finished())
{
llarp::LogDebug("RouterContact serialized list too long for specified version.");
return false;
}
llarp_buffer_t sigbuf(signature_string.data(), signature_string.size());
if (not signature.FromBytestring(&sigbuf))
{
llarp::LogDebug("RouterContact serialized signature had invalid length.");
return false;
}
llarp_buffer_t data_dict_buf(signed_bt_dict.data(), signed_bt_dict.size());
return bencode_decode_dict(*this, &data_dict_buf);
}
bool
RouterContact::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
@ -311,13 +415,22 @@ namespace llarp
llarp_buffer_t buf(tmp);
signature.Zero();
last_updated = time_now_ms();
if (!BEncode(&buf))
if (!BEncodeSignedSection(&buf))
{
return false;
}
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return CryptoManager::instance()->sign(signature, secretkey, buf);
signed_bt_dict = std::string(reinterpret_cast<char*>(buf.base), buf.sz);
if (version == 0 or version == 1)
{
return CryptoManager::instance()->sign(signature, secretkey, buf);
}
return false;
}
bool
@ -357,19 +470,30 @@ namespace llarp
bool
RouterContact::VerifySignature() const
{
RouterContact copy;
copy = *this;
copy.signature.Zero();
std::array<byte_t, MAX_RC_SIZE> tmp;
llarp_buffer_t buf(tmp);
if (!copy.BEncode(&buf))
if (version == 0)
{
llarp::LogError("bencode failed");
return false;
RouterContact copy;
copy = *this;
copy.signature.Zero();
std::array<byte_t, MAX_RC_SIZE> tmp;
llarp_buffer_t buf(tmp);
if (!copy.BEncode(&buf))
{
llarp::LogError("bencode failed");
return false;
}
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return CryptoManager::instance()->verify(pubkey, buf, signature);
}
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return CryptoManager::instance()->verify(pubkey, buf, signature);
/* else */
if (version == 1)
{
llarp_buffer_t buf(signed_bt_dict);
return CryptoManager::instance()->verify(pubkey, buf, signature);
}
return false;
}
bool

@ -17,6 +17,11 @@
#define MAX_RC_SIZE (1024)
#define NICKLEN (32)
namespace lokimq
{
class bt_list_consumer;
} // namespace lokimq
namespace llarp
{
/// NetID
@ -107,6 +112,8 @@ namespace llarp
/// should we serialize the exit info?
const static bool serializeExit = true;
std::string signed_bt_dict;
util::StatusObject
ExtractStatus() const;
@ -125,6 +132,9 @@ namespace llarp
bool
BEncode(llarp_buffer_t* buf) const;
bool
BEncodeSignedSection(llarp_buffer_t* buf) const;
bool
operator==(const RouterContact& other) const
{
@ -155,11 +165,7 @@ namespace llarp
}
bool
BDecode(llarp_buffer_t* buf)
{
Clear();
return bencode_decode_dict(*this, buf);
}
BDecode(llarp_buffer_t* buf);
bool
DecodeKey(const llarp_buffer_t& k, llarp_buffer_t* buf);
@ -215,6 +221,13 @@ namespace llarp
bool
VerifySignature() const;
private:
bool
DecodeVersion_0(llarp_buffer_t* buf);
bool
DecodeVersion_1(lokimq::bt_list_consumer& btlist);
};
inline std::ostream&

@ -1,5 +1,5 @@
#include "rpc_server.hpp"
#include <router/abstractrouter.hpp>
#include <router/route_poker.hpp>
#include <util/thread/logic.hpp>
#include <constants/version.hpp>
#include <nlohmann/json.hpp>
@ -167,7 +167,7 @@ namespace llarp::rpc
{
endpoint = endpoint_itr->get<std::string>();
}
LogicCall(r->logic(), [map, exit, range, token, endpoint, r, reply]() {
LogicCall(r->logic(), [map, exit, range, token, endpoint, r, reply]() mutable {
auto ep = r->hiddenServiceContext().GetEndpointByName(endpoint);
if (ep == nullptr)
{
@ -183,12 +183,18 @@ namespace llarp::rpc
}
ep->EnsurePathToService(
*exit,
[reply, ep](auto, service::OutboundContext* ctx) {
[reply, ep, r](auto, service::OutboundContext* ctx) {
if (ctx == nullptr)
{
reply(CreateJSONError("could not find exit"));
return;
}
r->ForEachPeer(
[r](auto session, auto) mutable {
const auto ip = session->GetRemoteEndpoint().toIP();
r->routePoker().AddRoute(ip);
},
false);
net::AddDefaultRouteViaInterface(ep->GetIfName());
reply(CreateJSONResponse("OK"));
},
@ -203,6 +209,13 @@ namespace llarp::rpc
else if (not map)
{
net::DelDefaultRouteViaInterface(ep->GetIfName());
r->ForEachPeer(
[r](auto session, auto) mutable {
const auto ip = session->GetRemoteEndpoint().toIP();
r->routePoker().DelRoute(ip);
},
false);
ep->UnmapExitRange(range);
}
reply(CreateJSONResponse("OK"));

@ -190,6 +190,14 @@ namespace llarp
auto obj = path::Builder::ExtractStatus();
obj["exitMap"] = m_ExitMap.ExtractStatus();
obj["identity"] = m_Identity.pub.Addr().ToString();
util::StatusObject authCodes;
for (const auto& [service, info] : m_RemoteAuthInfos)
{
authCodes[service.ToString()] = info.token;
}
obj["authCodes"] = authCodes;
return m_state->ExtractStatus(obj);
}
@ -764,6 +772,12 @@ namespace llarp
}
};
bool
Endpoint::HasExit() const
{
return not m_ExitMap.Empty();
}
bool
Endpoint::LookupNameAsync(std::string name, std::function<void(std::optional<Address>)> handler)
{

@ -360,6 +360,9 @@ namespace llarp
uint64_t
GetSeqNoForConvo(const ConvoTag& tag);
bool
HasExit() const;
bool
SelectHop(
llarp_nodedb* db,

@ -13,16 +13,10 @@ namespace llarp
{
if (!bencode_start_dict(buf))
return false;
if (!BEncodeWriteDictEntry("e", enckey, buf))
return false;
if (!BEncodeWriteDictEntry("q", pq, buf))
return false;
if (!BEncodeWriteDictEntry("s", signkey, buf))
return false;
if (!BEncodeWriteDictInt("v", version, buf))
return false;
if (!BEncodeWriteDictEntry("x", vanity, buf))
return false;
return bencode_end(buf);
}
@ -30,28 +24,23 @@ namespace llarp
Identity::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
bool read = false;
if (!BEncodeMaybeReadDictEntry("e", enckey, read, key, buf))
return false;
if (key == "q")
{
llarp_buffer_t str;
if (!bencode_read_string(buf, &str))
return false;
if (str.sz == 3200 || str.sz == 2818)
{
pq = str.base;
return true;
}
return false;
}
if (!BEncodeMaybeReadDictEntry("s", signkey, read, key, buf))
return false;
if (!BEncodeMaybeReadDictInt("v", version, read, key, buf))
return false;
if (!BEncodeMaybeReadDictEntry("x", vanity, read, key, buf))
return false;
return read;
if (not read)
return bencode_discard(buf);
return true;
}
void
Identity::Clear()
{
signkey.Zero();
enckey.Zero();
pq.Zero();
derivedSignKey.Zero();
vanity.Zero();
}
void
@ -64,7 +53,7 @@ namespace llarp
crypto->pqe_keygen(pq);
if (not crypto->derive_subkey_private(derivedSignKey, signkey, 1))
{
LogError("failed to generate derived key");
throw std::runtime_error("failed to derive subkey");
}
}
@ -87,6 +76,9 @@ namespace llarp
void
Identity::EnsureKeys(fs::path fname, bool needBackup)
{
// make sure we are empty
Clear();
std::array<byte_t, 4096> tmp;
llarp_buffer_t buf(tmp);
@ -137,12 +129,21 @@ namespace llarp
if (!bencode_decode_dict(*this, &buf))
throw std::length_error("could not decode service identity");
auto crypto = CryptoManager::instance();
// ensure that the encryption key is set
if (enckey.IsZero())
crypto->encryption_keygen(enckey);
// also ensure the ntru key is set
if (pq.IsZero())
crypto->pqe_keygen(pq);
std::optional<VanityNonce> van;
if (!vanity.IsZero())
van = vanity;
// update pubkeys
pub.Update(seckey_topublic(signkey), seckey_topublic(enckey), van);
auto crypto = CryptoManager::instance();
if (not crypto->derive_subkey_private(derivedSignKey, signkey, 1))
{
throw std::runtime_error("failed to derive subkey");

@ -55,6 +55,10 @@ namespace llarp
bool
Sign(Signature& sig, const llarp_buffer_t& buf) const;
/// zero out all secret key members
void
Clear();
};
inline bool

@ -229,6 +229,18 @@ namespace llarp
return m_data.cend();
}
bool
FromBytestring(llarp_buffer_t* buf)
{
if (buf->sz != sz)
{
llarp::LogError("bdecode buffer size mismatch ", buf->sz, "!=", sz);
return false;
}
memcpy(data(), buf->base, sz);
return true;
}
bool
BEncode(llarp_buffer_t* buf) const
{
@ -243,13 +255,7 @@ namespace llarp
{
return false;
}
if (strbuf.sz != sz)
{
llarp::LogError("bdecode buffer size mismatch ", strbuf.sz, "!=", sz);
return false;
}
memcpy(data(), strbuf.base, sz);
return true;
return FromBytestring(&strbuf);
}
std::string

@ -34,7 +34,6 @@ add_executable(testAll
routing/test_llarp_routing_obtainexitmessage.cpp
service/test_llarp_service_address.cpp
test_llarp_encrypted_frame.cpp
test_llarp_router_contact.cpp
util/meta/test_llarp_util_memfn.cpp
util/meta/test_llarp_util_traits.cpp
util/test_llarp_util_aligned.cpp
@ -78,6 +77,7 @@ add_executable(catchAll
iwp/test_iwp_session.cpp
service/test_llarp_service_identity.cpp
test_util.cpp
test_llarp_router_contact.cpp
check_main.cpp)
target_link_libraries(catchAll PUBLIC liblokinet Catch2::Catch2)

@ -1,49 +1,125 @@
#include <gtest/gtest.h>
#include <catch2/catch.hpp>
#include <crypto/crypto.hpp>
#include <crypto/crypto_libsodium.hpp>
#include <llarp_test.hpp>
#include <router_contact.hpp>
#include <net/net_int.hpp>
using namespace ::llarp;
using namespace ::testing;
namespace
{
llarp::sodium::CryptoLibSodium crypto;
llarp::CryptoManager cmanager(&crypto);
}
static const byte_t DEF_VALUE[] = "unittest";
namespace llarp
{
struct RCTest : public test::LlarpTest<>
TEST_CASE("RouterContact Sign and Verify", "[RC][RouterContact][signature][sign][verify]")
{
using RC_t = RouterContact;
using SecKey_t = SecretKey;
RouterContact rc;
SecretKey sign;
cmanager.instance()->identity_keygen(sign);
RCTest() : oldval(NetID::DefaultValue())
{
NetID::DefaultValue() = NetID(DEF_VALUE);
}
SecretKey encr;
cmanager.instance()->encryption_keygen(encr);
~RCTest()
{
NetID::DefaultValue() = oldval;
}
rc.enckey = encr.toPublic();
rc.pubkey = sign.toPublic();
const NetID oldval;
};
REQUIRE(rc.Sign(sign));
REQUIRE(rc.Verify(time_now_ms()));
}
TEST_F(RCTest, TestSignVerify)
TEST_CASE("RouterContact Decode Version 1", "[RC][RouterContact][V1]")
{
NetID netid(DEF_VALUE);
RC_t rc;
SecKey_t encr;
SecKey_t sign;
RouterContact rc;
SecretKey sign;
cmanager.instance()->identity_keygen(sign);
SecretKey encr;
cmanager.instance()->encryption_keygen(encr);
rc.version = 1;
rc.enckey = encr.toPublic();
rc.pubkey = sign.toPublic();
ASSERT_TRUE(rc.netID == netid);
ASSERT_TRUE(rc.netID == NetID::DefaultValue());
EXPECT_CALL(m_crypto, sign(_, sign, _)).WillOnce(Return(true));
EXPECT_CALL(m_crypto, verify(_, _, _)).WillOnce(Return(true));
REQUIRE(rc.Sign(sign));
std::array<byte_t, 5000> encoded_buffer;
llarp_buffer_t encoded_llarp(encoded_buffer);
rc.BEncode(&encoded_llarp);
encoded_llarp.sz = encoded_llarp.cur - encoded_llarp.base;
encoded_llarp.cur = encoded_llarp.base;
RouterContact decoded_rc;
REQUIRE(decoded_rc.BDecode(&encoded_llarp));
REQUIRE(decoded_rc.Verify(time_now_ms()));
ASSERT_TRUE(rc.Sign(sign));
ASSERT_TRUE(rc.Verify(time_now_ms()));
REQUIRE(decoded_rc == rc);
}
TEST_CASE("RouterContact Decode Mixed Versions", "[RC][RouterContact]")
{
RouterContact rc1, rc2, rc3, rc4;
rc1.version = 0;
rc2.version = 1;
rc3.version = 0;
rc4.version = 1;
SecretKey sign1, sign2, sign3, sign4;
cmanager.instance()->identity_keygen(sign1);
cmanager.instance()->identity_keygen(sign2);
cmanager.instance()->identity_keygen(sign3);
cmanager.instance()->identity_keygen(sign4);
SecretKey encr1, encr2, encr3, encr4;
cmanager.instance()->encryption_keygen(encr1);
cmanager.instance()->encryption_keygen(encr2);
cmanager.instance()->encryption_keygen(encr3);
cmanager.instance()->encryption_keygen(encr4);
rc1.enckey = encr1.toPublic();
rc2.enckey = encr2.toPublic();
rc3.enckey = encr3.toPublic();
rc4.enckey = encr4.toPublic();
rc1.pubkey = sign1.toPublic();
rc2.pubkey = sign2.toPublic();
rc3.pubkey = sign3.toPublic();
rc4.pubkey = sign4.toPublic();
REQUIRE(rc1.Sign(sign1));
REQUIRE(rc2.Sign(sign2));
REQUIRE(rc3.Sign(sign3));
REQUIRE(rc4.Sign(sign4));
std::vector<RouterContact> rc_vec;
rc_vec.push_back(rc1);
rc_vec.push_back(rc2);
rc_vec.push_back(rc3);
rc_vec.push_back(rc4);
std::array<byte_t, 20000> encoded_buffer;
llarp_buffer_t encoded_llarp(encoded_buffer);
BEncodeWriteList(rc_vec.begin(), rc_vec.end(), &encoded_llarp);
encoded_llarp.sz = encoded_llarp.cur - encoded_llarp.base;
encoded_llarp.cur = encoded_llarp.base;
std::vector<RouterContact> rc_vec_out;
BEncodeReadList(rc_vec_out, &encoded_llarp);
REQUIRE(rc_vec.size() == rc_vec_out.size());
for (size_t i=0; i<4; i++)
REQUIRE(rc_vec[i] == rc_vec_out[i]);
}
} // namespace llarp

@ -39,25 +39,22 @@ TEST_CASE("TrimWhitespace -- negative tests", "[str][trim]")
TEST_CASE("caseless comparison tests - less than", "[str][lt]") {
using namespace llarp;
CaselessLessThan lt;
// Workaround for gcc 5's stdlib; we can drop this crap (and drop all the `T`'s below) once we
// stop supporting it.
using T = std::tuple<const char*, const char*>;
auto expect_less_than = GENERATE(table<const char*, const char*>({
T{"", "1"},
T{"1", "11"},
T{"abc", "abcd"},
T{"ABC", "abcd"},
T{"abc", "ABCD"},
T{"abc", "Abcd"},
T{"abc", "abcD"},
T{"abc", "abCd"},
T{"abc", "zz"},
T{"abc", "zzzz"},
T{"abc", "abd"},
T{"abc", "aBd"},
T{"abc", "abD"},
T{"ABC", "abd"},
T{"abC", "abd"},
{"", "1"},
{"1", "11"},
{"abc", "abcd"},
{"ABC", "abcd"},
{"abc", "ABCD"},
{"abc", "Abcd"},
{"abc", "abcD"},
{"abc", "abCd"},
{"abc", "zz"},
{"abc", "zzzz"},
{"abc", "abd"},
{"abc", "aBd"},
{"abc", "abD"},
{"ABC", "abd"},
{"abC", "abd"},
}));
REQUIRE( lt(std::get<0>(expect_less_than), std::get<1>(expect_less_than)) );
REQUIRE( !lt(std::get<1>(expect_less_than), std::get<0>(expect_less_than)) );
@ -66,13 +63,12 @@ TEST_CASE("caseless comparison tests - less than", "[str][lt]") {
TEST_CASE("caseless comparison tests - equality", "[str][eq]") {
using namespace llarp;
CaselessLessThan lt;
using T = std::tuple<const char*, const char*>; // gcc 5 workaround
auto expect_equal = GENERATE(table<const char*, const char*>({
T{"1", "1"},
T{"a", "A"},
T{"abc", "ABC"},
T{"abc", "aBc"},
T{"ABC", "abc"},
{"1", "1"},
{"a", "A"},
{"abc", "ABC"},
{"abc", "aBc"},
{"ABC", "abc"},
}));
REQUIRE( !lt(std::get<0>(expect_equal), std::get<1>(expect_equal)) );
REQUIRE( !lt(std::get<1>(expect_equal), std::get<0>(expect_equal)) );

Loading…
Cancel
Save