Skip to content

Commit 6bfff41

Browse files
silabs-borislrzr
authored andcommitted
UIC-3222: Use raw data for credentials that are not PinCode or password
1 parent 44b23fa commit 6bfff41

File tree

4 files changed

+116
-56
lines changed

4 files changed

+116
-56
lines changed

applications/zpc/components/zcl_cluster_servers/src/user_credential_cluster_server.cpp

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -877,8 +877,7 @@ std::string mqtt_topic_add_attribute(const std::string &base_mqtt_topic,
877877
* @return The payload value.
878878
*/
879879
std::string get_payload_value(attribute_store::attribute updated_node_cpp,
880-
mqtt_data data,
881-
bool need_utf8_conversion = false)
880+
std::function<std::string(uint32_t)> convert_function = nullptr)
882881
{
883882
std::string payload_str = "";
884883

@@ -899,32 +898,15 @@ std::string get_payload_value(attribute_store::attribute updated_node_cpp,
899898
json_payload["value"] = updated_node_cpp.reported<std::string>();
900899
break;
901900
case BYTE_ARRAY_STORAGE_TYPE: {
902-
// Convert the byte array to a string
903-
// Credential data are encoded in different way that's why we store them as raw byte array and interpret their value
904-
905-
std::string output;
901+
// Convert the byte array to a string that contains the hex representation
906902
auto raw_data = updated_node_cpp.reported<std::vector<uint8_t>>();
907903

908-
// Check if we need to convert the value to UTF-8
909-
if (need_utf8_conversion) {
910-
std::u16string utf16_str;
911-
for (size_t i = 0; i < raw_data.size(); i += 2) {
912-
char16_t char16 = (raw_data[i] << 8) | raw_data[i + 1];
913-
utf16_str.push_back(char16);
914-
}
915-
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> cnv;
916-
output = cnv.to_bytes(utf16_str);
917-
if (cnv.converted() < utf16_str.size()) {
918-
sl_log_error(LOG_TAG, "Error converting UTF-16 to UTF-8");
919-
}
920-
} else {
921-
output.reserve(raw_data.size());
922-
for (auto c: raw_data) {
923-
output.push_back(static_cast<char>(c));
924-
}
904+
std::stringstream ss;
905+
ss << std::hex << std::setfill('0');
906+
for(auto c : raw_data) {
907+
ss << std::setw(2) << static_cast<unsigned int>(c);
925908
}
926-
927-
json_payload["value"] = output;
909+
json_payload["value"] = ss.str();
928910
} break;
929911

930912
default:
@@ -934,22 +916,57 @@ std::string get_payload_value(attribute_store::attribute updated_node_cpp,
934916
}
935917

936918
// Check if we need to convert the enum to a string
937-
const auto &enum_name_conversion = data.convert_function;
938-
if (enum_name_conversion) {
939-
json_payload["value"] = enum_name_conversion(json_payload["value"]);
919+
if (convert_function) {
920+
json_payload["value"] = convert_function(json_payload["value"]);
940921
}
941922

942923
// Create payload
943924
payload_str = json_payload.dump();
944925
// Handle booleans
945-
if (enum_name_conversion) {
926+
if (convert_function) {
946927
boost::replace_all(payload_str, "\"true\"", "true");
947928
boost::replace_all(payload_str, "\"false\"", "false");
948929
}
949930

950931
return payload_str;
951932
}
952933

934+
std::string
935+
get_credential_data_value(attribute_store::attribute updated_node_cpp,
936+
user_credential_type_t type)
937+
{
938+
std::string output;
939+
940+
auto raw_data = updated_node_cpp.reported<std::vector<uint8_t>>();
941+
// Convert the byte array to a string
942+
// Credential data are encoded in different way that's why we store them as raw byte array and interpret their value
943+
switch (type) {
944+
case ZCL_CRED_TYPE_PIN_CODE:
945+
output.reserve(raw_data.size());
946+
for (auto c: raw_data) {
947+
output.push_back(static_cast<char>(c));
948+
}
949+
break;
950+
case ZCL_CRED_TYPE_PASSWORD: {
951+
std::u16string utf16_str;
952+
for (size_t i = 0; i < raw_data.size(); i += 2) {
953+
char16_t char16 = (raw_data[i] << 8) | raw_data[i + 1];
954+
utf16_str.push_back(char16);
955+
}
956+
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> cnv;
957+
output = cnv.to_bytes(utf16_str);
958+
if (cnv.converted() < utf16_str.size()) {
959+
sl_log_error(LOG_TAG, "Error converting UTF-16 to UTF-8");
960+
}
961+
} break;
962+
default:
963+
return get_payload_value(updated_node_cpp);
964+
}
965+
nlohmann::json json_payload;
966+
json_payload["value"] = output;
967+
return json_payload.dump();
968+
}
969+
953970
void publish_mqtt_topic(const std::string &base_topic,
954971
mqtt_data data,
955972
attribute_store::attribute updated_node_cpp,
@@ -966,11 +983,9 @@ void publish_mqtt_topic(const std::string &base_topic,
966983
user_credential_type_t type
967984
= updated_node_cpp.first_parent(ATTRIBUTE(CREDENTIAL_TYPE))
968985
.reported<user_credential_type_t>();
969-
payload_str = get_payload_value(updated_node_cpp,
970-
data,
971-
(type == ZCL_CRED_TYPE_PASSWORD));
986+
payload_str = get_credential_data_value(updated_node_cpp, type);
972987
} else {
973-
payload_str = get_payload_value(updated_node_cpp, data);
988+
payload_str = get_payload_value(updated_node_cpp, data.convert_function);
974989
}
975990
if (payload_str.empty()) {
976991
return;

applications/zpc/components/zcl_cluster_servers/test/user_credential_cluster_server_test.cpp

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,8 @@ attribute_store_node_t
798798
helper_add_complete_credential(user_credential_user_unique_id_t user_id,
799799
user_credential_type_t credential_type,
800800
user_credential_slot_t credential_slot,
801-
const char *credential_data)
801+
const char *credential_data,
802+
std::vector<uint8_t> expected_credential_data_vector = {})
802803
{
803804
attribute_store_node_t user_id_node = helper_add_user_id(user_id);
804805

@@ -826,10 +827,12 @@ attribute_store_node_t
826827
credential_data_vector.push_back((uint8_t)(c >> 8));
827828
credential_data_vector.push_back((uint8_t)c);
828829
}
829-
} else {
830+
} else if (credential_type == ZCL_CRED_TYPE_PIN_CODE) {
830831
credential_data_vector
831832
= std::vector<uint8_t>(cpp_str_credential_data.begin(),
832833
cpp_str_credential_data.end());
834+
} else {
835+
credential_data_vector = expected_credential_data_vector;
833836
}
834837

835838
mock_expected_cred_mqtt_topic(
@@ -980,13 +983,15 @@ void helper_test_desired_user_attributes(
980983
"Expiring Timeout mismatch");
981984
}
982985

986+
// Need to specify credential_data_vector if credential_type is not ZCL_CRED_TYPE_PIN_CODE or ZCL_CRED_TYPE_PASSWORD
983987
void helper_test_desired_credential_attributes(
984988
user_credential_user_unique_id_t user_id_node,
985989
user_credential_type_t credential_type,
986990
user_credential_slot_t credential_slot,
987991
const char *credential_data,
988992
bool desired_credential_identifiers,
989-
user_credential_operation_type_t credential_operation_type)
993+
user_credential_operation_type_t credential_operation_type,
994+
std::vector<uint8_t> credential_data_vector = {})
990995
{
991996
attribute_store_node_value_state_t credential_identifier_state
992997
= desired_credential_identifiers ? DESIRED_ATTRIBUTE : REPORTED_ATTRIBUTE;
@@ -1031,11 +1036,13 @@ void helper_test_desired_credential_attributes(
10311036
expected_credential_data_vector.push_back((uint8_t)(c >> 8));
10321037
expected_credential_data_vector.push_back((uint8_t)c);
10331038
}
1034-
} else {
1039+
} else if (credential_type == ZCL_CRED_TYPE_PIN_CODE) { // Should be in ascii we can convert it
10351040
expected_credential_data_vector
10361041
= std::vector<uint8_t>(str_credential_data.begin(),
10371042
str_credential_data.end());
1038-
}
1043+
} else {
1044+
expected_credential_data_vector = credential_data_vector;
1045+
}
10391046

10401047
// Credential Data
10411048
attribute_store::attribute credential_data_node
@@ -1486,7 +1493,7 @@ void test_user_credential_cluster_add_credential_others_happy_case()
14861493
user_credential_user_unique_id_t user_unique_id = 12;
14871494
CredType credential_type = CredType::ZCL_CRED_TYPE_RFID_CODE;
14881495
user_credential_slot_t credential_slot = 1;
1489-
const char *credential_data = "hunter2";
1496+
const char *credential_data = "abcdef123456";
14901497

14911498
// Add simple user
14921499
helper_add_user_id(user_unique_id);
@@ -1515,7 +1522,8 @@ void test_user_credential_cluster_add_credential_others_happy_case()
15151522
credential_slot,
15161523
credential_data,
15171524
true,
1518-
USER_CREDENTIAL_OPERATION_TYPE_ADD);
1525+
USER_CREDENTIAL_OPERATION_TYPE_ADD,
1526+
{0xab, 0xcd, 0xef, 0x12, 0x34, 0x56});
15191527
}
15201528

15211529
///////////////////////////////////////////////////
@@ -1661,14 +1669,15 @@ void test_user_credential_cluster_modify_credential_others_happy_case()
16611669
user_credential_user_unique_id_t user_unique_id = 12;
16621670
CredType credential_type = CredType::ZCL_CRED_TYPE_BLE;
16631671
user_credential_slot_t credential_slot = 2;
1664-
std::string credential_data = "FAST TURBO ENGINE DOG PRO MAX";
1672+
std::string credential_data = "cafe12";
16651673

16661674
auto user_id_node = helper_add_complete_credential(user_unique_id,
16671675
credential_type,
16681676
credential_slot,
1669-
credential_data.c_str());
1670-
// Test UTF-16 conversion for password
1671-
credential_data = "FAE124A54E5F9325874A23E3646B";
1677+
credential_data.c_str(),
1678+
{0xca, 0xfe, 0x12});
1679+
// New data
1680+
credential_data = "eF12Ca";
16721681
TEST_ASSERT_EQUAL_MESSAGE(
16731682
SL_STATUS_OK,
16741683
modify_credential_command(supporting_node_unid,
@@ -1686,7 +1695,8 @@ void test_user_credential_cluster_modify_credential_others_happy_case()
16861695
credential_slot,
16871696
credential_data.c_str(),
16881697
false,
1689-
USER_CREDENTIAL_OPERATION_TYPE_MODIFY);
1698+
USER_CREDENTIAL_OPERATION_TYPE_MODIFY,
1699+
{0xef, 0x12, 0xca});
16901700
}
16911701

16921702
///////////////////////////////////////////////////
@@ -1829,7 +1839,7 @@ void test_user_credential_cluster_delete_all_credential_happy_case()
18291839
user_credential_slot_t credential_slot = 0;
18301840

18311841
std::vector<user_credential_user_unique_id_t> user_ids = {12, 12, 12, 15, 19};
1832-
std::vector<user_credential_type_t> credential_types = {1, 1, 2, 5, 1};
1842+
std::vector<user_credential_type_t> credential_types = {1, 1, 2, 2, 1};
18331843
std::vector<user_credential_slot_t> credential_slots = {1, 2, 2, 1, 3};
18341844

18351845
// WARNING : Make sure that all the vector above have the same size
@@ -1888,7 +1898,7 @@ void test_user_credential_cluster_delete_all_credential_for_user_happy_case()
18881898

18891899
std::vector<user_credential_user_unique_id_t> user_ids
18901900
= {user_unique_id, user_unique_id, user_unique_id, 15, 19};
1891-
std::vector<user_credential_type_t> credential_types = {1, 1, 2, 5, 1};
1901+
std::vector<user_credential_type_t> credential_types = {1, 1, 2, 2, 1};
18921902
std::vector<user_credential_slot_t> credential_slots = {1, 2, 2, 1, 3};
18931903

18941904
// WARNING : Make sure that all the vector above have the same size
@@ -1950,7 +1960,7 @@ void test_user_credential_cluster_delete_all_credential_for_user_by_type_happy_c
19501960
std::vector<user_credential_user_unique_id_t> user_ids
19511961
= {user_unique_id, user_unique_id, user_unique_id, 15, 19};
19521962
std::vector<user_credential_type_t> credential_types
1953-
= {credential_type, credential_type, 2, 5, credential_type};
1963+
= {credential_type, credential_type, 2, 2, credential_type};
19541964
std::vector<user_credential_slot_t> credential_slots = {1, 2, 2, 1, 3};
19551965

19561966
// WARNING : Make sure that all the vector above have the same size
@@ -2012,7 +2022,7 @@ void test_user_credential_cluster_delete_all_credential_by_type_happy_case()
20122022

20132023
std::vector<user_credential_user_unique_id_t> user_ids = {12, 12, 12, 15, 19};
20142024
std::vector<user_credential_type_t> credential_types
2015-
= {credential_type, credential_type, 2, 5, credential_type};
2025+
= {credential_type, credential_type, 2, 2, credential_type};
20162026
std::vector<user_credential_slot_t> credential_slots = {1, 2, 2, 1, 3};
20172027

20182028
// WARNING : Make sure that all the vector above have the same size

applications/zpc/components/zwave_command_classes/src/private/user_credential/user_credential_credential_type_capabilities.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
// Needed for credential data (password) per specification
2121
#include <locale>
2222
#include <codecvt>
23+
#include <regex> // std::regex_replace
2324

2425
// Boost
2526
#include <boost/format.hpp>
@@ -183,8 +184,23 @@ std::vector<uint8_t>
183184
}
184185
break;
185186
default:
186-
for (const auto &c: credential_data_str) {
187-
credential_data_vector.push_back(c);
187+
if (credential_data_str.size() % 2 != 0) {
188+
throw std::runtime_error(
189+
"Credential data size is not valid. Should be even since it expect raw hexa.");
190+
}
191+
if (!std::regex_match(credential_data_str, std::regex("[0-9a-fA-F]+"))) {
192+
throw std::runtime_error(
193+
"Credential data is not valid. It should be a raw hexa string (e.g. CAFE1234).");
194+
}
195+
196+
std::stringstream ss;
197+
int value;
198+
for (size_t i = 0; i < credential_data_str.size(); i += 2) {
199+
ss.clear();
200+
auto sub_str = credential_data_str.substr(i, 2);
201+
ss << std::hex << sub_str;
202+
ss >> value;
203+
credential_data_vector.push_back(value);
188204
}
189205
}
190206

applications/zpc/components/zwave_command_classes/test/zwave_command_class_user_credential_test.cpp

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2544,7 +2544,7 @@ void test_user_credential_credential_add_capabilites_happy_case()
25442544
user_id,
25452545
ZCL_CRED_TYPE_HAND_BIOMETRIC,
25462546
1,
2547-
"TURBO"),
2547+
"ABCD"),
25482548
"Credential #1 should be valid");
25492549

25502550
TEST_ASSERT_EQUAL_MESSAGE(
@@ -2577,7 +2577,7 @@ void test_user_credential_credential_modify_capabilites_failure_cases()
25772577
std::vector<uint8_t> supported_cl = {1};
25782578
std::vector<uint16_t> supported_credential_slots = {1};
25792579
std::vector<uint8_t> supported_cred_min_length = {2};
2580-
std::vector<uint8_t> supported_cred_max_length = {7};
2580+
std::vector<uint8_t> supported_cred_max_length = {17};
25812581
helper_simulate_credential_capabilites_report(supported_credential_checksum,
25822582
support_admin_code,
25832583
support_admin_code_deactivation,
@@ -2595,7 +2595,7 @@ void test_user_credential_credential_modify_capabilites_failure_cases()
25952595
user_id,
25962596
ZCL_CRED_TYPE_HAND_BIOMETRIC,
25972597
1,
2598-
"VOITURE"),
2598+
"ABCDEF0123456789"),
25992599
"Should be able to add credential");
26002600

26012601
TEST_ASSERT_EQUAL_MESSAGE(
@@ -2605,7 +2605,7 @@ void test_user_credential_credential_modify_capabilites_failure_cases()
26052605
user_id,
26062606
ZCL_CRED_TYPE_HAND_BIOMETRIC,
26072607
1,
2608-
"V"),
2608+
"A"),
26092609
"Should not be able to modify credential data : it's too short");
26102610

26112611
TEST_ASSERT_EQUAL_MESSAGE(
@@ -2615,8 +2615,27 @@ void test_user_credential_credential_modify_capabilites_failure_cases()
26152615
user_id,
26162616
ZCL_CRED_TYPE_HAND_BIOMETRIC,
26172617
1,
2618-
"MAX SPEEEEEEEEEEEEED TURBO"),
2618+
"ABCDEF0123456789A"),
26192619
"Should not be able to modify credential data : it's too long");
2620+
TEST_ASSERT_EQUAL_MESSAGE(
2621+
SL_STATUS_FAIL,
2622+
zwave_command_class_user_credential_modify_credential(
2623+
endpoint_id_node,
2624+
user_id,
2625+
ZCL_CRED_TYPE_HAND_BIOMETRIC,
2626+
1,
2627+
"TURBO"),
2628+
"Should not be able to modify credential data : it's not hexa");
2629+
2630+
TEST_ASSERT_EQUAL_MESSAGE(
2631+
SL_STATUS_FAIL,
2632+
zwave_command_class_user_credential_modify_credential(
2633+
endpoint_id_node,
2634+
user_id,
2635+
ZCL_CRED_TYPE_HAND_BIOMETRIC,
2636+
1,
2637+
"AAB"),
2638+
"Should not be able to modify credential data : odd size for hexa value");
26202639
}
26212640

26222641
void helper_test_credential_rejected_case(uint8_t report_type)

0 commit comments

Comments
 (0)