Commit bb2a95d9 authored by Luker's avatar Luker

Connect Lattice with handshake

Signed-off-by: Luker's avatarLuca Fulchir <luker@fenrirproject.org>
parent b9b6d10b
......@@ -219,6 +219,7 @@ SET(HEADERS src/Fenrir/v1/API/Report.hpp
src/Fenrir/v1/auth/Lattice.hpp
src/Fenrir/v1/auth/Lattice.ipp
src/Fenrir/v1/auth/Token.hpp
src/Fenrir/v1/auth/Token.ipp
src/Fenrir/v1/crypto/Crypto.hpp
src/Fenrir/v1/crypto/Crypto_NULL.hpp
src/Fenrir/v1/crypto/Sodium.hpp
......
......@@ -25,6 +25,7 @@
#include "Fenrir/v1/plugin/Loader.ipp"
#include "Fenrir/v1/auth/Lattice.ipp"
#include "Fenrir/v1/auth/Token.ipp"
#include "Fenrir/v1/data/control/Control.ipp"
#include "Fenrir/v1/data/Conn0.ipp"
#include "Fenrir/v1/data/packet/Stream.ipp"
......
......@@ -76,7 +76,10 @@ public:
Conn_ID get_next_free (const Conn_ID id);
void connect (const std::vector<uint8_t> &dest, const Service_ID &service);
std::unique_ptr<Report::Base> get_report();
std::shared_ptr<Lattice> search_lattice (const Service_ID service,
const std::vector<uint8_t> &vhost);
private:
// vhost: service_id + domain
struct FENRIR_LOCAL Vhost_Service :
type_safe::strong_typedef<Vhost_Service,
std::pair<Service_ID, std::vector<uint8_t>>>,
......@@ -108,9 +111,9 @@ private:
}
return x < 0;
}
};
};;
Shared_Lock _conn_lock, _sock_lock, _srv_lock, _res_lock;
Shared_Lock _conn_lock, _sock_lock, _srv_lock, _res_lock, _service_lock;
std::mutex _rep_lock;
Event::Loop _loop;
Random _rnd;
......
......@@ -374,5 +374,26 @@ FENRIR_INLINE void Handler::plg_ev (std::shared_ptr<Event::Plugin_Timer> ev)
return plugin->parse_event (std::move(ev));
}
FENRIR_INLINE std::shared_ptr<Lattice> Handler::search_lattice (
const Service_ID service,
const std::vector<uint8_t> &vhost)
{
Shared_Lock_Guard<Shared_Lock_Read> rlock (Shared_Lock_NN{&_service_lock});
// FIXME: ticket #1 avoid enumeration of vhost/services
for (const auto &vhost_info : _service_info) {
const auto vhost_s = std::get<Vhost_Service> (vhost_info);
if (vhost != std::get<std::vector<uint8_t>> (
static_cast<std::pair<Service_ID, std::vector<uint8_t>>> (
vhost_s))) {
continue;
}
if (service == std::get<Service_ID> (static_cast<const
std::pair<Service_ID, std::vector<uint8_t>>>(vhost_s))){
return std::get<std::shared_ptr<Lattice>> (
std::get<Service_Info> (vhost_info));
}
}
}
} // namespace Impl
} // namespace Fenrir__v1
......@@ -21,6 +21,7 @@
#pragma once
#include <vector>
#include "Fenrir/v1/auth/Lattice.hpp"
#include "Fenrir/v1/common.hpp"
#include "Fenrir/v1/data/Device_ID.hpp"
#include "Fenrir/v1/data/Username.hpp"
......@@ -42,7 +43,8 @@ class FENRIR_LOCAL Auth_Result
{
public:
Auth_Result()
: _user_id {0}, _anonymous (true), _failed (true) {}
: _user_id {0}, _lattice_node (Lattice::BOTTOM),
_anonymous (true), _failed (true) {}
Auth_Result (const Auth_Result&) = default;
Auth_Result& operator= (const Auth_Result&) = default;
......@@ -51,6 +53,7 @@ public:
~Auth_Result() = default;
User_ID _user_id;
Lattice_Node::ID _lattice_node;
bool _anonymous, _failed;
};
......@@ -75,6 +78,8 @@ public:
// see issue #1 (constant time) when implementing
virtual Auth_Result authenticate (const Device_ID &dev_id,
const Service_ID &service,
const std::shared_ptr<Lattice> lattice,
const Lattice_Node::ID lattice_node,
const Username &auth_user,
const Username &service_user,
const gsl::span<uint8_t> data, Db *db) = 0;
......
......@@ -23,21 +23,28 @@
#include "Fenrir/v1/common.hpp"
#include <gsl/span>
#include <memory>
#include <type_safe/strong_typedef.hpp>
#include <vector>
namespace Fenrir__v1 {
namespace Impl {
class FENRIR_LOCAL Lattice_Node
{
public:
std::vector<uint8_t> _name;
std::vector<std::weak_ptr<Lattice_Node>> _parents;
std::vector<std::shared_ptr<Lattice_Node>> _children;
uint8_t _id;
struct FENRIR_LOCAL ID :
type_safe::strong_typedef<ID, uint8_t>,
type_safe::strong_typedef_op::equality_comparison<ID>,
type_safe::strong_typedef_op::relational_comparison<ID>
{ using strong_typedef::strong_typedef; };
ID _id;
Lattice_Node() = delete;
Lattice_Node (const uint8_t id, const gsl::span<const uint8_t> name)
Lattice_Node (const ID id, const gsl::span<const uint8_t> name)
:_id (id)
{
_name.reserve (static_cast<size_t> (name.size()));
......@@ -54,6 +61,7 @@ public:
class FENRIR_LOCAL Lattice
{
public:
static const constexpr Lattice_Node::ID TOP {0x00}, BOTTOM {0xFF};
// id 0 is reserved (top), id 255 is reserved (bottom)
Lattice ();
Lattice (const gsl::span<const uint8_t> raw);
......@@ -64,10 +72,12 @@ public:
~Lattice() = default;
operator bool() const;
bool exists (const uint8_t id) const;
bool includes (const uint8_t parent, const uint8_t child) const;
bool add_node (const uint8_t id, const gsl::span<const uint8_t> name,
const std::vector<uint8_t> parents);
bool exists (const Lattice_Node::ID id) const;
bool includes (const Lattice_Node::ID parent,
const Lattice_Node::ID child) const;
bool add_node (const Lattice_Node::ID id,
const gsl::span<const uint8_t> name,
const std::vector<Lattice_Node::ID> parents);
size_t raw_size() const;
// output format:
// 1b Node ID
......@@ -76,12 +86,11 @@ public:
bool write (gsl::span<uint8_t> out) const;
private:
static constexpr uint8_t TOP = 0x00, BOTTOM = 0xFF;
static constexpr uint8_t MAX_NAME = 30;
std::shared_ptr<Lattice_Node> _top;
std::shared_ptr<Lattice_Node> find(const std::shared_ptr<Lattice_Node> from,
const uint8_t id) const;
const Lattice_Node::ID id) const;
};
......
......@@ -34,6 +34,8 @@ constexpr std::array<const uint8_t, 6> lattice_a_BOTTOM {{
'b','o','t','t','o','m' }};
}
constexpr Lattice_Node::ID Lattice::TOP, Lattice::BOTTOM;
FENRIR_INLINE Lattice::Lattice()
{
auto bottom = std::make_shared<Lattice_Node> (BOTTOM,
......@@ -59,7 +61,7 @@ FENRIR_INLINE Lattice::Lattice (const gsl::span<const uint8_t> raw)
_top = nullptr;
return;
}
const uint8_t node_id = raw[idx++];
const Lattice_Node::ID node_id {raw[idx++]};
if (node_id == TOP || node_id == BOTTOM) {
_top = nullptr;
return;
......@@ -76,9 +78,9 @@ FENRIR_INLINE Lattice::Lattice (const gsl::span<const uint8_t> raw)
_top = nullptr;
return;
}
std::vector<uint8_t> parents (parents_len);
std::vector<Lattice_Node::ID> parents (parents_len);
while (parents_len > 0) {
const uint8_t parent_id = raw[idx];
const Lattice_Node::ID parent_id {raw[idx]};
if (parent_id == BOTTOM) {
_top = nullptr;
return;
......@@ -96,15 +98,15 @@ FENRIR_INLINE Lattice::Lattice (const gsl::span<const uint8_t> raw)
FENRIR_INLINE Lattice::operator bool() const
{ return _top != nullptr; }
FENRIR_INLINE bool Lattice::exists (const uint8_t id) const
FENRIR_INLINE bool Lattice::exists (const Lattice_Node::ID id) const
{
if (find (_top, id) == nullptr)
return false;
return true;
}
FENRIR_INLINE bool Lattice::includes (const uint8_t parent,
const uint8_t child) const
FENRIR_INLINE bool Lattice::includes (const Lattice_Node::ID parent,
const Lattice_Node::ID child) const
{
auto node = find (_top, parent);
if (find (node, child) == nullptr)
......@@ -112,9 +114,9 @@ FENRIR_INLINE bool Lattice::includes (const uint8_t parent,
return true;
}
FENRIR_INLINE bool Lattice::add_node (const uint8_t id,
const gsl::span<const uint8_t> name,
const std::vector<uint8_t> parents)
FENRIR_INLINE bool Lattice::add_node (const Lattice_Node::ID id,
const gsl::span<const uint8_t> name,
const std::vector<Lattice_Node::ID> parents)
{
// limit name to 30 chars.
if (name.size() > MAX_NAME)
......@@ -123,7 +125,10 @@ FENRIR_INLINE bool Lattice::add_node (const uint8_t id,
return false; // already present
std::vector<std::shared_ptr<Lattice_Node>> sh_parents;
sh_parents.reserve (parents.size());
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wrange-loop-analysis"
for (const auto p : parents) {
#pragma clang diagnostic pop
if (p == BOTTOM)
return false;
auto tmp = find (_top, p);
......@@ -183,7 +188,7 @@ FENRIR_INLINE bool Lattice::write (gsl::span<uint8_t> out) const
queue.pop_front();
for (auto child : x->_children)
queue.push_back (child);
*it = x->_id;
*it = static_cast<uint8_t> (x->_id);
*it = static_cast<uint8_t> (x->_name.size());
for (const uint8_t el : x->_name)
*(it++) = el;
......@@ -191,7 +196,7 @@ FENRIR_INLINE bool Lattice::write (gsl::span<uint8_t> out) const
for (auto weak_p : x->_parents) {
auto sh_p = weak_p.lock();
assert (sh_p != nullptr && "Lattice_Write:: parent nullptr");
*(it++) = sh_p->_id;
*(it++) = static_cast<uint8_t> (sh_p->_id);
}
}
return true;
......@@ -199,7 +204,7 @@ FENRIR_INLINE bool Lattice::write (gsl::span<uint8_t> out) const
FENRIR_INLINE std::shared_ptr<Lattice_Node> Lattice::find (
const std::shared_ptr<Lattice_Node> from,
const uint8_t id) const
const Lattice_Node::ID id) const
{
// BFS
std::deque<std::shared_ptr<Lattice_Node>> queue;
......
......@@ -20,13 +20,14 @@
#pragma once
#include <memory>
#include <vector>
#include "Fenrir/v1/auth/Auth.hpp"
#include "Fenrir/v1/db/Db.hpp"
#include "Fenrir/v1/auth/Lattice.hpp"
#include "Fenrir/v1/common.hpp"
#include "Fenrir/v1/data/Username.hpp"
#include "Fenrir/v1/db/Db.hpp"
#include "Fenrir/v1/plugin/Lib.hpp"
#include "Fenrir/v1/common.hpp"
#include <memory>
#include <vector>
namespace Fenrir__v1 {
namespace Impl {
......@@ -42,12 +43,14 @@ public:
Token& operator= (const Token&) = default;
Token (Token &&) = default;
Token& operator= (Token &&) = default;
~Token() = default;
~Token() override = default;
void parse_event (std::shared_ptr<Event::Plugin_Timer> ev) override
{ FENRIR_UNUSED (ev); }
Auth_Result authenticate (const Device_ID &dev_id,
const Service_ID &service,
const std::shared_ptr<Lattice> lattice,
const Lattice_Node::ID lattice_node,
const Username &auth_user,
const Username &service_user,
const gsl::span<uint8_t> data, Db *db) override;
......@@ -55,35 +58,6 @@ public:
{ return Auth::ID {1}; }
};
// see issue #1 (constant time)
FENRIR_INLINE Auth_Result Token::authenticate (const Device_ID &dev_id,
const Service_ID &service,
const Username &auth_user,
const Username &service_user,
const gsl::span<uint8_t> data, Db *db)
{
auto db_result = db->get_auth (dev_id, service, auth_user, service_user,
id());
Auth_Result ret;
if (auth_user.is_anonymous() && service_user.is_anonymous()) {
ret._failed = false;
return ret;
}
// TODO: XORed, OTP version.
if (data.size() != sizeof(Token_t) || db_result._user_id == User_ID{0})
return ret;
const Token_t *t_ptr = reinterpret_cast<const Token_t*> (data.data());
if (db_result._token == *t_ptr) {
ret._user_id = db_result._user_id;
ret._anonymous = false;
ret._failed = false;
}
return ret;
}
} // namespace Auth
} // namespace Impl
} // namespace Fenrir__v1
/*
* Copyright (c) 2016-2017, Luca Fulchir<luca@fulchir.it>, All rights reserved.
*
* This file is part of libFenrir.
*
* libFenrir is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* libFenrir is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* and a copy of the GNU Lesser General Public License
* along with libFenrir. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "Fenrir/v1/auth/Token.hpp"
namespace Fenrir__v1 {
namespace Impl {
namespace Crypto {
// see issue #1 (constant time)
FENRIR_INLINE Auth_Result Token::authenticate (const Device_ID &dev_id,
const Service_ID &service,
const std::shared_ptr<Lattice> lattice,
const Lattice_Node::ID lattice_node,
const Username &auth_user,
const Username &service_user,
const gsl::span<uint8_t> data, Db *db)
{
auto db_result = db->get_auth (dev_id, service, auth_user, service_user,
id());
Auth_Result ret; // default values are safe (auth failed, anonimous, bottom)
if (auth_user.is_anonymous() && service_user.is_anonymous()) {
ret._failed = false;
return ret;
}
// TODO: XORed, OTP version.
if (data.size() != sizeof(Token_t) || db_result._user_id == User_ID{0})
return ret;
const Token_t *t_ptr = reinterpret_cast<const Token_t*> (data.data());
if (db_result._token == *t_ptr) {
ret._user_id = db_result._user_id;
ret._lattice_node = Lattice::TOP; // TODO: actually check
ret._anonymous = false;
ret._failed = false;
}
// override previous results if no lattice ot not TOP
// TODO: actually check the lattice
if (lattice == nullptr || lattice_node != Lattice::TOP) {
ret._user_id = User_ID {0};
ret._lattice_node = Lattice::BOTTOM;
ret._anonymous = true;
ret._failed = true;
}
return ret;
}
} // namespace Auth
} // namespace Impl
} // namespace Fenrir__v1
......@@ -22,6 +22,7 @@
#include "Fenrir/v1/common.hpp"
#include "Fenrir/v1/auth/Auth.hpp"
#include "Fenrir/v1/auth/Lattice.hpp"
#include "Fenrir/v1/crypto/Crypto.hpp"
#include "Fenrir/v1/data/Conn0_Type.hpp"
#include "Fenrir/v1/data/Device_ID.hpp"
......@@ -312,6 +313,7 @@ public:
Packet::Alignment_Flag _alignment;
Stream_ID _control_stream;
Crypto::Auth::ID _selected_auth;
Lattice_Node::ID _lattice_node;
};
struct stream_info {
Stream_ID _id;
......@@ -336,6 +338,7 @@ public:
const uint8_t padding,
const Packet::Alignment_Flag alignment,
const Crypto::Auth::ID selected_auth,
const Lattice_Node::ID lattice_node,
const Stream_ID control_stream,
const gsl::span<const uint8_t>auth_data,
const uint16_t streams);
......
......@@ -510,6 +510,7 @@ Conn0_Auth_Data::Conn0_Auth_Data (gsl::span<uint8_t> raw_pkt,
const uint8_t padding,
const Packet::Alignment_Flag alignment,
const Crypto::Auth::ID selected_auth,
const Lattice_Node::ID lattice_node,
const Stream_ID control_stream,
const gsl::span<const uint8_t>auth_data,
const uint16_t streams)
......@@ -552,6 +553,7 @@ Conn0_Auth_Data::Conn0_Auth_Data (gsl::span<uint8_t> raw_pkt,
w->_alignment = alignment;
w->_control_stream = control_stream;
w->_selected_auth = selected_auth;
w->_lattice_node = lattice_node;
auth_username (_auth_username);
service_username (_service_username);
memcpy (_auth_data.data(), auth_data.data(),
......
......@@ -20,6 +20,7 @@
#pragma once
#include "Fenrir/v1/auth/Lattice.hpp"
#include "Fenrir/v1/common.hpp"
#include "Fenrir/v1/util/Shared_Lock.ipp"
#include "Fenrir/v1/plugin/Loader.ipp"
......@@ -27,6 +28,7 @@
#include "Fenrir/v1/net/Handshake.hpp"
#include "Fenrir/v1/net/Connection.hpp"
#include "Fenrir/v1/data/Conn0.hpp"
#include "Fenrir/v1/data/Username.hpp"
#include <algorithm>
#include <array>
#include <chrono>
......@@ -870,6 +872,7 @@ FENRIR_INLINE void Handshake::answer_s_keys (const Link_ID recv_from,
_rnd->uniform<uint8_t> (0, 7), // TODO: more random?
Packet::Alignment_Flag::UINT8,
Crypto::Auth::ID {1}, // FIXME: generalize
Lattice::TOP, // FIXME: generalize
Stream_ID {_rnd->uniform<uint16_t>()},
test_token,
streams_num);
......@@ -1014,7 +1017,6 @@ FENRIR_INLINE void Handshake::answer_c_auth (const Link_ID recv_from,
return;
}
Shared_Lock_Guard<Shared_Lock_Read> readlock {Shared_Lock_NN{&_mtx_auths}};
auto auth_it = std::lower_bound (auths.begin(), auths.end(),
client_auth_data.r->_selected_auth,
......@@ -1029,11 +1031,15 @@ FENRIR_INLINE void Handshake::answer_c_auth (const Link_ID recv_from,
Username client_service_user { client_auth_data._service_username };
if (!client_auth_user || !client_service_user)
return;
auto sh_lattice = _handler->search_lattice (client_auth_data.r->_service,
client_service_user.domain);
auto auth_res = auth->authenticate (client_auth_data.r->_dev_id,
client_auth_data.r->_service,
client_auth_user,
client_service_user,
client_auth_data._auth_data, _db);
client_auth_data.r->_service,
std::move(sh_lattice),
client_auth_data.r->_lattice_node,
client_auth_user,
client_service_user,
client_auth_data._auth_data, _db);
const Stream_ID srv_control_stream {_rnd->uniform<uint16_t>()};
const Counter control_stream_start {_rnd->uniform<uint32_t> (0,
......
......@@ -36,88 +36,24 @@
namespace Fenrir__v1 {
namespace Impl {
// lockless, thread safe.
class FENRIR_LOCAL Service_Info
{
public:
using stream_info = std::vector<std::tuple<Storage_t, Stream_PRIO>>;
Service_Info()
: _info (nullptr)
{}
Service_Info (const Service_Info&) = delete;
Service_Info& operator= (const Service_Info&) = delete;
Service_Info (Service_Info &&) = default;
Service_Info& operator= (Service_Info &&) = default;
~Service_Info() = default;
stream_info get_streams (const Service_ID &service)
{
std::lock_guard<std::mutex> lock (_mtx);
FENRIR_UNUSED (lock);
auto p = _info;
if (p == nullptr)
return stream_info{};
auto res = std::lower_bound (p->begin(), p->end(), service,
[] (const auto it, const Service_ID &id)
{
return std::get<Service_ID> (it) < id;
});
if (std::get<Service_ID> (*res) == service)
return std::get<stream_info> (*res);
return stream_info{};
}
Lattice get_lattice (const Service_ID &service)
{
std::lock_guard<std::mutex> lock (_mtx);
FENRIR_UNUSED (lock);
auto p = _info;
if (p == nullptr)
return Lattice{};
auto res = std::lower_bound (p->begin(), p->end(), service,
[] (const auto it, const Service_ID &id)
{
return std::get<Service_ID> (it) < id;
});
if (std::get<Service_ID> (*res) == service)
return std::get<Lattice> (*res);
return Lattice{};
}
bool add_service (const Service_ID id, stream_info &streams,
Lattice &lattice)
{
while (true) {
std::shared_ptr<std::vector<std::tuple<
Service_ID, stream_info, Lattice>>> current, copy;
current = _info;
size_t cur_size = 0;
if (current != nullptr)
cur_size = current->size();
copy = std::make_shared<std::vector<
std::tuple<Service_ID, stream_info, Lattice>>> (
cur_size + 1);
for (size_t idx = 0; idx < cur_size; ++idx) {
copy->push_back ((*current)[idx]);
}
copy->emplace_back (id, streams, lattice);
std::lock_guard<std::mutex> lock (_mtx);
FENRIR_UNUSED (lock);
if (_info.get() == copy.get()) {
_info = current;
break;
}
}
return true;
}
private:
std::mutex _mtx;
std::shared_ptr<std::vector<
std::tuple<Service_ID, stream_info, Lattice>>> _info;
};
// a service is identified by its domain and its service_ID
// each service can create automatically a number of streams with different
// priorities. Different instances of the same service mught be able to handle
// a different number of streams, so this is a per-service setting.
//
// The same applies to the Lattices.
// Naively we can think that a Service_ID and a Lattice are interdependent,
// but protocols evolve, and we might have two services with slightly different
// lattices.
// This also implies that there will be a versioning / compatibility list
// between lattices. Nodes in the lattices are identified by a 8-bit ID, so
// extending an existing lattice while preserving the IDs should not be
// a problem. (TODO: versioning/compatiblity of lattices
// (hint: wither major/minor for compatibility or something tree-like)
using stream_info = std::vector<std::tuple<Storage_t, Stream_PRIO>>;
using Service_Info = std::tuple<stream_info, std::shared_ptr<Lattice>>;
} // namespace Impl
} // namespace Fenrir__v1
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment