From 045b48647e6f6196121e7bad30495eeea28d96d0 Mon Sep 17 00:00:00 2001 From: Ivan Rogach Date: Tue, 3 Dec 2024 10:04:28 +0100 Subject: [PATCH 1/4] Support hashing directories Signed-off-by: Ivan Rogach --- 3rd_party/cert_rehash/c_rehash.hpp | 310 ++++++++++++++++++ include/ocpp/common/evse_security.hpp | 2 +- include/ocpp/common/evse_security_impl.hpp | 2 +- lib/ocpp/common/evse_security_impl.cpp | 4 +- .../websocket/websocket_libwebsockets.cpp | 10 +- tests/lib/ocpp/common/evse_security_mock.hpp | 2 +- 6 files changed, 323 insertions(+), 7 deletions(-) create mode 100644 3rd_party/cert_rehash/c_rehash.hpp diff --git a/3rd_party/cert_rehash/c_rehash.hpp b/3rd_party/cert_rehash/c_rehash.hpp new file mode 100644 index 000000000..4c5f68e73 --- /dev/null +++ b/3rd_party/cert_rehash/c_rehash.hpp @@ -0,0 +1,310 @@ +/* c_rehash.c - Create hash symlinks for certificates + * C implementation based on the original Perl and shell versions + * + * Copyright (c) 2013-2014 Timo Teräs + * All rights reserved. + * + * This software is licensed under the MIT License. + * Full license available at: http://opensource.org/licenses/MIT + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define MAX_COLLISIONS 256 +#define countof(x) (sizeof(x) / sizeof(x[0])) + +namespace ocpp { + +struct entry_info { + struct entry_info* next; + char* filename; + unsigned short old_id; + unsigned char need_symlink; + unsigned char digest[EVP_MAX_MD_SIZE]; +}; + +struct bucket_info { + struct bucket_info* next; + struct entry_info *first_entry, *last_entry; + unsigned int hash; + unsigned short type; + unsigned short num_needed; +}; + +enum Type { + TYPE_CERT = 0, + TYPE_CRL +}; + +static const char* symlink_extensions[] = {"", "r"}; +static const char* file_extensions[] = {"pem", "crt", "cer", "crl"}; + +static int evpmdsize; +static const EVP_MD* evpmd; + +static struct bucket_info* hash_table[257]; + +static void bit_set(unsigned char* set, unsigned bit) { + set[bit / 8] |= 1 << (bit % 8); +} + +static int bit_isset(unsigned char* set, unsigned bit) { + return set[bit / 8] & (1 << (bit % 8)); +} + +static void add_entry(int type, unsigned int hash, const char* filename, const unsigned char* digest, int need_symlink, + unsigned short old_id) { + struct bucket_info* bi; + struct entry_info *ei, *found = NULL; + unsigned int ndx = (type + hash) % countof(hash_table); + + for (bi = hash_table[ndx]; bi; bi = bi->next) + if (bi->type == type && bi->hash == hash) + break; + if (!bi) { + bi = (bucket_info*)(calloc(1, sizeof(*bi))); + if (!bi) + return; + bi->next = hash_table[ndx]; + bi->type = type; + bi->hash = hash; + hash_table[ndx] = bi; + } + + for (ei = bi->first_entry; ei; ei = ei->next) { + if (digest && memcmp(digest, ei->digest, evpmdsize) == 0) { + EVLOG_warning << "Skipping duplicate certificate in file " << std::string(filename); + return; + } + if (!strcmp(filename, ei->filename)) { + found = ei; + if (!digest) + break; + } + } + ei = found; + if (!ei) { + if (bi->num_needed >= MAX_COLLISIONS) + return; + ei = (entry_info*)(calloc(1, sizeof(*ei))); + if (!ei) + return; + + ei->old_id = ~0; + ei->filename = strdup(filename); + if (bi->last_entry) + bi->last_entry->next = ei; + if (!bi->first_entry) + bi->first_entry = ei; + bi->last_entry = ei; + } + + if (old_id < ei->old_id) + ei->old_id = old_id; + if (need_symlink && !ei->need_symlink) { + ei->need_symlink = 1; + bi->num_needed++; + memcpy(ei->digest, digest, evpmdsize); + } +} + +static int handle_symlink(const char* filename, const char* fullpath) { + static char xdigit[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, + 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15}; + char linktarget[NAME_MAX], *endptr; + unsigned int hash = 0; + unsigned char ch; + int i, type, id; + ssize_t n; + + for (i = 0; i < 8; i++) { + ch = filename[i] - '0'; + if (ch >= countof(xdigit) || xdigit[ch] < 0) + return -1; + hash <<= 4; + hash += xdigit[ch]; + } + if (filename[i++] != '.') + return -1; + for (type = countof(symlink_extensions) - 1; type > 0; type--) + if (strcasecmp(symlink_extensions[type], &filename[i]) == 0) + break; + i += strlen(symlink_extensions[type]); + + id = strtoul(&filename[i], &endptr, 10); + if (*endptr != 0) + return -1; + + n = readlink(fullpath, linktarget, sizeof(linktarget)); + if (n >= sizeof(linktarget) || n < 0) + return -1; + linktarget[n] = 0; + + EVLOG_debug << "Found existing symlink " << std::string(filename) << " for " << hash << " (" << type + << "), certname " << std::string(linktarget, strlen(linktarget)); + add_entry(type, hash, linktarget, NULL, 0, id); + return 0; +} + +static int handle_certificate(const char* filename, const char* fullpath) { + STACK_OF(X509_INFO) * inf; + X509_INFO* x; + BIO* b; + const char* ext; + unsigned char digest[EVP_MAX_MD_SIZE]; + X509_NAME* name = NULL; + int i, type, ret = -1; + + ext = strrchr(filename, '.'); + if (ext == NULL) + return 0; + for (i = 0; i < countof(file_extensions); i++) { + if (strcasecmp(file_extensions[i], ext + 1) == 0) + break; + } + if (i >= countof(file_extensions)) + return -1; + + b = BIO_new_file(fullpath, "r"); + if (!b) + return -1; + inf = PEM_X509_INFO_read_bio(b, NULL, NULL, NULL); + BIO_free(b); + if (!inf) + return -1; + + if (sk_X509_INFO_num(inf) == 1) { + x = sk_X509_INFO_value(inf, 0); + if (x->x509) { + type = TYPE_CERT; + name = X509_get_subject_name(x->x509); + X509_digest(x->x509, evpmd, digest, NULL); + } else if (x->crl) { + type = TYPE_CRL; + name = X509_CRL_get_issuer(x->crl); + X509_CRL_digest(x->crl, evpmd, digest, NULL); + } + if (name) + add_entry(type, X509_NAME_hash(name), filename, digest, 1, ~0); + } else { + EVLOG_warning << std::string(filename) << " does not contain exactly one certificate or CRL: skipping"; + } + + sk_X509_INFO_pop_free(inf, X509_INFO_free); + + return ret; +} + +static int hash_dir(const char* dirname) { + struct bucket_info *bi, *nextbi; + struct entry_info *ei, *nextei; + struct dirent* de; + struct stat st; + unsigned char idmask[MAX_COLLISIONS / 8]; + int i, n, nextid, buflen, ret = -1; + const char* pathsep; + char* buf; + DIR* d; + + evpmd = EVP_sha1(); + evpmdsize = EVP_MD_size(evpmd); + + if (access(dirname, R_OK | W_OK | X_OK) != 0) { + EVLOG_error << "Access denied '" << std::string(dirname) << "'"; + return -1; + } + + buflen = strlen(dirname); + pathsep = (buflen && dirname[buflen - 1] == '/') ? "" : "/"; + buflen += NAME_MAX + 2; + buf = (char*)(malloc(buflen)); + if (buf == NULL) + goto err; + + EVLOG_debug << "Doing " << std::string(dirname); + d = opendir(dirname); + if (!d) + goto err; + + while ((de = readdir(d)) != NULL) { + if (snprintf(buf, buflen, "%s%s%s", dirname, pathsep, de->d_name) >= buflen) + continue; + if (lstat(buf, &st) < 0) + continue; + if (S_ISLNK(st.st_mode) && handle_symlink(de->d_name, buf) == 0) + continue; + if (strcmp(buf, "/etc/ssl/certs/ca-certificates.crt") == 0) { + /* Ignore the /etc/ssl/certs/ca-certificates.crt file */ + EVLOG_debug << "Skipping /etc/ssl/certs/ca-certificates.crt file"; + continue; + } + handle_certificate(de->d_name, buf); + } + closedir(d); + + for (i = 0; i < countof(hash_table); i++) { + for (bi = hash_table[i]; bi; bi = nextbi) { + nextbi = bi->next; + EVLOG_debug << "Type " << bi->type << " hash " << bi->hash << " num entries " << bi->num_needed << ":"; + + nextid = 0; + memset(idmask, 0, (bi->num_needed + 7) / 8); + for (ei = bi->first_entry; ei; ei = ei->next) + if (ei->old_id < bi->num_needed) + bit_set(idmask, ei->old_id); + + for (ei = bi->first_entry; ei; ei = nextei) { + nextei = ei->next; + EVLOG_debug << "\t(old_id " << ei->old_id << ", need_symlink " << ei->need_symlink << ") Cert " + << std::string(ei->filename, strlen(ei->filename)) << ":"; + + if (ei->old_id < bi->num_needed) { + /* Link exists, and is used as-is */ + snprintf(buf, buflen, "%08x.%s%d", bi->hash, symlink_extensions[bi->type], ei->old_id); + EVLOG_debug << "link " << std::string(ei->filename, strlen(ei->filename)) << " -> " + << std::string(buf, strlen(buf)); + } else if (ei->need_symlink) { + /* New link needed (it may replace something) */ + while (bit_isset(idmask, nextid)) + nextid++; + + snprintf(buf, buflen, "%s%s%n%08x.%s%d", dirname, pathsep, &n, bi->hash, + symlink_extensions[bi->type], nextid); + EVLOG_debug << "link " << std::string(ei->filename, strlen(ei->filename)) << " -> " + << std::string(buf + n, strlen(buf + n)); + unlink(buf); + symlink(ei->filename, buf); + } else { + /* Link to be deleted */ + snprintf(buf, buflen, "%s%s%n%08x.%s%d", dirname, pathsep, &n, bi->hash, + symlink_extensions[bi->type], ei->old_id); + EVLOG_debug << "unlink " << std::string(buf + n, strlen(buf + n)); + unlink(buf); + } + free(ei->filename); + free(ei); + } + free(bi); + } + hash_table[i] = NULL; + } + + ret = 0; +err: + free(buf); + return ret; +} + +} // namespace ocpp \ No newline at end of file diff --git a/include/ocpp/common/evse_security.hpp b/include/ocpp/common/evse_security.hpp index 042ee738b..5fdd35a2b 100644 --- a/include/ocpp/common/evse_security.hpp +++ b/include/ocpp/common/evse_security.hpp @@ -108,7 +108,7 @@ class EvseSecurity { /// \brief Retrieves the PEM formatted CA bundle file for the given \p certificate_type /// \param certificate_type /// \return CA certificate file - virtual std::string get_verify_file(const CaCertificateType& certificate_type) = 0; + virtual std::string get_verify_location(const CaCertificateType& certificate_type) = 0; /// \brief Gets the expiry day count for the leaf certificate of the given \p certificate_type /// \param certificate_type diff --git a/include/ocpp/common/evse_security_impl.hpp b/include/ocpp/common/evse_security_impl.hpp index 173b68a3d..f3c20b40d 100644 --- a/include/ocpp/common/evse_security_impl.hpp +++ b/include/ocpp/common/evse_security_impl.hpp @@ -55,7 +55,7 @@ class EvseSecurityImpl : public EvseSecurity { GetCertificateInfoResult get_leaf_certificate_info(const CertificateSigningUseEnum& certificate_type, bool include_ocsp = false) override; bool update_certificate_links(const CertificateSigningUseEnum& certificate_type) override; - std::string get_verify_file(const CaCertificateType& certificate_type) override; + std::string get_verify_location(const CaCertificateType& certificate_type) override; int get_leaf_expiry_days_count(const CertificateSigningUseEnum& certificate_type) override; }; diff --git a/lib/ocpp/common/evse_security_impl.cpp b/lib/ocpp/common/evse_security_impl.cpp index ef3df8628..596f93211 100644 --- a/lib/ocpp/common/evse_security_impl.cpp +++ b/lib/ocpp/common/evse_security_impl.cpp @@ -130,8 +130,8 @@ bool EvseSecurityImpl::update_certificate_links(const CertificateSigningUseEnum& return this->evse_security->update_certificate_links(conversions::from_ocpp(certificate_type)); } -std::string EvseSecurityImpl::get_verify_file(const CaCertificateType& certificate_type) { - return this->evse_security->get_verify_file(conversions::from_ocpp(certificate_type)); +std::string EvseSecurityImpl::get_verify_location(const CaCertificateType& certificate_type) { + return this->evse_security->get_verify_location(conversions::from_ocpp(certificate_type)); } int EvseSecurityImpl::get_leaf_expiry_days_count(const CertificateSigningUseEnum& certificate_type) { diff --git a/lib/ocpp/common/websocket/websocket_libwebsockets.cpp b/lib/ocpp/common/websocket/websocket_libwebsockets.cpp index 879e9a317..79dd337a8 100644 --- a/lib/ocpp/common/websocket/websocket_libwebsockets.cpp +++ b/lib/ocpp/common/websocket/websocket_libwebsockets.cpp @@ -1,5 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest +#include #include #include @@ -374,11 +375,16 @@ bool WebsocketLibwebsockets::tls_init(SSL_CTX* ctx, const std::string& path_chai } if (this->evse_security->is_ca_certificate_installed(ocpp::CaCertificateType::CSMS)) { - std::string ca_csms = this->evse_security->get_verify_file(ocpp::CaCertificateType::CSMS); + std::string ca_csms = this->evse_security->get_verify_location(ocpp::CaCertificateType::CSMS); EVLOG_info << "Loading CA csms bundle to verify server certificate: " << ca_csms; - rc = SSL_CTX_load_verify_locations(ctx, ca_csms.c_str(), NULL); + if (std::filesystem::is_directory(ca_csms)) { + hash_dir(ca_csms.c_str()); + rc = SSL_CTX_load_verify_locations(ctx, NULL, ca_csms.c_str()); + } else { + rc = SSL_CTX_load_verify_locations(ctx, ca_csms.c_str(), NULL); + } if (rc != 1) { EVLOG_error << "Could not load CA verify locations, error: " << ERR_error_string(ERR_get_error(), NULL); diff --git a/tests/lib/ocpp/common/evse_security_mock.hpp b/tests/lib/ocpp/common/evse_security_mock.hpp index b9b206876..fa4555a6f 100644 --- a/tests/lib/ocpp/common/evse_security_mock.hpp +++ b/tests/lib/ocpp/common/evse_security_mock.hpp @@ -32,7 +32,7 @@ class EvseSecurityMock : public EvseSecurity { MOCK_METHOD(GetCertificateInfoResult, get_leaf_certificate_info, (const CertificateSigningUseEnum&, bool), (override)); MOCK_METHOD(bool, update_certificate_links, (const CertificateSigningUseEnum&), (override)); - MOCK_METHOD(std::string, get_verify_file, (const CaCertificateType&), (override)); + MOCK_METHOD(std::string, get_verify_location, (const CaCertificateType&), (override)); MOCK_METHOD(int, get_leaf_expiry_days_count, (const CertificateSigningUseEnum&), (override)); }; From 99163ef8e1241fa5f5d3f91e1772d456a0f1ae9f Mon Sep 17 00:00:00 2001 From: Ivan Rogach Date: Tue, 3 Dec 2024 10:04:28 +0100 Subject: [PATCH 2/4] Fix after fixes in libevse-security Signed-off-by: Ivan Rogach --- include/ocpp/common/evse_security.hpp | 5 +++++ include/ocpp/common/evse_security_impl.hpp | 1 + lib/ocpp/common/evse_security_impl.cpp | 4 ++++ tests/lib/ocpp/common/evse_security_mock.hpp | 1 + 4 files changed, 11 insertions(+) diff --git a/include/ocpp/common/evse_security.hpp b/include/ocpp/common/evse_security.hpp index 5fdd35a2b..ef00d965b 100644 --- a/include/ocpp/common/evse_security.hpp +++ b/include/ocpp/common/evse_security.hpp @@ -108,6 +108,11 @@ class EvseSecurity { /// \brief Retrieves the PEM formatted CA bundle file for the given \p certificate_type /// \param certificate_type /// \return CA certificate file + virtual std::string get_verify_file(const CaCertificateType& certificate_type) = 0; + + /// \brief Retrieves the PEM formatted CA bundle location for the given \p certificate_type + /// \param certificate_type + /// \return CA certificate file virtual std::string get_verify_location(const CaCertificateType& certificate_type) = 0; /// \brief Gets the expiry day count for the leaf certificate of the given \p certificate_type diff --git a/include/ocpp/common/evse_security_impl.hpp b/include/ocpp/common/evse_security_impl.hpp index f3c20b40d..05c59a6a7 100644 --- a/include/ocpp/common/evse_security_impl.hpp +++ b/include/ocpp/common/evse_security_impl.hpp @@ -55,6 +55,7 @@ class EvseSecurityImpl : public EvseSecurity { GetCertificateInfoResult get_leaf_certificate_info(const CertificateSigningUseEnum& certificate_type, bool include_ocsp = false) override; bool update_certificate_links(const CertificateSigningUseEnum& certificate_type) override; + std::string get_verify_file(const CaCertificateType& certificate_type) override; std::string get_verify_location(const CaCertificateType& certificate_type) override; int get_leaf_expiry_days_count(const CertificateSigningUseEnum& certificate_type) override; }; diff --git a/lib/ocpp/common/evse_security_impl.cpp b/lib/ocpp/common/evse_security_impl.cpp index 596f93211..cd717f7a3 100644 --- a/lib/ocpp/common/evse_security_impl.cpp +++ b/lib/ocpp/common/evse_security_impl.cpp @@ -130,6 +130,10 @@ bool EvseSecurityImpl::update_certificate_links(const CertificateSigningUseEnum& return this->evse_security->update_certificate_links(conversions::from_ocpp(certificate_type)); } +std::string EvseSecurityImpl::get_verify_file(const CaCertificateType& certificate_type) { + return this->evse_security->get_verify_file(conversions::from_ocpp(certificate_type)); +} + std::string EvseSecurityImpl::get_verify_location(const CaCertificateType& certificate_type) { return this->evse_security->get_verify_location(conversions::from_ocpp(certificate_type)); } diff --git a/tests/lib/ocpp/common/evse_security_mock.hpp b/tests/lib/ocpp/common/evse_security_mock.hpp index fa4555a6f..50568360a 100644 --- a/tests/lib/ocpp/common/evse_security_mock.hpp +++ b/tests/lib/ocpp/common/evse_security_mock.hpp @@ -32,6 +32,7 @@ class EvseSecurityMock : public EvseSecurity { MOCK_METHOD(GetCertificateInfoResult, get_leaf_certificate_info, (const CertificateSigningUseEnum&, bool), (override)); MOCK_METHOD(bool, update_certificate_links, (const CertificateSigningUseEnum&), (override)); + MOCK_METHOD(std::string, get_verify_file, (const CaCertificateType&), (override)); MOCK_METHOD(std::string, get_verify_location, (const CaCertificateType&), (override)); MOCK_METHOD(int, get_leaf_expiry_days_count, (const CertificateSigningUseEnum&), (override)); }; From d335bad95ea7989526d4d6df6ee6f062ca666132 Mon Sep 17 00:00:00 2001 From: Ivan Rogach Date: Tue, 3 Dec 2024 10:04:28 +0100 Subject: [PATCH 3/4] Move hashing directories out of libocpp Signed-off-by: Ivan Rogach --- 3rd_party/cert_rehash/c_rehash.hpp | 310 ------------------ .../websocket/websocket_libwebsockets.cpp | 2 - 2 files changed, 312 deletions(-) delete mode 100644 3rd_party/cert_rehash/c_rehash.hpp diff --git a/3rd_party/cert_rehash/c_rehash.hpp b/3rd_party/cert_rehash/c_rehash.hpp deleted file mode 100644 index 4c5f68e73..000000000 --- a/3rd_party/cert_rehash/c_rehash.hpp +++ /dev/null @@ -1,310 +0,0 @@ -/* c_rehash.c - Create hash symlinks for certificates - * C implementation based on the original Perl and shell versions - * - * Copyright (c) 2013-2014 Timo Teräs - * All rights reserved. - * - * This software is licensed under the MIT License. - * Full license available at: http://opensource.org/licenses/MIT - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#define MAX_COLLISIONS 256 -#define countof(x) (sizeof(x) / sizeof(x[0])) - -namespace ocpp { - -struct entry_info { - struct entry_info* next; - char* filename; - unsigned short old_id; - unsigned char need_symlink; - unsigned char digest[EVP_MAX_MD_SIZE]; -}; - -struct bucket_info { - struct bucket_info* next; - struct entry_info *first_entry, *last_entry; - unsigned int hash; - unsigned short type; - unsigned short num_needed; -}; - -enum Type { - TYPE_CERT = 0, - TYPE_CRL -}; - -static const char* symlink_extensions[] = {"", "r"}; -static const char* file_extensions[] = {"pem", "crt", "cer", "crl"}; - -static int evpmdsize; -static const EVP_MD* evpmd; - -static struct bucket_info* hash_table[257]; - -static void bit_set(unsigned char* set, unsigned bit) { - set[bit / 8] |= 1 << (bit % 8); -} - -static int bit_isset(unsigned char* set, unsigned bit) { - return set[bit / 8] & (1 << (bit % 8)); -} - -static void add_entry(int type, unsigned int hash, const char* filename, const unsigned char* digest, int need_symlink, - unsigned short old_id) { - struct bucket_info* bi; - struct entry_info *ei, *found = NULL; - unsigned int ndx = (type + hash) % countof(hash_table); - - for (bi = hash_table[ndx]; bi; bi = bi->next) - if (bi->type == type && bi->hash == hash) - break; - if (!bi) { - bi = (bucket_info*)(calloc(1, sizeof(*bi))); - if (!bi) - return; - bi->next = hash_table[ndx]; - bi->type = type; - bi->hash = hash; - hash_table[ndx] = bi; - } - - for (ei = bi->first_entry; ei; ei = ei->next) { - if (digest && memcmp(digest, ei->digest, evpmdsize) == 0) { - EVLOG_warning << "Skipping duplicate certificate in file " << std::string(filename); - return; - } - if (!strcmp(filename, ei->filename)) { - found = ei; - if (!digest) - break; - } - } - ei = found; - if (!ei) { - if (bi->num_needed >= MAX_COLLISIONS) - return; - ei = (entry_info*)(calloc(1, sizeof(*ei))); - if (!ei) - return; - - ei->old_id = ~0; - ei->filename = strdup(filename); - if (bi->last_entry) - bi->last_entry->next = ei; - if (!bi->first_entry) - bi->first_entry = ei; - bi->last_entry = ei; - } - - if (old_id < ei->old_id) - ei->old_id = old_id; - if (need_symlink && !ei->need_symlink) { - ei->need_symlink = 1; - bi->num_needed++; - memcpy(ei->digest, digest, evpmdsize); - } -} - -static int handle_symlink(const char* filename, const char* fullpath) { - static char xdigit[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, - 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15}; - char linktarget[NAME_MAX], *endptr; - unsigned int hash = 0; - unsigned char ch; - int i, type, id; - ssize_t n; - - for (i = 0; i < 8; i++) { - ch = filename[i] - '0'; - if (ch >= countof(xdigit) || xdigit[ch] < 0) - return -1; - hash <<= 4; - hash += xdigit[ch]; - } - if (filename[i++] != '.') - return -1; - for (type = countof(symlink_extensions) - 1; type > 0; type--) - if (strcasecmp(symlink_extensions[type], &filename[i]) == 0) - break; - i += strlen(symlink_extensions[type]); - - id = strtoul(&filename[i], &endptr, 10); - if (*endptr != 0) - return -1; - - n = readlink(fullpath, linktarget, sizeof(linktarget)); - if (n >= sizeof(linktarget) || n < 0) - return -1; - linktarget[n] = 0; - - EVLOG_debug << "Found existing symlink " << std::string(filename) << " for " << hash << " (" << type - << "), certname " << std::string(linktarget, strlen(linktarget)); - add_entry(type, hash, linktarget, NULL, 0, id); - return 0; -} - -static int handle_certificate(const char* filename, const char* fullpath) { - STACK_OF(X509_INFO) * inf; - X509_INFO* x; - BIO* b; - const char* ext; - unsigned char digest[EVP_MAX_MD_SIZE]; - X509_NAME* name = NULL; - int i, type, ret = -1; - - ext = strrchr(filename, '.'); - if (ext == NULL) - return 0; - for (i = 0; i < countof(file_extensions); i++) { - if (strcasecmp(file_extensions[i], ext + 1) == 0) - break; - } - if (i >= countof(file_extensions)) - return -1; - - b = BIO_new_file(fullpath, "r"); - if (!b) - return -1; - inf = PEM_X509_INFO_read_bio(b, NULL, NULL, NULL); - BIO_free(b); - if (!inf) - return -1; - - if (sk_X509_INFO_num(inf) == 1) { - x = sk_X509_INFO_value(inf, 0); - if (x->x509) { - type = TYPE_CERT; - name = X509_get_subject_name(x->x509); - X509_digest(x->x509, evpmd, digest, NULL); - } else if (x->crl) { - type = TYPE_CRL; - name = X509_CRL_get_issuer(x->crl); - X509_CRL_digest(x->crl, evpmd, digest, NULL); - } - if (name) - add_entry(type, X509_NAME_hash(name), filename, digest, 1, ~0); - } else { - EVLOG_warning << std::string(filename) << " does not contain exactly one certificate or CRL: skipping"; - } - - sk_X509_INFO_pop_free(inf, X509_INFO_free); - - return ret; -} - -static int hash_dir(const char* dirname) { - struct bucket_info *bi, *nextbi; - struct entry_info *ei, *nextei; - struct dirent* de; - struct stat st; - unsigned char idmask[MAX_COLLISIONS / 8]; - int i, n, nextid, buflen, ret = -1; - const char* pathsep; - char* buf; - DIR* d; - - evpmd = EVP_sha1(); - evpmdsize = EVP_MD_size(evpmd); - - if (access(dirname, R_OK | W_OK | X_OK) != 0) { - EVLOG_error << "Access denied '" << std::string(dirname) << "'"; - return -1; - } - - buflen = strlen(dirname); - pathsep = (buflen && dirname[buflen - 1] == '/') ? "" : "/"; - buflen += NAME_MAX + 2; - buf = (char*)(malloc(buflen)); - if (buf == NULL) - goto err; - - EVLOG_debug << "Doing " << std::string(dirname); - d = opendir(dirname); - if (!d) - goto err; - - while ((de = readdir(d)) != NULL) { - if (snprintf(buf, buflen, "%s%s%s", dirname, pathsep, de->d_name) >= buflen) - continue; - if (lstat(buf, &st) < 0) - continue; - if (S_ISLNK(st.st_mode) && handle_symlink(de->d_name, buf) == 0) - continue; - if (strcmp(buf, "/etc/ssl/certs/ca-certificates.crt") == 0) { - /* Ignore the /etc/ssl/certs/ca-certificates.crt file */ - EVLOG_debug << "Skipping /etc/ssl/certs/ca-certificates.crt file"; - continue; - } - handle_certificate(de->d_name, buf); - } - closedir(d); - - for (i = 0; i < countof(hash_table); i++) { - for (bi = hash_table[i]; bi; bi = nextbi) { - nextbi = bi->next; - EVLOG_debug << "Type " << bi->type << " hash " << bi->hash << " num entries " << bi->num_needed << ":"; - - nextid = 0; - memset(idmask, 0, (bi->num_needed + 7) / 8); - for (ei = bi->first_entry; ei; ei = ei->next) - if (ei->old_id < bi->num_needed) - bit_set(idmask, ei->old_id); - - for (ei = bi->first_entry; ei; ei = nextei) { - nextei = ei->next; - EVLOG_debug << "\t(old_id " << ei->old_id << ", need_symlink " << ei->need_symlink << ") Cert " - << std::string(ei->filename, strlen(ei->filename)) << ":"; - - if (ei->old_id < bi->num_needed) { - /* Link exists, and is used as-is */ - snprintf(buf, buflen, "%08x.%s%d", bi->hash, symlink_extensions[bi->type], ei->old_id); - EVLOG_debug << "link " << std::string(ei->filename, strlen(ei->filename)) << " -> " - << std::string(buf, strlen(buf)); - } else if (ei->need_symlink) { - /* New link needed (it may replace something) */ - while (bit_isset(idmask, nextid)) - nextid++; - - snprintf(buf, buflen, "%s%s%n%08x.%s%d", dirname, pathsep, &n, bi->hash, - symlink_extensions[bi->type], nextid); - EVLOG_debug << "link " << std::string(ei->filename, strlen(ei->filename)) << " -> " - << std::string(buf + n, strlen(buf + n)); - unlink(buf); - symlink(ei->filename, buf); - } else { - /* Link to be deleted */ - snprintf(buf, buflen, "%s%s%n%08x.%s%d", dirname, pathsep, &n, bi->hash, - symlink_extensions[bi->type], ei->old_id); - EVLOG_debug << "unlink " << std::string(buf + n, strlen(buf + n)); - unlink(buf); - } - free(ei->filename); - free(ei); - } - free(bi); - } - hash_table[i] = NULL; - } - - ret = 0; -err: - free(buf); - return ret; -} - -} // namespace ocpp \ No newline at end of file diff --git a/lib/ocpp/common/websocket/websocket_libwebsockets.cpp b/lib/ocpp/common/websocket/websocket_libwebsockets.cpp index 79dd337a8..7a474ab36 100644 --- a/lib/ocpp/common/websocket/websocket_libwebsockets.cpp +++ b/lib/ocpp/common/websocket/websocket_libwebsockets.cpp @@ -1,6 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest -#include #include #include @@ -380,7 +379,6 @@ bool WebsocketLibwebsockets::tls_init(SSL_CTX* ctx, const std::string& path_chai EVLOG_info << "Loading CA csms bundle to verify server certificate: " << ca_csms; if (std::filesystem::is_directory(ca_csms)) { - hash_dir(ca_csms.c_str()); rc = SSL_CTX_load_verify_locations(ctx, NULL, ca_csms.c_str()); } else { rc = SSL_CTX_load_verify_locations(ctx, ca_csms.c_str(), NULL); From d64327888f1abd309f9b900ecb777a4d0757adf8 Mon Sep 17 00:00:00 2001 From: Ivan Rogach Date: Tue, 3 Dec 2024 10:04:28 +0100 Subject: [PATCH 4/4] Update tag to libevse-security Signed-off-by: Ivan Rogach --- dependencies.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.yaml b/dependencies.yaml index 6c5af9883..93d7cdae7 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -27,7 +27,7 @@ date: options: ["BUILD_TZ_LIB ON", "HAS_REMOTE_API 0", "USE_AUTOLOAD 0", "USE_SYSTEM_TZ_DB ON"] libevse-security: git: https://github.com/EVerest/libevse-security.git - git_tag: v0.9.1 + git_tag: v0.9.2 libwebsockets: git: https://github.com/warmcat/libwebsockets.git git_tag: v4.3.3