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 password_success = false;
unsigned i;
size_t length;
/* From 16.4.1.1.2 Password
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
do not require a password, this parameter shall be ignored.*/
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_code = ERROR_CODE_PARAMETER_OUT_OF_RANGE;
} else if (characterstring_ansi_same(
+26 -47
View File
@@ -265,10 +265,9 @@ int dcc_decode_service_request(
{
int apdu_len = 0;
int len = 0;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
BACNET_UNSIGNED_INTEGER decoded_unsigned = 0;
uint32_t decoded_enum = 0;
size_t password_length;
if (apdu && apdu_len_max) {
/* Tag 0: timeDuration, in minutes --optional-- */
@@ -290,55 +289,35 @@ int dcc_decode_service_request(
results in no timeout */
*timeDuration = 0;
}
if ((unsigned)apdu_len < apdu_len_max) {
/* Tag 1: enable_disable */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_len_max - apdu_len, 1, &decoded_enum);
if (len > 0) {
apdu_len += len;
if (enable_disable) {
*enable_disable =
(BACNET_COMMUNICATION_ENABLE_DISABLE)decoded_enum;
}
} else {
return BACNET_STATUS_ABORT;
/* Tag 1: enable_disable */
len = bacnet_enumerated_context_decode(
&apdu[apdu_len], apdu_len_max - apdu_len, 1, &decoded_enum);
if (len > 0) {
apdu_len += len;
if (enable_disable) {
*enable_disable =
(BACNET_COMMUNICATION_ENABLE_DISABLE)decoded_enum;
}
} else {
return BACNET_STATUS_ABORT;
}
if ((unsigned)apdu_len < apdu_len_max) {
/* Tag 2: password --optional-- */
if (!decode_is_context_tag(&apdu[apdu_len], 2)) {
/* since this is the last value of the packet,
if there is data here it must be the specific
context tag number or result in an error */
return BACNET_STATUS_ABORT;
}
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;
}
/* Tag 2: password --optional-- */
len = bacnet_character_string_context_decode(
&apdu[apdu_len], apdu_len_max - apdu_len, 2, password);
if (len > 0) {
if (characterstring_encoding(password) == CHARACTER_UTF8) {
/* UTF-8 code points can be up to 4 bytes long */
password_length = characterstring_utf8_length(password);
} 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) {
/* no optional password - set to 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 apdu_len = 0; /* total length of the apdu, return value */
size_t length;
/* reinitialized-state-of-device [0] ENUMERATED */
len = encode_context_enumerated(apdu, 0, state);
@@ -51,8 +52,13 @@ int reinitialize_device_encode(
}
/* password [1] CharacterString (SIZE (1..20)) OPTIONAL */
if (password) {
if ((password->length >= 1) &&
(characterstring_utf8_length(password) <= 20)) {
if (characterstring_encoding(password) == CHARACTER_UTF8) {
/* 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);
apdu_len += len;
}