Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reliability improvements for OpenSSL tpm2 provider on an embedded system #42

Merged
merged 2 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ find_package(everest-cmake 0.1 REQUIRED
option(${PROJECT_NAME}_BUILD_TESTING "Build unit tests, used if included as dependency" OFF)
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)

if(USING_TPM2)
# OpenSSL property string when using the default provider
set(PROPQUERY_DEFAULT "provider!=tpm2")
AssemblyJohn marked this conversation as resolved.
Show resolved Hide resolved
# OpenSSL property string when using the tpm2 provider
set(PROPQUERY_TPM2 "?provider=tpm2,tpm2.digest!=yes,tpm2.cipher!=yes")
endif()


# dependencies
if (NOT DISABLE_EDM)
Expand All @@ -30,6 +39,7 @@ option(LIBEVSE_CRYPTO_SUPPLIER_OPENSSL "Default OpenSSL cryptography supplier" O

# dependencies
find_package(OpenSSL REQUIRED)
find_package(date)

add_subdirectory(lib)

Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,27 @@
make -j$(nproc) install
make test
```

## TPM
There is a configuration option to configure OpenSSL for use with a TPM.<br>

Check notice on line 40 in README.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

README.md#L40

Element: br
`cmake` ... `-DUSING_TPM2=ON`<br>

Check notice on line 41 in README.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

README.md#L41

Element: br
Note OpenSSL providers are not available for OpenSSL v1, OpenSSL v3 is required.

The library will use the `UseTPM` flag and the PEM private key file to
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

Check notice on line 48 in README.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

README.md#L48

Lists should be surrounded by blank lines
- `PROPQUERY_TPM2` is the string to use when selecting the tpm2 provider

propquery|action
---------|------
"provider=default"|use the default provider
"provider=tpm2"|use the tpm2 provider
"provider!=tpm2"|don't use the tpm provider
"?provider=tpm2,tpm2.digest!=yes"|prefer the tpm2 provider but not for message digests

For more information see:
- [Provider for integration of TPM 2.0 to OpenSSL 3.x](https://github.com/tpm2-software/tpm2-openssl)

Check notice on line 59 in README.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

README.md#L59

Lists should be surrounded by blank lines
- [OpenSSL property](https://www.openssl.org/docs/man3.0/man7/property.html)
- [OpenSSL provider](https://www.openssl.org/docs/man3.0/man7/provider.html)
161 changes: 161 additions & 0 deletions include/evse_security/crypto/openssl/openssl_tpm.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest

#ifndef OPENSSL_TPM_HPP
#define OPENSSL_TPM_HPP

#include <cstdint>
#include <fstream>
#include <mutex>
#include <string>

// opaque types (from OpenSSL)
struct ossl_lib_ctx_st; // OpenSSL OSSL_LIB_CTX;
struct ossl_provider_st; // OpenSSL OSSL_PROVIDER

namespace evse_security {

/// @brief determine if the PEM string is a TSS2 private key
/// @param private_key_pem string containing the PEM encoded key
/// @return true when "-----BEGIN TSS2 PRIVATE KEY-----" found
/// @note works irrespective of OpenSSL version
bool is_tpm_key_string(const std::string& private_key_pem);

/// @brief determine if the PEM file contains a TSS2 private key
/// @param private_key_file_pem filename of the PEM file
/// @return true when file starts "-----BEGIN TSS2 PRIVATE KEY-----"
/// @note works irrespective of OpenSSL version
bool is_tpm_key_filename(const std::string& 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)
///
/// There are two contexts:
/// - 'global' for general use
/// - 'tls' for TLS connections
///
/// The class also acts as a scoped mutex to prevent changes in the
/// provider configuration during crypto operations
///
/// @note OpenSSL SSL_CTX caches the propquery so updates via
/// this class may not be effective. See SSL_CTX_new_ex()
///
/// This code provides a null implementation when OpenSSL 3 or later isn't
/// used. The null implementation is also used when -DUSING_TPM2=OFF is
/// set with cmake.
///
/// @note the tpm2-abrmd daemon is needed to support openssl-tpm2 for TLS
class OpenSSLProvider {
public:
/// @brief supported propquery strings
enum class mode_t {
default_provider,
tpm2_provider,
};

private:
typedef std::uint8_t flags_underlying_t;
enum class flags_t : flags_underlying_t {
initialised,
tpm2_available,
global_tpm2,
tls_tpm2,
};

static std::mutex s_mux;
AssemblyJohn marked this conversation as resolved.
Show resolved Hide resolved
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_tls_prov_default_p;
static struct ossl_provider_st* s_tls_prov_tpm_p;
static struct ossl_lib_ctx_st* s_tls_libctx_p;

static inline void reset(flags_t f) {
s_flags &= ~(1 << static_cast<flags_underlying_t>(f));
}

static inline void set(flags_t f) {
s_flags |= 1 << static_cast<flags_underlying_t>(f);
}

static inline bool is_set(flags_t f) {
return (s_flags & (1 << static_cast<flags_underlying_t>(f))) != 0;
}

static inline bool is_reset(flags_t f) {
return !is_set(f);
}

/// @brief uodate the flag
/// @param f - flag to update
/// @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);
if (val) {
set(f);
} else {
reset(f);
}
return bResult;
}

bool load(struct ossl_provider_st*& default_p, struct ossl_provider_st*& tpm2_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);
}
inline bool load_tls(mode_t mode) {
return load(s_tls_prov_default_p, s_tls_prov_tpm_p, s_tls_libctx_p, mode);
}

bool set_propstr(struct ossl_lib_ctx_st* libctx, mode_t mode);
bool set_mode(struct ossl_lib_ctx_st* libctx, mode_t mode);

public:
OpenSSLProvider();
~OpenSSLProvider();

inline void set_global_mode(mode_t mode) {
set_mode(nullptr, mode);
}

inline void set_tls_mode(mode_t mode) {
set_mode(s_tls_libctx_p, mode);
}

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;
}
inline mode_t propquery_tls() const {
return (is_set(flags_t::tls_tpm2)) ? mode_t::tpm2_provider : mode_t::default_provider;
}

inline const char* propquery_global_str() const {
return propquery(propquery_global());
}
inline const char* propquery_tls_str() const {
return propquery(propquery_tls());
}

/// @brief return the TLS OSSL library context
inline operator struct ossl_lib_ctx_st *() {
return s_tls_libctx_p;
}

static inline bool supports_tpm() {
return is_set(flags_t::tpm2_available);
}

static void cleanup();
};

} // namespace evse_security

#endif // OPENSSL_TPM_HPP
9 changes: 9 additions & 0 deletions lib/evse_security/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ target_sources(evse_security

crypto/interface/crypto_supplier.cpp
crypto/openssl/openssl_supplier.cpp
crypto/openssl/openssl_tpm.cpp
)

target_include_directories(evse_security
Expand Down Expand Up @@ -71,4 +72,12 @@ if(LIBEVSE_CRYPTO_SUPPLIER_OPENSSL)
add_compile_definitions(LIBEVSE_CRYPTO_SUPPLIER_OPENSSL)
endif()

if(USING_TPM2)
target_compile_definitions(evse_security PRIVATE
USING_TPM2
PROPQUERY_DEFAULT="${PROPQUERY_DEFAULT}"
PROPQUERY_TPM2="${PROPQUERY_TPM2}"
)
endif()

target_compile_features(evse_security PUBLIC cxx_std_17)
Loading
Loading