initial dht key blinding

pull/1075/head
Jeff Becker 4 years ago
parent 1543284f6b
commit 99eb7726ff
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -54,7 +54,7 @@ namespace llarp
/// blake2b 256 bit /// blake2b 256 bit
virtual bool virtual bool
shorthash(ShortHash &, const llarp_buffer_t &) = 0; shorthash(ShortHash &, const llarp_buffer_t &) = 0;
/// blake2s 256 bit hmac /// blake2s 256 bit "hmac" (keyed hash)
virtual bool virtual bool
hmac(byte_t *, const llarp_buffer_t &, const SharedSecret &) = 0; hmac(byte_t *, const llarp_buffer_t &, const SharedSecret &) = 0;
/// ed25519 sign /// ed25519 sign
@ -63,6 +63,15 @@ namespace llarp
/// ed25519 verify /// ed25519 verify
virtual bool virtual bool
verify(const PubKey &, const llarp_buffer_t &, const Signature &) = 0; verify(const PubKey &, const llarp_buffer_t &, const Signature &) = 0;
/// derive sub keys for public keys
virtual bool
derive_subkey(PubKey &, const PubKey &, uint64_t) = 0;
/// derive sub keys for secret keys
virtual bool
derive_subkey_secret(SecretKey &, const SecretKey &, uint64_t) = 0;
/// seed to secretkey /// seed to secretkey
virtual bool virtual bool
seed_to_secretkey(llarp::SecretKey &, const llarp::IdentitySecret &) = 0; seed_to_secretkey(llarp::SecretKey &, const llarp::IdentitySecret &) = 0;

@ -3,8 +3,9 @@
#include <sodium/crypto_sign.h> #include <sodium/crypto_sign.h>
#include <sodium/crypto_scalarmult.h> #include <sodium/crypto_scalarmult.h>
#include <sodium/crypto_stream_xchacha20.h> #include <sodium/crypto_stream_xchacha20.h>
#include <sodium/crypto_core_ed25519.h>
#include <util/mem.hpp> #include <util/mem.hpp>
#include <util/endian.hpp>
#include <cassert> #include <cassert>
extern "C" extern "C"
@ -180,6 +181,51 @@ namespace llarp
!= -1; != -1;
} }
template < typename K >
static bool
make_scalar(byte_t *out, const K &k, uint64_t i)
{
// b = i || k
std::array< byte_t, K::SIZE + sizeof(uint64_t) > buf;
htole64buf(buf.data(), i);
std::copy_n(k.begin(), K::SIZE, buf.begin() + sizeof(i));
LongHash h;
// n = H(b)
if(not hash(h.data(), llarp_buffer_t(buf)))
return false;
// return make_point(n)
return crypto_core_ed25519_from_hash(out, h.data()) != -1;
}
bool
CryptoLibSodium::derive_subkey(PubKey &out_k, const PubKey &in_k,
uint64_t key_n)
{
// scalar p
AlignedBuffer< 32 > p;
// p = H( i || in_k )
if(not make_scalar(p.data(), in_k, key_n))
return false;
// out_k = in_k * p % N
crypto_core_ed25519_scalar_mul(out_k.data(), in_k.data(), p.data());
return true;
}
bool
CryptoLibSodium::derive_subkey_secret(SecretKey &out_k,
const SecretKey &in_k, uint64_t key_n)
{
// scalar p
AlignedBuffer< 32 > p;
// p = H( i || in_k.pub)
if(not make_scalar(p.data(), in_k.toPublic(), key_n))
return false;
// out_k = in_n * p % N
crypto_core_ed25519_scalar_mul(out_k.data(), in_k.data(), p.data());
// recalculate out_K public component
return out_k.Recalculate();
}
bool bool
CryptoLibSodium::seed_to_secretkey(llarp::SecretKey &secret, CryptoLibSodium::seed_to_secretkey(llarp::SecretKey &secret,
const llarp::IdentitySecret &seed) const llarp::IdentitySecret &seed)

@ -53,6 +53,14 @@ namespace llarp
verify(const PubKey &, const llarp_buffer_t &, verify(const PubKey &, const llarp_buffer_t &,
const Signature &) override; const Signature &) override;
/// derive sub keys for public keys
bool
derive_subkey(PubKey &, const PubKey &, uint64_t) override;
/// derive sub keys for secret keys
bool
derive_subkey_secret(SecretKey &, const SecretKey &, uint64_t) override;
/// seed to secretkey /// seed to secretkey
bool bool
seed_to_secretkey(llarp::SecretKey &, seed_to_secretkey(llarp::SecretKey &,

@ -7,6 +7,9 @@
#include <iterator> #include <iterator>
#include <sodium/crypto_sign.h>
#include <sodium/crypto_sign_ed25519.h>
namespace llarp namespace llarp
{ {
bool bool
@ -51,6 +54,15 @@ namespace llarp
return BDecode(&buf); return BDecode(&buf);
} }
bool
SecretKey::Recalculate()
{
AlignedBuffer< 32 > seed;
if(crypto_sign_ed25519_sk_to_seed(seed.data(), data()) == -1)
return false;
return crypto_sign_seed_keypair(data() + 32, data(), seed.data()) != -1;
}
bool bool
SecretKey::SaveToFile(const char* fname) const SecretKey::SaveToFile(const char* fname) const
{ {
@ -94,25 +106,25 @@ namespace llarp
} }
byte_t* byte_t*
Signature::R() Signature::Lo()
{ {
return data(); return data();
} }
const byte_t* const byte_t*
Signature::R() const Signature::Lo() const
{ {
return data(); return data();
} }
byte_t* byte_t*
Signature::C() Signature::Hi()
{ {
return data() + 32; return data() + 32;
} }
const byte_t* const byte_t*
Signature::C() const Signature::Hi() const
{ {
return data() + 32; return data() + 32;
} }

@ -86,6 +86,10 @@ namespace llarp
{ {
} }
/// recalculate public component
bool
Recalculate();
std::ostream & std::ostream &
print(std::ostream &stream, int level, int spaces) const print(std::ostream &stream, int level, int spaces) const
{ {
@ -145,16 +149,16 @@ namespace llarp
struct Signature final : public AlignedBuffer< SIGSIZE > struct Signature final : public AlignedBuffer< SIGSIZE >
{ {
byte_t * byte_t *
R(); Hi();
const byte_t * const byte_t *
R() const; Hi() const;
byte_t * byte_t *
C(); Lo();
const byte_t * const byte_t *
C() const; Lo() const;
}; };
using TunnelNonce = AlignedBuffer< TUNNONCESIZE >; using TunnelNonce = AlignedBuffer< TUNNONCESIZE >;

@ -49,15 +49,15 @@ namespace llarp
/// key askpeer /// key askpeer
void void
LookupIntroSetRecursive( LookupIntroSetRecursive(
const service::Address& target, const Key_t& whoasked, const Key_t& target, const Key_t& whoasked, uint64_t whoaskedTX,
uint64_t whoaskedTX, const Key_t& askpeer, uint64_t R, const Key_t& askpeer, uint64_t R,
service::IntroSetLookupHandler result = nullptr) override; service::EncryptedIntroSetLookupHandler result = nullptr) override;
void void
LookupIntroSetIterative( LookupIntroSetIterative(
const service::Address& target, const Key_t& whoasked, const Key_t& target, const Key_t& whoasked, uint64_t whoaskedTX,
uint64_t whoaskedTX, const Key_t& askpeer, const Key_t& askpeer,
service::IntroSetLookupHandler result = nullptr) override; service::EncryptedIntroSetLookupHandler result = nullptr) override;
/// on behalf of whoasked request router with public key target from dht /// on behalf of whoasked request router with public key target from dht
/// router with key askpeer /// router with key askpeer
@ -84,19 +84,6 @@ namespace llarp
return pendingRouterLookups().HasLookupFor(target); return pendingRouterLookups().HasLookupFor(target);
} }
/// on behalf of whoasked request introsets with tag from dht router with
/// key askpeer with Recursion depth R
void
LookupTagRecursive(const service::Tag& tag, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
uint64_t R) override;
/// issue dht lookup for tag via askpeer and send reply to local path
void
LookupTagForPath(const service::Tag& tag, uint64_t txid,
const llarp::PathID_t& path,
const Key_t& askpeer) override;
/// issue dht lookup for router via askpeer and send reply to local path /// issue dht lookup for router via askpeer and send reply to local path
void void
LookupRouterForPath(const RouterID& target, uint64_t txid, LookupRouterForPath(const RouterID& target, uint64_t txid,
@ -105,7 +92,7 @@ namespace llarp
/// issue dht lookup for introset for addr via askpeer and send reply to /// issue dht lookup for introset for addr via askpeer and send reply to
/// local path /// local path
void void
LookupIntroSetForPath(const service::Address& addr, uint64_t txid, LookupIntroSetForPath(const Key_t& addr, uint64_t txid,
const llarp::PathID_t& path, const Key_t& askpeer, const llarp::PathID_t& path, const Key_t& askpeer,
uint64_t R) override; uint64_t R) override;
@ -121,11 +108,6 @@ namespace llarp
const Key_t& requester, uint64_t txid, const RouterID& target, const Key_t& requester, uint64_t txid, const RouterID& target,
std::vector< std::unique_ptr< IMessage > >& reply) override; std::vector< std::unique_ptr< IMessage > >& reply) override;
std::set< service::IntroSet >
FindRandomIntroSetsWithTagExcluding(
const service::Tag& tag, size_t max = 2,
const std::set< service::IntroSet >& excludes = {}) override;
/// handle rc lookup from requester for target /// handle rc lookup from requester for target
void void
LookupRouterRelayed( LookupRouterRelayed(
@ -141,8 +123,8 @@ namespace llarp
/// send introset to peer from source with S counter and excluding peers /// send introset to peer from source with S counter and excluding peers
void void
PropagateIntroSetTo(const Key_t& source, uint64_t sourceTX, PropagateIntroSetTo(const Key_t& source, uint64_t sourceTX,
const service::IntroSet& introset, const Key_t& peer, const service::EncryptedIntroSet& introset,
uint64_t S, const Key_t& peer, uint64_t S,
const std::set< Key_t >& exclude) override; const std::set< Key_t >& exclude) override;
/// initialize dht context and explore every exploreInterval milliseconds /// initialize dht context and explore every exploreInterval milliseconds
@ -151,9 +133,8 @@ namespace llarp
llarp_time_t exploreInterval) override; llarp_time_t exploreInterval) override;
/// get localally stored introset by service address /// get localally stored introset by service address
const llarp::service::IntroSet* absl::optional< llarp::service::EncryptedIntroSet >
GetIntroSetByServiceAddress( GetIntroSetByLocation(const Key_t& location) const override;
const llarp::service::Address& addr) const override;
void void
handle_cleaner_timer(uint64_t interval); handle_cleaner_timer(uint64_t interval);
@ -233,7 +214,6 @@ namespace llarp
FloodRCLater(const dht::Key_t from, const RouterContact rc) override; FloodRCLater(const dht::Key_t from, const RouterContact rc) override;
PendingIntrosetLookups _pendingIntrosetLookups; PendingIntrosetLookups _pendingIntrosetLookups;
PendingTagLookups _pendingTagLookups;
PendingRouterLookups _pendingRouterLookups; PendingRouterLookups _pendingRouterLookups;
PendingExploreLookups _pendingExploreLookups; PendingExploreLookups _pendingExploreLookups;
@ -259,18 +239,6 @@ namespace llarp
return _pendingIntrosetLookups; return _pendingIntrosetLookups;
} }
PendingTagLookups&
pendingTagLookups() override
{
return _pendingTagLookups;
}
const PendingTagLookups&
pendingTagLookups() const override
{
return _pendingTagLookups;
}
PendingRouterLookups& PendingRouterLookups&
pendingRouterLookups() override pendingRouterLookups() override
{ {
@ -416,7 +384,6 @@ namespace llarp
{ {
if(itr->second.introset.IsExpired(now)) if(itr->second.introset.IsExpired(now))
{ {
llarp::LogDebug("introset expired ", itr->second.introset.A.Addr());
itr = nodes.erase(itr); itr = nodes.erase(itr);
} }
else else
@ -426,53 +393,6 @@ namespace llarp
ScheduleCleanupTimer(); ScheduleCleanupTimer();
} }
std::set< service::IntroSet >
Context::FindRandomIntroSetsWithTagExcluding(
const service::Tag& tag, size_t max,
const std::set< service::IntroSet >& exclude)
{
std::set< service::IntroSet > found;
auto& nodes = _services->nodes;
if(nodes.size() == 0)
{
return found;
}
auto itr = nodes.begin();
// start at random middle point
auto start = llarp::randint() % nodes.size();
std::advance(itr, start);
auto end = itr;
std::string tagname = tag.ToString();
while(itr != nodes.end())
{
if(itr->second.introset.topic.ToString() == tagname)
{
if(exclude.count(itr->second.introset) == 0)
{
found.insert(itr->second.introset);
if(found.size() == max)
return found;
}
}
++itr;
}
itr = nodes.begin();
while(itr != end)
{
if(itr->second.introset.topic.ToString() == tagname)
{
if(exclude.count(itr->second.introset) == 0)
{
found.insert(itr->second.introset);
if(found.size() == max)
return found;
}
}
++itr;
}
return found;
}
void void
Context::LookupRouterRelayed( Context::LookupRouterRelayed(
const Key_t& requester, uint64_t txid, const Key_t& target, const Key_t& requester, uint64_t txid, const Key_t& target,
@ -534,15 +454,13 @@ namespace llarp
} }
} }
const llarp::service::IntroSet* absl::optional< llarp::service::EncryptedIntroSet >
Context::GetIntroSetByServiceAddress( Context::GetIntroSetByLocation(const Key_t& key) const
const llarp::service::Address& addr) const
{ {
auto key = addr.ToKey();
auto itr = _services->nodes.find(key); auto itr = _services->nodes.find(key);
if(itr == _services->nodes.end()) if(itr == _services->nodes.end())
return nullptr; return {};
return &itr->second.introset; return itr->second.introset;
} }
void void
@ -553,7 +471,6 @@ namespace llarp
pendingRouterLookups().Expire(now); pendingRouterLookups().Expire(now);
_pendingIntrosetLookups.Expire(now); _pendingIntrosetLookups.Expire(now);
pendingTagLookups().Expire(now);
pendingExploreLookups().Expire(now); pendingExploreLookups().Expire(now);
} }
@ -563,7 +480,6 @@ namespace llarp
util::StatusObject obj{ util::StatusObject obj{
{"pendingRouterLookups", pendingRouterLookups().ExtractStatus()}, {"pendingRouterLookups", pendingRouterLookups().ExtractStatus()},
{"pendingIntrosetLookups", _pendingIntrosetLookups.ExtractStatus()}, {"pendingIntrosetLookups", _pendingIntrosetLookups.ExtractStatus()},
{"pendingTagLookups", pendingTagLookups().ExtractStatus()},
{"pendingExploreLookups", pendingExploreLookups().ExtractStatus()}, {"pendingExploreLookups", pendingExploreLookups().ExtractStatus()},
{"nodes", _nodes->ExtractStatus()}, {"nodes", _nodes->ExtractStatus()},
{"services", _services->ExtractStatus()}, {"services", _services->ExtractStatus()},
@ -623,7 +539,7 @@ namespace llarp
} }
void void
Context::LookupIntroSetForPath(const service::Address& addr, uint64_t txid, Context::LookupIntroSetForPath(const Key_t& addr, uint64_t txid,
const llarp::PathID_t& path, const llarp::PathID_t& path,
const Key_t& askpeer, uint64_t R) const Key_t& askpeer, uint64_t R)
{ {
@ -637,23 +553,23 @@ namespace llarp
void void
Context::PropagateIntroSetTo(const Key_t& from, uint64_t txid, Context::PropagateIntroSetTo(const Key_t& from, uint64_t txid,
const service::IntroSet& introset, const service::EncryptedIntroSet& introset,
const Key_t& tellpeer, uint64_t S, const Key_t& tellpeer, uint64_t S,
const std::set< Key_t >& exclude) const std::set< Key_t >& exclude)
{ {
TXOwner asker(from, txid); TXOwner asker(from, txid);
TXOwner peer(tellpeer, ++ids); TXOwner peer(tellpeer, ++ids);
service::Address addr = introset.A.Addr(); const Key_t addr(introset.derivedSigningKey);
_pendingIntrosetLookups.NewTX( _pendingIntrosetLookups.NewTX(
peer, asker, addr, peer, asker, addr,
new PublishServiceJob(asker, introset, this, S, exclude)); new PublishServiceJob(asker, introset, this, S, exclude));
} }
void void
Context::LookupIntroSetRecursive(const service::Address& addr, Context::LookupIntroSetRecursive(
const Key_t& whoasked, uint64_t txid, const Key_t& addr, const Key_t& whoasked, uint64_t txid,
const Key_t& askpeer, uint64_t R, const Key_t& askpeer, uint64_t R,
service::IntroSetLookupHandler handler) service::EncryptedIntroSetLookupHandler handler)
{ {
TXOwner asker(whoasked, txid); TXOwner asker(whoasked, txid);
TXOwner peer(askpeer, ++ids); TXOwner peer(askpeer, ++ids);
@ -674,10 +590,9 @@ namespace llarp
} }
void void
Context::LookupIntroSetIterative(const service::Address& addr, Context::LookupIntroSetIterative(
const Key_t& whoasked, uint64_t txid, const Key_t& addr, const Key_t& whoasked, uint64_t txid,
const Key_t& askpeer, const Key_t& askpeer, service::EncryptedIntroSetLookupHandler handler)
service::IntroSetLookupHandler handler)
{ {
TXOwner asker(whoasked, txid); TXOwner asker(whoasked, txid);
TXOwner peer(askpeer, ++ids); TXOwner peer(askpeer, ++ids);
@ -686,29 +601,6 @@ namespace llarp
new ServiceAddressLookup(asker, addr, this, 0, handler), 1000); new ServiceAddressLookup(asker, addr, this, 0, handler), 1000);
} }
void
Context::LookupTagRecursive(const service::Tag& tag, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
uint64_t R)
{
TXOwner asker(whoasked, whoaskedTX);
TXOwner peer(askpeer, ++ids);
_pendingTagLookups.NewTX(peer, asker, tag,
new TagLookup(asker, tag, this, R));
llarp::LogDebug("ask ", askpeer.SNode(), " for ", tag, " on behalf of ",
whoasked.SNode(), " R=", R);
}
void
Context::LookupTagForPath(const service::Tag& tag, uint64_t txid,
const llarp::PathID_t& path, const Key_t& askpeer)
{
TXOwner peer(askpeer, ++ids);
TXOwner whoasked(OurKey(), txid);
_pendingTagLookups.NewTX(peer, whoasked, tag,
new LocalTagLookup(path, txid, tag, this));
}
bool bool
Context::HandleExploritoryRouterLookup( Context::HandleExploritoryRouterLookup(
const Key_t& requester, uint64_t txid, const RouterID& target, const Key_t& requester, uint64_t txid, const RouterID& target,

@ -26,10 +26,7 @@ namespace llarp
struct AbstractContext struct AbstractContext
{ {
using PendingIntrosetLookups = using PendingIntrosetLookups =
TXHolder< service::Address, service::IntroSet, TXHolder< Key_t, service::EncryptedIntroSet, Key_t::Hash >;
service::Address::Hash >;
using PendingTagLookups =
TXHolder< service::Tag, service::IntroSet, service::Tag::Hash >;
using PendingRouterLookups = using PendingRouterLookups =
TXHolder< RouterID, RouterContact, RouterID::Hash >; TXHolder< RouterID, RouterContact, RouterID::Hash >;
using PendingExploreLookups = using PendingExploreLookups =
@ -48,46 +45,29 @@ namespace llarp
/// on behalf of whoasked request introset for target from dht router with /// on behalf of whoasked request introset for target from dht router with
/// key askpeer /// key askpeer
virtual void virtual void
LookupIntroSetRecursive(const service::Address& target, LookupIntroSetRecursive(
const Key_t& whoasked, uint64_t whoaskedTX, const Key_t& target, const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer, uint64_t R, const Key_t& askpeer, uint64_t R,
service::IntroSetLookupHandler result = service::EncryptedIntroSetLookupHandler result =
service::IntroSetLookupHandler()) = 0; service::EncryptedIntroSetLookupHandler()) = 0;
virtual void virtual void
LookupIntroSetIterative(const service::Address& target, LookupIntroSetIterative(
const Key_t& whoasked, uint64_t whoaskedTX, const Key_t& target, const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer, const Key_t& askpeer,
service::IntroSetLookupHandler result = service::EncryptedIntroSetLookupHandler result =
service::IntroSetLookupHandler()) = 0; service::EncryptedIntroSetLookupHandler()) = 0;
virtual std::set< service::IntroSet >
FindRandomIntroSetsWithTagExcluding(
const service::Tag& tag, size_t max = 2,
const std::set< service::IntroSet >& excludes = {}) = 0;
virtual bool virtual bool
HasRouterLookup(const RouterID& target) const = 0; HasRouterLookup(const RouterID& target) const = 0;
/// on behalf of whoasked request introsets with tag from dht router with
/// key askpeer with Recursion depth R
virtual void
LookupTagRecursive(const service::Tag& tag, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
uint64_t R) = 0;
/// issue dht lookup for tag via askpeer and send reply to local path
virtual void
LookupTagForPath(const service::Tag& tag, uint64_t txid,
const PathID_t& path, const Key_t& askpeer) = 0;
/// issue dht lookup for router via askpeer and send reply to local path /// issue dht lookup for router via askpeer and send reply to local path
virtual void virtual void
LookupRouterForPath(const RouterID& target, uint64_t txid, LookupRouterForPath(const RouterID& target, uint64_t txid,
const PathID_t& path, const Key_t& askpeer) = 0; const PathID_t& path, const Key_t& askpeer) = 0;
virtual void virtual void
LookupIntroSetForPath(const service::Address& addr, uint64_t txid, LookupIntroSetForPath(const Key_t& addr, uint64_t txid,
const PathID_t& path, const Key_t& askpeer, const PathID_t& path, const Key_t& askpeer,
uint64_t R) = 0; uint64_t R) = 0;
@ -113,16 +93,16 @@ namespace llarp
/// send introset to peer from source with S counter and excluding peers /// send introset to peer from source with S counter and excluding peers
virtual void virtual void
PropagateIntroSetTo(const Key_t& source, uint64_t sourceTX, PropagateIntroSetTo(const Key_t& source, uint64_t sourceTX,
const service::IntroSet& introset, const Key_t& peer, const service::EncryptedIntroSet& introset,
uint64_t S, const std::set< Key_t >& exclude) = 0; const Key_t& peer, uint64_t S,
const std::set< Key_t >& exclude) = 0;
virtual void virtual void
Init(const Key_t& us, AbstractRouter* router, Init(const Key_t& us, AbstractRouter* router,
llarp_time_t exploreInterval) = 0; llarp_time_t exploreInterval) = 0;
virtual const llarp::service::IntroSet* virtual absl::optional< llarp::service::EncryptedIntroSet >
GetIntroSetByServiceAddress( GetIntroSetByLocation(const Key_t& location) const = 0;
const llarp::service::Address& addr) const = 0;
virtual llarp_time_t virtual llarp_time_t
Now() const = 0; Now() const = 0;
@ -145,12 +125,6 @@ namespace llarp
virtual const PendingIntrosetLookups& virtual const PendingIntrosetLookups&
pendingIntrosetLookups() const = 0; pendingIntrosetLookups() const = 0;
virtual PendingTagLookups&
pendingTagLookups() = 0;
virtual const PendingTagLookups&
pendingTagLookups() const = 0;
virtual PendingRouterLookups& virtual PendingRouterLookups&
pendingRouterLookups() = 0; pendingRouterLookups() = 0;

@ -12,7 +12,7 @@ namespace llarp
namespace dht namespace dht
{ {
LocalServiceAddressLookup::LocalServiceAddressLookup( LocalServiceAddressLookup::LocalServiceAddressLookup(
const PathID_t &pathid, uint64_t txid, const service::Address &addr, const PathID_t &pathid, uint64_t txid, const Key_t &addr,
AbstractContext *ctx, __attribute__((unused)) const Key_t &askpeer) AbstractContext *ctx, __attribute__((unused)) const Key_t &askpeer)
: ServiceAddressLookup(TXOwner{ctx->OurKey(), txid}, addr, ctx, 5, : ServiceAddressLookup(TXOwner{ctx->OurKey(), txid}, addr, ctx, 5,
nullptr) nullptr)
@ -36,7 +36,7 @@ namespace llarp
// pick newest if we have more than 1 result // pick newest if we have more than 1 result
if(valuesFound.size()) if(valuesFound.size())
{ {
service::IntroSet found; service::EncryptedIntroSet found;
for(const auto &introset : valuesFound) for(const auto &introset : valuesFound)
{ {
if(found.OtherIsNewer(introset)) if(found.OtherIsNewer(introset))

@ -14,8 +14,7 @@ namespace llarp
PathID_t localPath; PathID_t localPath;
LocalServiceAddressLookup(const PathID_t &pathid, uint64_t txid, LocalServiceAddressLookup(const PathID_t &pathid, uint64_t txid,
const service::Address &addr, const Key_t &addr, AbstractContext *ctx,
AbstractContext *ctx,
__attribute__((unused)) const Key_t &askpeer); __attribute__((unused)) const Key_t &askpeer);
void void

@ -24,7 +24,7 @@ namespace llarp
if(!BEncodeMaybeReadDictInt("R", recursionDepth, read, k, val)) if(!BEncodeMaybeReadDictInt("R", recursionDepth, read, k, val))
return false; return false;
if(!BEncodeMaybeReadDictEntry("S", serviceAddress, read, k, val)) if(!BEncodeMaybeReadDictEntry("S", location, read, k, val))
return false; return false;
if(!BEncodeMaybeReadDictInt("T", txID, read, k, val)) if(!BEncodeMaybeReadDictInt("T", txID, read, k, val))
@ -52,7 +52,7 @@ namespace llarp
if(!BEncodeWriteDictInt("R", recursionDepth, buf)) if(!BEncodeWriteDictInt("R", recursionDepth, buf))
return false; return false;
// service address // service address
if(!BEncodeWriteDictEntry("S", serviceAddress, buf)) if(!BEncodeWriteDictEntry("S", location, buf))
return false; return false;
} }
else else
@ -91,111 +91,58 @@ namespace llarp
} }
Key_t peer; Key_t peer;
std::set< Key_t > exclude = {dht.OurKey(), From}; std::set< Key_t > exclude = {dht.OurKey(), From};
if(tagName.Empty()) if(not tagName.Empty())
return false;
if(location.IsZero())
{ {
if(serviceAddress.IsZero()) // we dont got it
{ replies.emplace_back(new GotIntroMessage({}, txID));
// we dont got it
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
llarp::LogInfo("lookup ", serviceAddress.ToString());
const auto introset = dht.GetIntroSetByServiceAddress(serviceAddress);
if(introset)
{
replies.emplace_back(new GotIntroMessage({*introset}, txID));
return true;
}
const Key_t target = serviceAddress.ToKey();
const Key_t us = dht.OurKey();
if(recursionDepth == 0)
{
// we don't have it
Key_t closer;
// find closer peer
if(!dht.Nodes()->FindClosest(target, closer))
return false;
replies.emplace_back(new GotIntroMessage(From, closer, txID));
return true;
}
// we are recursive
const auto rc = dht.GetRouter()->nodedb()->FindClosestTo(target);
peer = Key_t(rc.pubkey);
if((us ^ target) < (peer ^ target) || peer == us)
{
// we are not closer than our peer to the target so don't
// recurse farther
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
if(relayed)
{
dht.LookupIntroSetForPath(serviceAddress, txID, pathID, peer,
recursionDepth - 1);
}
else
{
dht.LookupIntroSetRecursive(serviceAddress, From, txID, peer,
recursionDepth - 1);
}
return true; return true;
} }
const auto maybe = dht.GetIntroSetByLocation(location);
if(maybe.has_value())
{
replies.emplace_back(new GotIntroMessage({maybe.value()}, txID));
return true;
}
const Key_t us = dht.OurKey();
if(recursionDepth == 0)
{
// we don't have it
Key_t closer;
// find closer peer
if(!dht.Nodes()->FindClosest(location, closer))
return false;
replies.emplace_back(new GotIntroMessage(From, closer, txID));
return true;
}
// we are recursive
const auto rc = dht.GetRouter()->nodedb()->FindClosestTo(location);
peer = Key_t(rc.pubkey);
if((us ^ location) < (peer ^ location) || peer == us)
{
// we are not closer than our peer to the target so don't
// recurse farther
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
if(relayed) if(relayed)
{ {
// tag lookup dht.LookupIntroSetForPath(location, txID, pathID, peer,
if(dht.Nodes()->GetRandomNodeExcluding(peer, exclude)) recursionDepth - 1);
{
dht.LookupTagForPath(tagName, txID, pathID, peer);
}
else
{
// no more closer peers
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
} }
else else
{ {
if(recursionDepth == 0) dht.LookupIntroSetRecursive(location, From, txID, peer,
{ recursionDepth - 1);
// base case
auto introsets =
dht.FindRandomIntroSetsWithTagExcluding(tagName, 2, {});
std::vector< service::IntroSet > reply;
for(const auto& introset : introsets)
{
reply.emplace_back(introset);
}
replies.emplace_back(new GotIntroMessage(reply, txID));
return true;
}
if(recursionDepth < MaxRecursionDepth)
{
// tag lookup
if(dht.Nodes()->GetRandomNodeExcluding(peer, exclude))
{
dht.LookupTagRecursive(tagName, From, txID, peer,
recursionDepth - 1);
}
else
{
replies.emplace_back(new GotIntroMessage({}, txID));
}
}
else
{
// too big recursion depth
replies.emplace_back(new GotIntroMessage({}, txID));
}
} }
return true; return true;
} }
} // namespace dht } // namespace dht

@ -14,7 +14,7 @@ namespace llarp
{ {
static const uint64_t MaxRecursionDepth; static const uint64_t MaxRecursionDepth;
uint64_t recursionDepth = 0; uint64_t recursionDepth = 0;
llarp::service::Address serviceAddress; Key_t location;
llarp::service::Tag tagName; llarp::service::Tag tagName;
uint64_t txID = 0; uint64_t txID = 0;
bool relayed = false; bool relayed = false;
@ -28,19 +28,17 @@ namespace llarp
bool iterate = true) bool iterate = true)
: IMessage({}), tagName(tag), txID(txid) : IMessage({}), tagName(tag), txID(txid)
{ {
serviceAddress.Zero();
if(iterate) if(iterate)
recursionDepth = 0; recursionDepth = 0;
else else
recursionDepth = 1; recursionDepth = 1;
} }
explicit FindIntroMessage(uint64_t txid, explicit FindIntroMessage(uint64_t txid, const Key_t& addr,
const llarp::service::Address& addr,
uint64_t maxRecursionDepth) uint64_t maxRecursionDepth)
: IMessage({}) : IMessage({})
, recursionDepth(maxRecursionDepth) , recursionDepth(maxRecursionDepth)
, serviceAddress(addr) , location(addr)
, txID(txid) , txID(txid)
{ {
tagName.Zero(); tagName.Zero();

@ -11,8 +11,8 @@ namespace llarp
{ {
namespace dht namespace dht
{ {
GotIntroMessage::GotIntroMessage(std::vector< service::IntroSet > results, GotIntroMessage::GotIntroMessage(
uint64_t tx) std::vector< service::EncryptedIntroSet > results, uint64_t tx)
: IMessage({}), found(std::move(results)), txid(tx) : IMessage({}), found(std::move(results)), txid(tx)
{ {
} }
@ -37,12 +37,7 @@ namespace llarp
} }
} }
TXOwner owner(From, txid); TXOwner owner(From, txid);
auto tagLookup = dht.pendingTagLookups().GetPendingLookupFrom(owner);
if(tagLookup)
{
dht.pendingTagLookups().Found(owner, tagLookup->target, found);
return true;
}
auto serviceLookup = auto serviceLookup =
dht.pendingIntrosetLookups().GetPendingLookupFrom(owner); dht.pendingIntrosetLookups().GetPendingLookupFrom(owner);
if(serviceLookup) if(serviceLookup)

@ -16,7 +16,7 @@ namespace llarp
struct GotIntroMessage : public IMessage struct GotIntroMessage : public IMessage
{ {
/// the found introsets /// the found introsets
std::vector< service::IntroSet > found; std::vector< service::EncryptedIntroSet > found;
/// txid /// txid
uint64_t txid = 0; uint64_t txid = 0;
/// the key of a router closer in keyspace if iterative lookup /// the key of a router closer in keyspace if iterative lookup
@ -42,7 +42,8 @@ namespace llarp
} }
/// for recursive reply /// for recursive reply
GotIntroMessage(std::vector< service::IntroSet > results, uint64_t txid); GotIntroMessage(std::vector< service::EncryptedIntroSet > results,
uint64_t txid);
~GotIntroMessage() override = default; ~GotIntroMessage() override = default;

@ -55,20 +55,7 @@ namespace llarp
return true; return true;
} }
if(introset.W && !introset.W->IsValid(now)) const llarp::dht::Key_t addr(introset.derivedSigningKey);
{
llarp::LogWarn("proof of work not good enough for IntroSet");
// don't propogate or store
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
llarp::dht::Key_t addr;
if(not introset.A.CalculateAddress(addr.as_array()))
{
llarp::LogWarn(
"failed to calculate hidden service address for PubIntro message");
return false;
}
now += llarp::service::MAX_INTROSET_TIME_DELTA; now += llarp::service::MAX_INTROSET_TIME_DELTA;
if(introset.IsExpired(now)) if(introset.IsExpired(now))

@ -13,7 +13,7 @@ namespace llarp
struct PublishIntroMessage final : public IMessage struct PublishIntroMessage final : public IMessage
{ {
static const uint64_t MaxPropagationDepth; static const uint64_t MaxPropagationDepth;
llarp::service::IntroSet introset; llarp::service::EncryptedIntroSet introset;
std::vector< Key_t > exclude; std::vector< Key_t > exclude;
uint64_t depth = 0; uint64_t depth = 0;
uint64_t txID = 0; uint64_t txID = 0;
@ -21,8 +21,9 @@ namespace llarp
{ {
} }
PublishIntroMessage(const llarp::service::IntroSet& i, uint64_t tx, PublishIntroMessage(const llarp::service::EncryptedIntroSet& i,
uint64_t s, std::vector< Key_t > _exclude = {}) uint64_t tx, uint64_t s,
std::vector< Key_t > _exclude = {})
: IMessage({}) : IMessage({})
, introset(i) , introset(i)
, exclude(std::move(_exclude)) , exclude(std::move(_exclude))

@ -39,7 +39,7 @@ namespace llarp
struct ISNode struct ISNode
{ {
service::IntroSet introset; service::EncryptedIntroSet introset;
Key_t ID; Key_t ID;
@ -48,9 +48,9 @@ namespace llarp
ID.Zero(); ID.Zero();
} }
ISNode(service::IntroSet other) : introset(std::move(other)) ISNode(service::EncryptedIntroSet other) : introset(std::move(other))
{ {
introset.A.CalculateAddress(ID.as_array()); ID = Key_t(introset.derivedSigningKey.as_array());
} }
util::StatusObject util::StatusObject
@ -62,7 +62,7 @@ namespace llarp
bool bool
operator<(const ISNode& other) const operator<(const ISNode& other) const
{ {
return introset.T < other.introset.T; return introset.signedAt < other.introset.signedAt;
} }
}; };
} // namespace dht } // namespace dht

@ -9,27 +9,28 @@ namespace llarp
namespace dht namespace dht
{ {
PublishServiceJob::PublishServiceJob(const TXOwner &asker, PublishServiceJob::PublishServiceJob(const TXOwner &asker,
const service::IntroSet &introset, const service::EncryptedIntroSet &I,
AbstractContext *ctx, uint64_t s, AbstractContext *ctx, uint64_t s,
std::set< Key_t > exclude) std::set< Key_t > exclude)
: TX< service::Address, service::IntroSet >(asker, introset.A.Addr(), : TX< Key_t, service::EncryptedIntroSet >(
ctx) asker, Key_t{I.derivedSigningKey}, ctx)
, S(s) , S(s)
, dontTell(std::move(exclude)) , dontTell(std::move(exclude))
, I(introset) , introset(I)
{ {
} }
bool bool
PublishServiceJob::Validate(const service::IntroSet &introset) const PublishServiceJob::Validate(const service::EncryptedIntroSet &value) const
{ {
if(I.A != introset.A) if(value.derivedSigningKey != introset.derivedSigningKey)
{ {
llarp::LogWarn( llarp::LogWarn(
"publish introset acknowledgement acked a different service"); "publish introset acknowledgement acked a different service");
return false; return false;
} }
return true; const llarp_time_t now = llarp::time_now_ms();
return value.Verify(now);
} }
void void
@ -40,8 +41,9 @@ namespace llarp
{ {
exclude.push_back(router); exclude.push_back(router);
} }
parent->DHTSendTo(peer.node.as_array(), parent->DHTSendTo(
new PublishIntroMessage(I, peer.txid, S, exclude)); peer.node.as_array(),
new PublishIntroMessage(introset, peer.txid, S, exclude));
} }
} // namespace dht } // namespace dht
} // namespace llarp } // namespace llarp

@ -12,18 +12,19 @@ namespace llarp
{ {
namespace dht namespace dht
{ {
struct PublishServiceJob : public TX< service::Address, service::IntroSet > struct PublishServiceJob : public TX< Key_t, service::EncryptedIntroSet >
{ {
uint64_t S; uint64_t S;
std::set< Key_t > dontTell; std::set< Key_t > dontTell;
service::IntroSet I; service::EncryptedIntroSet introset;
PublishServiceJob(const TXOwner &asker, const service::IntroSet &introset, PublishServiceJob(const TXOwner &asker,
const service::EncryptedIntroSet &introset,
AbstractContext *ctx, uint64_t s, AbstractContext *ctx, uint64_t s,
std::set< Key_t > exclude); std::set< Key_t > exclude);
bool bool
Validate(const service::IntroSet &introset) const override; Validate(const service::EncryptedIntroSet &introset) const override;
void void
Start(const TXOwner &peer) override; Start(const TXOwner &peer) override;

@ -10,10 +10,9 @@ namespace llarp
namespace dht namespace dht
{ {
ServiceAddressLookup::ServiceAddressLookup( ServiceAddressLookup::ServiceAddressLookup(
const TXOwner &asker, const service::Address &addr, const TXOwner &asker, const Key_t &addr, AbstractContext *ctx,
AbstractContext *ctx, uint64_t r, uint64_t r, service::EncryptedIntroSetLookupHandler handler)
service::IntroSetLookupHandler handler) : TX< Key_t, service::EncryptedIntroSet >(asker, addr, ctx)
: TX< service::Address, service::IntroSet >(asker, addr, ctx)
, handleResult(std::move(handler)) , handleResult(std::move(handler))
, R(r) , R(r)
{ {
@ -21,14 +20,15 @@ namespace llarp
} }
bool bool
ServiceAddressLookup::Validate(const service::IntroSet &value) const ServiceAddressLookup::Validate(
const service::EncryptedIntroSet &value) const
{ {
if(!value.Verify(parent->Now())) if(!value.Verify(parent->Now()))
{ {
llarp::LogWarn("Got invalid introset from service lookup"); llarp::LogWarn("Got invalid introset from service lookup");
return false; return false;
} }
if(value.A.Addr() != target) if(value.derivedSigningKey != target)
{ {
llarp::LogWarn("got introset with wrong target from service lookup"); llarp::LogWarn("got introset with wrong target from service lookup");
return false; return false;
@ -40,11 +40,10 @@ namespace llarp
ServiceAddressLookup::GetNextPeer(Key_t &next, ServiceAddressLookup::GetNextPeer(Key_t &next,
const std::set< Key_t > &exclude) const std::set< Key_t > &exclude)
{ {
Key_t k = target.ToKey();
const auto &nodes = parent->Nodes(); const auto &nodes = parent->Nodes();
if(nodes) if(nodes)
{ {
return nodes->FindCloseExcluding(k, next, exclude); return nodes->FindCloseExcluding(target, next, exclude);
} }
return false; return false;
@ -78,7 +77,7 @@ namespace llarp
// get newest introset // get newest introset
if(valuesFound.size()) if(valuesFound.size())
{ {
llarp::service::IntroSet found; llarp::service::EncryptedIntroSet found;
for(const auto &introset : valuesFound) for(const auto &introset : valuesFound)
{ {
if(found.OtherIsNewer(introset)) if(found.OtherIsNewer(introset))

@ -12,18 +12,17 @@ namespace llarp
{ {
struct TXOwner; struct TXOwner;
struct ServiceAddressLookup struct ServiceAddressLookup : public TX< Key_t, service::EncryptedIntroSet >
: public TX< service::Address, service::IntroSet >
{ {
service::IntroSetLookupHandler handleResult; service::EncryptedIntroSetLookupHandler handleResult;
uint64_t R; uint64_t R;
ServiceAddressLookup(const TXOwner &asker, const service::Address &addr, ServiceAddressLookup(const TXOwner &asker, const Key_t &addr,
AbstractContext *ctx, uint64_t r, AbstractContext *ctx, uint64_t r,
service::IntroSetLookupHandler handler); service::EncryptedIntroSetLookupHandler handler);
bool bool
Validate(const service::IntroSet &value) const override; Validate(const service::EncryptedIntroSet &value) const override;
bool bool
GetNextPeer(Key_t &next, const std::set< Key_t > &exclude) override; GetNextPeer(Key_t &next, const std::set< Key_t > &exclude) override;

@ -8,14 +8,16 @@ namespace llarp
namespace dht namespace dht
{ {
bool bool
TagLookup::Validate(const service::IntroSet &introset) const TagLookup::Validate(const service::EncryptedIntroSet &introset) const
{ {
if(!introset.Verify(parent->Now())) if(!introset.Verify(parent->Now()))
{ {
llarp::LogWarn("got invalid introset from tag lookup"); llarp::LogWarn("got invalid introset from tag lookup");
return false; return false;
} }
if(introset.topic != target) if(not introset.topic.has_value())
return false;
if(introset.topic.value() != target)
{ {
llarp::LogWarn("got introset with missmatched topic in tag lookup"); llarp::LogWarn("got introset with missmatched topic in tag lookup");
return false; return false;
@ -33,20 +35,8 @@ namespace llarp
void void
TagLookup::SendReply() TagLookup::SendReply()
{ {
std::set< service::IntroSet > found(valuesFound.begin(),
valuesFound.end());
// collect our local values if we haven't hit a limit
if(found.size() < 2)
{
auto tags =
parent->FindRandomIntroSetsWithTagExcluding(target, 1, found);
std::copy(tags.begin(), tags.end(), std::inserter(found, found.end()));
}
std::vector< service::IntroSet > values(found.begin(), found.end());
parent->DHTSendTo(whoasked.node.as_array(), parent->DHTSendTo(whoasked.node.as_array(),
new GotIntroMessage(values, whoasked.txid)); new GotIntroMessage({}, whoasked.txid));
} }
} // namespace dht } // namespace dht
} // namespace llarp } // namespace llarp

@ -9,17 +9,18 @@ namespace llarp
{ {
namespace dht namespace dht
{ {
struct TagLookup : public TX< service::Tag, service::IntroSet > struct TagLookup : public TX< service::Tag, service::EncryptedIntroSet >
{ {
uint64_t R; uint64_t R;
TagLookup(const TXOwner &asker, const service::Tag &tag, TagLookup(const TXOwner &asker, const service::Tag &tag,
AbstractContext *ctx, uint64_t r) AbstractContext *ctx, uint64_t r)
: TX< service::Tag, service::IntroSet >(asker, tag, ctx), R(r) : TX< service::Tag, service::EncryptedIntroSet >(asker, tag, ctx)
, R(r)
{ {
} }
bool bool
Validate(const service::IntroSet &introset) const override; Validate(const service::EncryptedIntroSet &introset) const override;
void void
Start(const TXOwner &peer) override; Start(const TXOwner &peer) override;

@ -247,7 +247,7 @@ namespace llarp
GetCurrentIntroductions(std::set< service::Introduction >& intros) const; GetCurrentIntroductions(std::set< service::Introduction >& intros) const;
virtual bool virtual bool
PublishIntroSet(__attribute__((unused)) AbstractRouter* r) PublishIntroSet(const service::EncryptedIntroSet&, AbstractRouter*)
{ {
return false; return false;
} }

@ -1,5 +1,5 @@
#include <service/address.hpp> #include <service/address.hpp>
#include <crypto/crypto.hpp>
#include <algorithm> #include <algorithm>
namespace llarp namespace llarp
@ -60,5 +60,14 @@ namespace llarp
// make sure it's lowercase // make sure it's lowercase
return Base32Decode(lowercase(sub, true), *this); return Base32Decode(lowercase(sub, true), *this);
} }
dht::Key_t
Address::ToKey() const
{
PubKey k;
CryptoManager::instance()->derive_subkey(k, PubKey(data()), 1);
return dht::Key_t{k.as_array()};
}
} // namespace service } // namespace service
} // namespace llarp } // namespace llarp

@ -14,7 +14,7 @@ namespace llarp
{ {
namespace service namespace service
{ {
/// Snapp/Snode Address /// Snapp Address
struct Address : public AlignedBuffer< 32 > struct Address : public AlignedBuffer< 32 >
{ {
/// if parsed using FromString this contains the subdomain /// if parsed using FromString this contains the subdomain
@ -35,21 +35,21 @@ namespace llarp
bool bool
FromString(const std::string& str, const char* tld = ".loki"); FromString(const std::string& str, const char* tld = ".loki");
Address() : AlignedBuffer< SIZE >() Address() : AlignedBuffer< 32 >()
{ {
} }
explicit Address(const Data& buf) : AlignedBuffer< SIZE >(buf) explicit Address(const Data& buf) : AlignedBuffer< 32 >(buf)
{ {
} }
Address(const Address& other) Address(const Address& other)
: AlignedBuffer< SIZE >(other.as_array()), subdomain(other.subdomain) : AlignedBuffer< 32 >(other.as_array()), subdomain(other.subdomain)
{ {
} }
explicit Address(const AlignedBuffer< SIZE >& other) explicit Address(const AlignedBuffer< 32 >& other)
: AlignedBuffer< SIZE >(other) : AlignedBuffer< 32 >(other)
{ {
} }
@ -81,10 +81,7 @@ namespace llarp
operator=(const Address& other) = default; operator=(const Address& other) = default;
dht::Key_t dht::Key_t
ToKey() const ToKey() const;
{
return dht::Key_t(as_array());
}
RouterID RouterID
ToRouter() const ToRouter() const

@ -99,12 +99,13 @@ namespace llarp
return; return;
} }
introSet().topic = m_state->m_Tag; introSet().topic = m_state->m_Tag;
if(!m_Identity.SignIntroSet(introSet(), now)) auto maybe = m_Identity.EncryptAndSignIntroSet(introSet(), now);
if(not maybe.has_value())
{ {
LogWarn("failed to sign introset for endpoint ", Name()); LogWarn("failed to generate introset for endpoint ", Name());
return; return;
} }
if(PublishIntroSet(Router())) if(PublishIntroSet(maybe.value(), Router()))
{ {
LogInfo("(re)publishing introset for endpoint ", Name()); LogInfo("(re)publishing introset for endpoint ", Name());
} }
@ -204,48 +205,6 @@ namespace llarp
} }
} }
} }
#ifdef TESTNET
// prefetch tags
for(const auto& tag : m_state->m_PrefetchTags)
{
auto itr = m_state->m_PrefetchedTags.find(tag);
if(itr == m_state->m_PrefetchedTags.end())
{
itr =
m_state->m_PrefetchedTags.emplace(tag, CachedTagResult(tag, this))
.first;
}
for(const auto& introset : itr->second.result)
{
if(HasPendingPathToService(introset.A.Addr()))
continue;
std::array< byte_t, 128 > tmp = {0};
llarp_buffer_t buf(tmp);
if(SendToServiceOrQueue(introset.A.Addr(), buf, eProtocolControl))
LogInfo(Name(), " send message to ", introset.A.Addr(), " for tag ",
tag.ToString());
else
LogWarn(Name(), " failed to send/queue data to ", introset.A.Addr(),
" for tag ", tag.ToString());
}
itr->second.Expire(now);
if(itr->second.ShouldRefresh(now))
{
auto path = PickRandomEstablishedPath();
if(path)
{
auto job = new TagLookupJob(this, &itr->second);
if(!job->SendRequestViaPath(path, Router()))
LogError(Name(), " failed to send tag lookup");
}
else
{
LogError(Name(), " has no paths for tag lookup");
}
}
}
#endif
// deregister dead sessions // deregister dead sessions
EndpointUtil::DeregisterDeadSessions(now, m_state->m_DeadSessions); EndpointUtil::DeregisterDeadSessions(now, m_state->m_DeadSessions);
@ -294,17 +253,16 @@ namespace llarp
bool bool
Endpoint::HandleGotIntroMessage(dht::GotIntroMessage_constptr msg) Endpoint::HandleGotIntroMessage(dht::GotIntroMessage_constptr msg)
{ {
std::set< IntroSet > remote; std::set< EncryptedIntroSet > remote;
auto currentPub = m_state->m_CurrentPublishTX; auto currentPub = m_state->m_CurrentPublishTX;
for(const auto& introset : msg->found) for(const auto& introset : msg->found)
{ {
if(!introset.Verify(Now())) if(not introset.Verify(Now()))
{ {
if(m_Identity.pub == introset.A && currentPub == msg->txid) LogError(Name(), " got invalid introset");
IntroSetPublishFail(); return false;
return true;
} }
if(m_Identity.pub == introset.A && currentPub == msg->txid) if(currentPub == msg->txid)
{ {
LogInfo( LogInfo(
"got introset publish confirmation for hidden service endpoint ", "got introset publish confirmation for hidden service endpoint ",
@ -312,7 +270,6 @@ namespace llarp
IntroSetPublished(); IntroSetPublished();
return true; return true;
} }
remote.insert(introset); remote.insert(introset);
} }
auto& lookups = m_state->m_PendingLookups; auto& lookups = m_state->m_PendingLookups;
@ -501,19 +458,19 @@ namespace llarp
} }
bool bool
Endpoint::PublishIntroSet(AbstractRouter* r) Endpoint::PublishIntroSet(const EncryptedIntroSet& i, AbstractRouter* r)
{ {
// publish via near router // publish via near router
RouterID location = m_Identity.pub.Addr().as_array(); const auto path = GetEstablishedPathClosestTo(i.derivedSigningKey);
auto path = GetEstablishedPathClosestTo(location); return path && PublishIntroSetVia(i, r, path);
return path && PublishIntroSetVia(r, path);
} }
struct PublishIntroSetJob : public IServiceLookup struct PublishIntroSetJob : public IServiceLookup
{ {
IntroSet m_IntroSet; EncryptedIntroSet m_IntroSet;
Endpoint* m_Endpoint; Endpoint* m_Endpoint;
PublishIntroSetJob(Endpoint* parent, uint64_t id, IntroSet introset) PublishIntroSetJob(Endpoint* parent, uint64_t id,
EncryptedIntroSet introset)
: IServiceLookup(parent, id, "PublishIntroSet") : IServiceLookup(parent, id, "PublishIntroSet")
, m_IntroSet(std::move(introset)) , m_IntroSet(std::move(introset))
, m_Endpoint(parent) , m_Endpoint(parent)
@ -530,9 +487,9 @@ namespace llarp
} }
bool bool
HandleResponse(const std::set< IntroSet >& response) override HandleResponse(const std::set< EncryptedIntroSet >& response) override
{ {
if(response.size()) if(not response.empty())
m_Endpoint->IntroSetPublished(); m_Endpoint->IntroSetPublished();
else else
m_Endpoint->IntroSetPublishFail(); m_Endpoint->IntroSetPublishFail();
@ -557,9 +514,10 @@ namespace llarp
} }
bool bool
Endpoint::PublishIntroSetVia(AbstractRouter* r, path::Path_ptr path) Endpoint::PublishIntroSetVia(const EncryptedIntroSet& i, AbstractRouter* r,
path::Path_ptr path)
{ {
auto job = new PublishIntroSetJob(this, GenTXID(), introSet()); auto job = new PublishIntroSetJob(this, GenTXID(), i);
if(job->SendRequestViaPath(path, r)) if(job->SendRequestViaPath(path, r))
{ {
m_state->m_LastPublishAttempt = Now(); m_state->m_LastPublishAttempt = Now();
@ -952,13 +910,14 @@ namespace llarp
} }
bool bool
Endpoint::OnLookup(const Address& addr, const IntroSet* introset, Endpoint::OnLookup(const Address& addr,
absl::optional< const IntroSet > introset,
const RouterID& endpoint) const RouterID& endpoint)
{ {
const auto now = Router()->Now(); const auto now = Router()->Now();
auto& fails = m_state->m_ServiceLookupFails; auto& fails = m_state->m_ServiceLookupFails;
auto& lookups = m_state->m_PendingServiceLookups; auto& lookups = m_state->m_PendingServiceLookups;
if(introset == nullptr || introset->IsExpired(now)) if(not introset.has_value() || introset->IsExpired(now))
{ {
LogError(Name(), " failed to lookup ", addr.ToString(), " from ", LogError(Name(), " failed to lookup ", addr.ToString(), " from ",
endpoint); endpoint);
@ -973,8 +932,7 @@ namespace llarp
} }
return false; return false;
} }
PutNewOutboundContext(introset.value());
PutNewOutboundContext(*introset);
return true; return true;
} }
@ -983,11 +941,12 @@ namespace llarp
ABSL_ATTRIBUTE_UNUSED llarp_time_t timeoutMS, ABSL_ATTRIBUTE_UNUSED llarp_time_t timeoutMS,
bool randomPath) bool randomPath)
{ {
path::Path_ptr path = nullptr; const dht::Key_t location = remote.ToKey();
path::Path_ptr path = nullptr;
if(randomPath) if(randomPath)
path = PickRandomEstablishedPath(); path = PickRandomEstablishedPath();
else else
path = GetEstablishedPathClosestTo(remote.ToRouter()); path = GetEstablishedPathClosestTo(location.as_array());
if(!path) if(!path)
{ {
LogWarn("No outbound path for lookup yet"); LogWarn("No outbound path for lookup yet");
@ -1017,7 +976,8 @@ namespace llarp
using namespace std::placeholders; using namespace std::placeholders;
HiddenServiceAddressLookup* job = new HiddenServiceAddressLookup( HiddenServiceAddressLookup* job = new HiddenServiceAddressLookup(
this, util::memFn(&Endpoint::OnLookup, this), remote, GenTXID()); this, util::memFn(&Endpoint::OnLookup, this), location,
PubKey{remote.as_array()}, GenTXID());
LogInfo("doing lookup for ", remote, " via ", path->Endpoint()); LogInfo("doing lookup for ", remote, " via ", path->Endpoint());
if(job->SendRequestViaPath(path, Router())) if(job->SendRequestViaPath(path, Router()))
{ {

@ -168,10 +168,11 @@ namespace llarp
HandlePathDied(path::Path_ptr p) override; HandlePathDied(path::Path_ptr p) override;
bool bool
PublishIntroSet(AbstractRouter* r) override; PublishIntroSet(const EncryptedIntroSet& i, AbstractRouter* r) override;
bool bool
PublishIntroSetVia(AbstractRouter* r, path::Path_ptr p); PublishIntroSetVia(const EncryptedIntroSet& i, AbstractRouter* r,
path::Path_ptr p);
bool bool
HandleGotIntroMessage( HandleGotIntroMessage(
@ -410,7 +411,7 @@ namespace llarp
llarp_async_verify_rc* j); llarp_async_verify_rc* j);
bool bool
OnLookup(const service::Address& addr, const IntroSet* i, OnLookup(const service::Address& addr, absl::optional< const IntroSet > i,
const RouterID& endpoint); /* */ const RouterID& endpoint); /* */
bool bool

@ -10,28 +10,36 @@ namespace llarp
{ {
HiddenServiceAddressLookup::HiddenServiceAddressLookup(Endpoint* p, HiddenServiceAddressLookup::HiddenServiceAddressLookup(Endpoint* p,
HandlerFunc h, HandlerFunc h,
const Address& addr, const dht::Key_t& l,
const PubKey& k,
uint64_t tx) uint64_t tx)
: IServiceLookup(p, tx, "HSLookup"), remote(addr), handle(std::move(h)) : IServiceLookup(p, tx, "HSLookup")
, rootkey(k)
, location(l)
, handle(std::move(h))
{ {
} }
bool bool
HiddenServiceAddressLookup::HandleResponse( HiddenServiceAddressLookup::HandleResponse(
const std::set< IntroSet >& results) const std::set< EncryptedIntroSet >& results)
{ {
absl::optional< IntroSet > found;
const Address remote(rootkey);
LogInfo("found ", results.size(), " for ", remote.ToString()); LogInfo("found ", results.size(), " for ", remote.ToString());
if(results.size() > 0) if(results.size() > 0)
{ {
IntroSet selected; EncryptedIntroSet selected;
for(const auto& introset : results) for(const auto& introset : results)
{ {
if(selected.OtherIsNewer(introset) && introset.A.Addr() == remote) if(selected.OtherIsNewer(introset))
selected = introset; selected = introset;
} }
return handle(remote, &selected, endpoint); const auto maybe = selected.MaybeDecrypt(rootkey);
if(maybe.has_value())
found = maybe.value();
} }
return handle(remote, nullptr, endpoint); return handle(remote, found, endpoint);
} }
std::shared_ptr< routing::IMessage > std::shared_ptr< routing::IMessage >
@ -39,7 +47,7 @@ namespace llarp
{ {
auto msg = std::make_shared< routing::DHTMessage >(); auto msg = std::make_shared< routing::DHTMessage >();
msg->M.emplace_back(std::make_unique< dht::FindIntroMessage >( msg->M.emplace_back(std::make_unique< dht::FindIntroMessage >(
txid, remote, dht::FindIntroMessage::MaxRecursionDepth)); txid, location, dht::FindIntroMessage::MaxRecursionDepth));
return msg; return msg;
} }

@ -12,18 +12,20 @@ namespace llarp
struct Endpoint; struct Endpoint;
struct HiddenServiceAddressLookup : public IServiceLookup struct HiddenServiceAddressLookup : public IServiceLookup
{ {
Address remote; const PubKey rootkey;
using HandlerFunc = std::function< bool(const Address&, const IntroSet*, const dht::Key_t location;
const RouterID&) >; using HandlerFunc = std::function< bool(
const Address&, absl::optional< const IntroSet >, const RouterID&) >;
HandlerFunc handle; HandlerFunc handle;
HiddenServiceAddressLookup(Endpoint* p, HandlerFunc h, HiddenServiceAddressLookup(Endpoint* p, HandlerFunc h,
const Address& addr, uint64_t tx); const dht::Key_t& location,
const PubKey& rootkey, uint64_t tx);
~HiddenServiceAddressLookup() override = default; ~HiddenServiceAddressLookup() override = default;
bool bool
HandleResponse(const std::set< IntroSet >& results) override; HandleResponse(const std::set< EncryptedIntroSet >& results) override;
std::shared_ptr< routing::IMessage > std::shared_ptr< routing::IMessage >
BuildRequestMessage() override; BuildRequestMessage() override;

@ -2,6 +2,7 @@
#include <crypto/crypto.hpp> #include <crypto/crypto.hpp>
#include <util/fs.hpp> #include <util/fs.hpp>
#include <sodium/crypto_sign_ed25519.h>
namespace llarp namespace llarp
{ {
@ -57,10 +58,11 @@ namespace llarp
Identity::RegenerateKeys() Identity::RegenerateKeys()
{ {
auto crypto = CryptoManager::instance(); auto crypto = CryptoManager::instance();
crypto->encryption_keygen(enckey);
crypto->identity_keygen(signkey); crypto->identity_keygen(signkey);
pub.Update(seckey_topublic(enckey), seckey_topublic(signkey)); crypto_sign_ed25519_sk_to_curve25519(enckey.data(), signkey.data());
pub.Update(seckey_topublic(signkey));
crypto->pqe_keygen(pq); crypto->pqe_keygen(pq);
crypto->derive_subkey_secret(derivedSignKey, signkey, 1);
} }
bool bool
@ -141,32 +143,44 @@ namespace llarp
if(!vanity.IsZero()) if(!vanity.IsZero())
van = vanity; van = vanity;
// update pubkeys // update pubkeys
pub.Update(seckey_topublic(enckey), seckey_topublic(signkey), van); pub.Update(seckey_topublic(signkey), van);
return true; crypto_sign_ed25519_sk_to_curve25519(enckey.data(), signkey.data());
auto crypto = CryptoManager::instance();
return crypto->derive_subkey_secret(derivedSignKey, signkey, 1);
} }
bool absl::optional< EncryptedIntroSet >
Identity::SignIntroSet(IntroSet& i, llarp_time_t now) const Identity::EncryptAndSignIntroSet(const IntroSet& other_i,
llarp_time_t now) const
{ {
if(i.I.size() == 0) EncryptedIntroSet encrypted;
return false;
if(other_i.I.size() == 0)
return {};
IntroSet i(other_i);
encrypted.nounce.Randomize();
// set timestamp // set timestamp
// TODO: round to nearest 1000 ms // TODO: round to nearest 1000 ms
i.T = now; i.T = now;
encrypted.signedAt = now;
// set service info // set service info
i.A = pub; i.A = pub;
// set public encryption key // set public encryption key
i.K = pq_keypair_to_public(pq); i.K = pq_keypair_to_public(pq);
// zero out signature for signing process
i.Z.Zero();
std::array< byte_t, MAX_INTROSET_SIZE > tmp; std::array< byte_t, MAX_INTROSET_SIZE > tmp;
llarp_buffer_t buf(tmp); llarp_buffer_t buf(tmp);
if(!i.BEncode(&buf)) if(not i.BEncode(&buf))
return false; return {};
// rewind and resize buffer // rewind and resize buffer
buf.sz = buf.cur - buf.base; buf.sz = buf.cur - buf.base;
buf.cur = buf.base; buf.cur = buf.base;
return Sign(i.Z, buf); const SharedSecret k(i.A.Addr());
CryptoManager::instance()->xchacha20(buf, k, encrypted.nounce);
encrypted.introsetPayload.reserve(buf.sz);
std::copy_n(buf.base, buf.sz, encrypted.introsetPayload.data());
if(not encrypted.Sign(derivedSignKey))
return {};
return encrypted;
} }
} // namespace service } // namespace service
} // namespace llarp } // namespace llarp

@ -21,6 +21,7 @@ namespace llarp
{ {
SecretKey enckey; SecretKey enckey;
SecretKey signkey; SecretKey signkey;
SecretKey derivedSignKey;
PQKeyPair pq; PQKeyPair pq;
uint64_t version = LLARP_PROTO_VERSION; uint64_t version = LLARP_PROTO_VERSION;
VanityNonce vanity; VanityNonce vanity;
@ -46,8 +47,8 @@ namespace llarp
bool bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf); DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf);
bool absl::optional< EncryptedIntroSet >
SignIntroSet(IntroSet& i, llarp_time_t now) const; EncryptAndSignIntroSet(const IntroSet& i, llarp_time_t now) const;
bool bool
Sign(Signature& sig, const llarp_buffer_t& buf) const; Sign(Signature& sig, const llarp_buffer_t& buf) const;

@ -7,6 +7,7 @@
#include <cassert> #include <cassert>
#include <sodium/crypto_generichash.h> #include <sodium/crypto_generichash.h>
#include <sodium/crypto_sign_ed25519.h>
namespace llarp namespace llarp
{ {
@ -19,6 +20,19 @@ namespace llarp
return CryptoManager::instance()->verify(signkey, payload, sig); return CryptoManager::instance()->verify(signkey, payload, sig);
} }
bool
ServiceInfo::Update(const byte_t* pubkey, const OptNonce& nonce)
{
signkey = pubkey;
if(crypto_sign_ed25519_pk_to_curve25519(enckey.data(), pubkey) == -1)
return false;
if(nonce)
{
vanity = nonce.value();
}
return UpdateAddr();
}
bool bool
ServiceInfo::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val) ServiceInfo::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val)
{ {
@ -67,13 +81,8 @@ namespace llarp
bool ServiceInfo::CalculateAddress(std::array< byte_t, 32 >& data) const bool ServiceInfo::CalculateAddress(std::array< byte_t, 32 >& data) const
{ {
std::array< byte_t, 256 > tmp; data = signkey.as_array();
llarp_buffer_t buf(tmp); return true;
if(!BEncode(&buf))
return false;
return crypto_generichash_blake2b(data.data(), data.size(), buf.base,
buf.cur - buf.base, nullptr, 0)
!= -1;
} }
bool bool

@ -45,17 +45,7 @@ namespace llarp
} }
bool bool
Update(const byte_t* enc, const byte_t* sign, Update(const byte_t* pubkey, const OptNonce& nonce = OptNonce());
const OptNonce& nonce = OptNonce())
{
enckey = enc;
signkey = sign;
if(nonce)
{
vanity = nonce.value();
}
return UpdateAddr();
}
bool bool
operator==(const ServiceInfo& other) const operator==(const ServiceInfo& other) const

@ -1,11 +1,140 @@
#include <service/intro_set.hpp> #include <service/intro_set.hpp>
#include <crypto/crypto.hpp>
#include <path/path.hpp> #include <path/path.hpp>
namespace llarp namespace llarp
{ {
namespace service namespace service
{ {
util::StatusObject
EncryptedIntroSet::ExtractStatus() const
{
const auto sz = introsetPayload.size();
return {{"location", derivedSigningKey.ToString()},
{"signedAt", signedAt},
{"size", sz}};
}
bool
EncryptedIntroSet::BEncode(llarp_buffer_t* buf) const
{
if(not bencode_start_dict(buf))
return false;
if(not BEncodeWriteDictEntry("d", derivedSigningKey, buf))
return false;
if(not BEncodeWriteDictEntry("n", nounce, buf))
return false;
if(not BEncodeWriteDictInt("s", signedAt, buf))
return false;
if(not bencode_write_bytestring(buf, "x", 1))
return false;
if(not bencode_write_bytestring(buf, introsetPayload.data(),
introsetPayload.size()))
return false;
if(not BEncodeWriteDictEntry("z", sig, buf))
return false;
return bencode_end(buf);
}
bool
EncryptedIntroSet::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
bool read = false;
if(key == "x")
{
llarp_buffer_t strbuf;
if(not bencode_read_string(buf, &strbuf))
return false;
if(strbuf.sz > MAX_INTROSET_SIZE)
return false;
introsetPayload.resize(strbuf.sz);
std::copy_n(strbuf.base, strbuf.sz, introsetPayload.data());
return true;
}
if(not BEncodeMaybeReadDictEntry("d", derivedSigningKey, read, key, buf))
return false;
if(not BEncodeMaybeReadDictEntry("n", nounce, read, key, buf))
return false;
if(not BEncodeMaybeReadDictInt("s", signedAt, read, key, buf))
return false;
if(not BEncodeMaybeReadDictEntry("z", sig, read, key, buf))
return false;
return read;
}
bool
EncryptedIntroSet::OtherIsNewer(const EncryptedIntroSet& other) const
{
return signedAt < other.signedAt;
}
std::ostream&
EncryptedIntroSet::print(std::ostream& out, int levels, int spaces) const
{
Printer printer(out, levels, spaces);
printer.printAttribute("d", derivedSigningKey);
printer.printAttribute("n", nounce);
printer.printAttribute("s", signedAt);
printer.printAttribute("x", introsetPayload);
printer.printAttribute("z", sig);
return out;
}
absl::optional< IntroSet >
EncryptedIntroSet::MaybeDecrypt(const PubKey& root) const
{
SharedSecret k(root);
IntroSet i;
std::vector< byte_t > payload = introsetPayload;
llarp_buffer_t buf(payload);
CryptoManager::instance()->xchacha20(buf, k, nounce);
if(not i.BDecode(&buf))
return {};
return i;
}
bool
EncryptedIntroSet::IsExpired(llarp_time_t now) const
{
return now >= signedAt + path::default_lifetime;
}
bool
EncryptedIntroSet::Sign(const SecretKey& k)
{
signedAt = llarp::time_now_ms();
derivedSigningKey = k.toPublic();
sig.Zero();
std::array< byte_t, MAX_INTROSET_SIZE + 128 > tmp;
llarp_buffer_t buf(tmp);
if(not BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return CryptoManager::instance()->sign(sig, k, buf);
}
bool
EncryptedIntroSet::Verify(llarp_time_t now) const
{
if(signedAt > now)
return false;
if(IsExpired(now))
return false;
std::array< byte_t, MAX_INTROSET_SIZE + 128 > tmp;
llarp_buffer_t buf(tmp);
EncryptedIntroSet copy(*this);
copy.sig.Zero();
if(not copy.BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return CryptoManager::instance()->verify(derivedSigningKey, buf, sig);
}
util::StatusObject util::StatusObject
IntroSet::ExtractStatus() const IntroSet::ExtractStatus() const
{ {

@ -23,6 +23,7 @@ namespace llarp
constexpr std::size_t MAX_INTROSET_SIZE = 4096; constexpr std::size_t MAX_INTROSET_SIZE = 4096;
// 10 seconds clock skew permitted for introset expiration // 10 seconds clock skew permitted for introset expiration
constexpr llarp_time_t MAX_INTROSET_TIME_DELTA = (10 * 1000); constexpr llarp_time_t MAX_INTROSET_TIME_DELTA = (10 * 1000);
struct IntroSet struct IntroSet
{ {
ServiceInfo A; ServiceInfo A;
@ -101,6 +102,80 @@ namespace llarp
return i.print(out, -1, -1); return i.print(out, -1, -1);
} }
/// public version of the intrset that is encrypted
struct EncryptedIntroSet
{
using Payload_t = std::vector< byte_t >;
PubKey derivedSigningKey;
llarp_time_t signedAt = 0;
Payload_t introsetPayload;
TunnelNonce nounce;
absl::optional< Tag > topic;
Signature sig;
bool
Sign(const SecretKey& k);
bool
IsExpired(llarp_time_t now) const;
bool
BEncode(llarp_buffer_t* buf) const;
bool
BDecode(llarp_buffer_t* buf)
{
return bencode_decode_dict(*this, buf);
}
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf);
bool
OtherIsNewer(const EncryptedIntroSet& other) const;
/// verify signature and timestamp
bool
Verify(llarp_time_t now) const;
std::ostream&
print(std::ostream& stream, int level, int spaces) const;
util::StatusObject
ExtractStatus() const;
absl::optional< IntroSet >
MaybeDecrypt(const PubKey& rootKey) const;
};
inline std::ostream&
operator<<(std::ostream& out, const EncryptedIntroSet& i)
{
return i.print(out, -1, -1);
}
inline bool
operator<(const EncryptedIntroSet& lhs, const EncryptedIntroSet& rhs)
{
return lhs.derivedSigningKey < rhs.derivedSigningKey;
}
inline bool
operator==(const EncryptedIntroSet& lhs, const EncryptedIntroSet& rhs)
{
return std::tie(lhs.signedAt, lhs.derivedSigningKey, lhs.nounce, lhs.sig)
== std::tie(rhs.signedAt, rhs.derivedSigningKey, rhs.nounce, rhs.sig);
}
inline bool
operator!=(const EncryptedIntroSet& lhs, const EncryptedIntroSet& rhs)
{
return !(lhs == rhs);
}
using EncryptedIntroSetLookupHandler =
std::function< void(const std::vector< EncryptedIntroSet >&) >;
using IntroSetLookupHandler = using IntroSetLookupHandler =
std::function< void(const std::vector< IntroSet >&) >; std::function< void(const std::vector< IntroSet >&) >;

@ -28,8 +28,7 @@ namespace llarp
/// handle lookup result /// handle lookup result
virtual bool virtual bool
HandleResponse(__attribute__((unused)) HandleResponse(const std::set< EncryptedIntroSet >&)
const std::set< IntroSet >& results)
{ {
return false; return false;
} }

@ -56,6 +56,7 @@ namespace llarp
OutboundContext::OutboundContext(const IntroSet& introset, Endpoint* parent) OutboundContext::OutboundContext(const IntroSet& introset, Endpoint* parent)
: path::Builder(parent->Router(), 4, path::default_len) : path::Builder(parent->Router(), 4, path::default_len)
, SendContext(introset.A, {}, this, parent) , SendContext(introset.A, {}, this, parent)
, location(introset.A.Addr().ToKey())
, currentIntroSet(introset) , currentIntroSet(introset)
{ {
@ -83,15 +84,14 @@ namespace llarp
} }
bool bool
OutboundContext::OnIntroSetUpdate(__attribute__((unused)) OutboundContext::OnIntroSetUpdate(const Address&,
const Address& addr, absl::optional< const IntroSet > i,
const IntroSet* i,
const RouterID& endpoint) const RouterID& endpoint)
{ {
if(markedBad) if(markedBad)
return true; return true;
updatingIntroSet = false; updatingIntroSet = false;
if(i) if(i.has_value())
{ {
if(currentIntroSet.T >= i->T) if(currentIntroSet.T >= i->T)
{ {
@ -105,7 +105,7 @@ namespace llarp
LogError("got expired introset from lookup from ", endpoint); LogError("got expired introset from lookup from ", endpoint);
return true; return true;
} }
currentIntroSet = *i; currentIntroSet = i.value();
} }
else else
{ {
@ -238,7 +238,7 @@ namespace llarp
HiddenServiceAddressLookup* job = new HiddenServiceAddressLookup( HiddenServiceAddressLookup* job = new HiddenServiceAddressLookup(
m_Endpoint, m_Endpoint,
util::memFn(&OutboundContext::OnIntroSetUpdate, shared_from_this()), util::memFn(&OutboundContext::OnIntroSetUpdate, shared_from_this()),
addr, m_Endpoint->GenTXID()); location, PubKey{addr.as_array()}, m_Endpoint->GenTXID());
updatingIntroSet = job->SendRequestViaPath(path, m_Endpoint->Router()); updatingIntroSet = job->SendRequestViaPath(path, m_Endpoint->Router());
} }

@ -115,9 +115,10 @@ namespace llarp
OnGeneratedIntroFrame(AsyncKeyExchange* k, PathID_t p); OnGeneratedIntroFrame(AsyncKeyExchange* k, PathID_t p);
bool bool
OnIntroSetUpdate(const Address& addr, const IntroSet* i, OnIntroSetUpdate(const Address& addr, absl::optional< const IntroSet > i,
const RouterID& endpoint); const RouterID& endpoint);
const dht::Key_t location;
uint64_t m_UpdateIntrosetTX = 0; uint64_t m_UpdateIntrosetTX = 0;
IntroSet currentIntroSet; IntroSet currentIntroSet;
Introduction m_NextIntro; Introduction m_NextIntro;

@ -9,17 +9,8 @@ namespace llarp
namespace service namespace service
{ {
bool bool
CachedTagResult::HandleResponse(const std::set< IntroSet >& introsets) CachedTagResult::HandleResponse(const std::set< EncryptedIntroSet >&)
{ {
auto now = m_parent->Now();
for(const auto& introset : introsets)
if(result.insert(introset).second)
lastModified = now;
LogInfo("Tag result for ", tag.ToString(), " got ", introsets.size(),
" results from lookup, have ", result.size(),
" cached last modified at ", lastModified, " is ",
now - lastModified, "ms old");
return true; return true;
} }
@ -29,9 +20,8 @@ namespace llarp
auto itr = result.begin(); auto itr = result.begin();
while(itr != result.end()) while(itr != result.end())
{ {
if(itr->HasExpiredIntros(now)) if(itr->IsExpired(now))
{ {
LogInfo("Removing expired tag Entry ", itr->A.Name());
itr = result.erase(itr); itr = result.erase(itr);
lastModified = now; lastModified = now;
} }

@ -20,7 +20,7 @@ namespace llarp
const static llarp_time_t TTL = 10000; const static llarp_time_t TTL = 10000;
llarp_time_t lastRequest = 0; llarp_time_t lastRequest = 0;
llarp_time_t lastModified = 0; llarp_time_t lastModified = 0;
std::set< IntroSet > result; std::set< EncryptedIntroSet > result;
Tag tag; Tag tag;
Endpoint* m_parent; Endpoint* m_parent;
@ -45,7 +45,7 @@ namespace llarp
BuildRequestMessage(uint64_t txid); BuildRequestMessage(uint64_t txid);
bool bool
HandleResponse(const std::set< IntroSet >& results); HandleResponse(const std::set< EncryptedIntroSet >& results);
}; };
struct TagLookupJob : public IServiceLookup struct TagLookupJob : public IServiceLookup
@ -61,7 +61,7 @@ namespace llarp
} }
bool bool
HandleResponse(const std::set< IntroSet >& results) override HandleResponse(const std::set< EncryptedIntroSet >& results) override
{ {
return m_result->HandleResponse(results); return m_result->HandleResponse(results);
} }

@ -43,6 +43,11 @@ namespace llarp
bool(byte_t *, const llarp_buffer_t &, bool(byte_t *, const llarp_buffer_t &,
const SharedSecret &)); const SharedSecret &));
MOCK_METHOD3(derive_subkey, bool(PubKey &, const PubKey &, uint64_t));
MOCK_METHOD3(derive_subkey_secret,
bool(SecretKey &, const SecretKey &, uint64_t));
MOCK_METHOD3(sign, MOCK_METHOD3(sign,
bool(Signature &, const SecretKey &, bool(Signature &, const SecretKey &,
const llarp_buffer_t &)); const llarp_buffer_t &));
@ -70,7 +75,7 @@ namespace llarp
MOCK_METHOD3(pqe_encrypt, MOCK_METHOD3(pqe_encrypt,
bool(PQCipherBlock &, SharedSecret &, const PQPubKey &)); bool(PQCipherBlock &, SharedSecret &, const PQPubKey &));
MOCK_METHOD1(check_identity_privkey, bool(const SecretKey&)); MOCK_METHOD1(check_identity_privkey, bool(const SecretKey &));
}; };
} // namespace test } // namespace test
} // namespace llarp } // namespace llarp

@ -20,35 +20,23 @@ namespace llarp
const dht::Key_t&, RouterLookupHandler)); const dht::Key_t&, RouterLookupHandler));
MOCK_METHOD6(LookupIntroSetRecursive, MOCK_METHOD6(LookupIntroSetRecursive,
void(const service::Address&, const dht::Key_t&, uint64_t, void(const dht::Key_t&, const dht::Key_t&, uint64_t,
const dht::Key_t&, uint64_t, const dht::Key_t&, uint64_t,
service::IntroSetLookupHandler)); service::EncryptedIntroSetLookupHandler));
MOCK_METHOD5(LookupIntroSetIterative, MOCK_METHOD5(LookupIntroSetIterative,
void(const service::Address&, const dht::Key_t&, uint64_t, void(const dht::Key_t&, const dht::Key_t&, uint64_t,
const dht::Key_t&, service::IntroSetLookupHandler)); const dht::Key_t&,
service::EncryptedIntroSetLookupHandler));
MOCK_METHOD3(
FindRandomIntroSetsWithTagExcluding,
std::set< service::IntroSet >(const service::Tag&, size_t,
const std::set< service::IntroSet >&));
MOCK_CONST_METHOD1(HasRouterLookup, bool(const RouterID& target)); MOCK_CONST_METHOD1(HasRouterLookup, bool(const RouterID& target));
MOCK_METHOD5(LookupTagRecursive,
void(const service::Tag&, const dht::Key_t&, uint64_t,
const dht::Key_t&, uint64_t));
MOCK_METHOD4(LookupTagForPath,
void(const service::Tag&, uint64_t, const PathID_t&,
const dht::Key_t&));
MOCK_METHOD4(LookupRouterForPath, MOCK_METHOD4(LookupRouterForPath,
void(const RouterID& target, uint64_t txid, void(const RouterID& target, uint64_t txid,
const PathID_t& path, const dht::Key_t& askpeer)); const PathID_t& path, const dht::Key_t& askpeer));
MOCK_METHOD5(LookupIntroSetForPath, MOCK_METHOD5(LookupIntroSetForPath,
void(const service::Address&, uint64_t, const PathID_t&, void(const dht::Key_t&, uint64_t, const PathID_t&,
const dht::Key_t&, uint64_t)); const dht::Key_t&, uint64_t));
MOCK_METHOD3(DHTSendTo, void(const RouterID&, dht::IMessage*, bool)); MOCK_METHOD3(DHTSendTo, void(const RouterID&, dht::IMessage*, bool));
@ -73,16 +61,16 @@ namespace llarp
MOCK_METHOD6(PropagateIntroSetTo, MOCK_METHOD6(PropagateIntroSetTo,
void(const dht::Key_t& source, uint64_t sourceTX, void(const dht::Key_t& source, uint64_t sourceTX,
const service::IntroSet& introset, const service::EncryptedIntroSet& introset,
const dht::Key_t& peer, uint64_t S, const dht::Key_t& peer, uint64_t S,
const std::set< dht::Key_t >& exclude)); const std::set< dht::Key_t >& exclude));
MOCK_METHOD3(Init, MOCK_METHOD3(Init,
void(const dht::Key_t&, AbstractRouter*, llarp_time_t)); void(const dht::Key_t&, AbstractRouter*, llarp_time_t));
MOCK_CONST_METHOD1( MOCK_CONST_METHOD1(GetIntroSetByLocation,
GetIntroSetByServiceAddress, absl::optional< llarp::service::EncryptedIntroSet >(
const llarp::service::IntroSet*(const llarp::service::Address&)); const llarp::dht::Key_t&));
MOCK_CONST_METHOD0(ExtractStatus, util::StatusObject()); MOCK_CONST_METHOD0(ExtractStatus, util::StatusObject());
@ -98,10 +86,6 @@ namespace llarp
const PendingIntrosetLookups&()); const PendingIntrosetLookups&());
MOCK_METHOD0(pendingIntrosetLookups, PendingIntrosetLookups&()); MOCK_METHOD0(pendingIntrosetLookups, PendingIntrosetLookups&());
MOCK_METHOD0(pendingTagLookups, PendingTagLookups&());
MOCK_CONST_METHOD0(pendingTagLookups, const PendingTagLookups&());
MOCK_METHOD0(pendingRouterLookups, PendingRouterLookups&()); MOCK_METHOD0(pendingRouterLookups, PendingRouterLookups&());
MOCK_CONST_METHOD0(pendingRouterLookups, const PendingRouterLookups&()); MOCK_CONST_METHOD0(pendingRouterLookups, const PendingRouterLookups&());

@ -72,19 +72,18 @@ TEST_F(TestDhtISNode, construct)
ASSERT_THAT(node.ID, Property(&dht::Key_t::IsZero, true)); ASSERT_THAT(node.ID, Property(&dht::Key_t::IsZero, true));
node.ID.Fill(0xCA); node.ID.Fill(0xCA);
node.introset.K.Fill(0xDB); node.introset.derivedSigningKey.Fill(0xDB);
dht::ISNode other{node}; dht::ISNode other{node};
ASSERT_EQ(node.ID, other.ID); ASSERT_EQ(node.ID, other.ID);
ASSERT_EQ(node.introset, other.introset); ASSERT_EQ(node.introset, other.introset);
service::IntroSet introSet; service::EncryptedIntroSet introSet;
introSet.K.Randomize(); introSet.derivedSigningKey.Randomize();
introSet.A.UpdateAddr();
dht::ISNode fromIntro{introSet}; dht::ISNode fromIntro{introSet};
ASSERT_EQ(fromIntro.ID.as_array(), introSet.A.Addr().as_array()); ASSERT_EQ(fromIntro.ID.as_array(), introSet.derivedSigningKey);
} }
TEST_F(TestDhtISNode, lt) TEST_F(TestDhtISNode, lt)
@ -94,10 +93,10 @@ TEST_F(TestDhtISNode, lt)
dht::ISNode three; dht::ISNode three;
dht::ISNode eqThree; dht::ISNode eqThree;
one.introset.T = 1; one.introset.signedAt = 1;
two.introset.T = 2; two.introset.signedAt = 2;
three.introset.T = 3; three.introset.signedAt = 3;
eqThree.introset.T = 3; eqThree.introset.signedAt = 3;
// LT cases // LT cases
ASSERT_THAT(one, Lt(two)); ASSERT_THAT(one, Lt(two));

@ -10,6 +10,8 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gmock/gmock.h> #include <gmock/gmock.h>
#if 0
using namespace llarp; using namespace llarp;
using namespace ::testing; using namespace ::testing;
@ -17,7 +19,7 @@ using test::makeBuf;
struct MockIntroSetHandler struct MockIntroSetHandler
{ {
MOCK_METHOD1(call, void(const std::vector< service::IntroSet > &)); MOCK_METHOD1(call, void(const std::vector< service::EncryptedIntroSet > &));
}; };
static constexpr uint64_t EXPIRY = 1548503831ull; static constexpr uint64_t EXPIRY = 1548503831ull;
@ -59,9 +61,8 @@ TEST_F(TestDhtServiceAddressLookup, validate)
// - introset fails to verify // - introset fails to verify
// - introset topic is not the target // - introset topic is not the target
// - happy path // - happy path
{ {
service::IntroSet introset; service::EncryptedIntroSet introset;
EXPECT_CALL(context, Now()).WillOnce(Return(EXPIRY)); EXPECT_CALL(context, Now()).WillOnce(Return(EXPIRY));
EXPECT_CALL(m_crypto, verify(_, _, _)).WillOnce(Return(false)); EXPECT_CALL(m_crypto, verify(_, _, _)).WillOnce(Return(false));
@ -217,3 +218,5 @@ TEST_F(TestDhtServiceAddressLookup, send_reply)
ASSERT_NO_THROW(serviceAddressLookup->SendReply()); ASSERT_NO_THROW(serviceAddressLookup->SendReply());
} }
} }
#endif

@ -8,7 +8,7 @@
#include <test_util.hpp> #include <test_util.hpp>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#if 0
using namespace llarp; using namespace llarp;
using namespace ::testing; using namespace ::testing;
@ -228,3 +228,5 @@ TEST_F(TestDhtTagLookup, send_reply)
ASSERT_NO_THROW(tagLookup.SendReply()); ASSERT_NO_THROW(tagLookup.SendReply());
} }
} }
#endif

@ -39,9 +39,9 @@ TEST_F(HiddenServiceTest, TestGenerateIntroSet)
EXPECT_CALL(m_crypto, sign(I.Z, _, _)).WillOnce(Return(true)); EXPECT_CALL(m_crypto, sign(I.Z, _, _)).WillOnce(Return(true));
EXPECT_CALL(m_crypto, verify(_, _, I.Z)).WillOnce(Return(true)); EXPECT_CALL(m_crypto, verify(_, _, I.Z)).WillOnce(Return(true));
const auto maybe = ident.EncryptAndSignIntroSet(I, now);
ASSERT_TRUE(ident.SignIntroSet(I, now)); ASSERT_TRUE(maybe.has_value());
ASSERT_TRUE(I.Verify(now)); ASSERT_TRUE(maybe->Verify(now));
} }
TEST_F(HiddenServiceTest, TestAddressToFromString) TEST_F(HiddenServiceTest, TestAddressToFromString)
@ -73,8 +73,7 @@ TEST_F(ServiceIdentityTest, EnsureKeys)
test::FileGuard guard(p); test::FileGuard guard(p);
EXPECT_CALL(m_crypto, encryption_keygen(_)) const SecretKey k;
.WillOnce(WithArg< 0 >(FillArg< SecretKey >(0x01)));
EXPECT_CALL(m_crypto, identity_keygen(_)) EXPECT_CALL(m_crypto, identity_keygen(_))
.WillOnce(WithArg< 0 >(FillArg< SecretKey >(0x02))); .WillOnce(WithArg< 0 >(FillArg< SecretKey >(0x02)));

Loading…
Cancel
Save