Fixed the ReinitializeDevice and DeviceCommunicationControl password length checking for non-UTF8 passwords. (#914)

This commit is contained in:
Steve Karg
2025-02-13 12:58:54 -06:00
committed by GitHub
parent f8e9ab8d86
commit adff1f9c0f
3 changed files with 41 additions and 50 deletions
+7 -1
View File
@@ -668,6 +668,7 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
bool status = false; bool status = false;
bool password_success = false; bool password_success = false;
unsigned i; unsigned i;
size_t length;
/* From 16.4.1.1.2 Password /* From 16.4.1.1.2 Password
This optional parameter shall be a CharacterString of up to This optional parameter shall be a CharacterString of up to
@@ -676,7 +677,12 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
is absent or if the password is incorrect. For those devices that is absent or if the password is incorrect. For those devices that
do not require a password, this parameter shall be ignored.*/ do not require a password, this parameter shall be ignored.*/
if (Reinit_Password && strlen(Reinit_Password) > 0) { if (Reinit_Password && strlen(Reinit_Password) > 0) {
if (characterstring_utf8_length(&rd_data->password) > 20) { if (characterstring_encoding(&rd_data->password) == CHARACTER_UTF8) {
length = characterstring_utf8_length(&rd_data->password);
} else {
length = characterstring_length(&rd_data->password);
}
if (length > 20) {
rd_data->error_class = ERROR_CLASS_SERVICES; rd_data->error_class = ERROR_CLASS_SERVICES;
rd_data->error_code = ERROR_CODE_PARAMETER_OUT_OF_RANGE; rd_data->error_code = ERROR_CODE_PARAMETER_OUT_OF_RANGE;
} else if (characterstring_ansi_same( } else if (characterstring_ansi_same(
+26 -47
View File
@@ -265,10 +265,9 @@ int dcc_decode_service_request(
{ {
int apdu_len = 0; int apdu_len = 0;
int len = 0; int len = 0;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
BACNET_UNSIGNED_INTEGER decoded_unsigned = 0; BACNET_UNSIGNED_INTEGER decoded_unsigned = 0;
uint32_t decoded_enum = 0; uint32_t decoded_enum = 0;
size_t password_length;
if (apdu && apdu_len_max) { if (apdu && apdu_len_max) {
/* Tag 0: timeDuration, in minutes --optional-- */ /* Tag 0: timeDuration, in minutes --optional-- */
@@ -290,55 +289,35 @@ int dcc_decode_service_request(
results in no timeout */ results in no timeout */
*timeDuration = 0; *timeDuration = 0;
} }
if ((unsigned)apdu_len < apdu_len_max) { /* Tag 1: enable_disable */
/* Tag 1: enable_disable */ len = bacnet_enumerated_context_decode(
len = bacnet_enumerated_context_decode( &apdu[apdu_len], apdu_len_max - apdu_len, 1, &decoded_enum);
&apdu[apdu_len], apdu_len_max - apdu_len, 1, &decoded_enum); if (len > 0) {
if (len > 0) { apdu_len += len;
apdu_len += len; if (enable_disable) {
if (enable_disable) { *enable_disable =
*enable_disable = (BACNET_COMMUNICATION_ENABLE_DISABLE)decoded_enum;
(BACNET_COMMUNICATION_ENABLE_DISABLE)decoded_enum;
}
} else {
return BACNET_STATUS_ABORT;
} }
} else {
return BACNET_STATUS_ABORT;
} }
if ((unsigned)apdu_len < apdu_len_max) { /* Tag 2: password --optional-- */
/* Tag 2: password --optional-- */ len = bacnet_character_string_context_decode(
if (!decode_is_context_tag(&apdu[apdu_len], 2)) { &apdu[apdu_len], apdu_len_max - apdu_len, 2, password);
/* since this is the last value of the packet, if (len > 0) {
if there is data here it must be the specific if (characterstring_encoding(password) == CHARACTER_UTF8) {
context tag number or result in an error */ /* UTF-8 code points can be up to 4 bytes long */
return BACNET_STATUS_ABORT; password_length = characterstring_utf8_length(password);
}
len = bacnet_tag_number_and_value_decode(
&apdu[apdu_len], apdu_len_max - apdu_len, &tag_number,
&len_value_type);
if (len > 0) {
apdu_len += len;
if ((unsigned)apdu_len < apdu_len_max) {
len = bacnet_character_string_decode(
&apdu[apdu_len], apdu_len_max - apdu_len,
len_value_type, password);
if (len > 0) {
size_t password_length =
characterstring_utf8_length(password);
/* UTF-8 code points can be up to 4 bytes long */
if ((password_length >= 1) && (password_length <= 20)) {
apdu_len += len;
} else {
return BACNET_STATUS_REJECT;
}
} else {
return BACNET_STATUS_ABORT;
}
} else {
return BACNET_STATUS_ABORT;
}
} else { } else {
return BACNET_STATUS_ABORT; password_length = characterstring_length(password);
} }
if ((password_length >= 1) && (password_length <= 20)) {
apdu_len += len;
} else {
return BACNET_STATUS_REJECT;
}
} else if (len < 0) {
return BACNET_STATUS_ABORT;
} else if (password) { } else if (password) {
/* no optional password - set to NULL */ /* no optional password - set to NULL */
characterstring_init_ansi(password, NULL); characterstring_init_ansi(password, NULL);
+8 -2
View File
@@ -42,6 +42,7 @@ int reinitialize_device_encode(
{ {
int len = 0; /* length of each encoding */ int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */ int apdu_len = 0; /* total length of the apdu, return value */
size_t length;
/* reinitialized-state-of-device [0] ENUMERATED */ /* reinitialized-state-of-device [0] ENUMERATED */
len = encode_context_enumerated(apdu, 0, state); len = encode_context_enumerated(apdu, 0, state);
@@ -51,8 +52,13 @@ int reinitialize_device_encode(
} }
/* password [1] CharacterString (SIZE (1..20)) OPTIONAL */ /* password [1] CharacterString (SIZE (1..20)) OPTIONAL */
if (password) { if (password) {
if ((password->length >= 1) && if (characterstring_encoding(password) == CHARACTER_UTF8) {
(characterstring_utf8_length(password) <= 20)) { /* UTF-8 code points can be up to 4 bytes long */
length = characterstring_utf8_length(password);
} else {
length = characterstring_length(password);
}
if ((length >= 1) && (length <= 20)) {
len = encode_context_character_string(apdu, 1, password); len = encode_context_character_string(apdu, 1, password);
apdu_len += len; apdu_len += len;
} }