Bugfix/deprecate decode tag number and value (#481)

* added or updated secure the BACnet primitive value decoders - the core codecs - named bacnet_x_decode(), bacnet_x_application_decode() and bacnet_x_context_decode where x is one of the 13 BACnet primitive value names.  The updated API includes an APDU size to prevent over-reading of an APDU buffer while decoding.  Improved or added unit test code coverage for the BACnet primitive value decoders.

* marked the insecure decoding API as 'deprecated' which is defined in src/bacnet/basic/sys/platform.h and can be disabled during a build. 

* added secure decoders for BACnetTimeValue, BACnetHostNPort, BACnetTimeStamp, BACnetAddress, and Weekly_Schedule and improved unit test code coverage.

* improved test code coverage for BACnet objects and properties.

* secured AtomicReadFile and AtomicWriteFile service decoders and improved unit test code coverage.

* secured BACnet Error service decoder and improved unit test code coverage.

---------

Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
Steve Karg
2023-09-08 11:39:27 -05:00
committed by GitHub
parent bc8c261153
commit f641aacddb
67 changed files with 6103 additions and 3145 deletions
+90 -78
View File
@@ -42,42 +42,37 @@ int host_n_port_encode(uint8_t *apdu, BACNET_HOST_N_PORT *address)
{
int len = 0;
int apdu_len = 0;
uint8_t *apdu_offset = NULL;
if (address) {
/* host [0] BACnetHostAddress - opening */
len = encode_opening_tag(apdu, 0);
apdu_len += len;
if (apdu) {
apdu += len;
}
if (address->host_ip_address) {
/* CHOICE - ip-address [1] OCTET STRING */
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
len = encode_context_octet_string(
apdu_offset, 1, &address->host.ip_address);
apdu_len += len;
len =
encode_context_octet_string(apdu, 1, &address->host.ip_address);
} else if (address->host_name) {
/* CHOICE - name [2] CharacterString */
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
len = encode_context_character_string(
apdu_offset, 1, &address->host.name);
apdu_len += len;
len = encode_context_character_string(apdu, 2, &address->host.name);
} else {
/* none */
/* CHOICE - none [0] NULL */
len = encode_context_null(apdu, 0);
}
apdu_len += len;
if (apdu) {
apdu += len;
}
/* host [0] BACnetHostAddress - closing */
if (apdu) {
apdu_offset = &apdu[apdu_len];
}
len = encode_closing_tag(apdu_offset, 0);
len = encode_closing_tag(apdu, 0);
apdu_len += len;
/* port [1] Unsigned16 */
if (apdu) {
apdu_offset = &apdu[apdu_len];
apdu += len;
}
len = encode_context_unsigned(apdu_offset, 1, address->port);
/* port [1] Unsigned16 */
len = encode_context_unsigned(apdu, 1, address->port);
apdu_len += len;
}
@@ -87,7 +82,7 @@ int host_n_port_encode(uint8_t *apdu, BACNET_HOST_N_PORT *address)
/**
* @brief Encode a BACnetHostNPort complex data type
* @param apdu - the APDU buffer
* @param tag_number - the APDU buffer size
* @param tag_number - context tag number to be encoded
* @param address - IP address and port number
* @return length of the APDU buffer, or 0 if not able to encode
*/
@@ -96,21 +91,19 @@ int host_n_port_context_encode(
{
int len = 0;
int apdu_len = 0;
uint8_t *apdu_offset = NULL;
if (address) {
apdu_offset = apdu;
len = encode_opening_tag(apdu_offset, tag_number);
len = encode_opening_tag(apdu, tag_number);
apdu_len += len;
if (apdu) {
apdu_offset = &apdu[apdu_len];
apdu += len;
}
len = host_n_port_encode(apdu_offset, address);
len = host_n_port_encode(apdu, address);
apdu_len += len;
if (apdu) {
apdu_offset = &apdu[apdu_len];
apdu += len;
}
len = encode_closing_tag(apdu_offset, tag_number);
len = encode_closing_tag(apdu, tag_number);
apdu_len += len;
}
@@ -134,64 +127,80 @@ int host_n_port_context_encode(
* }
*
* @param apdu - the APDU buffer
* @param apdu_len - the APDU buffer length
* @param apdu_size - the APDU buffer length
* @param error_code - error or reject or abort when error occurs
* @param ip_address - IP address and port number
* @return length of the APDU buffer decoded, or ERROR, REJECT, or ABORT
*/
int host_n_port_decode(uint8_t *apdu,
uint16_t apdu_len,
uint32_t apdu_size,
BACNET_ERROR_CODE *error_code,
BACNET_HOST_N_PORT *address)
{
int len = 0;
BACNET_OCTET_STRING octet_string = { 0 };
BACNET_CHARACTER_STRING char_string = { 0 };
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
int apdu_len = 0, len = 0;
BACNET_OCTET_STRING *octet_string = NULL;
BACNET_CHARACTER_STRING *char_string = NULL;
BACNET_TAG tag = { 0 };
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
/* default reject code */
if (error_code) {
*error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
}
/* check for value pointers */
if ((apdu_len == 0) || (!apdu)) {
return BACNET_STATUS_REJECT;
}
/* host [0] BACnetHostAddress - opening */
if (!decode_is_opening_tag_number(&apdu[len++], 0)) {
if (!bacnet_is_opening_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
if (error_code) {
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
if (len > apdu_len) {
apdu_len += len;
len = bacnet_tag_decode(&apdu[apdu_len], apdu_size - apdu_len, &tag);
if (len <= 0) {
if (error_code) {
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
len +=
decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
if (tag_number == 0) {
apdu_len += len;
if (tag.context && (tag.number == 0)) {
/* CHOICE - none [0] NULL */
address->host_ip_address = false;
address->host_name = false;
} else if (tag_number == 1) {
if (address) {
address->host_ip_address = false;
address->host_name = false;
}
} else if (tag.context && (tag.number == 1)) {
/* CHOICE - ip-address [1] OCTET STRING */
address->host_ip_address = true;
address->host_name = false;
len += decode_octet_string(&apdu[len], len_value_type, &octet_string);
if (len > apdu_len) {
if (address) {
address->host_ip_address = true;
address->host_name = false;
octet_string = &address->host.ip_address;
}
len = bacnet_octet_string_decode(&apdu[apdu_len], apdu_size - apdu_len,
tag.len_value_type, octet_string);
if (len < 0) {
if (error_code) {
*error_code = ERROR_CODE_REJECT_BUFFER_OVERFLOW;
}
return BACNET_STATUS_REJECT;
}
(void)octetstring_copy(&address->host.ip_address, &octet_string);
} else if (tag_number == 2) {
address->host_ip_address = false;
address->host_name = true;
len +=
decode_character_string(&apdu[len], len_value_type, &char_string);
if (len > apdu_len) {
apdu_len += len;
} else if (tag.context && (tag.number == 2)) {
if (address) {
address->host_ip_address = false;
address->host_name = true;
char_string = &address->host.name;
}
len = bacnet_character_string_decode(&apdu[apdu_len],
apdu_size - apdu_len, tag.len_value_type, char_string);
if (len == 0) {
if (error_code) {
*error_code = ERROR_CODE_REJECT_BUFFER_OVERFLOW;
}
return BACNET_STATUS_REJECT;
}
(void)characterstring_copy(&address->host.name, &char_string);
apdu_len += len;
} else {
if (error_code) {
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
@@ -199,36 +208,39 @@ int host_n_port_decode(uint8_t *apdu,
return BACNET_STATUS_REJECT;
}
/* host [0] BACnetHostAddress - closing */
if (!decode_is_closing_tag_number(&apdu[len++], 0)) {
if (!bacnet_is_closing_tag_number(
&apdu[apdu_len], apdu_size - apdu_len, 0, &len)) {
if (error_code) {
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
}
return BACNET_STATUS_REJECT;
}
if (len > apdu_len) {
return BACNET_STATUS_REJECT;
}
apdu_len += len;
/* port [1] Unsigned16 */
len +=
decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
if (tag_number != 1) {
if (error_code) {
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
len = bacnet_unsigned_context_decode(
&apdu[apdu_len], apdu_size - apdu_len, 1, &unsigned_value);
if (len > 0) {
if (unsigned_value <= UINT16_MAX) {
if (address) {
address->port = unsigned_value;
}
} else {
if (error_code) {
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
}
return BACNET_STATUS_REJECT;
}
return BACNET_STATUS_REJECT;
}
len += decode_unsigned(&apdu[len], len_value_type, &unsigned_value);
if (len > apdu_len) {
return BACNET_STATUS_REJECT;
}
if (unsigned_value <= UINT16_MAX) {
address->port = unsigned_value;
} else {
if (error_code) {
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
if (len == 0) {
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
} else {
*error_code = ERROR_CODE_REJECT_OTHER;
}
}
return BACNET_STATUS_REJECT;
}
apdu_len += len;
return apdu_len;
}