2022-05-13 15:03:13 +00:00
|
|
|
#include <Common/config.h>
|
2022-05-14 19:45:07 +00:00
|
|
|
#include <DataTypes/DataTypeNullable.h>
|
2022-05-12 06:55:35 +00:00
|
|
|
#include <DataTypes/DataTypeString.h>
|
2022-05-13 20:48:34 +00:00
|
|
|
#include <DataTypes/DataTypesNumber.h>
|
2022-05-12 06:55:35 +00:00
|
|
|
#include <Storages/System/StorageSystemCertificates.h>
|
2022-05-16 17:31:28 +00:00
|
|
|
#include <re2/re2.h>
|
|
|
|
#include <boost/algorithm/string.hpp>
|
2022-05-12 06:55:35 +00:00
|
|
|
#include <filesystem>
|
2022-05-12 12:34:26 +00:00
|
|
|
#include "Poco/File.h"
|
2022-05-13 15:03:13 +00:00
|
|
|
#if USE_SSL
|
2022-05-12 15:51:00 +00:00
|
|
|
#include <openssl/x509v3.h>
|
2022-05-13 20:48:34 +00:00
|
|
|
#include "Poco/Net/SSLManager.h"
|
2022-05-12 12:34:26 +00:00
|
|
|
#include "Poco/Crypto/X509Certificate.h"
|
2022-05-12 22:37:52 +00:00
|
|
|
#endif
|
2022-05-12 06:55:35 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
NamesAndTypesList StorageSystemCertificates::getNamesAndTypes()
|
|
|
|
{
|
|
|
|
return
|
|
|
|
{
|
2022-05-14 19:45:07 +00:00
|
|
|
{"version", std::make_shared<DataTypeNumber<Int32>>()},
|
|
|
|
{"serial_number", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeString>())},
|
|
|
|
{"signature_algo", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeString>())},
|
|
|
|
{"issuer", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeString>())},
|
|
|
|
{"not_before", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeString>())},
|
|
|
|
{"not_after", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeString>())},
|
|
|
|
{"subject", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeString>())},
|
|
|
|
{"pkey_algo", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeString>())},
|
|
|
|
{"path", std::make_shared<DataTypeString>()},
|
|
|
|
{"default", std::make_shared<DataTypeNumber<UInt8>>()}
|
2022-05-12 06:55:35 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-05-13 15:03:13 +00:00
|
|
|
#if USE_SSL
|
2022-05-12 12:34:26 +00:00
|
|
|
|
2022-05-12 06:55:35 +00:00
|
|
|
static std::unordered_set<std::string> parse_dir(const std::string & dir)
|
|
|
|
{
|
2022-05-16 17:31:28 +00:00
|
|
|
std::vector<std::string> dirs;
|
|
|
|
boost::split(dirs, dir, boost::is_any_of(":"), boost::token_compress_on);
|
2022-05-12 06:55:35 +00:00
|
|
|
|
2022-05-16 17:31:28 +00:00
|
|
|
std::unordered_set<std::string> ret;
|
|
|
|
for (auto & d : dirs)
|
|
|
|
ret.emplace(std::move(d));
|
2022-05-12 06:55:35 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-05-13 20:48:34 +00:00
|
|
|
static void populateTable(const X509 * cert, MutableColumns & res_columns, const std::string & path, bool def)
|
2022-05-12 06:55:35 +00:00
|
|
|
{
|
|
|
|
BIO * b = BIO_new(BIO_s_mem());
|
|
|
|
size_t col = 0;
|
|
|
|
|
2022-05-14 19:45:07 +00:00
|
|
|
res_columns[col++]->insert(X509_get_version(cert) + 1);
|
2022-05-12 06:55:35 +00:00
|
|
|
|
|
|
|
{
|
2022-05-14 19:45:07 +00:00
|
|
|
char buf[1024] = {0};
|
2022-05-12 06:55:35 +00:00
|
|
|
const ASN1_INTEGER * sn = cert->cert_info->serialNumber;
|
|
|
|
BIGNUM * bnsn = ASN1_INTEGER_to_BN(sn, nullptr);
|
2022-05-14 19:45:07 +00:00
|
|
|
if (BN_print(b, bnsn) > 0 && BIO_read(b, buf, sizeof(buf)) > 0)
|
|
|
|
res_columns[col]->insert(buf);
|
|
|
|
else
|
2022-05-16 17:31:28 +00:00
|
|
|
res_columns[col]->insertDefault();
|
2022-05-12 06:55:35 +00:00
|
|
|
BN_free(bnsn);
|
|
|
|
}
|
2022-05-14 19:45:07 +00:00
|
|
|
++col;
|
2022-05-12 06:55:35 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
const ASN1_BIT_STRING *sig = nullptr;
|
|
|
|
const X509_ALGOR *al = nullptr;
|
|
|
|
char buf[1024] = {0};
|
|
|
|
X509_get0_signature(&sig, &al, cert);
|
2022-05-14 19:45:07 +00:00
|
|
|
if (al)
|
|
|
|
{
|
|
|
|
OBJ_obj2txt(buf, sizeof(buf), al->algorithm, 0);
|
|
|
|
res_columns[col]->insert(buf);
|
|
|
|
}
|
|
|
|
else
|
2022-05-16 17:31:28 +00:00
|
|
|
res_columns[col]->insertDefault();
|
2022-05-12 06:55:35 +00:00
|
|
|
}
|
2022-05-14 19:45:07 +00:00
|
|
|
++col;
|
2022-05-12 06:55:35 +00:00
|
|
|
|
|
|
|
char * issuer = X509_NAME_oneline(cert->cert_info->issuer, nullptr, 0);
|
|
|
|
if (issuer)
|
|
|
|
{
|
2022-05-14 19:45:07 +00:00
|
|
|
res_columns[col]->insert(issuer);
|
2022-05-12 06:55:35 +00:00
|
|
|
OPENSSL_free(issuer);
|
|
|
|
}
|
2022-05-14 19:45:07 +00:00
|
|
|
else
|
2022-05-16 17:31:28 +00:00
|
|
|
res_columns[col]->insertDefault();
|
2022-05-14 19:45:07 +00:00
|
|
|
++col;
|
2022-05-12 06:55:35 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
char buf[1024] = {0};
|
2022-05-14 19:45:07 +00:00
|
|
|
if (ASN1_TIME_print(b, X509_get_notBefore(cert)) && BIO_read(b, buf, sizeof(buf)) > 0)
|
|
|
|
res_columns[col]->insert(buf);
|
|
|
|
else
|
2022-05-16 17:31:28 +00:00
|
|
|
res_columns[col]->insertDefault();
|
2022-05-12 06:55:35 +00:00
|
|
|
}
|
2022-05-14 19:45:07 +00:00
|
|
|
++col;
|
2022-05-12 06:55:35 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
char buf[1024] = {0};
|
2022-05-14 19:45:07 +00:00
|
|
|
if (ASN1_TIME_print(b, X509_get_notAfter(cert)) && BIO_read(b, buf, sizeof(buf)) > 0)
|
|
|
|
res_columns[col]->insert(buf);
|
|
|
|
else
|
2022-05-16 17:31:28 +00:00
|
|
|
res_columns[col]->insertDefault();
|
2022-05-12 06:55:35 +00:00
|
|
|
}
|
2022-05-14 19:45:07 +00:00
|
|
|
++col;
|
2022-05-12 06:55:35 +00:00
|
|
|
|
|
|
|
char * subject = X509_NAME_oneline(cert->cert_info->subject, nullptr, 0);
|
|
|
|
if (subject)
|
|
|
|
{
|
2022-05-14 19:45:07 +00:00
|
|
|
res_columns[col]->insert(subject);
|
2022-05-12 06:55:35 +00:00
|
|
|
OPENSSL_free(subject);
|
|
|
|
}
|
2022-05-14 19:45:07 +00:00
|
|
|
else
|
2022-05-16 17:31:28 +00:00
|
|
|
res_columns[col]->insertDefault();
|
2022-05-14 19:45:07 +00:00
|
|
|
++col;
|
2022-05-12 06:55:35 +00:00
|
|
|
|
|
|
|
if (X509_PUBKEY * pkey = X509_get_X509_PUBKEY(cert))
|
|
|
|
{
|
2022-05-14 19:45:07 +00:00
|
|
|
char buf[1024] = {0};
|
2022-05-12 06:55:35 +00:00
|
|
|
ASN1_OBJECT *ppkalg = nullptr;
|
|
|
|
const unsigned char *pk = nullptr;
|
|
|
|
int ppklen = 0;
|
|
|
|
X509_ALGOR *pa = nullptr;
|
2022-05-14 19:45:07 +00:00
|
|
|
if (X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pkey) &&
|
|
|
|
i2a_ASN1_OBJECT(b, ppkalg) > 0 && BIO_read(b, buf, sizeof(buf)) > 0)
|
|
|
|
res_columns[col]->insert(buf);
|
|
|
|
else
|
2022-05-16 17:31:28 +00:00
|
|
|
res_columns[col]->insertDefault();
|
2022-05-12 06:55:35 +00:00
|
|
|
}
|
2022-05-14 19:45:07 +00:00
|
|
|
else
|
2022-05-16 17:31:28 +00:00
|
|
|
res_columns[col]->insertDefault();
|
2022-05-14 19:45:07 +00:00
|
|
|
++col;
|
2022-05-12 06:55:35 +00:00
|
|
|
|
2022-05-13 20:48:34 +00:00
|
|
|
res_columns[col++]->insert(path);
|
|
|
|
res_columns[col++]->insert(def);
|
|
|
|
|
2022-05-12 06:55:35 +00:00
|
|
|
BIO_free(b);
|
|
|
|
}
|
|
|
|
|
2022-05-13 20:48:34 +00:00
|
|
|
static void enumCertificates(const std::string & dir, bool def, MutableColumns & res_columns)
|
2022-05-12 06:55:35 +00:00
|
|
|
{
|
2022-05-16 17:31:28 +00:00
|
|
|
static const RE2 cert_name("^[a-fA-F0-9]{8}\\.\\d$");
|
|
|
|
assert(cert_name.ok());
|
2022-05-12 06:55:35 +00:00
|
|
|
|
|
|
|
const std::filesystem::path p(dir);
|
|
|
|
|
|
|
|
for (auto const& dir_entry : std::filesystem::directory_iterator(p))
|
|
|
|
{
|
2022-05-16 17:31:28 +00:00
|
|
|
if (!dir_entry.is_regular_file() || !RE2::FullMatch(dir_entry.path().filename().string(), cert_name))
|
2022-05-12 06:55:35 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
Poco::Crypto::X509Certificate cert(dir_entry.path());
|
2022-05-13 20:48:34 +00:00
|
|
|
populateTable(cert.certificate(), res_columns, dir_entry.path(), def);
|
2022-05-12 06:55:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-12 12:34:26 +00:00
|
|
|
#endif
|
|
|
|
|
2022-05-13 15:31:42 +00:00
|
|
|
void StorageSystemCertificates::fillData([[maybe_unused]] MutableColumns & res_columns, ContextPtr/* context*/, const SelectQueryInfo &) const
|
2022-05-12 06:55:35 +00:00
|
|
|
{
|
2022-05-13 15:03:13 +00:00
|
|
|
#if USE_SSL
|
2022-05-13 20:48:34 +00:00
|
|
|
auto & ca_paths = Poco::Net::SSLManager::instance().defaultServerContext()->getCAPaths();
|
2022-05-12 06:55:35 +00:00
|
|
|
|
2022-05-13 20:48:34 +00:00
|
|
|
if (!ca_paths.caLocation.empty())
|
2022-05-12 06:55:35 +00:00
|
|
|
{
|
2022-05-13 20:48:34 +00:00
|
|
|
Poco::File afile(ca_paths.caLocation);
|
2022-05-12 22:10:19 +00:00
|
|
|
if (afile.exists())
|
2022-05-12 06:55:35 +00:00
|
|
|
{
|
2022-05-12 22:10:19 +00:00
|
|
|
if (afile.isDirectory())
|
2022-05-12 06:55:35 +00:00
|
|
|
{
|
2022-05-13 20:48:34 +00:00
|
|
|
auto dir_set = parse_dir(ca_paths.caLocation);
|
2022-05-12 06:55:35 +00:00
|
|
|
for (const auto & entry : dir_set)
|
2022-05-13 20:48:34 +00:00
|
|
|
enumCertificates(entry, false, res_columns);
|
2022-05-12 06:55:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-05-12 22:10:19 +00:00
|
|
|
auto certs = Poco::Crypto::X509Certificate::readPEM(afile.path());
|
2022-05-12 06:55:35 +00:00
|
|
|
for (const auto & cert : certs)
|
2022-05-13 20:48:34 +00:00
|
|
|
populateTable(cert.certificate(), res_columns, afile.path(), false);
|
2022-05-12 06:55:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-13 20:48:34 +00:00
|
|
|
if (!ca_paths.caDefaultDir.empty())
|
2022-05-12 06:55:35 +00:00
|
|
|
{
|
2022-05-13 20:48:34 +00:00
|
|
|
auto dir_set = parse_dir(ca_paths.caDefaultDir);
|
|
|
|
for (const auto & entry : dir_set)
|
|
|
|
enumCertificates(entry, true, res_columns);
|
|
|
|
}
|
2022-05-12 07:03:59 +00:00
|
|
|
|
2022-05-13 20:48:34 +00:00
|
|
|
if (!ca_paths.caDefaultFile.empty())
|
|
|
|
{
|
|
|
|
Poco::File afile(ca_paths.caDefaultFile);
|
|
|
|
if (afile.exists())
|
2022-05-12 06:55:35 +00:00
|
|
|
{
|
2022-05-13 20:48:34 +00:00
|
|
|
auto certs = Poco::Crypto::X509Certificate::readPEM(ca_paths.caDefaultFile);
|
|
|
|
for (const auto & cert : certs)
|
|
|
|
populateTable(cert.certificate(), res_columns, ca_paths.caDefaultFile, true);
|
2022-05-12 06:55:35 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-12 12:34:26 +00:00
|
|
|
#endif
|
2022-05-12 06:55:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|