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

Added support for libwebsockets for tpm/secprofile 2/3 #320

Merged
merged 11 commits into from
Dec 22, 2023
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Libocpp provides a complete implementation of OCPP 1.6. The implementation of OC
- [Building the doxygen documentation](#building-the-doxygen-documentation)
- [Unit testing](#unit-testing)
- [Building with FetchContent instead of EDM](#building-with-fetchcontent-instead-of-edm)
- [Support for security profile 2 and 3 with TPM in OCPP 1.6 using libwebsockets](#support-for-security-profile-2-and-3-with-tpm-in-ocpp-16-using-libwebsockets)

## Feature Support

Expand Down Expand Up @@ -514,3 +515,11 @@ Run the unit tests

## Building with FetchContent instead of EDM
In [doc/build-with-fetchcontent](doc/build-with-fetchcontent) you can find an example how to build libocpp with FetchContent instead of EDM.

## Support for security profile 2 and 3 with TPM in OCPP 1.6 using libwebsockets

If you want to try the new websocket implementation based on libwebsockets (supporting security profile 2 and 3 with TPM) you can set the following cmake option.

```bash
cmake .. -DLIBOCPP_ENABLE_LIBWEBSOCKETS=ON
```
3 changes: 2 additions & 1 deletion config/v16/config-docker.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"ChargePointModel": "Yeti",
"ChargePointVendor": "Pionix",
"FirmwareVersion": "0.1",
"AllowChargingProfileWithoutStartSchedule": true
"AllowChargingProfileWithoutStartSchedule": true,
"UseTPM" : false
AssemblyJohn marked this conversation as resolved.
Show resolved Hide resolved
},
"Core": {
"AuthorizeRemoteTxRequests": false,
Expand Down
5 changes: 5 additions & 0 deletions config/v16/profile_schemas/Internal.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@
"TLS_AES_128_GCM_SHA256"
]
},
"UseTPM": {
"type": "boolean",
"readOnly": true,
"default": false
},
"RetryBackoffRandomRange": {
"$comment": "maximum value for the random part of the websocket reconnect back-off time",
"type": "integer",
Expand Down
24 changes: 24 additions & 0 deletions dependencies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,27 @@ websocketpp:
libevse-security:
git: https://github.com/EVerest/libevse-security.git
git_tag: v0.3.0
libwebsockets:
hikinggrass marked this conversation as resolved.
Show resolved Hide resolved
git: https://github.com/warmcat/libwebsockets.git
git_tag: v4.3.3
cmake_condition: "LIBOCPP_ENABLE_LIBWEBSOCKETS"
options:
- CMAKE_POLICY_DEFAULT_CMP0077 NEW
- LWS_ROLE_RAW_FILE OFF
- LWS_UNIX_SOCK OFF
- LWS_WITH_SYS_STATE OFF
- LWS_WITH_SYS_SMD OFF
- LWS_WITH_UPNG OFF
- LWS_WITH_JPEG OFF
- LWS_WITH_DLO OFF
- LWS_WITH_SECURE_STREAMS OFF
- LWS_WITH_STATIC OFF
- LWS_WITH_LHP OFF
- LWS_WITH_LEJP_CONF OFF
- LWS_WITH_MINIMAL_EXAMPLES OFF
- LWS_WITH_CACHE_NSCOOKIEJAR OFF
- LWS_WITHOUT_TESTAPPS ON
- LWS_WITHOUT_TEST_SERVER ON
- LWS_WITHOUT_TEST_SERVER_EXTPOLL ON
- LWS_WITHOUT_TEST_PING ON
- LWS_WITHOUT_TEST_CLIENT ON
1 change: 1 addition & 0 deletions include/ocpp/common/websocket/websocket_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
std::optional<bool> additional_root_certificate_check;
std::optional<std::string> hostName;
bool verify_csms_common_name;
bool use_tpm_tls;

Check notice on line 38 in include/ocpp/common/websocket/websocket_base.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/common/websocket/websocket_base.hpp#L38

struct member 'WebsocketConnectionOptions::use_tpm_tls' is never used.
};

///
Expand Down
92 changes: 92 additions & 0 deletions include/ocpp/common/websocket/websocket_tls_tpm.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_WEBSOCKET_TLS_TPM_HPP
#define OCPP_WEBSOCKET_TLS_TPM_HPP

#include <ocpp/common/evse_security.hpp>
#include <ocpp/common/websocket/websocket_base.hpp>

#include <queue>
namespace ocpp {

struct ConnectionData;
struct WebsocketMessage;

/// \brief Experimental libwebsockets TLS connection
class WebsocketTlsTPM final : public WebsocketBase {
AssemblyJohn marked this conversation as resolved.
Show resolved Hide resolved
public:
/// \brief Creates a new Websocket object with the providede \p connection_options
AssemblyJohn marked this conversation as resolved.
Show resolved Hide resolved
explicit WebsocketTlsTPM(const WebsocketConnectionOptions& connection_options,
std::shared_ptr<EvseSecurity> evse_security);

~WebsocketTlsTPM();

void set_connection_options(const WebsocketConnectionOptions& connection_options) override;

/// \brief connect to a TLS websocket
/// \returns true if the websocket is initialized and a connection attempt is made
bool connect() override;

/// \brief Reconnects the websocket using the delay, a reason for this reconnect can be provided with the
/// \param reason parameter
AssemblyJohn marked this conversation as resolved.
Show resolved Hide resolved
/// \param delay delay of the reconnect attempt
void reconnect(std::error_code reason, long delay) override;

/// \brief closes the websocket
void close(websocketpp::close::status::value code, const std::string& reason) override;

/// \brief send a \p message over the websocket
/// \returns true if the message was sent successfully
bool send(const std::string& message) override;

/// \brief send a websocket ping
void ping() override;

public:
int process_callback(void* wsi_ptr, int callback_reason, void* user, void* in, size_t len);

private:
void tls_init();
void client_loop();
void recv_loop();

/// \brief Called when a TLS websocket connection is established, calls the connected callback
void on_conn_connected();

/// \brief Called when a TLS websocket connection is closed
void on_conn_close();

/// \brief Called when a TLS websocket connection fails to be established
void on_conn_fail();

/// \brief When the connection can send data
void on_writable();

/// \brief Called when a message is received over the TLS websocket, calls the message callback
void on_message(void* msg, size_t len);

void request_write();

void poll_message(const std::shared_ptr<WebsocketMessage>& msg, bool wait_sendaf);

private:
std::shared_ptr<EvseSecurity> evse_security;

// Connection related data
std::unique_ptr<Everest::SteadyTimer> reconnect_timer_tpm;
std::unique_ptr<std::thread> websocket_thread;
std::shared_ptr<ConnectionData> conn_data;
std::condition_variable conn_cv;

std::mutex queue_mutex;
std::queue<std::shared_ptr<WebsocketMessage>> message_queue;

Check notice on line 82 in include/ocpp/common/websocket/websocket_tls_tpm.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/common/websocket/websocket_tls_tpm.hpp#L82

class member 'WebsocketTlsTPM::message_queue' is never used.
std::condition_variable msg_send_cv;

std::unique_ptr<std::thread> recv_message_thread;
std::mutex recv_mutex;
std::queue<std::string> recv_message_queue;

Check notice on line 87 in include/ocpp/common/websocket/websocket_tls_tpm.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/common/websocket/websocket_tls_tpm.hpp#L87

class member 'WebsocketTlsTPM::recv_message_queue' is never used.
std::condition_variable recv_message_cv;
};

} // namespace ocpp
#endif // OCPP_WEBSOCKET_HPP
8 changes: 8 additions & 0 deletions include/ocpp/common/websocket/websocket_uri.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ class Uri {
return this->chargepoint_id;
}

std::string get_path() {
return this->path_without_chargepoint_id;
}

uint16_t get_port() {
return this->port;
}

std::string string() {
auto uri = get_websocketpp_uri();
return uri.str();
Expand Down
1 change: 1 addition & 0 deletions include/ocpp/v16/charge_point_configuration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class ChargePointConfiguration {
KeyValue getUseSslDefaultVerifyPathsKeyValue();
bool getVerifyCsmsCommonName();
KeyValue getVerifyCsmsCommonNameKeyValue();
bool getUseTPM();

int32_t getRetryBackoffRandomRange();
void setRetryBackoffRandomRange(int32_t retry_backoff_random_range);
Expand Down
15 changes: 14 additions & 1 deletion lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ add_subdirectory(ocpp/v16/messages)
add_subdirectory(ocpp/v201/messages)

option(LIBOCPP_USE_BOOST_FILESYSTEM "Usage of boost/filesystem.hpp instead of std::filesystem" OFF)
option(LIBOCPP_ENABLE_LIBWEBSOCKETS "Usage of libwebsockets instead of websockets++" OFF)

target_include_directories(ocpp
PUBLIC
Expand Down Expand Up @@ -103,13 +104,25 @@ target_link_libraries(ocpp
date::date-tz
)

if(LIBOCPP_ENABLE_LIBWEBSOCKETS)
find_package(libwebsockets REQUIRED)
target_link_libraries(ocpp
PUBLIC
websockets_shared
)
target_compile_definitions(ocpp
PRIVATE
LIBOCPP_ENABLE_LIBWEBSOCKETS
)
endif()

if(LIBOCPP_USE_BOOST_FILESYSTEM)
find_package(Boost REQUIRED COMPONENTS filesystem)
target_link_libraries(ocpp
PRIVATE
Boost::filesystem
)
target_compile_definitions(log
target_compile_definitions(ocpp
PRIVATE
LIBOCPP_USE_BOOST_FILESYSTEM
)
Expand Down
7 changes: 7 additions & 0 deletions lib/ocpp/common/websocket/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,10 @@ target_sources(ocpp
websocket_tls.cpp
websocket.cpp
)

if(LIBOCPP_ENABLE_LIBWEBSOCKETS)
target_sources(ocpp
PRIVATE
websocket_tls_tpm.cpp
)
endif()
9 changes: 9 additions & 0 deletions lib/ocpp/common/websocket/websocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
#include <ocpp/common/websocket/websocket.hpp>
#include <ocpp/v16/types.hpp>

#ifdef LIBOCPP_ENABLE_LIBWEBSOCKETS
#include <ocpp/common/websocket/websocket_tls_tpm.hpp>
#endif

#include <boost/algorithm/string.hpp>

using json = nlohmann::json;
Expand All @@ -14,11 +18,16 @@ namespace ocpp {
Websocket::Websocket(const WebsocketConnectionOptions& connection_options, std::shared_ptr<EvseSecurity> evse_security,
std::shared_ptr<MessageLogging> logging) :
logging(logging) {

#ifdef LIBOCPP_ENABLE_LIBWEBSOCKETS
this->websocket = std::make_unique<WebsocketTlsTPM>(connection_options, evse_security);
#else
if (connection_options.security_profile <= 1) {
this->websocket = std::make_unique<WebsocketPlain>(connection_options);
} else if (connection_options.security_profile >= 2) {
this->websocket = std::make_unique<WebsocketTLS>(connection_options, evse_security);
}
#endif
}

Websocket::~Websocket() {
Expand Down
Loading