From 7624055c9a23c75e310ea7b3ebb7010063cf4c6c Mon Sep 17 00:00:00 2001 From: John Date: Fri, 26 Jul 2024 11:36:36 +0300 Subject: [PATCH] Feature/custom openssl provider (#86) * Added cmake config for custom provider * Prepared library for custom provider integration * Updated readme/docs --------- Signed-off-by: AssemblyJohn --- CMakeLists.txt | 22 +++- README.md | 23 ++-- include/evse_security/crypto/evse_crypto.hpp | 2 +- .../crypto/interface/crypto_supplier.hpp | 2 + .../crypto/interface/crypto_types.hpp | 5 +- ...pplier.hpp => openssl_crypto_supplier.hpp} | 1 + .../{openssl_tpm.hpp => openssl_provider.hpp} | 46 +++---- include/evse_security/evse_security.hpp | 6 +- include/evse_security/evse_types.hpp | 2 +- lib/evse_security/CMakeLists.txt | 13 +- ...pplier.cpp => openssl_crypto_supplier.cpp} | 22 ++-- .../{openssl_tpm.cpp => openssl_provider.cpp} | 113 +++++++++++------- lib/evse_security/evse_security.cpp | 16 +-- tests/openssl_supplier_test.cpp | 2 +- tests/openssl_supplier_test_tpm.cpp | 16 +-- tests/tests.cpp | 6 +- 16 files changed, 178 insertions(+), 119 deletions(-) rename include/evse_security/crypto/openssl/{openssl_supplier.hpp => openssl_crypto_supplier.hpp} (98%) rename include/evse_security/crypto/openssl/{openssl_tpm.hpp => openssl_provider.hpp} (72%) rename lib/evse_security/crypto/openssl/{openssl_supplier.cpp => openssl_crypto_supplier.cpp} (97%) rename lib/evse_security/crypto/openssl/{openssl_tpm.cpp => openssl_provider.cpp} (66%) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec0088b..8e13231 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.14) -project(everest-evse_security VERSION 0.6 +project(everest-evse_security VERSION 0.8 DESCRIPTION "Implementation of EVSE related security operations" LANGUAGES CXX C ) @@ -14,18 +14,30 @@ option(${PROJECT_NAME}_BUILD_TESTING "Build unit tests, used if included as depe option(BUILD_TESTING "Build unit tests, used if standalone project" OFF) option(EVSE_SECURITY_INSTALL "Install the library (shared data might be installed anyway)" ${EVC_MAIN_PROJECT}) option(USING_TPM2 "Include code for using OpenSSL 3 and the tpm2 provider" OFF) +option(USING_CUSTOM_PROVIDER "Include code for using OpenSSL 3 and the custom provider" OFF) if((${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME} OR ${PROJECT_NAME}_BUILD_TESTING) AND BUILD_TESTING) set(LIBEVSE_SECURITY_BUILD_TESTING ON) endif() +if(USING_TPM2 AND USING_CUSTOM_PROVIDER) + message(FATAL_ERROR, "TPM2 provider and custom provider are incompatible") +endif() + if(USING_TPM2) - # OpenSSL property string when using the default provider - set(PROPQUERY_DEFAULT "provider!=tpm2") - # OpenSSL property string when using the tpm2 provider - set(PROPQUERY_TPM2 "?provider=tpm2,tpm2.digest!=yes,tpm2.cipher!=yes") + set(CUSTOM_PROVIDER_NAME "tpm2") endif() +if(USING_CUSTOM_PROVIDER) + set(CUSTOM_PROVIDER_NAME "custom_provider") +endif() + +if(USING_TPM2 OR USING_CUSTOM_PROVIDER) +# OpenSSL property string when using the default provider + set(PROPQUERY_PROVIDER_DEFAULT "provider!=${CUSTOM_PROVIDER_NAME}") + # OpenSSL property string when using the tpm2/custom provider + set(PROPQUERY_PROVIDER_CUSTOM "?provider=${CUSTOM_PROVIDER_NAME},${CUSTOM_PROVIDER_NAME}.digest!=yes,${CUSTOM_PROVIDER_NAME}.cipher!=yes") +endif() # dependencies if (NOT DISABLE_EDM) diff --git a/README.md b/README.md index 25f3abe..f65ba0a 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,6 @@ This is a C++ library for security related operations for charging stations. It respects the requirements specified in OCPP and ISO15118 and can be used in combination with OCPP and ISO15118 implementations. -In the near future this library will also contain support for secure storage on TPM2.0. - All documentation and the issue tracking can be found in our main repository here: https://github.com/EVerest/everest ## Prerequisites @@ -43,7 +41,7 @@ We allow any certificate structure with the following recommendations: - Root CA certificate directories/bundles should not overlap leaf certificates - It is not recommended to store any SUBCAs in the root certificate bundle (if using files) -**Important:** when requesting leaf certificates with [get_key_pair](https://github.com/EVerest/libevse-security/blob/5cd5f8284229ffd28ae1dfed2137ef194c39e732/lib/evse_security/evse_security.cpp#L820) care should be taken if you require the full certificate chain. +**Important:** when requesting leaf certificates with [get_leaf_certificate_info](https://github.com/EVerest/libevse-security/blob/b140c17b0a5eaf09b60035605ed8aeb84627eb78/include/evse_security/evse_security.hpp#L195) care should be taken if you require the full certificate chain. If a full chain is **Leaf->SubCA2->SubCA1->Root**, it is recommended to have the root certificate in a single file, **V2G_ROOT_CA.pem** for example. The **Leaf->SubCA2->SubCA1** should be placed in a file e.g. **SECC_CERT_CHAIN.pem**. @@ -56,9 +54,9 @@ By default they are not added. - `cmake -DCSR_DNS_NAME=charger.pionix.de ...` to include a DNS name - `cmake -DCSR_IP_ADDRESS=192.168.2.1 ...` to include an IPv4 address -When receiving back a signed CSR, the library will take care to create two files, one containing the **Leaf->SubCA2->SubCA1** chain and another containing the single **Leaf**. When they both exist, the return of [get_key_pair](https://github.com/EVerest/libevse-security/blob/5cd5f8284229ffd28ae1dfed2137ef194c39e732/include/evse_security/evse_types.hpp#L126) will contain a path to both the single file and the chain file. +When receiving back a signed CSR, the library will take care to create two files, one containing the **Leaf->SubCA2->SubCA1** chain and another containing the single **Leaf**. When they both exist, the return of [get_leaf_certificate_info](https://github.com/EVerest/libevse-security/blob/b140c17b0a5eaf09b60035605ed8aeb84627eb78/include/evse_security/evse_security.hpp#L195) will contain a path to both the single file and the chain file. -## TPM +## TPM Provider There is a configuration option to configure OpenSSL for use with a TPM.
`cmake` ... `-DUSING_TPM2=ON`
@@ -67,8 +65,8 @@ configure whether to use the `default` provider or the `tpm2` provider. Configuration is managed via propquery strings (see CMakeLists.txt) -- `PROPQUERY_DEFAULT` is the string to use when selecting the default provider -- `PROPQUERY_TPM2` is the string to use when selecting the tpm2 provider +- `PROPQUERY_PROVIDER_DEFAULT` is the string to use when selecting the default provider +- `PROPQUERY_PROVIDER_CUSTOM` is the string to use when selecting the tpm2 provider propquery|action ---------|------ @@ -83,6 +81,17 @@ For more information see: - [OpenSSL property](https://www.openssl.org/docs/man3.0/man7/property.html) - [OpenSSL provider](https://www.openssl.org/docs/man3.0/man7/provider.html) +Note: In case of errors related to CSR signing, update tpm2-openssl to v 1.2.0. + +## Custom Provider +There is a configuration option to configure OpenSSL for use with a custom provider.
+`cmake` ... `-DUSING_CUSTOM_PROVIDER=ON`
+ +The workflow follows the same steps as using the TPM provider. The library will +have a flag to configure whether it uses the `default` provider or the `custom` one. + +Note: The custom provider name has to be defined [here](https://github.com/EVerest/libevse-security/blob/4afe644cb62d0bf06fff1e2ca5d2dbc489342e0c/CMakeLists.txt#L32). Change the name from "custom_provider" to the required provider. + ## Garbage Collect By default a garbage collect function will run and delete all expired leaf certificates and their respective keys, only if the certificate storage is full. A minimum count of leaf certificates will be kept even if they are expired. diff --git a/include/evse_security/crypto/evse_crypto.hpp b/include/evse_security/crypto/evse_crypto.hpp index e25703c..704a5e5 100644 --- a/include/evse_security/crypto/evse_crypto.hpp +++ b/include/evse_security/crypto/evse_crypto.hpp @@ -6,7 +6,7 @@ // Include other required suppliers here #ifdef LIBEVSE_CRYPTO_SUPPLIER_OPENSSL -#include +#include namespace evse_security { typedef OpenSSLSupplier CryptoSupplier; // Define others with the same 'CryptoSupplier' name } diff --git a/include/evse_security/crypto/interface/crypto_supplier.hpp b/include/evse_security/crypto/interface/crypto_supplier.hpp index d73ddde..ed9a88b 100644 --- a/include/evse_security/crypto/interface/crypto_supplier.hpp +++ b/include/evse_security/crypto/interface/crypto_supplier.hpp @@ -22,6 +22,8 @@ class AbstractCryptoSupplier { /// @brief If any TPM operations are supported static bool supports_tpm(); static bool supports_tpm_key_creation(); + /// @brief If creation from a custom provider is supported + static bool supports_custom_key_creation(); public: // Key utilities static bool generate_key(const KeyGenerationInfo& generation_info, KeyHandle_ptr& out_key); diff --git a/include/evse_security/crypto/interface/crypto_types.hpp b/include/evse_security/crypto/interface/crypto_types.hpp index a29e4b4..1c4bf1f 100644 --- a/include/evse_security/crypto/interface/crypto_types.hpp +++ b/include/evse_security/crypto/interface/crypto_types.hpp @@ -39,9 +39,10 @@ enum class CertificateSignRequestResult { struct KeyGenerationInfo { CryptoKeyType key_type; - /// @brief If the key should be generated on the TPM, should check before if + /// @brief If the key should be generated using the custom provider. The custom + /// provider can be the TPM if it was so configured. Should check before if /// the provider supports the operation, or the operation will fail by default - bool generate_on_tpm; + bool generate_on_custom; /// @brief If we should export the public key to a file std::optional public_key_file; diff --git a/include/evse_security/crypto/openssl/openssl_supplier.hpp b/include/evse_security/crypto/openssl/openssl_crypto_supplier.hpp similarity index 98% rename from include/evse_security/crypto/openssl/openssl_supplier.hpp rename to include/evse_security/crypto/openssl/openssl_crypto_supplier.hpp index b0fe169..8400332 100644 --- a/include/evse_security/crypto/openssl/openssl_supplier.hpp +++ b/include/evse_security/crypto/openssl/openssl_crypto_supplier.hpp @@ -12,6 +12,7 @@ class OpenSSLSupplier : public AbstractCryptoSupplier { static bool supports_tpm(); static bool supports_tpm_key_creation(); + static bool supports_custom_key_creation(); public: static bool generate_key(const KeyGenerationInfo& key_info, KeyHandle_ptr& out_key); diff --git a/include/evse_security/crypto/openssl/openssl_tpm.hpp b/include/evse_security/crypto/openssl/openssl_provider.hpp similarity index 72% rename from include/evse_security/crypto/openssl/openssl_tpm.hpp rename to include/evse_security/crypto/openssl/openssl_provider.hpp index 80853e7..eac04ba 100644 --- a/include/evse_security/crypto/openssl/openssl_tpm.hpp +++ b/include/evse_security/crypto/openssl/openssl_provider.hpp @@ -17,23 +17,26 @@ struct ossl_provider_st; // OpenSSL OSSL_PROVIDER namespace evse_security { -/// @brief determine if the PEM string is a TSS2 private key +/// @brief determine if the PEM string is a custom private key. Will +/// only work for private keys, public keys will always return true /// @param private_key_pem string containing the PEM encoded key -/// @return true when "-----BEGIN TSS2 PRIVATE KEY-----" found +/// @return true when file does not start "-----BEGIN PRIVATE KEY-----" /// @note works irrespective of OpenSSL version -bool is_tpm_key_string(const std::string& private_key_pem); +bool is_custom_private_key_string(const std::string& private_key_pem); -/// @brief determine if the PEM file contains a TSS2 private key +/// @brief determine if the PEM file contains a custom private key. Will +/// only work for private keys, public keys will always return true /// @param private_key_file_pem filename of the PEM file -/// @return true when file starts "-----BEGIN TSS2 PRIVATE KEY-----" +/// @return true when file does not start "-----BEGIN PRIVATE KEY-----" /// @note works irrespective of OpenSSL version -bool is_tpm_key_file(const fs::path& private_key_file_pem); +bool is_custom_private_key_file(const fs::path& private_key_file_pem); /// @brief Manage the loading and configuring of OpenSSL providers /// /// There are two providers considered: /// - 'default' /// - 'tpm2' for working with TSS2 keys (protected by a TPM) +/// The 'tpm2' can be replaced with a custom provider (see CMakeLists.txt) /// /// There are two contexts: /// - 'global' for general use @@ -55,25 +58,25 @@ class OpenSSLProvider { /// @brief supported propquery strings enum class mode_t { default_provider, - tpm2_provider, + custom_provider, }; private: typedef std::uint8_t flags_underlying_t; enum class flags_t : flags_underlying_t { initialised, - tpm2_available, - global_tpm2, - tls_tpm2, + custom_provider_available, + global_custom_provider, + tls_custom_provider, }; static std::mutex s_mux; static flags_underlying_t s_flags; static struct ossl_provider_st* s_global_prov_default_p; - static struct ossl_provider_st* s_global_prov_tpm_p; + static struct ossl_provider_st* s_global_prov_custom_p; static struct ossl_provider_st* s_tls_prov_default_p; - static struct ossl_provider_st* s_tls_prov_tpm_p; + static struct ossl_provider_st* s_tls_prov_custom_p; static struct ossl_lib_ctx_st* s_tls_libctx_p; static inline void reset(flags_t f) { @@ -97,22 +100,22 @@ class OpenSSLProvider { /// @param val - whether to set or reset the flag /// @return true when the flag was changed static inline bool update(flags_t f, bool val) { - bool bResult = val != is_set(f); + bool result = (val != is_set(f)); if (val) { set(f); } else { reset(f); } - return bResult; + return result; } - bool load(struct ossl_provider_st*& default_p, struct ossl_provider_st*& tpm2_p, struct ossl_lib_ctx_st* libctx_p, + bool load(struct ossl_provider_st*& default_p, struct ossl_provider_st*& custom_p, struct ossl_lib_ctx_st* libctx_p, mode_t mode); inline bool load_global(mode_t mode) { - return load(s_global_prov_default_p, s_global_prov_tpm_p, nullptr, mode); + return load(s_global_prov_default_p, s_global_prov_custom_p, nullptr, mode); } inline bool load_tls(mode_t mode) { - return load(s_tls_prov_default_p, s_tls_prov_tpm_p, s_tls_libctx_p, mode); + return load(s_tls_prov_default_p, s_tls_prov_custom_p, s_tls_libctx_p, mode); } bool set_propstr(struct ossl_lib_ctx_st* libctx, mode_t mode); @@ -133,10 +136,10 @@ class OpenSSLProvider { const char* propquery(mode_t mode) const; inline mode_t propquery_global() const { - return (is_set(flags_t::global_tpm2)) ? mode_t::tpm2_provider : mode_t::default_provider; + return (is_set(flags_t::global_custom_provider)) ? mode_t::custom_provider : mode_t::default_provider; } inline mode_t propquery_tls() const { - return (is_set(flags_t::tls_tpm2)) ? mode_t::tpm2_provider : mode_t::default_provider; + return (is_set(flags_t::tls_custom_provider)) ? mode_t::custom_provider : mode_t::default_provider; } inline const char* propquery_global_str() const { @@ -151,9 +154,8 @@ class OpenSSLProvider { return s_tls_libctx_p; } - static inline bool supports_tpm() { - return is_set(flags_t::tpm2_available); - } + static bool supports_provider_tpm(); + static bool supports_provider_custom(); static void cleanup(); }; diff --git a/include/evse_security/evse_security.hpp b/include/evse_security/evse_security.hpp index db8b9e2..e1a7507 100644 --- a/include/evse_security/evse_security.hpp +++ b/include/evse_security/evse_security.hpp @@ -164,12 +164,14 @@ class EvseSecurity { /// @param country /// @param organization /// @param common - /// @param use_tpm If the TPM should be used for the CSR request + /// @param use_custom_provider If the custom provider (which can be the TPM if using -DUSING_TPM2=ON) should be + /// used for the CSR request /// @return the status and an optional PEM formatted certificate signing request string GetCertificateSignRequestResult generate_certificate_signing_request(LeafCertificateType certificate_type, const std::string& country, const std::string& organization, - const std::string& common, bool use_tpm); + const std::string& common, + bool use_custom_provider); /// @brief Generates a certificate signing request for the given \p certificate_type , \p country , \p organization /// and \p common without using the TPM diff --git a/include/evse_security/evse_types.hpp b/include/evse_security/evse_types.hpp index 804004d..a038e48 100644 --- a/include/evse_security/evse_types.hpp +++ b/include/evse_security/evse_types.hpp @@ -13,7 +13,7 @@ namespace evse_security { const fs::path PEM_EXTENSION = ".pem"; const fs::path DER_EXTENSION = ".der"; const fs::path KEY_EXTENSION = ".key"; -const fs::path TPM_KEY_EXTENSION = ".tkey"; +const fs::path CUSTOM_KEY_EXTENSION = ".tkey"; const fs::path CERT_HASH_EXTENSION = ".hash"; enum class EncodingFormat { diff --git a/lib/evse_security/CMakeLists.txt b/lib/evse_security/CMakeLists.txt index 3c0ad29..45defdd 100644 --- a/lib/evse_security/CMakeLists.txt +++ b/lib/evse_security/CMakeLists.txt @@ -15,8 +15,8 @@ target_sources(evse_security crypto/interface/crypto_supplier.cpp crypto/interface/crypto_types.cpp - crypto/openssl/openssl_supplier.cpp - crypto/openssl/openssl_tpm.cpp + crypto/openssl/openssl_crypto_supplier.cpp + crypto/openssl/openssl_provider.cpp ) target_include_directories(evse_security @@ -83,11 +83,12 @@ if(LIBEVSE_CRYPTO_SUPPLIER_OPENSSL) add_compile_definitions(LIBEVSE_CRYPTO_SUPPLIER_OPENSSL) endif() -if(USING_TPM2) +if(USING_TPM2 OR USING_CUSTOM_PROVIDER) target_compile_definitions(evse_security PRIVATE - USING_TPM2 - PROPQUERY_DEFAULT="${PROPQUERY_DEFAULT}" - PROPQUERY_TPM2="${PROPQUERY_TPM2}" + USING_CUSTOM_PROVIDER + CUSTOM_PROVIDER_NAME="${CUSTOM_PROVIDER_NAME}" + PROPQUERY_PROVIDER_DEFAULT="${PROPQUERY_PROVIDER_DEFAULT}" + PROPQUERY_PROVIDER_CUSTOM="${PROPQUERY_PROVIDER_CUSTOM}" ) endif() diff --git a/lib/evse_security/crypto/openssl/openssl_supplier.cpp b/lib/evse_security/crypto/openssl/openssl_crypto_supplier.cpp similarity index 97% rename from lib/evse_security/crypto/openssl/openssl_supplier.cpp rename to lib/evse_security/crypto/openssl/openssl_crypto_supplier.cpp index b011609..4952c2b 100644 --- a/lib/evse_security/crypto/openssl/openssl_supplier.cpp +++ b/lib/evse_security/crypto/openssl/openssl_crypto_supplier.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Pionix GmbH and Contributors to EVerest -#include +#include #include #include @@ -22,7 +22,7 @@ #include #include -#include +#include namespace evse_security { @@ -68,7 +68,7 @@ const char* OpenSSLSupplier::get_supplier_name() { bool OpenSSLSupplier::supports_tpm_key_creation() { OpenSSLProvider provider; - return provider.supports_tpm(); + return provider.supports_provider_tpm(); } static bool export_key_internal(const KeyGenerationInfo& key_info, const EVP_PKEY_ptr& evp_key) { @@ -218,8 +218,8 @@ bool OpenSSLSupplier::generate_key(const KeyGenerationInfo& key_info, KeyHandle_ OpenSSLProvider provider; bool bResult = true; - if (key_info.generate_on_tpm) { - provider.set_global_mode(OpenSSLProvider::mode_t::tpm2_provider); + if (key_info.generate_on_custom) { + provider.set_global_mode(OpenSSLProvider::mode_t::custom_provider); } else { provider.set_global_mode(OpenSSLProvider::mode_t::default_provider); @@ -564,13 +564,13 @@ KeyValidationResult OpenSSLSupplier::x509_check_private_key(X509Handle* handle, OpenSSLProvider provider; - const bool tpm_key = is_tpm_key_string(private_key); - if (tpm_key) { - provider.set_global_mode(OpenSSLProvider::mode_t::tpm2_provider); + const bool custom_key = is_custom_private_key_string(private_key); + if (custom_key) { + provider.set_global_mode(OpenSSLProvider::mode_t::custom_provider); } else { provider.set_global_mode(OpenSSLProvider::mode_t::default_provider); } - EVLOG_debug << "TPM Key: " << tpm_key; + EVLOG_debug << "Is Custom Key: " << custom_key; BIO_ptr bio(BIO_new_mem_buf(private_key.c_str(), -1)); // Passing password string since if NULL is provided, the password CB will be called @@ -648,8 +648,8 @@ CertificateSignRequestResult OpenSSLSupplier::x509_generate_csr(const Certificat EVP_PKEY_CTX_ptr ctx; OpenSSLProvider provider; - if (csr_info.key_info.generate_on_tpm) { - provider.set_global_mode(OpenSSLProvider::mode_t::tpm2_provider); + if (csr_info.key_info.generate_on_custom) { + provider.set_global_mode(OpenSSLProvider::mode_t::custom_provider); } else { provider.set_global_mode(OpenSSLProvider::mode_t::default_provider); } diff --git a/lib/evse_security/crypto/openssl/openssl_tpm.cpp b/lib/evse_security/crypto/openssl/openssl_provider.cpp similarity index 66% rename from lib/evse_security/crypto/openssl/openssl_tpm.cpp rename to lib/evse_security/crypto/openssl/openssl_provider.cpp index c4edb0d..5d83fcb 100644 --- a/lib/evse_security/crypto/openssl/openssl_tpm.cpp +++ b/lib/evse_security/crypto/openssl/openssl_provider.cpp @@ -1,18 +1,18 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Pionix GmbH and Contributors to EVerest -#include +#include +#include #include -#if USING_TPM2 +#if USING_CUSTOM_PROVIDER // OpenSSL3 without TPM will use the default provider anyway #include #include #include #include -#define USING_OPENSSL_3_TPM #else // dummy structures for non-OpenSSL 3 struct ossl_provider_st {}; @@ -23,45 +23,57 @@ typedef struct ossl_lib_ctx_st OSSL_LIB_CTX; namespace evse_security { -bool is_tpm_key_string(const std::string& private_key_pem) { - return private_key_pem.find("-----BEGIN TSS2 PRIVATE KEY-----") != std::string::npos; +static auto KEY_HEADER_DEFAULT = "-----BEGIN PRIVATE KEY-----"; +static auto KEY_HEADER_TPM2 = "-----BEGIN TSS2 PRIVATE KEY-----"; + +bool is_custom_private_key_string(const std::string& private_key_pem) { + // If we can't find the standard header it means it's a custom key + return private_key_pem.find(KEY_HEADER_DEFAULT) == std::string::npos; } -bool is_tpm_key_file(const fs::path& private_key_file_pem) { +bool is_custom_private_key_file(const fs::path& private_key_file_pem) { if (fs::is_regular_file(private_key_file_pem)) { std::ifstream key_file(private_key_file_pem); std::string line; std::getline(key_file, line); key_file.close(); - return line.find("-----BEGIN TSS2 PRIVATE KEY-----") != std::string::npos; + // Search for the standard header + return is_custom_private_key_string(line); } return false; } -#ifdef USING_OPENSSL_3_TPM +#ifdef USING_CUSTOM_PROVIDER + +constexpr bool is_custom_provider_tpm() { + // custom provider string (see CMakeLists.txt) + constexpr const std::string_view custom_provider(CUSTOM_PROVIDER_NAME); + return (custom_provider == "tpm2"); +} + // ---------------------------------------------------------------------------- // class OpenSSLProvider OpenSSL 3 static const char* mode_t_str[2] = { "default provider", // mode_t::default_provider - "tpm2 provider" // mode_t::tpm2_provider + "custom provider" // mode_t::custom_provider }; static_assert(static_cast(OpenSSLProvider::mode_t::default_provider) == 0); -static_assert(static_cast(OpenSSLProvider::mode_t::tpm2_provider) == 1); +static_assert(static_cast(OpenSSLProvider::mode_t::custom_provider) == 1); std::ostream& operator<<(std::ostream& out, OpenSSLProvider::mode_t mode) { const unsigned int idx = static_cast(mode); - if (idx <= static_cast(OpenSSLProvider::mode_t::tpm2_provider)) { + if (idx <= static_cast(OpenSSLProvider::mode_t::custom_provider)) { out << mode_t_str[idx]; } return out; } static bool s_load_and_test_provider(OSSL_PROVIDER*& provider, OSSL_LIB_CTX* libctx, const char* provider_name) { - bool bResult = true; + bool result = true; #ifdef DEBUG const char* modestr = (libctx == nullptr) ? "global" : "TLS"; EVLOG_info << "Loading " << modestr << " provider: " << provider_name; @@ -69,7 +81,7 @@ static bool s_load_and_test_provider(OSSL_PROVIDER*& provider, OSSL_LIB_CTX* lib if ((provider = OSSL_PROVIDER_load(libctx, provider_name)) == nullptr) { EVLOG_error << "Unable to load OSSL_PROVIDER: " << provider_name; ERR_print_errors_fp(stderr); - bResult = false; + result = false; } else { #ifdef DEBUG EVLOG_info << "Testing " << modestr << " provider: " << provider_name; @@ -79,24 +91,24 @@ static bool s_load_and_test_provider(OSSL_PROVIDER*& provider, OSSL_LIB_CTX* lib ERR_print_errors_fp(stderr); OSSL_PROVIDER_unload(provider); provider = nullptr; - bResult = false; + result = false; } } - return bResult; + return result; } std::mutex OpenSSLProvider::s_mux; OpenSSLProvider::flags_underlying_t OpenSSLProvider::s_flags = 0; OSSL_PROVIDER* OpenSSLProvider::s_global_prov_default_p = nullptr; -OSSL_PROVIDER* OpenSSLProvider::s_global_prov_tpm_p = nullptr; +OSSL_PROVIDER* OpenSSLProvider::s_global_prov_custom_p = nullptr; OSSL_PROVIDER* OpenSSLProvider::s_tls_prov_default_p = nullptr; -OSSL_PROVIDER* OpenSSLProvider::s_tls_prov_tpm_p = nullptr; +OSSL_PROVIDER* OpenSSLProvider::s_tls_prov_custom_p = nullptr; OSSL_LIB_CTX* OpenSSLProvider::s_tls_libctx_p = nullptr; // propquery strings (see CMakeLists.txt) -static const char* s_default_provider = PROPQUERY_DEFAULT; -static const char* s_tpm2_provider = PROPQUERY_TPM2; +static const char* s_default_provider = PROPQUERY_PROVIDER_DEFAULT; +static const char* s_custom_provider = PROPQUERY_PROVIDER_CUSTOM; OpenSSLProvider::OpenSSLProvider() { s_mux.lock(); @@ -115,12 +127,12 @@ OpenSSLProvider::OpenSSLProvider() { // load providers for global context (void)load_global(mode_t::default_provider); - (void)load_global(mode_t::tpm2_provider); + (void)load_global(mode_t::custom_provider); (void)set_propstr(nullptr, mode_t::default_provider); // load providers for tls context (void)load_tls(mode_t::default_provider); - (void)load_tls(mode_t::tpm2_provider); + (void)load_tls(mode_t::custom_provider); (void)set_propstr(s_tls_libctx_p, mode_t::default_provider); } } @@ -129,23 +141,24 @@ OpenSSLProvider::~OpenSSLProvider() { s_mux.unlock(); } -bool OpenSSLProvider::load(OSSL_PROVIDER*& default_p, OSSL_PROVIDER*& tpm2_p, OSSL_LIB_CTX* libctx_p, mode_t mode) { - bool bResult = true; +bool OpenSSLProvider::load(OSSL_PROVIDER*& default_p, OSSL_PROVIDER*& custom_p, OSSL_LIB_CTX* libctx_p, mode_t mode) { + bool result = true; switch (mode) { - case mode_t::tpm2_provider: - if (tpm2_p == nullptr) { - bResult = s_load_and_test_provider(tpm2_p, libctx_p, "tpm2"); - update(flags_t::tpm2_available, bResult); + case mode_t::custom_provider: + if (custom_p == nullptr) { + // custom provider string (see CMakeLists.txt) + result = s_load_and_test_provider(custom_p, libctx_p, CUSTOM_PROVIDER_NAME); + update(flags_t::custom_provider_available, result); } break; case mode_t::default_provider: default: if (default_p == nullptr) { - bResult = s_load_and_test_provider(default_p, libctx_p, "default"); + result = s_load_and_test_provider(default_p, libctx_p, "default"); } break; } - return bResult; + return result; } bool OpenSSLProvider::set_propstr(OSSL_LIB_CTX* libctx, mode_t mode) { @@ -162,15 +175,15 @@ bool OpenSSLProvider::set_propstr(OSSL_LIB_CTX* libctx, mode_t mode) { } bool OpenSSLProvider::set_mode(OSSL_LIB_CTX* libctx, mode_t mode) { - bool bResult; - const flags_t f = (libctx == nullptr) ? flags_t::global_tpm2 : flags_t::tls_tpm2; + bool result; + const flags_t f = (libctx == nullptr) ? flags_t::global_custom_provider : flags_t::tls_custom_provider; - const bool apply = update(f, mode == mode_t::tpm2_provider); + const bool apply = update(f, mode == mode_t::custom_provider); if (apply) { - bResult = set_propstr(libctx, mode); + result = set_propstr(libctx, mode); } - return bResult; + return result; } const char* OpenSSLProvider::propquery(mode_t mode) const { @@ -180,8 +193,8 @@ const char* OpenSSLProvider::propquery(mode_t mode) const { case mode_t::default_provider: propquery_str = s_default_provider; break; - case mode_t::tpm2_provider: - propquery_str = s_tpm2_provider; + case mode_t::custom_provider: + propquery_str = s_custom_provider; break; default: break; @@ -194,22 +207,22 @@ void OpenSSLProvider::cleanup() { // at the point this is called logging may not be available // relying on OpenSSL errors std::lock_guard guard(s_mux); - if (OSSL_PROVIDER_unload(s_tls_prov_tpm_p) == 0) { + if (OSSL_PROVIDER_unload(s_tls_prov_custom_p) == 0) { ERR_print_errors_fp(stderr); } if (OSSL_PROVIDER_unload(s_tls_prov_default_p) == 0) { ERR_print_errors_fp(stderr); } - if (OSSL_PROVIDER_unload(s_global_prov_tpm_p) == 0) { + if (OSSL_PROVIDER_unload(s_global_prov_custom_p) == 0) { ERR_print_errors_fp(stderr); } if (OSSL_PROVIDER_unload(s_global_prov_default_p) == 0) { ERR_print_errors_fp(stderr); } - s_tls_prov_tpm_p = nullptr; + s_tls_prov_custom_p = nullptr; s_tls_prov_default_p = nullptr; - s_global_prov_tpm_p = nullptr; + s_global_prov_custom_p = nullptr; s_global_prov_default_p = nullptr; OSSL_LIB_CTX_free(s_tls_libctx_p); @@ -218,6 +231,14 @@ void OpenSSLProvider::cleanup() { s_flags = 0; } +bool OpenSSLProvider::supports_provider_tpm() { + return is_set(flags_t::custom_provider_available) && is_custom_provider_tpm(); +} + +bool OpenSSLProvider::supports_provider_custom() { + return is_set(flags_t::custom_provider_available); +} + #else // USING_OPENSSL_3_TPM // ---------------------------------------------------------------------------- // class OpenSSLProvider dummy where OpenSSL 3 is not available @@ -225,9 +246,9 @@ void OpenSSLProvider::cleanup() { OpenSSLProvider::flags_underlying_t OpenSSLProvider::s_flags = 0; OSSL_PROVIDER* OpenSSLProvider::s_global_prov_default_p = nullptr; -OSSL_PROVIDER* OpenSSLProvider::s_global_prov_tpm_p = nullptr; +OSSL_PROVIDER* OpenSSLProvider::s_global_prov_custom_p = nullptr; OSSL_PROVIDER* OpenSSLProvider::s_tls_prov_default_p = nullptr; -OSSL_PROVIDER* OpenSSLProvider::s_tls_prov_tpm_p = nullptr; +OSSL_PROVIDER* OpenSSLProvider::s_tls_prov_custom_p = nullptr; OSSL_LIB_CTX* OpenSSLProvider::s_tls_libctx_p = nullptr; OpenSSLProvider::OpenSSLProvider() { @@ -255,6 +276,14 @@ const char* OpenSSLProvider::propquery(mode_t mode) const { void OpenSSLProvider::cleanup() { } +bool OpenSSLProvider::supports_provider_tpm() { + return false; +} + +bool OpenSSLProvider::supports_provider_custom() { + return false; +} + #endif // USING_OPENSSL_3_TPM } // namespace evse_security diff --git a/lib/evse_security/evse_security.cpp b/lib/evse_security/evse_security.cpp index 8bf6261..e23264a 100644 --- a/lib/evse_security/evse_security.cpp +++ b/lib/evse_security/evse_security.cpp @@ -82,7 +82,7 @@ static bool is_keyfile(const fs::path& file_path) { if (fs::is_regular_file(file_path)) { if (file_path.has_extension()) { auto extension = file_path.extension(); - if (extension == KEY_EXTENSION || extension == TPM_KEY_EXTENSION) { + if (extension == KEY_EXTENSION || extension == CUSTOM_KEY_EXTENSION) { return true; } } @@ -97,7 +97,7 @@ static fs::path get_private_key_path_of_certificate(const X509Wrapper& certifica // Before iterating the whole dir check by the filename first 'key_path'.key/.tkey if (certificate.get_file().has_value()) { // Check normal keyfile & tpm filename - for (const auto& extension : {KEY_EXTENSION, TPM_KEY_EXTENSION}) { + for (const auto& extension : {KEY_EXTENSION, CUSTOM_KEY_EXTENSION}) { fs::path potential_keyfile = certificate.get_file().value(); potential_keyfile.replace_extension(extension); @@ -1020,13 +1020,13 @@ GetCertificateSignRequestResult EvseSecurity::generate_certificate_signing_reque const std::string& country, const std::string& organization, const std::string& common, - bool use_tpm) { + bool use_custom_provider) { std::lock_guard guard(EvseSecurity::security_mutex); // Make a difference between normal and tpm keys for identification - const auto file_name = - conversions::leaf_certificate_type_to_filename(certificate_type) + - filesystem_utils::get_random_file_name(use_tpm ? TPM_KEY_EXTENSION.string() : KEY_EXTENSION.string()); + const auto file_name = conversions::leaf_certificate_type_to_filename(certificate_type) + + filesystem_utils::get_random_file_name(use_custom_provider ? CUSTOM_KEY_EXTENSION.string() + : KEY_EXTENSION.string()); fs::path key_path; if (certificate_type == LeafCertificateType::CSMS) { @@ -1060,10 +1060,10 @@ GetCertificateSignRequestResult EvseSecurity::generate_certificate_signing_reque #endif info.key_info.key_type = CryptoKeyType::EC_prime256v1; - info.key_info.generate_on_tpm = use_tpm; + info.key_info.generate_on_custom = use_custom_provider; info.key_info.private_key_file = key_path; - if ((use_tpm == false) && private_key_password.has_value()) { + if ((use_custom_provider == false) && private_key_password.has_value()) { info.key_info.private_key_pass = private_key_password; } diff --git a/tests/openssl_supplier_test.cpp b/tests/openssl_supplier_test.cpp index d1106c3..ed73e7a 100644 --- a/tests/openssl_supplier_test.cpp +++ b/tests/openssl_supplier_test.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include // #define OUTPUT_CSR diff --git a/tests/openssl_supplier_test_tpm.cpp b/tests/openssl_supplier_test_tpm.cpp index 0315317..e0d1f2d 100644 --- a/tests/openssl_supplier_test_tpm.cpp +++ b/tests/openssl_supplier_test_tpm.cpp @@ -4,8 +4,8 @@ #include #include -#include -#include +#include +#include using namespace evse_security; @@ -23,18 +23,18 @@ class OpenSSLSupplierTpmTest : public testing::Test { } }; -TEST_F(OpenSSLSupplierTpmTest, supports_tpm) { +TEST_F(OpenSSLSupplierTpmTest, supports_provider_tpm) { OpenSSLProvider::cleanup(); - ASSERT_FALSE(OpenSSLProvider::supports_tpm()); + ASSERT_FALSE(OpenSSLProvider::supports_provider_tpm()); // calculates OpenSSLProvider provider; // returns cached - ASSERT_TRUE(OpenSSLProvider::supports_tpm()); + ASSERT_TRUE(OpenSSLProvider::supports_provider_tpm()); } -TEST_F(OpenSSLSupplierTpmTest, supports_tpm_key_creation) { +TEST_F(OpenSSLSupplierTpmTest, supports_provider_tpm_key_creation) { OpenSSLProvider::cleanup(); - ASSERT_FALSE(OpenSSLProvider::supports_tpm()); + ASSERT_FALSE(OpenSSLProvider::supports_provider_tpm()); // should calculate ASSERT_TRUE(OpenSSLSupplier::supports_tpm_key_creation()); } @@ -51,7 +51,7 @@ TEST_F(OpenSSLSupplierTpmTest, generate_key_RSA_TPM20) { TEST_F(OpenSSLSupplierTpmTest, generate_key_RSA_3072) { // Enable this test manually only if your platform supports 3072 TPM keys GTEST_SKIP() << "Skipping TPM2.0 GEN_RSA_3072 test since it is a non-spec value" - "which probably will not be supported on many platforms!"; + " which probably will not be supported on many platforms!"; KeyGenerationInfo info = { CryptoKeyType::RSA_3072, true, std::nullopt, std::nullopt, std::nullopt, diff --git a/tests/tests.cpp b/tests/tests.cpp index efb6d53..c31c016 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -21,7 +21,7 @@ #ifdef USING_TPM2 // updates so that existing tests run with the OpenSSLProvider -#include +#include #include namespace evse_security { @@ -277,7 +277,7 @@ TEST_F(EvseSecurityTests, verify_normal_keygen) { KeyHandle_ptr key; info.key_type = CryptoKeyType::RSA_3072; - info.generate_on_tpm = false; + info.generate_on_custom = false; info.public_key_file = fs::path("key/nrm_pubkey.key"); info.private_key_file = fs::path("key/nrm_privkey.key"); @@ -291,7 +291,7 @@ TEST_F(EvseSecurityTests, verify_keygen_csr) { KeyHandle_ptr key; info.key_type = CryptoKeyType::EC_prime256v1; - info.generate_on_tpm = false; + info.generate_on_custom = false; info.public_key_file = fs::path("key/pubkey.key"); info.private_key_file = fs::path("key/privkey.key");