Checkpoint the party/runtime stack before share-program and malicious-mode work.
Ship the TLS mesh, composer, Beaver/Yao/leaf MPC, prep/online paths, apps, and docs so the tree is pushable before elevating share_expr, security_mode, and prep resume. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
695f8e84f7
commit
0d22946a0e
1835 changed files with 170291 additions and 2849 deletions
177
include/dpf/net/secure_channel.hpp
Normal file
177
include/dpf/net/secure_channel.hpp
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/// @file dpf/net/secure_channel.hpp
|
||||
/// @brief Framed `channel` edges using the same peer TLS policy as `party_session`.
|
||||
/// @details Mux paths go through `party_session`. Framed APIs (`tcp_pair`,
|
||||
/// `trio`) keep length/tag framing but run the same `peer_security`
|
||||
/// defaults: TLS 1.3 when `encrypt` is on, optional per-direction
|
||||
/// authentication, socket tuning, and link logging.
|
||||
#ifndef LIBDPF_INCLUDE_DPF_NET_SECURE_CHANNEL_HPP__
|
||||
#define LIBDPF_INCLUDE_DPF_NET_SECURE_CHANNEL_HPP__
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "dpf/log.hpp"
|
||||
#include "dpf/net/channel.hpp"
|
||||
#include "dpf/net/identity.hpp"
|
||||
#include "dpf/net/link_log.hpp"
|
||||
#include "dpf/net/policy.hpp"
|
||||
#include "dpf/net/security.hpp"
|
||||
#include "dpf/net/socket_tune.hpp"
|
||||
#include "dpf/net/tls.hpp"
|
||||
|
||||
namespace dpf
|
||||
{
|
||||
namespace net
|
||||
{
|
||||
|
||||
/// @brief This process's key for a party link, or a fresh one (logged).
|
||||
inline std::shared_ptr<const identity> resolve_peer_identity(
|
||||
const peer_security & sec, const std::string & who)
|
||||
{
|
||||
if (sec.self)
|
||||
{
|
||||
DPF_LOG(info, "security.identity").kv("who", who)
|
||||
.kv("key", sec.self->key().base64()).kv("ephemeral", false)
|
||||
.kv("trusted", sec.trusted.size());
|
||||
return sec.self;
|
||||
}
|
||||
auto id = std::make_shared<identity>(identity::generate());
|
||||
DPF_LOG(info, "security.identity").kv("who", who).kv("key", id->key().base64())
|
||||
.kv("ephemeral", true).kv("trusted", sec.trusted.size());
|
||||
if (log::first_time("security.no_identity." + log::role() + "." + who))
|
||||
DPF_LOG(warning, "security.no_identity").kv("who", who)
|
||||
.kv("detail", "no identity key configured: links are encrypted to a fresh "
|
||||
"key for this run, so peers cannot authenticate " + who);
|
||||
return id;
|
||||
}
|
||||
|
||||
inline void note_channel_security(const std::string & peer_role,
|
||||
const link_security & sec)
|
||||
{
|
||||
if (!sec.encrypted)
|
||||
return;
|
||||
const std::string me = log::role().empty() ? std::string("this party") : log::role();
|
||||
if (sec.peer_auth == "none"
|
||||
&& log::first_time("security.unauthenticated." + me + "." + peer_role))
|
||||
DPF_LOG(warning, "security.unauthenticated").kv("peer", peer_role)
|
||||
.kv("peer_key", sec.peer_key ? sec.peer_key->base64() : std::string("none"))
|
||||
.kv("detail", "no key configured for " + peer_role + ": the link is "
|
||||
"encrypted but " + peer_role + " is not authenticated");
|
||||
}
|
||||
|
||||
/// @brief Adopt a TCP socket as a framed channel under `peer_security`.
|
||||
inline channel secure_tcp_channel(asio::io_context & io, asio::ip::tcp::socket sock,
|
||||
bool server, std::uint32_t peer_party, const peer_security & sec = {},
|
||||
const socket_options & so = {},
|
||||
std::chrono::milliseconds handshake = std::chrono::milliseconds(30000),
|
||||
const std::string & peer_role = {}, const char * how = "connect")
|
||||
{
|
||||
const std::string who = peer_role.empty()
|
||||
? ("party " + std::to_string(peer_party))
|
||||
: peer_role;
|
||||
tune_tcp(sock, so);
|
||||
if (!sec.encrypt)
|
||||
{
|
||||
const int fd = sock.native_handle();
|
||||
log_link_up(how, who, transport::mux, 1, 0, 0, fd, so, nullptr);
|
||||
return channel(std::move(sock));
|
||||
}
|
||||
#if DPF_HAS_OPENSSL
|
||||
auto self = resolve_peer_identity(sec, log::role().empty() ? "channel" : log::role());
|
||||
auto ctx = make_peer_tls_context(*self);
|
||||
auto tls = std::make_unique<tls_stream>(std::move(sock), *ctx);
|
||||
try
|
||||
{
|
||||
tls_handshake(io, *tls, server, handshake, who + " TLS");
|
||||
}
|
||||
catch (const std::system_error & e)
|
||||
{
|
||||
throw std::runtime_error(std::string(e.what())
|
||||
+ " (if the peer has encryption off, set it the same at both ends)");
|
||||
}
|
||||
link_security desc = tls_describe(*tls);
|
||||
try
|
||||
{
|
||||
check_peer(desc, sec, peer_party, who);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::error_code e;
|
||||
tls->lowest_layer().close(e);
|
||||
throw;
|
||||
}
|
||||
note_channel_security(who, desc);
|
||||
const int fd = tls->lowest_layer().native_handle();
|
||||
log_link_up(how, who, transport::mux, 1, 0, 0, fd, so, &desc);
|
||||
return channel::from_tls(io, std::move(*tls), std::move(ctx));
|
||||
#else
|
||||
(void)io;
|
||||
(void)server;
|
||||
(void)handshake;
|
||||
(void)how;
|
||||
throw std::logic_error("secure_tcp_channel: built without OpenSSL; set "
|
||||
"encryption=off for plaintext links");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DPF_HAS_OPENSSL
|
||||
/// @brief Adopt a unix-domain socket under the same peer TLS policy.
|
||||
inline channel secure_local_channel(asio::io_context & io,
|
||||
asio::local::stream_protocol::socket sock, bool server,
|
||||
std::uint32_t peer_party, const peer_security & sec = {},
|
||||
std::chrono::milliseconds handshake = std::chrono::milliseconds(30000),
|
||||
const std::string & peer_role = {}, const char * how = "connect")
|
||||
{
|
||||
const std::string who = peer_role.empty()
|
||||
? ("party " + std::to_string(peer_party))
|
||||
: peer_role;
|
||||
if (!sec.encrypt)
|
||||
return channel(std::move(sock));
|
||||
auto self = resolve_peer_identity(sec, log::role().empty() ? "channel" : log::role());
|
||||
auto ctx = make_peer_tls_context(*self);
|
||||
auto tls = std::make_unique<tls_local_stream>(std::move(sock), *ctx);
|
||||
try
|
||||
{
|
||||
tls_handshake(io, *tls, server, handshake, who + " TLS");
|
||||
}
|
||||
catch (const std::system_error & e)
|
||||
{
|
||||
throw std::runtime_error(std::string(e.what())
|
||||
+ " (if the peer has encryption off, set it the same at both ends)");
|
||||
}
|
||||
link_security desc = tls_describe(*tls);
|
||||
try
|
||||
{
|
||||
check_peer(desc, sec, peer_party, who);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::error_code e;
|
||||
tls->lowest_layer().close(e);
|
||||
throw;
|
||||
}
|
||||
note_channel_security(who, desc);
|
||||
(void)how;
|
||||
return channel::from_tls_local(io, std::move(*tls), std::move(ctx));
|
||||
}
|
||||
#else
|
||||
inline channel secure_local_channel(asio::io_context &,
|
||||
asio::local::stream_protocol::socket sock, bool, std::uint32_t,
|
||||
const peer_security & sec = {}, std::chrono::milliseconds = {},
|
||||
const std::string & = {}, const char * = nullptr)
|
||||
{
|
||||
if (sec.encrypt)
|
||||
throw std::logic_error("secure_local_channel: built without OpenSSL; set "
|
||||
"encryption=off for plaintext links");
|
||||
return channel(std::move(sock));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace net
|
||||
} // namespace dpf
|
||||
|
||||
#endif // LIBDPF_INCLUDE_DPF_NET_SECURE_CHANNEL_HPP__
|
||||
Loading…
Add table
Add a link
Reference in a new issue