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
# 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
# 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"
# hash="sha-256">
# hash="sha-256"
# localsecure="yes">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# mbedTLS TLS module: Adds support for TLS connections using mbedTLS.

View File

@ -303,6 +303,11 @@ public:
*/
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.
* @param user The user whose certificate to set.
* @param cert The TLS certificate to set for the user.

View File

@ -114,17 +114,14 @@ private:
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
// is unavailable.
return servertracker.IsOnline();
return OnList(user);
}
bool OnList(LocalUser* user) override
{
if (requiressl && sslapi && !sslapi->GetCertificate(user))
if (requiressl && sslapi && !sslapi->IsSecure(user))
return false;
// Servers MUST NOT advertise the sasl capability if the authentication layer
@ -189,7 +186,7 @@ private:
params.reserve(3);
params.push_back(user->GetRealHost());
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);
}

View File

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

View File

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