Secure ReadProperty decoding and BACnetActionCommand (#702)

* Refactored and secured BACnetActionCommand codec into bacaction.c module for command object and added to bacapp module encode/decode with define for enabling and pseudo application tag for internal use.

* Simplified bacapp_data_len() and moved into bacdcode module as bacnet_enclosed_data_len() function.

* Secured ReadProperty-REQUEST and -ACK decoding.

* Removed deprecated Keylist_Key() functions from usage.

* Removed pseudo application datatypes from bacapp_data_decode() which only uses primitive application tag encoded values.

* Defined INT_MAX when it is not already defined by compiler or libc.

* Deprecated bacapp_decode_application_data_len() and bacapp_decode_context_data_len() as they are no longer used in any code in the library.

* Added BACnetScale to bacapp module. Improved complex property value decoding. Refactored bacapp_decode_known_property() function.

* Refactored and improved the bacapp_snprintf() function for printing EPICS.

* Fixed Lighting Output WriteProperty to handle known property decoding.
This commit is contained in:
Steve Karg
2024-07-25 17:12:08 -05:00
committed by GitHub
parent 923eaf2313
commit 4326128e72
191 changed files with 3856 additions and 2099 deletions
+131
View File
@@ -756,6 +756,137 @@ int bacnet_tag_number_and_value_decode(
return len;
}
/**
* @brief Determine the data length from the application tag number
* @param tag_number application tag number to be evaluated.
* @param len_value_type Length of the data in bytes.
* @return datalength for the given tag, or INT_MAX if out of range.
*/
int bacnet_application_data_length(
uint8_t tag_number, uint32_t len_value_type)
{
int len = 0;
switch (tag_number) {
case BACNET_APPLICATION_TAG_NULL:
break;
case BACNET_APPLICATION_TAG_BOOLEAN:
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
case BACNET_APPLICATION_TAG_SIGNED_INT:
case BACNET_APPLICATION_TAG_REAL:
case BACNET_APPLICATION_TAG_DOUBLE:
case BACNET_APPLICATION_TAG_OCTET_STRING:
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
case BACNET_APPLICATION_TAG_BIT_STRING:
case BACNET_APPLICATION_TAG_ENUMERATED:
case BACNET_APPLICATION_TAG_DATE:
case BACNET_APPLICATION_TAG_TIME:
case BACNET_APPLICATION_TAG_OBJECT_ID:
len = INT_MAX;
if (len_value_type < INT_MAX) {
len = (int)len_value_type;
}
break;
default:
break;
}
return len;
}
/**
* @brief Returns the length of data between an opening tag and a closing tag.
* @note Expects that the first octet contain the opening tag.
* @param apdu Pointer to the APDU buffer
* @param apdu_size Bytes valid in the buffer
* @param property ID of the property to get the length for.
* @return length of data between an opening tag and a closing tag 0..N,
* or BACNET_STATUS_ERROR.
*/
int bacnet_enclosed_data_length(
uint8_t *apdu, size_t apdu_size)
{
int len = 0;
int total_len = 0;
int apdu_len = 0;
BACNET_TAG tag = { 0 };
uint8_t opening_tag_number = 0;
uint8_t opening_tag_number_counter = 0;
bool total_len_enable = false;
if (!apdu) {
return BACNET_STATUS_ERROR;
}
if (apdu_size <= apdu_len) {
/* error: exceeding our buffer limit */
return BACNET_STATUS_ERROR;
}
if (!bacnet_is_opening_tag(apdu, apdu_size)) {
/* error: opening tag is missing */
return BACNET_STATUS_ERROR;
}
do {
len = bacnet_tag_decode(apdu, apdu_size - apdu_len, &tag);
if (len == 0) {
return BACNET_STATUS_ERROR;
}
if (tag.opening) {
if (opening_tag_number_counter == 0) {
opening_tag_number = tag.number;
opening_tag_number_counter = 1;
total_len_enable = false;
} else if (tag.number == opening_tag_number) {
total_len_enable = true;
opening_tag_number_counter++;
} else {
total_len_enable = true;
}
} else if (tag.closing) {
if (tag.number == opening_tag_number) {
if (opening_tag_number_counter > 0) {
opening_tag_number_counter--;
}
}
total_len_enable = true;
} else if (tag.context) {
if (tag.len_value_type > INT_MAX) {
/* error: length is out of range */
return BACNET_STATUS_ERROR;
}
len += tag.len_value_type;
total_len_enable = true;
} else {
if (tag.len_value_type > INT_MAX) {
/* error: length is out of range */
return BACNET_STATUS_ERROR;
}
/* application tagged data */
len += bacnet_application_data_length(tag.number,
tag.len_value_type);
total_len_enable = true;
}
if (opening_tag_number_counter > 0) {
if (len > 0) {
if (total_len_enable) {
total_len += len;
}
} else {
/* error: len is not incrementing */
return BACNET_STATUS_ERROR;
}
apdu_len += len;
if (apdu_size <= apdu_len) {
/* error: exceeding our buffer limit */
return BACNET_STATUS_ERROR;
}
apdu += len;
}
} while (opening_tag_number_counter > 0);
return total_len;
}
/**
* @brief Returns true if the tag is context specific
* and matches, as defined in clause 20.2.1.3.2 Constructed