Add an option so local non-SSL users can be seen as securely connected.

This commit is contained in:
Sadie Powell 2023-02-11 09:27:46 +00:00
parent b75fbe320d
commit 416661d17d
5 changed files with 35 additions and 15 deletions

View File

@ -2336,9 +2336,12 @@
# If you want to prevent users from viewing TLS certificate information # If you want to prevent users from viewing TLS certificate information
# and fingerprints of other users, set operonly to yes. You can also set hash # and fingerprints of other users, set operonly to yes. You can also set hash
# to an IANA Hash Function Textual Name to use the TLS fingerprint sent by a # to an IANA Hash Function Textual Name to use the TLS fingerprint sent by a
# WebIRC gateway (requires the gateway module). # WebIRC gateway (requires the gateway module) and localsecure to allow
# locally-connected connections where TLS is not necessary to be considered
# secure.
#<sslinfo operonly="no" #<sslinfo operonly="no"
# hash="sha-256"> # hash="sha-256"
# localsecure="yes">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# mbedTLS TLS module: Adds support for TLS connections using mbedTLS. # mbedTLS TLS module: Adds support for TLS connections using mbedTLS.

View File

@ -303,6 +303,11 @@ public:
*/ */
virtual ssl_cert* GetCertificate(User* user) = 0; virtual ssl_cert* GetCertificate(User* user) = 0;
/** Determines whether the specified user is connected securely.
* @return True if the user is connected securely; otherwise, false.
*/
virtual bool IsSecure(User* user) = 0;
/** Set the TLS certificate of a user. /** Set the TLS certificate of a user.
* @param user The user whose certificate to set. * @param user The user whose certificate to set.
* @param cert The TLS certificate to set for the user. * @param cert The TLS certificate to set for the user.

View File

@ -114,17 +114,14 @@ private:
bool OnRequest(LocalUser* user, bool adding) override bool OnRequest(LocalUser* user, bool adding) override
{ {
if (requiressl && sslapi && !sslapi->GetCertificate(user))
return false;
// Servers MUST NAK any sasl capability request if the authentication layer // Servers MUST NAK any sasl capability request if the authentication layer
// is unavailable. // is unavailable.
return servertracker.IsOnline(); return OnList(user);
} }
bool OnList(LocalUser* user) override bool OnList(LocalUser* user) override
{ {
if (requiressl && sslapi && !sslapi->GetCertificate(user)) if (requiressl && sslapi && !sslapi->IsSecure(user))
return false; return false;
// Servers MUST NOT advertise the sasl capability if the authentication layer // Servers MUST NOT advertise the sasl capability if the authentication layer
@ -189,7 +186,7 @@ private:
params.reserve(3); params.reserve(3);
params.push_back(user->GetRealHost()); params.push_back(user->GetRealHost());
params.push_back(user->GetAddress()); params.push_back(user->GetAddress());
params.emplace_back(sslapi && sslapi->GetCertificate(user) ? "S" : "P"); params.emplace_back(sslapi && sslapi->IsSecure(user) ? "S" : "P");
SendSASL(user, "*", 'H', params); SendSASL(user, "*", 'H', params);
} }

View File

@ -136,6 +136,7 @@ class UserCertificateAPIImpl final
public: public:
BoolExtItem nosslext; BoolExtItem nosslext;
SSLCertExt sslext; SSLCertExt sslext;
bool localsecure;
UserCertificateAPIImpl(Module* mod) UserCertificateAPIImpl(Module* mod)
: UserCertificateAPIBase(mod) : UserCertificateAPIBase(mod)
@ -162,6 +163,18 @@ public:
return cert; return cert;
} }
bool IsSecure(User* user) override
{
auto* cert = GetCertificate(user);
if (cert)
return !!cert;
if (localsecure)
return user->client_sa.is_local();
return false;
}
void SetCertificate(User* user, ssl_cert* cert) override void SetCertificate(User* user, ssl_cert* cert) override
{ {
ServerInstance->Logs.Debug(MODNAME, "Setting TLS client certificate for {}: {}", ServerInstance->Logs.Debug(MODNAME, "Setting TLS client certificate for {}: {}",
@ -307,15 +320,18 @@ public:
{ {
const auto& tag = ServerInstance->Config->ConfValue("sslinfo"); const auto& tag = ServerInstance->Config->ConfValue("sslinfo");
cmd.operonlyfp = tag->getBool("operonly"); cmd.operonlyfp = tag->getBool("operonly");
cmd.sslapi.localsecure = tag->getBool("localsecure", true);
hash = tag->getString("hash"); hash = tag->getString("hash");
} }
void OnWhois(Whois::Context& whois) override void OnWhois(Whois::Context& whois) override
{ {
if (cmd.sslapi.IsSecure(whois.GetTarget()))
whois.SendLine(RPL_WHOISSECURE, "is using a secure connection");
ssl_cert* cert = cmd.sslapi.GetCertificate(whois.GetTarget()); ssl_cert* cert = cmd.sslapi.GetCertificate(whois.GetTarget());
if (cert) if (cert)
{ {
whois.SendLine(RPL_WHOISSECURE, "is using a secure connection");
if ((!cmd.operonlyfp || whois.IsSelfWhois() || whois.GetSource()->IsOper()) && !cert->fingerprint.empty()) if ((!cmd.operonlyfp || whois.IsSelfWhois() || whois.GetSource()->IsOper()) && !cert->fingerprint.empty())
whois.SendLine(RPL_WHOISCERTFP, INSP_FORMAT("has TLS client certificate fingerprint {}", cert->fingerprint)); whois.SendLine(RPL_WHOISCERTFP, INSP_FORMAT("has TLS client certificate fingerprint {}", cert->fingerprint));
} }

View File

@ -93,8 +93,7 @@ public:
size_t nonssl = 0; size_t nonssl = 0;
for (const auto& [u, _] : channel->GetUsers()) for (const auto& [u, _] : channel->GetUsers())
{ {
ssl_cert* cert = API->GetCertificate(u); if (!API->IsSecure(u) && !u->server->IsService())
if (!cert && !u->server->IsService())
nonssl++; nonssl++;
} }
@ -146,7 +145,7 @@ public:
if (change.adding == dest->IsModeSet(this)) if (change.adding == dest->IsModeSet(this))
return false; return false;
if (change.adding && IS_LOCAL(user) && (!API || !API->GetCertificate(user))) if (change.adding && IS_LOCAL(user) && (!API || !API->IsSecure(user)))
return false; return false;
dest->SetMode(this, change.adding); dest->SetMode(this, change.adding);
@ -185,7 +184,7 @@ public:
return MOD_RES_DENY; return MOD_RES_DENY;
} }
if (!api->GetCertificate(user)) if (!api->IsSecure(user))
{ {
user->WriteNumeric(ERR_SECUREONLYCHAN, cname, "Cannot join channel; TLS users only (+z is set)"); user->WriteNumeric(ERR_SECUREONLYCHAN, cname, "Cannot join channel; TLS users only (+z is set)");
return MOD_RES_DENY; return MOD_RES_DENY;
@ -209,7 +208,7 @@ public:
/* If the target is +z */ /* If the target is +z */
if (target->IsModeSet(sslquery)) if (target->IsModeSet(sslquery))
{ {
if (!api || !api->GetCertificate(user)) if (!api || !api->IsSecure(user))
{ {
/* The sending user is not on an TLS connection */ /* The sending user is not on an TLS connection */
user->WriteNumeric(Numerics::CannotSendTo(target, "messages", &sslquery)); user->WriteNumeric(Numerics::CannotSendTo(target, "messages", &sslquery));
@ -219,7 +218,7 @@ public:
/* If the user is +z */ /* If the user is +z */
else if (user->IsModeSet(sslquery)) else if (user->IsModeSet(sslquery))
{ {
if (!api || !api->GetCertificate(target)) if (!api || !api->IsSecure(target))
{ {
user->WriteNumeric(Numerics::CannotSendTo(target, "messages", &sslquery, true)); user->WriteNumeric(Numerics::CannotSendTo(target, "messages", &sslquery, true));
return MOD_RES_DENY; return MOD_RES_DENY;