From 4753db29246e24ad598d2e3c15c376aee771f016 Mon Sep 17 00:00:00 2001 From: jolavillette Date: Wed, 18 Feb 2026 18:00:50 +0100 Subject: [PATCH 1/3] implement persistent Ignore/Deny list with Names and PGP ID --- src/pqi/authssl.cc | 47 ++++++++++++++++++++++++++++++++++++++++++++-- src/pqi/authssl.h | 12 ++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/pqi/authssl.cc b/src/pqi/authssl.cc index 565315ea37..f147145edd 100644 --- a/src/pqi/authssl.cc +++ b/src/pqi/authssl.cc @@ -1426,7 +1426,7 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx) RsInfo() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; - if(rsEvents) + if(rsEvents && !isNotifyDenied(pgpId)) { ev->mSslId = sslId; ev->mSslCn = sslCn; @@ -1467,7 +1467,7 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx) Dbg1() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; - if(rsEvents) + if(rsEvents && !isNotifyDenied(pgpId)) { ev->mSslId = sslId; ev->mSslCn = sslCn; @@ -1874,6 +1874,18 @@ bool AuthSSLimpl::saveList(bool& cleanup, std::list& lst) } lst.push_back(vitem); + /* Save Deny List */ + if (!mDenyList.empty()) { + RsConfigKeyValueSet* denyItem = new RsConfigKeyValueSet; + for (const auto& pair : mDenyList) { + RsTlvKeyValue kv; + kv.key = pair.first.toStdString(); + kv.value = "DENY:" + pair.second; + denyItem->tlvkvs.pairs.push_back(kv); + } + lst.push_back(denyItem); + } + return true ; } @@ -1903,6 +1915,11 @@ bool AuthSSLimpl::loadList(std::list& load) continue; } + if (kit->value.compare(0, 5, "DENY:") == 0) { + mDenyList[RsPgpId(kit->key)] = kit->value.substr(5); + continue; + } + X509 *peer = loadX509FromPEM(kit->value); /* authenticate it */ uint32_t diagnos ; @@ -1918,6 +1935,32 @@ bool AuthSSLimpl::loadList(std::list& load) return true; } +void AuthSSLimpl::addNotifyDeny(const RsPgpId& pgpId, const std::string& name) +{ + RsStackMutex stack(sslMtx); + mDenyList[pgpId] = name; + IndicateConfigChanged(); +} + +void AuthSSLimpl::removeNotifyDeny(const RsPgpId& pgpId) +{ + RsStackMutex stack(sslMtx); + mDenyList.erase(pgpId); + IndicateConfigChanged(); +} + +bool AuthSSLimpl::isNotifyDenied(const RsPgpId& pgpId) +{ + RsStackMutex stack(sslMtx); + return mDenyList.find(pgpId) != mDenyList.end(); +} + +void AuthSSLimpl::getNotifyDenyList(std::map& ids) +{ + RsStackMutex stack(sslMtx); + ids = mDenyList; +} + const EVP_PKEY*RsX509Cert::getPubKey(const X509& x509) { #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) diff --git a/src/pqi/authssl.h b/src/pqi/authssl.h index 1184018764..86ff05483c 100644 --- a/src/pqi/authssl.h +++ b/src/pqi/authssl.h @@ -112,6 +112,11 @@ class AuthSSL virtual X509* SignX509ReqWithGPG(X509_REQ* req, long days) = 0; + virtual void addNotifyDeny(const RsPgpId& pgpId, const std::string& name) = 0; + virtual void removeNotifyDeny(const RsPgpId& pgpId) = 0; + virtual bool isNotifyDenied(const RsPgpId& pgpId) = 0; + virtual void getNotifyDenyList(std::map& ids) = 0; + /** * @brief Verify PGP signature correcteness on given X509 certificate * Beware this doesn't check if the PGP signer is friend or not, just if the @@ -207,6 +212,11 @@ class AuthSSLimpl : public AuthSSL, public p3Config bool decrypt(void *&out, int &outlen, const void *in, int inlen) override; virtual X509* SignX509ReqWithGPG(X509_REQ *req, long days) override; + + void addNotifyDeny(const RsPgpId& pgpId, const std::string& name) override; + void removeNotifyDeny(const RsPgpId& pgpId) override; + bool isNotifyDenied(const RsPgpId& pgpId) override; + void getNotifyDenyList(std::map& ids) override; /// @see AuthSSL bool AuthX509WithGPG(X509 *x509, bool verbose, uint32_t& auth_diagnostic) override; @@ -265,4 +275,6 @@ class AuthSSLimpl : public AuthSSL, public p3Config RsPgpId _last_gpgid_to_connect; std::string _last_sslcn_to_connect; RsPeerId _last_sslid_to_connect; + + std::map mDenyList; }; From 76773dd1afb0fd77cb607f5befad5a929fdd4989 Mon Sep 17 00:00:00 2001 From: jolavillette Date: Wed, 18 Feb 2026 21:20:31 +0100 Subject: [PATCH 2/3] fix persistence for denied list & fix zero-ID not handled properly --- src/pqi/authssl.cc | 14 +++++++++++--- src/rsserver/rsinit.cc | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/pqi/authssl.cc b/src/pqi/authssl.cc index f147145edd..5ef9345f11 100644 --- a/src/pqi/authssl.cc +++ b/src/pqi/authssl.cc @@ -1312,6 +1312,14 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx) return std::string(); }; + auto isStringDenied = [&](const std::string& s) -> bool { + RsStackMutex stack(sslMtx); + for(const auto& pair : mDenyList) { + if(pair.first.toStdString() == s) return true; + } + return false; + }; + using Evt_t = RsAuthSslConnectionAutenticationEvent; std::unique_ptr ev = std::unique_ptr(new Evt_t); @@ -1339,14 +1347,14 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx) if(!pgpFpr.isNull()) pgpId = PGPHandler::pgpIdFromFingerprint(pgpFpr); // in the future, we drop PGP ids and keep the fingerprint all along } - + if(sslId.isNull()) { std::string errMsg = "x509Cert has invalid sslId!"; RsInfo() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; - if(rsEvents) + if(rsEvents && !isNotifyDenied(pgpId) && !isStringDenied(pgpId.toStdString())) { ev->mSslCn = sslCn; ev->mSslId = sslId; @@ -1368,7 +1376,7 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx) RsInfo() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; - if(rsEvents) + if(rsEvents && !isNotifyDenied(pgpId) && !isStringDenied(pgpId.toStdString())) { ev->mSslId = sslId; ev->mSslCn = sslCn; diff --git a/src/rsserver/rsinit.cc b/src/rsserver/rsinit.cc index 1629eb3c8c..44dd0e3af9 100644 --- a/src/rsserver/rsinit.cc +++ b/src/rsserver/rsinit.cc @@ -1757,6 +1757,7 @@ int RsServer::StartupRetroShare() mConfigMgr->addConfiguration("gxsnettunnel.cfg", mGxsNetTunnel); mConfigMgr->addConfiguration("peers.cfg" , mPeerMgr); mConfigMgr->addConfiguration("general.cfg" , mGeneralConfig); + mConfigMgr->addConfiguration("authssl.cfg" , dynamic_cast(&AuthSSL::instance())); mConfigMgr->addConfiguration("msgs.cfg" , msgSrv); mConfigMgr->addConfiguration("chat.cfg" , chatSrv); mConfigMgr->addConfiguration("p3History.cfg" , mHistoryMgr); From 1d848b9c1cf3b5fe7e93de2ed32f27febeaa52c1 Mon Sep 17 00:00:00 2001 From: jolavillette Date: Wed, 18 Feb 2026 22:28:59 +0100 Subject: [PATCH 3/3] robust deny-check for zero-IDs & suppress notifications in listener --- src/pqi/authssl.cc | 38 ++++++++++++++++++++++++++++---------- src/pqi/pqissllistener.cc | 31 +++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/pqi/authssl.cc b/src/pqi/authssl.cc index 5ef9345f11..90cb4b45cc 100644 --- a/src/pqi/authssl.cc +++ b/src/pqi/authssl.cc @@ -1354,6 +1354,8 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx) RsInfo() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; + + if(rsEvents && !isNotifyDenied(pgpId) && !isStringDenied(pgpId.toStdString())) { ev->mSslCn = sslCn; @@ -1376,6 +1378,8 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx) RsInfo() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; + + if(rsEvents && !isNotifyDenied(pgpId) && !isStringDenied(pgpId.toStdString())) { ev->mSslId = sslId; @@ -1434,6 +1438,8 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx) RsInfo() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; + + if(rsEvents && !isNotifyDenied(pgpId)) { ev->mSslId = sslId; @@ -1475,6 +1481,8 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx) Dbg1() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl; + + if(rsEvents && !isNotifyDenied(pgpId)) { ev->mSslId = sslId; @@ -1943,6 +1951,17 @@ bool AuthSSLimpl::loadList(std::list& load) return true; } + + +const EVP_PKEY*RsX509Cert::getPubKey(const X509& x509) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) + return x509.cert_info->key->pkey; +#else + return X509_get0_pubkey(&x509); +#endif +} + void AuthSSLimpl::addNotifyDeny(const RsPgpId& pgpId, const std::string& name) { RsStackMutex stack(sslMtx); @@ -1960,7 +1979,15 @@ void AuthSSLimpl::removeNotifyDeny(const RsPgpId& pgpId) bool AuthSSLimpl::isNotifyDenied(const RsPgpId& pgpId) { RsStackMutex stack(sslMtx); - return mDenyList.find(pgpId) != mDenyList.end(); + if(mDenyList.find(pgpId) != mDenyList.end()) return true; + + if(pgpId.isNull()) { + std::string s = pgpId.toStdString(); + for(const auto& pair : mDenyList) { + if(pair.first.toStdString() == s) return true; + } + } + return false; } void AuthSSLimpl::getNotifyDenyList(std::map& ids) @@ -1968,12 +1995,3 @@ void AuthSSLimpl::getNotifyDenyList(std::map& ids) RsStackMutex stack(sslMtx); ids = mDenyList; } - -const EVP_PKEY*RsX509Cert::getPubKey(const X509& x509) -{ -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - return x509.cert_info->key->pkey; -#else - return X509_get0_pubkey(&x509); -#endif -} diff --git a/src/pqi/pqissllistener.cc b/src/pqi/pqissllistener.cc index 7e027c5a98..0692bb1101 100644 --- a/src/pqi/pqissllistener.cc +++ b/src/pqi/pqissllistener.cc @@ -493,10 +493,33 @@ int pqissllistenbase::continueSSL(IncomingSSLInfo& incoming_connexion_info, bool if(vres == X509_V_OK && nullptr != rsEvents) { - auto ev = std::make_shared(); - ev->mLocator = RsUrl(incoming_connexion_info.addr); - ev->mErrorCode = RsAuthSslError::MISSING_AUTHENTICATION_INFO; - rsEvents->postEvent(ev); + // Check if denied before posting event + bool denied = false; + X509 *x509_check = SSL_get_peer_certificate(incoming_connexion_info.ssl); + RsPgpId checkedPgpId; // Default 0 + if(x509_check) { + checkedPgpId = RsX509Cert::getCertIssuer(*x509_check); + X509_free(x509_check); + } + + if(AuthSSL::instance().isNotifyDenied(checkedPgpId)) { + denied = true; + } + + if(!denied) { + auto ev = std::make_shared(); + ev->mLocator = RsUrl(incoming_connexion_info.addr); + // Try to fill in more info if available + if((x509_check = SSL_get_peer_certificate(incoming_connexion_info.ssl))) { + ev->mPgpId = RsX509Cert::getCertIssuer(*x509_check); + ev->mSslId = RsX509Cert::getCertSslId(*x509_check); + ev->mSslCn = RsX509Cert::getCertName(*x509_check); + X509_free(x509_check); + } + + ev->mErrorCode = RsAuthSslError::MISSING_AUTHENTICATION_INFO; + rsEvents->postEvent(ev); + } } closeConnection(fd, incoming_connexion_info.ssl);