mirror of
				https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
				synced 2025-10-30 18:27:49 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			337 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			337 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //
 | |
| // Created by stephane bourque on 2022-10-25.
 | |
| //
 | |
| 
 | |
| #include "fmt/format.h"
 | |
| 
 | |
| #include "framework/SubSystemServer.h"
 | |
| 
 | |
| #include "Poco/DateTimeFormat.h"
 | |
| #include "Poco/DateTimeFormatter.h"
 | |
| #include "Poco/Net/SSLManager.h"
 | |
| 
 | |
| #include "framework/MicroServiceFuncs.h"
 | |
| 
 | |
| namespace OpenWifi {
 | |
| 
 | |
| 	PropertiesFileServerEntry::PropertiesFileServerEntry(
 | |
| 		std::string Address, uint32_t port, std::string Key_file, std::string Cert_file,
 | |
| 		std::string RootCa, std::string Issuer, std::string ClientCas, std::string Cas,
 | |
| 		std::string Key_file_password, std::string Name, Poco::Net::Context::VerificationMode M,
 | |
| 		int backlog)
 | |
| 		: address_(std::move(Address)), port_(port), cert_file_(std::move(Cert_file)),
 | |
| 		  key_file_(std::move(Key_file)), root_ca_(std::move(RootCa)),
 | |
| 		  key_file_password_(std::move(Key_file_password)), issuer_cert_file_(std::move(Issuer)),
 | |
| 		  client_cas_(std::move(ClientCas)), cas_(std::move(Cas)), name_(std::move(Name)),
 | |
| 		  backlog_(backlog), level_(M){
 | |
| 
 | |
| 							 };
 | |
| 
 | |
| 	[[nodiscard]] Poco::Net::SecureServerSocket
 | |
| 	PropertiesFileServerEntry::CreateSecureSocket(Poco::Logger &L) const {
 | |
| 		Poco::Net::Context::Params P;
 | |
| 
 | |
| 		P.verificationMode = level_;
 | |
| 		P.verificationDepth = 9;
 | |
| 		P.loadDefaultCAs = root_ca_.empty();
 | |
| 		P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
 | |
| 		P.dhUse2048Bits = true;
 | |
| 		P.caLocation = cas_;
 | |
|         // P.securityLevel =
 | |
| 
 | |
| 		auto Context = Poco::AutoPtr<Poco::Net::Context>(
 | |
| 			new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
 | |
| 
 | |
| 		if (!key_file_password_.empty()) {
 | |
| 			auto PassphraseHandler = Poco::SharedPtr<MyPrivateKeyPassphraseHandler>(
 | |
| 				new MyPrivateKeyPassphraseHandler(key_file_password_, L));
 | |
| 			Poco::Net::SSLManager::instance().initializeServer(PassphraseHandler, nullptr, Context);
 | |
| 		}
 | |
| 
 | |
| 		if (!cert_file_.empty() && !key_file_.empty()) {
 | |
| 			Poco::Crypto::X509Certificate Cert(cert_file_);
 | |
| 			Poco::Crypto::X509Certificate Root(root_ca_);
 | |
| 
 | |
| 			Context->useCertificate(Cert);
 | |
| 			Context->addChainCertificate(Root);
 | |
| 			Context->addCertificateAuthority(Root);
 | |
| 
 | |
| 			if (level_ == Poco::Net::Context::VERIFY_STRICT) {
 | |
| 				if (issuer_cert_file_.empty()) {
 | |
| 					L.fatal("In strict mode, you must supply ans issuer certificate");
 | |
| 				}
 | |
| 				if (client_cas_.empty()) {
 | |
| 					L.fatal("In strict mode, client cas must be supplied");
 | |
| 				}
 | |
| 				Poco::Crypto::X509Certificate Issuing(issuer_cert_file_);
 | |
| 				Context->addChainCertificate(Issuing);
 | |
| 				Context->addCertificateAuthority(Issuing);
 | |
| 			}
 | |
| 
 | |
| 			Poco::Crypto::RSAKey Key("", key_file_, key_file_password_);
 | |
| 			Context->usePrivateKey(Key);
 | |
| 
 | |
| 			SSL_CTX *SSLCtx = Context->sslContext();
 | |
| 			if (!SSL_CTX_check_private_key(SSLCtx)) {
 | |
| 				L.fatal(fmt::format("Wrong Certificate({}) for Key({})", cert_file_, key_file_));
 | |
| 			}
 | |
| 
 | |
|             SSL_CTX_set_verify(SSLCtx, level_==Poco::Net::Context::VERIFY_NONE ? SSL_VERIFY_NONE : SSL_VERIFY_PEER, nullptr);
 | |
| 
 | |
| 			if (level_ == Poco::Net::Context::VERIFY_STRICT) {
 | |
| 				SSL_CTX_set_client_CA_list(SSLCtx, SSL_load_client_CA_file(client_cas_.c_str()));
 | |
|                 SSL_CTX_enable_ct(SSLCtx, SSL_CT_VALIDATION_STRICT);
 | |
| 			}
 | |
| 			SSL_CTX_dane_enable(SSLCtx);
 | |
| 
 | |
| 			Context->enableSessionCache();
 | |
| 			Context->setSessionCacheSize(0);
 | |
| 			Context->setSessionTimeout(60);
 | |
| 			Context->enableExtendedCertificateVerification( level_!= Poco::Net::Context::VERIFY_NONE );
 | |
| 			Context->disableStatelessSessionResumption();
 | |
| 		}
 | |
| 
 | |
| 		if (address_ == "*") {
 | |
| 			Poco::Net::IPAddress Addr(Poco::Net::IPAddress::wildcard(
 | |
| 				Poco::Net::Socket::supportsIPv6() ? Poco::Net::AddressFamily::IPv6
 | |
| 												  : Poco::Net::AddressFamily::IPv4));
 | |
| 			Poco::Net::SocketAddress SockAddr(Addr, port_);
 | |
| 
 | |
| 			return Poco::Net::SecureServerSocket(SockAddr, backlog_, Context);
 | |
| 		} else {
 | |
| 			Poco::Net::IPAddress Addr(address_);
 | |
| 			Poco::Net::SocketAddress SockAddr(Addr, port_);
 | |
| 
 | |
| 			return Poco::Net::SecureServerSocket(SockAddr, backlog_, Context);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	[[nodiscard]] Poco::Net::ServerSocket
 | |
| 	PropertiesFileServerEntry::CreateSocket([[maybe_unused]] Poco::Logger &L) const {
 | |
| 		Poco::Net::Context::Params P;
 | |
| 
 | |
| 		if (address_ == "*") {
 | |
| 			Poco::Net::IPAddress Addr(Poco::Net::IPAddress::wildcard(
 | |
| 				Poco::Net::Socket::supportsIPv6() ? Poco::Net::AddressFamily::IPv6
 | |
| 												  : Poco::Net::AddressFamily::IPv4));
 | |
| 			Poco::Net::SocketAddress SockAddr(Addr, port_);
 | |
| 			return Poco::Net::ServerSocket(SockAddr, backlog_);
 | |
| 		} else {
 | |
| 			Poco::Net::IPAddress Addr(address_);
 | |
| 			Poco::Net::SocketAddress SockAddr(Addr, port_);
 | |
| 			return Poco::Net::ServerSocket(SockAddr, backlog_);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	void PropertiesFileServerEntry::LogCertInfo(Poco::Logger &L,
 | |
| 												const Poco::Crypto::X509Certificate &C) const {
 | |
| 		L.information("============================================================================"
 | |
| 					  "=================");
 | |
| 		L.information(fmt::format(">          Issuer: {}", C.issuerName()));
 | |
| 		L.information("----------------------------------------------------------------------------"
 | |
| 					  "-----------------");
 | |
| 		L.information(fmt::format(">     Common Name: {}",
 | |
| 								  C.issuerName(Poco::Crypto::X509Certificate::NID_COMMON_NAME)));
 | |
| 		L.information(fmt::format(">         Country: {}",
 | |
| 								  C.issuerName(Poco::Crypto::X509Certificate::NID_COUNTRY)));
 | |
| 		L.information(fmt::format(">        Locality: {}",
 | |
| 								  C.issuerName(Poco::Crypto::X509Certificate::NID_LOCALITY_NAME)));
 | |
| 		L.information(
 | |
| 			fmt::format(">      State/Prov: {}",
 | |
| 						C.issuerName(Poco::Crypto::X509Certificate::NID_STATE_OR_PROVINCE)));
 | |
| 		L.information(
 | |
| 			fmt::format(">        Org name: {}",
 | |
| 						C.issuerName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_NAME)));
 | |
| 		L.information(
 | |
| 			fmt::format(">        Org unit: {}",
 | |
| 						C.issuerName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_UNIT_NAME)));
 | |
| 		L.information(
 | |
| 			fmt::format(">           Email: {}",
 | |
| 						C.issuerName(Poco::Crypto::X509Certificate::NID_PKCS9_EMAIL_ADDRESS)));
 | |
| 		L.information(fmt::format(">         Serial#: {}",
 | |
| 								  C.issuerName(Poco::Crypto::X509Certificate::NID_SERIAL_NUMBER)));
 | |
| 		L.information("----------------------------------------------------------------------------"
 | |
| 					  "-----------------");
 | |
| 		L.information(fmt::format(">         Subject: {}", C.subjectName()));
 | |
| 		L.information("----------------------------------------------------------------------------"
 | |
| 					  "-----------------");
 | |
| 		L.information(fmt::format(">     Common Name: {}",
 | |
| 								  C.subjectName(Poco::Crypto::X509Certificate::NID_COMMON_NAME)));
 | |
| 		L.information(fmt::format(">         Country: {}",
 | |
| 								  C.subjectName(Poco::Crypto::X509Certificate::NID_COUNTRY)));
 | |
| 		L.information(fmt::format(">        Locality: {}",
 | |
| 								  C.subjectName(Poco::Crypto::X509Certificate::NID_LOCALITY_NAME)));
 | |
| 		L.information(
 | |
| 			fmt::format(">      State/Prov: {}",
 | |
| 						C.subjectName(Poco::Crypto::X509Certificate::NID_STATE_OR_PROVINCE)));
 | |
| 		L.information(
 | |
| 			fmt::format(">        Org name: {}",
 | |
| 						C.subjectName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_NAME)));
 | |
| 		L.information(
 | |
| 			fmt::format(">        Org unit: {}",
 | |
| 						C.subjectName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_UNIT_NAME)));
 | |
| 		L.information(
 | |
| 			fmt::format(">           Email: {}",
 | |
| 						C.subjectName(Poco::Crypto::X509Certificate::NID_PKCS9_EMAIL_ADDRESS)));
 | |
| 		L.information(fmt::format(">         Serial#: {}",
 | |
| 								  C.subjectName(Poco::Crypto::X509Certificate::NID_SERIAL_NUMBER)));
 | |
| 		L.information("----------------------------------------------------------------------------"
 | |
| 					  "-----------------");
 | |
| 		L.information(fmt::format(">  Signature Algo: {}", C.signatureAlgorithm()));
 | |
| 		auto From =
 | |
| 			Poco::DateTimeFormatter::format(C.validFrom(), Poco::DateTimeFormat::HTTP_FORMAT);
 | |
| 		L.information(fmt::format(">      Valid from: {}", From));
 | |
| 		auto Expires =
 | |
| 			Poco::DateTimeFormatter::format(C.expiresOn(), Poco::DateTimeFormat::HTTP_FORMAT);
 | |
| 		L.information(fmt::format(">      Expires on: {}", Expires));
 | |
| 		L.information(fmt::format(">         Version: {}", (int)C.version()));
 | |
| 		L.information(fmt::format(">        Serial #: {}", C.serialNumber()));
 | |
| 		L.information("============================================================================"
 | |
| 					  "=================");
 | |
| 	}
 | |
| 
 | |
| 	void PropertiesFileServerEntry::LogCert(Poco::Logger &L) const {
 | |
| 		try {
 | |
| 			Poco::Crypto::X509Certificate C(cert_file_);
 | |
| 			L.information("========================================================================"
 | |
| 						  "=====================");
 | |
| 			L.information("========================================================================"
 | |
| 						  "=====================");
 | |
| 			L.information(fmt::format("Certificate Filename: {}", cert_file_));
 | |
| 			LogCertInfo(L, C);
 | |
| 			L.information("========================================================================"
 | |
| 						  "=====================");
 | |
| 
 | |
| 			if (!issuer_cert_file_.empty()) {
 | |
| 				Poco::Crypto::X509Certificate C1(issuer_cert_file_);
 | |
| 				L.information("===================================================================="
 | |
| 							  "=========================");
 | |
| 				L.information("===================================================================="
 | |
| 							  "=========================");
 | |
| 				L.information(fmt::format("Issues Certificate Filename: {}", issuer_cert_file_));
 | |
| 				LogCertInfo(L, C1);
 | |
| 				L.information("===================================================================="
 | |
| 							  "=========================");
 | |
| 			}
 | |
| 
 | |
| 			if (!client_cas_.empty()) {
 | |
| 				std::vector<Poco::Crypto::X509Certificate> Certs =
 | |
| 					Poco::Net::X509Certificate::readPEM(client_cas_);
 | |
| 
 | |
| 				L.information("===================================================================="
 | |
| 							  "=========================");
 | |
| 				L.information("===================================================================="
 | |
| 							  "=========================");
 | |
| 				L.information(fmt::format("Client CAs Filename: {}", client_cas_));
 | |
| 				L.information("===================================================================="
 | |
| 							  "=========================");
 | |
| 				auto i = 1;
 | |
| 				for (const auto &C3 : Certs) {
 | |
| 					L.information(fmt::format(" Index: {}", i));
 | |
| 					L.information("================================================================"
 | |
| 								  "=============================");
 | |
| 					LogCertInfo(L, C3);
 | |
| 					i++;
 | |
| 				}
 | |
| 				L.information("===================================================================="
 | |
| 							  "=========================");
 | |
| 			}
 | |
| 
 | |
| 		} catch (const Poco::Exception &E) {
 | |
| 			L.log(E);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	void PropertiesFileServerEntry::LogCas(Poco::Logger &L) const {
 | |
| 		try {
 | |
| 			std::vector<Poco::Crypto::X509Certificate> Certs =
 | |
| 				Poco::Net::X509Certificate::readPEM(root_ca_);
 | |
| 
 | |
| 			L.information("========================================================================"
 | |
| 						  "=====================");
 | |
| 			L.information("========================================================================"
 | |
| 						  "=====================");
 | |
| 			L.information(fmt::format("CA Filename: {}", root_ca_));
 | |
| 			L.information("========================================================================"
 | |
| 						  "=====================");
 | |
| 			auto i = 1;
 | |
| 			for (const auto &C : Certs) {
 | |
| 				L.information(fmt::format(" Index: {}", i));
 | |
| 				L.information("===================================================================="
 | |
| 							  "=========================");
 | |
| 				LogCertInfo(L, C);
 | |
| 				i++;
 | |
| 			}
 | |
| 			L.information("========================================================================"
 | |
| 						  "=====================");
 | |
| 		} catch (const Poco::Exception &E) {
 | |
| 			L.log(E);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	SubSystemServer::SubSystemServer(const std::string &Name, const std::string &LoggingPrefix,
 | |
| 									 const std::string &SubSystemConfigPrefix)
 | |
| 		: Name_(Name), LoggerPrefix_(LoggingPrefix), SubSystemConfigPrefix_(SubSystemConfigPrefix) {
 | |
| 	}
 | |
| 
 | |
| 	void SubSystemServer::initialize([[maybe_unused]] Poco::Util::Application &self) {
 | |
| 		auto i = 0;
 | |
| 		bool good = true;
 | |
| 
 | |
| 		auto NewLevel = MicroServiceConfigGetString("logging.level." + Name_, "");
 | |
| 		if (NewLevel.empty())
 | |
| 			Logger_ = std::make_unique<LoggerWrapper>(Poco::Logger::create(
 | |
| 				LoggerPrefix_, Poco::Logger::root().getChannel(), Poco::Logger::root().getLevel()));
 | |
| 		else
 | |
| 			Logger_ = std::make_unique<LoggerWrapper>(
 | |
| 				Poco::Logger::create(LoggerPrefix_, Poco::Logger::root().getChannel(),
 | |
| 									 Poco::Logger::parseLevel(NewLevel)));
 | |
| 
 | |
| 		ConfigServersList_.clear();
 | |
| 		while (good) {
 | |
| 			std::string root{SubSystemConfigPrefix_ + ".host." + std::to_string(i) + "."};
 | |
| 
 | |
| 			std::string address{root + "address"};
 | |
| 			if (MicroServiceConfigGetString(address, "").empty()) {
 | |
| 				good = false;
 | |
| 			} else {
 | |
| 				std::string port{root + "port"};
 | |
| 				std::string key{root + "key"};
 | |
| 				std::string key_password{root + "key.password"};
 | |
| 				std::string cert{root + "cert"};
 | |
| 				std::string name{root + "name"};
 | |
| 				std::string backlog{root + "backlog"};
 | |
| 				std::string rootca{root + "rootca"};
 | |
| 				std::string issuer{root + "issuer"};
 | |
| 				std::string clientcas(root + "clientcas");
 | |
| 				std::string cas{root + "cas"};
 | |
| 
 | |
| 				std::string level{root + "security"};
 | |
| 				Poco::Net::Context::VerificationMode M = Poco::Net::Context::VERIFY_RELAXED;
 | |
| 
 | |
| 				auto L = MicroServiceConfigGetString(level, "");
 | |
| 
 | |
| 				if (L == "strict") {
 | |
| 					M = Poco::Net::Context::VERIFY_STRICT;
 | |
| 				} else if (L == "none") {
 | |
| 					M = Poco::Net::Context::VERIFY_NONE;
 | |
| 				} else if (L == "relaxed") {
 | |
| 					M = Poco::Net::Context::VERIFY_RELAXED;
 | |
| 				} else if (L == "once")
 | |
| 					M = Poco::Net::Context::VERIFY_ONCE;
 | |
| 
 | |
| 				PropertiesFileServerEntry entry(
 | |
| 					MicroServiceConfigGetString(address, ""), MicroServiceConfigGetInt(port, 0),
 | |
| 					MicroServiceConfigPath(key, ""), MicroServiceConfigPath(cert, ""),
 | |
| 					MicroServiceConfigPath(rootca, ""), MicroServiceConfigPath(issuer, ""),
 | |
| 					MicroServiceConfigPath(clientcas, ""), MicroServiceConfigPath(cas, ""),
 | |
| 					MicroServiceConfigGetString(key_password, ""),
 | |
| 					MicroServiceConfigGetString(name, ""), M,
 | |
| 					(int)MicroServiceConfigGetInt(backlog, 64));
 | |
| 				ConfigServersList_.push_back(entry);
 | |
| 				i++;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| } // namespace OpenWifi
 | 
