Skip to content

TLV

Type-Length-Value (TLV) is the structured message format used by the agent, its ExecUnits, and the Command and Control (C2) system. This page describes the shared encoding; the C2 and Agent, Agent and Command ExecUnits, and Agent and Listener ExecUnits references describe their respective messages.

For the roles that use these messages, see Command ExecUnits and Listener ExecUnits.

Communication context

The listener plugin and its agent-side ExecUnit implement the outer protocol that transports agent-C2 communication. Within the agent, components also use TLV structures for configuration and result data. The encoding described here is shared by these uses; the meaning of a message depends on the protocol reference for that communication channel.

Protocol general specifications

The TLV (Type-Length-Value) structure, a fundamental component of the communication protocol within the Tuoni framework, comprises three distinct parts, each serving a specific purpose in the encoding and interpretation of data:

  • Type: This segment is represented by a 1-byte value. Within this byte, the most significant bit is used to indicate the nature of the TLV structure. Specifically, if this bit is set to 0x80 (in hexadecimal) or 10000000 (in binary), the TLV is identified as a parent type. This designation means that the TLV can contain other TLV structures within it. The remaining 7 bits of this byte are allocated for the ID value, which is contextual and determined by the parser handling the TLV. For instance, an ID of 0x92 could signify different data or commands in varying contexts; however, if its most significant bit is set, it unequivocally identifies the structure as a parent type, capable of encapsulating other TLVs.
  • Length: Following the type portion is the length segment, which is a 4-byte integer formatted in little-endian order. This design choice allows for a substantial maximum size for the value part, up to 4GB. The length specifies the size of the subsequent value segment, enabling the parser to accurately extract and process the contained data.
  • Value: The final part of the TLV structure is the value itself, whose size is explicitly defined by the length part mentioned earlier. This segment contains the actual data or information that the TLV is meant to convey. The nature and format of this data can vary widely, depending on the type of TLV and the specific application or context in which it is used.

Tuoni Type name reference

  • EMPTY - empty value
  • BYTE - one byte value
  • INT16 - two byte integer
  • INT32 - four byte integer
  • GUID - 16 byte GUID/UUID
  • STR_UTF8 - UTF8 string (by default TLV should use UTF8 strings only, it's not enforced in any way, you can use any encoding if both sides agree, but it's nice to do it in a standardized way)
  • BLOB - binary blob
  • UNDEFINED - Not required to be some exact type so can change according to context

Arrays

In the TLV (Type-Length-Value) structure, a parent element can contain multiple child elements that share the same type value. When this occurs, these child elements are treated as an array within the context of the parent TLV. This interpretation aligns with the flexible and hierarchical nature of the TLV protocol, allowing for a rich representation of data structures.

This concept essentially means that each type value, even when appearing singularly, can be considered as an array with a single element. This approach simplifies the handling of TLV structures, as it standardizes the way data is parsed and accessed, regardless of the number of elements present. It ensures consistency in data structure interpretation, facilitating the development of parsing logic that can elegantly handle both singular and multiple occurrences of the same type value within a parent TLV.

Example

One parent (id 0x12) with two child (ids 0x1 and 0x2) values

  • TYPE = 0x12 PARENT VALUE = contains 2 other values, so it's a parent type
    • TYPE = 0x1 VALUE = ascii string "ABC"
    • TYPE = 0x2 VALUE = 4 byte integer 0x12345678 in little endian
TYPE + ID LENGTH (SubElements) TYPE - First Child LENGTH - First Child VALUE - First Child TYPE - Second Child Length - Second Child VALUE - Second Child
92 11 00 00 00 01 03 00 00 00 41 42 43 02 04 00 00 00 78 56 34 12

External references