0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-26 15:33:54 +01:00

ircd::net: Shlock certificate common-name verification into the net stack.

This commit is contained in:
Jason Volk 2018-01-04 23:14:21 -08:00
parent b878fd6ed0
commit 72317c07c3
4 changed files with 128 additions and 21 deletions

View file

@ -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);
}

View file

@ -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
{

View file

@ -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);

View file

@ -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