Fixed: Simplify certificates management

--HG--
branch : develop
This commit is contained in:
kervala 2018-08-11 21:47:50 +02:00
parent ad98b1414a
commit b86bf43090
6 changed files with 78 additions and 75 deletions

View file

@ -27,9 +27,6 @@ namespace NLGUI
class CCurlCertificates class CCurlCertificates
{ {
public: public:
// check if compiled with OpenSSL backend
static void init(CURL *curl);
// allow to use custom PEM certificates // allow to use custom PEM certificates
static void addCertificateFile(const std::string &cert); static void addCertificateFile(const std::string &cert);

View file

@ -66,8 +66,6 @@ namespace NLGUI
std::vector< std::string > trustedDomains; std::vector< std::string > trustedDomains;
/// Maximum concurrent MultiCurl connections per CGroupHTML instance /// Maximum concurrent MultiCurl connections per CGroupHTML instance
sint32 curlMaxConnections; sint32 curlMaxConnections;
/// cacert.pem location
std::string curlCABundle;
SWebOptions(): curlMaxConnections(2) SWebOptions(): curlMaxConnections(2)
{ {

View file

@ -40,29 +40,43 @@ namespace NLGUI
class SX509Certificates class SX509Certificates
{ {
public: public:
std::vector<X509 *> CertList; struct CertEntry
std::vector<std::string> FilesList; {
X509 *cert;
std::string name;
std::string file;
bool operator == (const std::string &str)
{
return file == str;
}
};
std::vector<CertEntry> CertList;
bool isUsingOpenSSLBackend; bool isUsingOpenSSLBackend;
bool isInitialized; bool isInitialized;
SX509Certificates():isUsingOpenSSLBackend(false), isInitialized(false) SX509Certificates():isUsingOpenSSLBackend(false), isInitialized(false)
{ {
init();
} }
~SX509Certificates() ~SX509Certificates()
{ {
for (uint i = 0; i < CertList.size(); ++i) for (uint i = 0; i < CertList.size(); ++i)
{ {
X509_free(CertList[i]); X509_free(CertList[i].cert);
} }
CertList.clear(); CertList.clear();
} }
void init(CURL *curl) void init()
{ {
if (isInitialized) return; // init CURL
CURL *curl = curl_easy_init();
if (!curl) return;
// get information on CURL // get information on CURL
curl_version_info_data *data = curl_version_info(CURLVERSION_NOW); curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
@ -98,9 +112,39 @@ namespace NLGUI
isUsingOpenSSLBackend = false; isUsingOpenSSLBackend = false;
} }
// clean up CURL
curl_easy_cleanup(curl);
isInitialized = true; isInitialized = true;
} }
static std::string getCertName(X509 *cert)
{
// NULL certificate
if (!cert) return "";
X509_NAME *subject = X509_get_subject_name(cert);
std::string name;
unsigned char *tmp = NULL;
// construct a multiline string with name
for (int j = 0, jlen = X509_NAME_entry_count(subject); j < jlen; ++j)
{
X509_NAME_ENTRY *e = X509_NAME_get_entry(subject, j);
ASN1_STRING *d = X509_NAME_ENTRY_get_data(e);
if (ASN1_STRING_to_UTF8(&tmp, d) > 0)
{
name += NLMISC::toString("%s\n", tmp);
OPENSSL_free(tmp);
}
}
return name;
}
#ifdef NL_OS_WINDOWS #ifdef NL_OS_WINDOWS
void addCertificatesFrom(LPCSTR root) void addCertificatesFrom(LPCSTR root)
{ {
@ -114,38 +158,36 @@ namespace NLGUI
{ {
x509 = NULL; x509 = NULL;
x509 = d2i_X509(NULL, (const unsigned char **)&pContext->pbCertEncoded, pContext->cbCertEncoded); x509 = d2i_X509(NULL, (const unsigned char **)&pContext->pbCertEncoded, pContext->cbCertEncoded);
if (x509) if (x509)
{ {
CertList.push_back(x509); CertEntry entry;
entry.cert = x509;
entry.file = root;
entry.name = getCertName(x509);
CertList.push_back(entry);
} }
} }
CertFreeCertificateContext(pContext); CertFreeCertificateContext(pContext);
CertCloseStore(hStore, 0); CertCloseStore(hStore, 0);
} }
// this is called before debug context is set and log ends up in log.log // this is called before debug context is set and log ends up in log.log
nlinfo("Loaded %d certificates from '%s' certificate store", (int)CertList.size(), root); //nlinfo("Loaded %d certificates from '%s' certificate store", (int)CertList.size(), root);
} }
#endif #endif
void addCertificatesFromFile(const std::string &cert) void addCertificatesFromFile(const std::string &cert)
{ {
if (!isUsingOpenSSLBackend) return; if (!isInitialized || !isUsingOpenSSLBackend) return;
if (!isInitialized)
{
nlwarning("You MUST call NLGUI::CCurlCertificates::init before adding new certificates");
return;
}
// this file was already loaded // this file was already loaded
if (std::find(FilesList.begin(), FilesList.end(), cert) != FilesList.end()) return; if (std::find(CertList.begin(), CertList.end(), cert) != CertList.end()) return;
FilesList.push_back(cert);
// look for certificate in search paths // look for certificate in search paths
string path = CPath::lookup(cert, false); string path = CPath::lookup(cert, false);
nlinfo("Cert path '%s'", path.c_str());
if (path.empty()) if (path.empty())
{ {
@ -153,6 +195,8 @@ namespace NLGUI
return; return;
} }
nlinfo("CURL CA bundle '%s'", path.c_str());
CIFile file; CIFile file;
// open certificate // open certificate
@ -184,7 +228,12 @@ namespace NLGUI
if (itmp && itmp->x509) if (itmp && itmp->x509)
{ {
CertList.push_back(X509_dup(itmp->x509)); CertEntry entry;
entry.cert = X509_dup(itmp->x509);
entry.file = cert;
entry.name = getCertName(entry.cert);
CertList.push_back(entry);
} }
} }
@ -224,27 +273,10 @@ namespace NLGUI
for (uint i = 0, ilen = x509CertListManager.CertList.size(); i < ilen; ++i) for (uint i = 0, ilen = x509CertListManager.CertList.size(); i < ilen; ++i)
{ {
X509_NAME *subject = X509_get_subject_name(x509CertListManager.CertList[i]); SX509Certificates::CertEntry entry = x509CertListManager.CertList[i];
std::string name;
unsigned char *tmp = NULL;
// construct a multiline string with name
for (int j = 0, jlen = X509_NAME_entry_count(subject); j < jlen; ++j)
{
X509_NAME_ENTRY *e = X509_NAME_get_entry(subject, j);
ASN1_STRING *d = X509_NAME_ENTRY_get_data(e);
if (ASN1_STRING_to_UTF8(&tmp, d) > 0)
{
name += NLMISC::toString("%s\n", tmp);
OPENSSL_free(tmp);
}
}
// add our certificate to this store // add our certificate to this store
if (X509_STORE_add_cert(x509store, x509CertListManager.CertList[i]) == 0) if (X509_STORE_add_cert(x509store, entry.cert) == 0)
{ {
uint errCode = ERR_get_error(); uint errCode = ERR_get_error();
@ -252,13 +284,13 @@ namespace NLGUI
if (ERR_GET_LIB(errCode) != ERR_LIB_X509 || ERR_GET_REASON(errCode) != X509_R_CERT_ALREADY_IN_HASH_TABLE) if (ERR_GET_LIB(errCode) != ERR_LIB_X509 || ERR_GET_REASON(errCode) != X509_R_CERT_ALREADY_IN_HASH_TABLE)
{ {
ERR_error_string_n(errCode, errorBuffer, 1024); ERR_error_string_n(errCode, errorBuffer, 1024);
nlwarning("Error adding certificate %s: %s", name.c_str(), errorBuffer); nlwarning("Error adding certificate %s: %s", entry.name.c_str(), errorBuffer);
res = CURLE_SSL_CACERT; res = CURLE_SSL_CACERT;
} }
} }
else else
{ {
nldebug("Added certificate %s", name.c_str()); nldebug("Added certificate %s", entry.name.c_str());
} }
} }
} }
@ -275,13 +307,6 @@ namespace NLGUI
return res; return res;
} }
// ***************************************************************************
// static
void CCurlCertificates::init(CURL *curl)
{
x509CertListManager.init(curl);
}
// *************************************************************************** // ***************************************************************************
// static // static
void CCurlCertificates::addCertificateFile(const std::string &cert) void CCurlCertificates::addCertificateFile(const std::string &cert)
@ -294,7 +319,7 @@ namespace NLGUI
void CCurlCertificates::useCertificates(CURL *curl) void CCurlCertificates::useCertificates(CURL *curl)
{ {
// CURL must be valid, using OpenSSL backend and certificates must be loaded, else return // CURL must be valid, using OpenSSL backend and certificates must be loaded, else return
if (!curl || !x509CertListManager.isUsingOpenSSLBackend || x509CertListManager.CertList.empty()) return; if (!curl || !x509CertListManager.isInitialized || !x509CertListManager.isUsingOpenSSLBackend || x509CertListManager.CertList.empty()) return;
curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM"); curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");

View file

@ -398,12 +398,6 @@ namespace NLGUI
// https:// // https://
if (toLower(download.url.substr(0, 8)) == "https://") if (toLower(download.url.substr(0, 8)) == "https://")
{ {
// check if compiled with OpenSSL backend
CCurlCertificates::init(curl);
// specify custom CA certs
CCurlCertificates::addCertificateFile(options.curlCABundle);
// if supported, use custom SSL context function to load certificates // if supported, use custom SSL context function to load certificates
CCurlCertificates::useCertificates(curl); CCurlCertificates::useCertificates(curl);
} }
@ -5410,12 +5404,6 @@ namespace NLGUI
// https:// // https://
if (toLower(url.substr(0, 8)) == "https://") if (toLower(url.substr(0, 8)) == "https://")
{ {
// check if compiled with OpenSSL backend
CCurlCertificates::init(curl);
// specify custom CA certs
CCurlCertificates::addCertificateFile(options.curlCABundle);
// if supported, use custom SSL context function to load certificates // if supported, use custom SSL context function to load certificates
CCurlCertificates::useCertificates(curl); CCurlCertificates::useCertificates(curl);
} }

View file

@ -71,9 +71,6 @@ bool CCurlHttpClient::verifyServer(bool verify)
curl_easy_setopt(_Curl, CURLOPT_SSL_VERIFYHOST, verify ? 2 : 0); curl_easy_setopt(_Curl, CURLOPT_SSL_VERIFYHOST, verify ? 2 : 0);
curl_easy_setopt(_Curl, CURLOPT_SSL_VERIFYPEER, verify ? 1 : 0); curl_easy_setopt(_Curl, CURLOPT_SSL_VERIFYPEER, verify ? 1 : 0);
// check if compiled with OpenSSL backend
NLGUI::CCurlCertificates::init(_Curl);
// specify custom CA certs // specify custom CA certs
NLGUI::CCurlCertificates::addCertificateFile(CAFilename); NLGUI::CCurlCertificates::addCertificateFile(CAFilename);

View file

@ -113,6 +113,8 @@
#include "nel/gui/lua_helper.h" #include "nel/gui/lua_helper.h"
using namespace NLGUI; using namespace NLGUI;
#include "nel/gui/lua_ihm.h" #include "nel/gui/lua_ihm.h"
#include "nel/gui/curl_certificates.h"
#include "lua_ihm_ryzom.h" #include "lua_ihm_ryzom.h"
#include "add_on_manager.h" #include "add_on_manager.h"
@ -471,15 +473,11 @@ CInterfaceManager::CInterfaceManager()
CGroupHTML::options.appName = getUserAgentName(); CGroupHTML::options.appName = getUserAgentName();
CGroupHTML::options.appVersion = getUserAgentVersion(); CGroupHTML::options.appVersion = getUserAgentVersion();
CGroupHTML::options.curlMaxConnections = ClientCfg.CurlMaxConnections; CGroupHTML::options.curlMaxConnections = ClientCfg.CurlMaxConnections;
if (!ClientCfg.CurlCABundle.empty()) if (!ClientCfg.CurlCABundle.empty())
{ {
string filename = CPath::lookup(ClientCfg.CurlCABundle, false); // specify custom CA certs, lookup will be made in this function
if (!filename.empty()) NLGUI::CCurlCertificates::addCertificateFile(ClientCfg.CurlCABundle);
{
filename = CPath::getFullPath(filename, false);
CGroupHTML::options.curlCABundle = filename;
nlinfo("curl ca bundle '%s'", filename.c_str());
}
} }
NLGUI::CDBManager::getInstance()->resizeBanks( NB_CDB_BANKS ); NLGUI::CDBManager::getInstance()->resizeBanks( NB_CDB_BANKS );