Skip to content
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
20 changes: 20 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@
"target": "${workspaceRoot}/build_gcc_native/tests/chargepoint/smartcharging/test_smartcharging_setpoint",
"cwd": "${workspaceRoot}",
"valuesFormatting": "parseText"
},
{
"type": "cppdbg",
"request": "attach",
"name": "Join process",
"program": "${workspaceRoot}/bin/gcc_native/quick_start_chargepoint",
"processId": "${command:pickProcess}",
"MIMode": "gdb",
"setupCommands": [
{
"description": "Activer l'impression en mode Pretty pour gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Définir la version désassemblage sur Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
]
}
22 changes: 14 additions & 8 deletions examples/security_centralsystem/CentralSystemEventsHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ SOFTWARE.
#include "CentralSystemEventsHandler.h"
#include "ChargePointDatabase.h"

#include <array>
#include <iostream>
#include <random>
#include <sstream>
Expand Down Expand Up @@ -99,7 +100,8 @@ bool CentralSystemEventsHandler::checkCredentials(const std::string& chargepoint
{
bool ret = false;

cout << "Check credentials for [" << chargepoint_id << "] : " << password << endl;
std::string hex_encoded_password = ocpp::helpers::toHexString(password);
cout << "Check credentials for [" << chargepoint_id << "] : " << hex_encoded_password << endl;

// HTTP Basic Authentication is for Charge Points configured with Security Profile 1 or 2 only

Expand All @@ -111,7 +113,7 @@ bool CentralSystemEventsHandler::checkCredentials(const std::string& chargepoint
{
if ((security_profile == 1u) || (security_profile == 2u))
{
ret = (password == authent_key);
ret = (hex_encoded_password == authent_key);
}
else
{
Expand Down Expand Up @@ -257,14 +259,18 @@ ocpp::types::RegistrationStatus CentralSystemEventsHandler::ChargePointRequestHa
}
else
{
// Generate an authent key for the charge point : minimal 16 bytes, max : 20 bytes
std::stringstream ss_authent_key;
ss_authent_key << std::hex;
for (int i = 0; i < 5; i++)
// Generate an authent key for the charge point : minimal 8 bytes, max : 20 bytes
std::mt19937 rand_gen;
std::uniform_int_distribution<unsigned int> rand_distrib;
std::random_device rd;
rand_gen.seed(rd());

std::array<uint8_t, 17u> authent_key_bytes;
for (auto& val : authent_key_bytes)
{
ss_authent_key << std::setfill('0') << std::setw(4) << std::rand();
val = static_cast<uint8_t>(rand_distrib(rand_gen));
}
m_authent_key = ss_authent_key.str();
m_authent_key = ocpp::helpers::toHexString(authent_key_bytes);

// Add the charge point to the database
m_chargepoint_db.addChargePoint(this->proxy()->identifier(), serial_number, vendor, model, 0, m_authent_key);
Expand Down
6 changes: 4 additions & 2 deletions src/chargepoint/ChargePoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1164,8 +1164,10 @@ bool ChargePoint::doConnect()
std::string authorization_key = m_ocpp_config.authorizationKey();
if (!authorization_key.empty() && (security_profile <= 2))
{
credentials.user = m_stack_config.chargePointIdentifier();
credentials.password = authorization_key;
auto authentication_key = ocpp::helpers::fromHexString(authorization_key);
credentials.user = m_stack_config.chargePointIdentifier();
credentials.password = std::string(reinterpret_cast<const char*>(authentication_key.data()), authorization_key.size());
credentials.password.resize(authentication_key.size());
}
if (security_profile != 1)
{
Expand Down
13 changes: 7 additions & 6 deletions src/chargepoint/security/SecurityManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,15 +669,16 @@ bool SecurityManager::handleMessage(const ocpp::messages::InstallCertificateReq&
ocpp::types::ConfigurationStatus SecurityManager::checkAuthorizationKeyParameter(const std::string& key, const std::string& value)
{
(void)key;
ConfigurationStatus ret = ConfigurationStatus::Accepted;
ConfigurationStatus ret = ConfigurationStatus::Rejected;

// Authorization key length for security profiles 1 and 2 must be between 32 and 40 bytes
unsigned int security_profile = m_ocpp_config.securityProfile();
if ((security_profile == 1) || (security_profile == 2))
// Authorization key length for security profiles 1 and 2 must be between 16 and 40 bytes
// and must be a valid hexadecimal representation
if ((value.size() >= 16u) && (value.size() <= 40u))
{
if ((value.size() < 32u) || (value.size() > 40u))
auto key_bytes = ocpp::helpers::fromHexString(value);
if (key_bytes.size() == (value.size() / 2u))
{
ret = ConfigurationStatus::Rejected;
ret = ConfigurationStatus::Accepted;
}
}

Expand Down
48 changes: 48 additions & 0 deletions src/tools/helpers/StringHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.

#include "StringHelpers.h"

#include <iomanip>
#include <sstream>

namespace ocpp
{
namespace helpers
Expand Down Expand Up @@ -114,5 +117,50 @@ bool endsWith(const std::string& str, const std::string& substr)
return ret;
}

/** @brief Helper function to convert a buffer to an hexadecimal string representation */
std::string toHexString(const void* buffer, size_t size)
{
std::stringstream ss;
const uint8_t* data = reinterpret_cast<const uint8_t*>(buffer);
if (data)
{
ss << std::hex;
for (size_t i = 0; i < size; i++)
{
ss << std::setw(2) << std::setfill('0') << static_cast<int>(data[i]) << "";
}
}
return ss.str();
}

/** @brief Helper function to convert an hexadecimal string representation into an array of bytes */
std::vector<uint8_t> fromHexString(const std::string& hex_string)
{
std::vector<uint8_t> ret;
if ((hex_string.size() & 1) == 0)
{
try
{
for (size_t i = 0; i < hex_string.size(); i += 2u)
{
std::string ss = hex_string.substr(i, 2u);
for (const auto& c : ss)
{
if (!((c >= '0') && (c <= '9')) && !((c >= 'a') && (c <= 'f')) && !((c >= 'A') && (c <= 'F')))
{
throw std::out_of_range(ss);
}
}
ret.push_back(static_cast<uint8_t>(std::stoul(ss, nullptr, 16)));
}
}
catch (...)
{
ret.clear();
}
}
return ret;
}

} // namespace helpers
} // namespace ocpp
28 changes: 28 additions & 0 deletions src/tools/helpers/StringHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
#ifndef OPENOCPP_STRING_H
#define OPENOCPP_STRING_H

#include <cstdint>
#include <string>
#include <vector>

namespace ocpp
{
namespace helpers
Expand Down Expand Up @@ -87,6 +89,32 @@ bool startsWith(const std::string& str, const std::string& substr);
*/
bool endsWith(const std::string& str, const std::string& substr);

/**
* @brief Helper function to convert a buffer to an hexadecimal string representation
* @param buffer Buffer to convert
* @param size Size of the buffer in bytes
* @return Buffer contents as an hexadecimal string
*/
std::string toHexString(const void* buffer, size_t size);

/**
* @brief Helper function to convert a ContiguousContainer to an hexadecimal string representation
* @param cont container to convert
* @return Container contents as an hexadecimal string
*/
template <typename ContiguousContainer>
std::string toHexString(const ContiguousContainer& cont)
{
return toHexString(&cont[0], cont.size() * sizeof(cont[0]));
}

/**
* @brief Helper function to convert an hexadecimal string representation into an array of bytes
* @param hex_string Hexadecimal string to convert
* @return Corresponding array of bytes, empty if the input string is invalid
*/
std::vector<uint8_t> fromHexString(const std::string& hex_string);

} // namespace helpers
} // namespace ocpp

Expand Down
29 changes: 28 additions & 1 deletion src/websockets/libwebsockets/LibWebsocketClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,29 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
#include <functional>
#include <iostream>

/** @brief Generate basic authent header with bytes password (may contain \0 char) */
int lws_http_basic_auth_gen2(const char* user, const void* pw, size_t pwd_len, char* buf, size_t len)
{
size_t n = strlen(user), m = pwd_len;
char b[128];

if (len < 6 + ((4 * (n + m + 1)) / 3) + 1)
return 1;

memcpy(buf, "Basic ", 6);

n = (unsigned int)lws_snprintf(b, sizeof(b), "%s:", user);
if ((n + pwd_len) >= sizeof(b) - 2)
return 2;
memcpy(&b[n], pw, pwd_len);
n += pwd_len;

lws_b64_encode_string(b, (int)n, buf + 6, (int)len - 6);
buf[len - 1] = '\0';

return 0;
}

namespace ocpp
{
namespace websockets
Expand Down Expand Up @@ -411,7 +434,11 @@ int LibWebsocketClient::eventCallback(struct lws* wsi, enum lws_callback_reasons
if (client->m_credentials.user.empty())
break;

if (lws_http_basic_auth_gen(client->m_credentials.user.c_str(), client->m_credentials.password.c_str(), b, sizeof(b)))
if (lws_http_basic_auth_gen2(client->m_credentials.user.c_str(),
client->m_credentials.password.data(),
client->m_credentials.password.size(),
b,
sizeof(b)))
break;
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_AUTHORIZATION, (unsigned char*)b, (int)strlen(b), p, end))
return -1;
Expand Down
11 changes: 9 additions & 2 deletions src/websockets/libwebsockets/LibWebsocketClientPool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
#include <cstdint>
#include <functional>

/** @brief Generate basic authent header with bytes password (may contain \0 char) => implemented in LibWebsocketClient.cpp*/
extern int lws_http_basic_auth_gen2(const char* user, const void* pw, size_t pwd_len, char* buf, size_t len);

namespace ocpp
{
namespace websockets
Expand Down Expand Up @@ -144,7 +147,7 @@ void LibWebsocketClientPool::process()

// Dummy vhost to handle context related events
struct lws_protocols protocols[] = {{"LibWebsocketClientPool", &LibWebsocketClientPool::eventCallback, 0, 0, 0, this, 0},
LWS_PROTOCOL_LIST_TERM};
LWS_PROTOCOL_LIST_TERM};
struct lws_context_creation_info vhost_info;
memset(&vhost_info, 0, sizeof(vhost_info));
vhost_info.protocols = protocols;
Expand Down Expand Up @@ -599,7 +602,11 @@ int LibWebsocketClientPool::Client::eventCallback(
if (client->m_credentials.user.empty())
break;

if (lws_http_basic_auth_gen(client->m_credentials.user.c_str(), client->m_credentials.password.c_str(), b, sizeof(b)))
if (lws_http_basic_auth_gen2(client->m_credentials.user.c_str(),
client->m_credentials.password.data(),
client->m_credentials.password.size(),
b,
sizeof(b)))
break;
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_AUTHORIZATION, (unsigned char*)b, (int)strlen(b), p, end))
return -1;
Expand Down
3 changes: 2 additions & 1 deletion src/websockets/libwebsockets/LibWebsocketServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,8 @@ int LibWebsocketServer::eventCallback(struct lws* wsi, enum lws_callback_reasons
{
// Check credentials
std::string username(plain, static_cast<size_t>(pcolon - plain));
std::string password(pcolon + 1u);
std::string password(pcolon + 1u, m - (username.size() + 1u));
password.resize(m - (username.size() + 1u));
authorized = server->m_listener->wsCheckCredentials(uri, username, password);
}
}
Expand Down