Skip to content

Commit db379c0

Browse files
authored
Merge pull request #192 from c-jimenez/fix/authorization_key
Fix authorization key management for security profiles 1 et 2
2 parents ed3a647 + 68cd353 commit db379c0

File tree

9 files changed

+160
-20
lines changed

9 files changed

+160
-20
lines changed

.vscode/launch.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,26 @@
3838
"target": "${workspaceRoot}/build_gcc_native/tests/chargepoint/smartcharging/test_smartcharging_setpoint",
3939
"cwd": "${workspaceRoot}",
4040
"valuesFormatting": "parseText"
41+
},
42+
{
43+
"type": "cppdbg",
44+
"request": "attach",
45+
"name": "Join process",
46+
"program": "${workspaceRoot}/bin/gcc_native/quick_start_chargepoint",
47+
"processId": "${command:pickProcess}",
48+
"MIMode": "gdb",
49+
"setupCommands": [
50+
{
51+
"description": "Activer l'impression en mode Pretty pour gdb",
52+
"text": "-enable-pretty-printing",
53+
"ignoreFailures": true
54+
},
55+
{
56+
"description": "Définir la version désassemblage sur Intel",
57+
"text": "-gdb-set disassembly-flavor intel",
58+
"ignoreFailures": true
59+
}
60+
]
4161
}
4262
]
4363
}

examples/security_centralsystem/CentralSystemEventsHandler.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ SOFTWARE.
2525
#include "CentralSystemEventsHandler.h"
2626
#include "ChargePointDatabase.h"
2727

28+
#include <array>
2829
#include <iostream>
2930
#include <random>
3031
#include <sstream>
@@ -99,7 +100,8 @@ bool CentralSystemEventsHandler::checkCredentials(const std::string& chargepoint
99100
{
100101
bool ret = false;
101102

102-
cout << "Check credentials for [" << chargepoint_id << "] : " << password << endl;
103+
std::string hex_encoded_password = ocpp::helpers::toHexString(password);
104+
cout << "Check credentials for [" << chargepoint_id << "] : " << hex_encoded_password << endl;
103105

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

@@ -111,7 +113,7 @@ bool CentralSystemEventsHandler::checkCredentials(const std::string& chargepoint
111113
{
112114
if ((security_profile == 1u) || (security_profile == 2u))
113115
{
114-
ret = (password == authent_key);
116+
ret = (hex_encoded_password == authent_key);
115117
}
116118
else
117119
{
@@ -257,14 +259,18 @@ ocpp::types::RegistrationStatus CentralSystemEventsHandler::ChargePointRequestHa
257259
}
258260
else
259261
{
260-
// Generate an authent key for the charge point : minimal 16 bytes, max : 20 bytes
261-
std::stringstream ss_authent_key;
262-
ss_authent_key << std::hex;
263-
for (int i = 0; i < 5; i++)
262+
// Generate an authent key for the charge point : minimal 8 bytes, max : 20 bytes
263+
std::mt19937 rand_gen;
264+
std::uniform_int_distribution<unsigned int> rand_distrib;
265+
std::random_device rd;
266+
rand_gen.seed(rd());
267+
268+
std::array<uint8_t, 17u> authent_key_bytes;
269+
for (auto& val : authent_key_bytes)
264270
{
265-
ss_authent_key << std::setfill('0') << std::setw(4) << std::rand();
271+
val = static_cast<uint8_t>(rand_distrib(rand_gen));
266272
}
267-
m_authent_key = ss_authent_key.str();
273+
m_authent_key = ocpp::helpers::toHexString(authent_key_bytes);
268274

269275
// Add the charge point to the database
270276
m_chargepoint_db.addChargePoint(this->proxy()->identifier(), serial_number, vendor, model, 0, m_authent_key);

src/chargepoint/ChargePoint.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,8 +1164,10 @@ bool ChargePoint::doConnect()
11641164
std::string authorization_key = m_ocpp_config.authorizationKey();
11651165
if (!authorization_key.empty() && (security_profile <= 2))
11661166
{
1167-
credentials.user = m_stack_config.chargePointIdentifier();
1168-
credentials.password = authorization_key;
1167+
auto authentication_key = ocpp::helpers::fromHexString(authorization_key);
1168+
credentials.user = m_stack_config.chargePointIdentifier();
1169+
credentials.password = std::string(reinterpret_cast<const char*>(authentication_key.data()), authorization_key.size());
1170+
credentials.password.resize(authentication_key.size());
11691171
}
11701172
if (security_profile != 1)
11711173
{

src/chargepoint/security/SecurityManager.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -669,15 +669,16 @@ bool SecurityManager::handleMessage(const ocpp::messages::InstallCertificateReq&
669669
ocpp::types::ConfigurationStatus SecurityManager::checkAuthorizationKeyParameter(const std::string& key, const std::string& value)
670670
{
671671
(void)key;
672-
ConfigurationStatus ret = ConfigurationStatus::Accepted;
672+
ConfigurationStatus ret = ConfigurationStatus::Rejected;
673673

674-
// Authorization key length for security profiles 1 and 2 must be between 32 and 40 bytes
675-
unsigned int security_profile = m_ocpp_config.securityProfile();
676-
if ((security_profile == 1) || (security_profile == 2))
674+
// Authorization key length for security profiles 1 and 2 must be between 16 and 40 bytes
675+
// and must be a valid hexadecimal representation
676+
if ((value.size() >= 16u) && (value.size() <= 40u))
677677
{
678-
if ((value.size() < 32u) || (value.size() > 40u))
678+
auto key_bytes = ocpp::helpers::fromHexString(value);
679+
if (key_bytes.size() == (value.size() / 2u))
679680
{
680-
ret = ConfigurationStatus::Rejected;
681+
ret = ConfigurationStatus::Accepted;
681682
}
682683
}
683684

src/tools/helpers/StringHelpers.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
1818

1919
#include "StringHelpers.h"
2020

21+
#include <iomanip>
22+
#include <sstream>
23+
2124
namespace ocpp
2225
{
2326
namespace helpers
@@ -114,5 +117,50 @@ bool endsWith(const std::string& str, const std::string& substr)
114117
return ret;
115118
}
116119

120+
/** @brief Helper function to convert a buffer to an hexadecimal string representation */
121+
std::string toHexString(const void* buffer, size_t size)
122+
{
123+
std::stringstream ss;
124+
const uint8_t* data = reinterpret_cast<const uint8_t*>(buffer);
125+
if (data)
126+
{
127+
ss << std::hex;
128+
for (size_t i = 0; i < size; i++)
129+
{
130+
ss << std::setw(2) << std::setfill('0') << static_cast<int>(data[i]) << "";
131+
}
132+
}
133+
return ss.str();
134+
}
135+
136+
/** @brief Helper function to convert an hexadecimal string representation into an array of bytes */
137+
std::vector<uint8_t> fromHexString(const std::string& hex_string)
138+
{
139+
std::vector<uint8_t> ret;
140+
if ((hex_string.size() & 1) == 0)
141+
{
142+
try
143+
{
144+
for (size_t i = 0; i < hex_string.size(); i += 2u)
145+
{
146+
std::string ss = hex_string.substr(i, 2u);
147+
for (const auto& c : ss)
148+
{
149+
if (!((c >= '0') && (c <= '9')) && !((c >= 'a') && (c <= 'f')) && !((c >= 'A') && (c <= 'F')))
150+
{
151+
throw std::out_of_range(ss);
152+
}
153+
}
154+
ret.push_back(static_cast<uint8_t>(std::stoul(ss, nullptr, 16)));
155+
}
156+
}
157+
catch (...)
158+
{
159+
ret.clear();
160+
}
161+
}
162+
return ret;
163+
}
164+
117165
} // namespace helpers
118166
} // namespace ocpp

src/tools/helpers/StringHelpers.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
1919
#ifndef OPENOCPP_STRING_H
2020
#define OPENOCPP_STRING_H
2121

22+
#include <cstdint>
2223
#include <string>
2324
#include <vector>
25+
2426
namespace ocpp
2527
{
2628
namespace helpers
@@ -87,6 +89,32 @@ bool startsWith(const std::string& str, const std::string& substr);
8789
*/
8890
bool endsWith(const std::string& str, const std::string& substr);
8991

92+
/**
93+
* @brief Helper function to convert a buffer to an hexadecimal string representation
94+
* @param buffer Buffer to convert
95+
* @param size Size of the buffer in bytes
96+
* @return Buffer contents as an hexadecimal string
97+
*/
98+
std::string toHexString(const void* buffer, size_t size);
99+
100+
/**
101+
* @brief Helper function to convert a ContiguousContainer to an hexadecimal string representation
102+
* @param cont container to convert
103+
* @return Container contents as an hexadecimal string
104+
*/
105+
template <typename ContiguousContainer>
106+
std::string toHexString(const ContiguousContainer& cont)
107+
{
108+
return toHexString(&cont[0], cont.size() * sizeof(cont[0]));
109+
}
110+
111+
/**
112+
* @brief Helper function to convert an hexadecimal string representation into an array of bytes
113+
* @param hex_string Hexadecimal string to convert
114+
* @return Corresponding array of bytes, empty if the input string is invalid
115+
*/
116+
std::vector<uint8_t> fromHexString(const std::string& hex_string);
117+
90118
} // namespace helpers
91119
} // namespace ocpp
92120

src/websockets/libwebsockets/LibWebsocketClient.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,29 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
2323
#include <functional>
2424
#include <iostream>
2525

26+
/** @brief Generate basic authent header with bytes password (may contain \0 char) */
27+
int lws_http_basic_auth_gen2(const char* user, const void* pw, size_t pwd_len, char* buf, size_t len)
28+
{
29+
size_t n = strlen(user), m = pwd_len;
30+
char b[128];
31+
32+
if (len < 6 + ((4 * (n + m + 1)) / 3) + 1)
33+
return 1;
34+
35+
memcpy(buf, "Basic ", 6);
36+
37+
n = (unsigned int)lws_snprintf(b, sizeof(b), "%s:", user);
38+
if ((n + pwd_len) >= sizeof(b) - 2)
39+
return 2;
40+
memcpy(&b[n], pw, pwd_len);
41+
n += pwd_len;
42+
43+
lws_b64_encode_string(b, (int)n, buf + 6, (int)len - 6);
44+
buf[len - 1] = '\0';
45+
46+
return 0;
47+
}
48+
2649
namespace ocpp
2750
{
2851
namespace websockets
@@ -411,7 +434,11 @@ int LibWebsocketClient::eventCallback(struct lws* wsi, enum lws_callback_reasons
411434
if (client->m_credentials.user.empty())
412435
break;
413436

414-
if (lws_http_basic_auth_gen(client->m_credentials.user.c_str(), client->m_credentials.password.c_str(), b, sizeof(b)))
437+
if (lws_http_basic_auth_gen2(client->m_credentials.user.c_str(),
438+
client->m_credentials.password.data(),
439+
client->m_credentials.password.size(),
440+
b,
441+
sizeof(b)))
415442
break;
416443
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_AUTHORIZATION, (unsigned char*)b, (int)strlen(b), p, end))
417444
return -1;

src/websockets/libwebsockets/LibWebsocketClientPool.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
2222
#include <cstdint>
2323
#include <functional>
2424

25+
/** @brief Generate basic authent header with bytes password (may contain \0 char) => implemented in LibWebsocketClient.cpp*/
26+
extern int lws_http_basic_auth_gen2(const char* user, const void* pw, size_t pwd_len, char* buf, size_t len);
27+
2528
namespace ocpp
2629
{
2730
namespace websockets
@@ -144,7 +147,7 @@ void LibWebsocketClientPool::process()
144147

145148
// Dummy vhost to handle context related events
146149
struct lws_protocols protocols[] = {{"LibWebsocketClientPool", &LibWebsocketClientPool::eventCallback, 0, 0, 0, this, 0},
147-
LWS_PROTOCOL_LIST_TERM};
150+
LWS_PROTOCOL_LIST_TERM};
148151
struct lws_context_creation_info vhost_info;
149152
memset(&vhost_info, 0, sizeof(vhost_info));
150153
vhost_info.protocols = protocols;
@@ -599,7 +602,11 @@ int LibWebsocketClientPool::Client::eventCallback(
599602
if (client->m_credentials.user.empty())
600603
break;
601604

602-
if (lws_http_basic_auth_gen(client->m_credentials.user.c_str(), client->m_credentials.password.c_str(), b, sizeof(b)))
605+
if (lws_http_basic_auth_gen2(client->m_credentials.user.c_str(),
606+
client->m_credentials.password.data(),
607+
client->m_credentials.password.size(),
608+
b,
609+
sizeof(b)))
603610
break;
604611
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_AUTHORIZATION, (unsigned char*)b, (int)strlen(b), p, end))
605612
return -1;

src/websockets/libwebsockets/LibWebsocketServer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,8 @@ int LibWebsocketServer::eventCallback(struct lws* wsi, enum lws_callback_reasons
383383
{
384384
// Check credentials
385385
std::string username(plain, static_cast<size_t>(pcolon - plain));
386-
std::string password(pcolon + 1u);
386+
std::string password(pcolon + 1u, m - (username.size() + 1u));
387+
password.resize(m - (username.size() + 1u));
387388
authorized = server->m_listener->wsCheckCredentials(uri, username, password);
388389
}
389390
}

0 commit comments

Comments
 (0)