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:
+90
-78
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user