mirror of
https://github.com/matrix-construct/construct
synced 2024-12-26 07:23:53 +01:00
ircd::net: Shlock certificate common-name verification into the net stack.
This commit is contained in:
parent
b878fd6ed0
commit
72317c07c3
4 changed files with 128 additions and 21 deletions
|
@ -83,7 +83,7 @@ namespace ircd::net
|
|||
std::shared_ptr<socket> connect(const remote &, const milliseconds &timeout = 30000ms);
|
||||
bool disconnect(socket &, const dc &type = dc::SSL_NOTIFY) noexcept;
|
||||
|
||||
ctx::future<std::shared_ptr<socket>> open(const ipport &, const milliseconds &timeout = 30000ms);
|
||||
ctx::future<std::shared_ptr<socket>> open(const ipport &, std::string cn, const milliseconds &timeout = 30000ms);
|
||||
ctx::future<std::shared_ptr<socket>> open(const hostport &, const milliseconds &timeout = 30000ms);
|
||||
}
|
||||
|
||||
|
|
|
@ -129,8 +129,9 @@ struct ircd::net::ipport
|
|||
/// This structure combines features of hostport and ipport to hold a remote's
|
||||
/// resolved IP in bytes, a port number, and an optional hostname string which
|
||||
/// may have been used to resolve the IP, or may have been resolved from the
|
||||
/// IP, or may just be empty, but either way still has some use being carried
|
||||
/// along as part of this struct.
|
||||
/// IP, or may be used for certificate Common Name verification, or may just
|
||||
/// be empty, but anyway still has some use in most cases being carried along.
|
||||
///
|
||||
struct ircd::net::remote
|
||||
:ircd::net::ipport
|
||||
{
|
||||
|
|
|
@ -33,9 +33,10 @@ namespace ircd::net
|
|||
{
|
||||
struct socket;
|
||||
|
||||
extern asio::ssl::context sslv23_client;
|
||||
|
||||
std::shared_ptr<socket> connect(const ip::tcp::endpoint &remote, const milliseconds &timeout);
|
||||
|
||||
bool handle_verify(bool, asio::ssl::verify_context &) noexcept;
|
||||
extern asio::ssl::context sslv23_client;
|
||||
}
|
||||
|
||||
struct ircd::net::socket
|
||||
|
@ -66,9 +67,10 @@ struct ircd::net::socket
|
|||
bool timedout {false};
|
||||
|
||||
void call_user(const handler &, const error_code &ec) noexcept;
|
||||
bool handle_verify(bool, asio::ssl::verify_context &, std::string cn) noexcept;
|
||||
void handle_timeout(std::weak_ptr<socket> wp, const error_code &ec) noexcept;
|
||||
void handle_handshake(std::weak_ptr<socket> wp, handler, const error_code &ec) noexcept;
|
||||
void handle_connect(std::weak_ptr<socket> wp, handler, const error_code &ec) noexcept;
|
||||
void handle_connect(std::weak_ptr<socket> wp, std::string cn, handler, const error_code &ec) noexcept;
|
||||
void handle(std::weak_ptr<socket>, handler, const error_code &) noexcept;
|
||||
|
||||
public:
|
||||
|
@ -120,16 +122,16 @@ struct ircd::net::socket
|
|||
bool cancel() noexcept;
|
||||
|
||||
// SSL handshake after connect (untimed)
|
||||
void handshake(const handshake_type &, handler callback);
|
||||
void handshake(const handshake_type & = handshake_type::client);
|
||||
void handshake(const handshake_type &, std::string cn, handler callback);
|
||||
void handshake(const handshake_type &, std::string cn);
|
||||
|
||||
// Connect to host (untimed)
|
||||
void connect(const endpoint &ep, handler callback);
|
||||
void connect(const endpoint &ep);
|
||||
|
||||
// Connect to host and handshake composit (timed)
|
||||
void open(const endpoint &ep, const milliseconds &timeout, handler callback);
|
||||
void open(const endpoint &ep, const milliseconds &timeout);
|
||||
void open(const endpoint &ep, std::string cn, const milliseconds &timeout, handler callback);
|
||||
void open(const endpoint &ep, std::string cn, const milliseconds &timeout);
|
||||
|
||||
bool disconnect(const dc &type);
|
||||
|
||||
|
|
126
ircd/net.cc
126
ircd/net.cc
|
@ -49,6 +49,9 @@ ircd::net::init::init()
|
|||
{
|
||||
assert(ircd::ios);
|
||||
resolve::resolver.reset(new ip::tcp::resolver{*ircd::ios});
|
||||
sslv23_client.set_verify_callback(net::handle_verify);
|
||||
sslv23_client.set_verify_mode(asio::ssl::verify_peer);
|
||||
sslv23_client.set_default_verify_paths();
|
||||
}
|
||||
|
||||
/// Network subsystem shutdown
|
||||
|
@ -86,7 +89,7 @@ ircd::net::open(const hostport &hostport,
|
|||
{
|
||||
ctx::promise<std::shared_ptr<ircd::net::socket>> p;
|
||||
ctx::future<std::shared_ptr<ircd::net::socket>> f(p);
|
||||
resolve(hostport, [p(std::move(p)), timeout]
|
||||
resolve(hostport, [p(std::move(p)), timeout, cn(std::string(hostport.host))]
|
||||
(auto eptr, const ipport &ipport)
|
||||
mutable
|
||||
{
|
||||
|
@ -95,7 +98,7 @@ ircd::net::open(const hostport &hostport,
|
|||
|
||||
const auto ep{make_endpoint(ipport)};
|
||||
const auto s(std::make_shared<socket>());
|
||||
s->open(ep, timeout, [p(std::move(p)), s]
|
||||
s->open(ep, std::move(cn), timeout, [p(std::move(p)), s]
|
||||
(const error_code &ec)
|
||||
mutable
|
||||
{
|
||||
|
@ -113,13 +116,14 @@ ircd::net::open(const hostport &hostport,
|
|||
|
||||
ircd::ctx::future<std::shared_ptr<ircd::net::socket>>
|
||||
ircd::net::open(const ipport &ipport,
|
||||
std::string cn,
|
||||
const milliseconds &timeout)
|
||||
{
|
||||
ctx::promise<std::shared_ptr<ircd::net::socket>> p;
|
||||
ctx::future<std::shared_ptr<ircd::net::socket>> f(p);
|
||||
const auto ep{make_endpoint(ipport)};
|
||||
const auto s(std::make_shared<socket>());
|
||||
s->open(ep, timeout, [p(std::move(p)), s]
|
||||
s->open(ep, std::move(cn), timeout, [p(std::move(p)), s]
|
||||
(const error_code &ec)
|
||||
mutable
|
||||
{
|
||||
|
@ -147,7 +151,7 @@ ircd::net::connect(const ip::tcp::endpoint &remote,
|
|||
const milliseconds &timeout)
|
||||
{
|
||||
const auto ret(std::make_shared<socket>());
|
||||
ret->open(remote, timeout);
|
||||
ret->open(remote, std::string{}, timeout);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -903,6 +907,7 @@ catch(const std::exception &e)
|
|||
|
||||
void
|
||||
ircd::net::socket::open(const ip::tcp::endpoint &ep,
|
||||
std::string cn,
|
||||
const milliseconds &timeout)
|
||||
try
|
||||
{
|
||||
|
@ -914,12 +919,13 @@ try
|
|||
timeout.count());
|
||||
|
||||
connect(ep);
|
||||
log.debug("socket(%p) connected to remote: %s from local: %s; performing handshake...",
|
||||
log.debug("socket(%p) connected to remote: %s from local: %s; performing handshake to '%s'...",
|
||||
this,
|
||||
string(ep),
|
||||
string(local()));
|
||||
string(local()),
|
||||
cn);
|
||||
|
||||
handshake(handshake_type::client);
|
||||
handshake(handshake_type::client, std::move(cn));
|
||||
log.debug("socket(%p) secure session with %s from local: %s established.",
|
||||
this,
|
||||
string(ep),
|
||||
|
@ -940,17 +946,19 @@ catch(const std::exception &e)
|
|||
///
|
||||
void
|
||||
ircd::net::socket::open(const ip::tcp::endpoint &ep,
|
||||
std::string cn,
|
||||
const milliseconds &timeout,
|
||||
handler callback)
|
||||
{
|
||||
log.debug("socket(%p) attempting connect to remote: %s for the next %ld$ms",
|
||||
log.debug("socket(%p) attempting connect to remote: %s '%s' for the next %ld$ms",
|
||||
this,
|
||||
string(ep),
|
||||
cn,
|
||||
timeout.count());
|
||||
|
||||
auto handler
|
||||
{
|
||||
std::bind(&socket::handle_connect, this, weak_from(*this), std::move(callback), ph::_1)
|
||||
std::bind(&socket::handle_connect, this, weak_from(*this), std::move(cn), std::move(callback), ph::_1)
|
||||
};
|
||||
|
||||
this->connect(ep, std::move(handler));
|
||||
|
@ -971,15 +979,29 @@ ircd::net::socket::connect(const ip::tcp::endpoint &ep,
|
|||
}
|
||||
|
||||
void
|
||||
ircd::net::socket::handshake(const handshake_type &type)
|
||||
ircd::net::socket::handshake(const handshake_type &type,
|
||||
std::string cn)
|
||||
{
|
||||
auto handler
|
||||
{
|
||||
std::bind(&socket::handle_verify, this, ph::_1, ph::_2, std::move(cn))
|
||||
};
|
||||
|
||||
ssl.set_verify_callback(std::move(handler));
|
||||
ssl.async_handshake(type, yield_context{to_asio{}});
|
||||
}
|
||||
|
||||
void
|
||||
ircd::net::socket::handshake(const handshake_type &type,
|
||||
std::string cn,
|
||||
handler callback)
|
||||
{
|
||||
auto handler
|
||||
{
|
||||
std::bind(&socket::handle_verify, this, ph::_1, ph::_2, std::move(cn))
|
||||
};
|
||||
|
||||
ssl.set_verify_callback(std::move(handler));
|
||||
ssl.async_handshake(type, std::move(callback));
|
||||
}
|
||||
|
||||
|
@ -1206,6 +1228,7 @@ catch(const std::exception &e)
|
|||
|
||||
void
|
||||
ircd::net::socket::handle_connect(std::weak_ptr<socket> wp,
|
||||
std::string cn,
|
||||
handler callback,
|
||||
const error_code &ec)
|
||||
noexcept try
|
||||
|
@ -1231,7 +1254,7 @@ noexcept try
|
|||
std::bind(&socket::handle_handshake, this, wp, std::move(callback), ph::_1)
|
||||
};
|
||||
|
||||
handshake(handshake_type::client, std::move(handler));
|
||||
handshake(handshake_type::client, std::move(cn), std::move(handler));
|
||||
}
|
||||
catch(const std::bad_weak_ptr &e)
|
||||
{
|
||||
|
@ -1328,6 +1351,66 @@ catch(const std::exception &e)
|
|||
e.what());
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::socket::handle_verify(const bool valid,
|
||||
asio::ssl::verify_context &vc,
|
||||
std::string cn)
|
||||
noexcept try
|
||||
{
|
||||
assert(vc.native_handle());
|
||||
const auto &stctx{*vc.native_handle()};
|
||||
|
||||
bool verify;
|
||||
switch(openssl::get_error(stctx))
|
||||
{
|
||||
case X509_V_OK:
|
||||
assert(valid);
|
||||
verify = true;
|
||||
break;
|
||||
|
||||
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||
assert(openssl::get_error_depth(stctx) == 0);
|
||||
verify = true;
|
||||
break;
|
||||
|
||||
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
||||
verify = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
verify = false;
|
||||
break;
|
||||
}
|
||||
|
||||
log.debug("handle_verify: verify_context(%p) %s %s :%s",
|
||||
(const void *)&vc,
|
||||
valid? "VALID" : "INVALID",
|
||||
verify? "VERIFIABLE" : "UNVERIFIABLE",
|
||||
openssl::get_error_string(stctx));
|
||||
|
||||
bool verified;
|
||||
if(verify)
|
||||
{
|
||||
boost::asio::ssl::rfc2818_verification verify_cn{cn};
|
||||
verified = verify_cn(verify, vc);
|
||||
}
|
||||
else verified = false;
|
||||
|
||||
if(!verified)
|
||||
log.error("Failed to verify peer '%s' certificate: %s %s %s",
|
||||
cn,
|
||||
valid? "VALID" : "INVALID",
|
||||
verify? "VERIFIABLE" : "UNVERIFIABLE",
|
||||
openssl::get_error_string(stctx));
|
||||
|
||||
return verified;
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
log.critical("socket::handle_verify: %s", e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ircd::net::socket::call_user(const handler &callback,
|
||||
const error_code &ec)
|
||||
|
@ -1562,6 +1645,27 @@ const
|
|||
return *ssl.native_handle();
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::net::handle_verify(const bool preverified,
|
||||
asio::ssl::verify_context &vc)
|
||||
noexcept try
|
||||
{
|
||||
assert(vc.native_handle());
|
||||
const auto &stctx{*vc.native_handle()};
|
||||
const auto &cert{openssl::current_cert(stctx)};
|
||||
log.debug("net::handle_verify: verify_context(%p): pre:%d :%s",
|
||||
(const void *)&vc,
|
||||
preverified,
|
||||
openssl::get_error_string(stctx));
|
||||
|
||||
return preverified;
|
||||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
log.critical("net::handle_verify: %s", e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// net/resolve.h
|
||||
|
|
Loading…
Reference in a new issue