SSL & TLS Encoder & Decoder - HoLyVieR/tls-attack GitHub Wiki
Structure initialization
With data
If you want to automatically fill an object based on serialized data, you can use the method decode
of an instance of the object that matches the serialized typed. This will be in almost all cases TLSHeader
.
Example :
from tls_attack.structure import *
header = TLSHeader()
header.decode(b'\x16\x03\x03\x00\xdc\x01\x00\x00\xd8\x03\x03\x53\x43\x5b\x90\x9d\x9b\x72\x0b\xbc\x0c\xbc\x2b\x92\xa8\x48\x97\xcf\xbd\x39\x04\xcc\x16\x0a\x85\x03\x90\x9f\x77\x04\x33\xd4\xde\x00\x00\x66\xc0\x14\xc0\x0a\xc0\x22\xc0\x21\x00\x39\x00\x38\x00\x88\x00\x87\xc0\x0f\xc0\x05\x00\x35\x00\x84\xc0\x12\xc0\x08\xc0\x1c\xc0\x1b\x00\x16\x00\x13\xc0\x0d\xc0\x03\x00\x0a\xc0\x13\xc0\x09\xc0\x1f\xc0\x1e\x00\x33\x00\x32\x00\x9a\x00\x99\x00\x45\x00\x44\xc0\x0e\xc0\x04\x00\x2f\x00\x96\x00\x41\xc0\x11\xc0\x07\xc0\x0c\xc0\x02\x00\x05\x00\x04\x00\x15\x00\x12\x00\x09\x00\x14\x00\x11\x00\x08\x00\x06\x00\x03\x00\xff\x01\x00\x00\x49\x00\x0b\x00\x04\x03\x00\x01\x02\x00\x0a\x00\x34\x00\x32\x00\x0e\x00\x0d\x00\x19\x00\x0b\x00\x0c\x00\x18\x00\x09\x00\x0a\x00\x16\x00\x17\x00\x08\x00\x06\x00\x07\x00\x14\x00\x15\x00\x04\x00\x05\x00\x12\x00\x13\x00\x01\x00\x02\x00\x03\x00\x0f\x00\x10\x00\x11\x00\x23\x00\x00\x00\x0f\x00\x01\x01')
print(header)
Output :
TLSHeader {
content_type = 22
version = TLSVersion.TLS12
length = 220
body = TLSHandshake {
[...] Truncating the output [...]
}
}
Without data
Structure value can be assigned with the constructor.
Example :
header = TLSHeader (
version = TLSVersion.TLS10,
body = TLSHeartbeat (
heartbeat_type = TLSHeartbeatMessageType.HEARTBEAT_REQUEST,
length = 0x4000,
payload = b""
)
)
If you wish to modify field value after the initialization it's possible to do so by changing the attribute value.
Example :
header.version = TLSVersion.TLS11
When manually filling structure data, you can use the magic class TLSAuto
to automatically assign the correct value to a length field or a type field. The correct value will be computed when encoding the structure or displaying it.
Example :
header = TLSHeader (
content_type = TLSAuto(),
version = TLSVersion.TLS10,
body = TLSHeartbeat (
heartbeat_type = TLSHeartbeatMessageType.HEARTBEAT_REQUEST,
length = 0x4000,
payload = b""
)
)
Here content_type
will have the value 24 assigned when it's encoded or printed.
Structure definition
Every structure must inherit from the class TLSStructure
. You usually want to import two things : TLSStructure
and the annotation from TLSAnnotation
.
Example :
from tls_attack.structure.TLSStructure import TLSStructure
from tls_attack.structure.TLSAnnotation import *
class TLSEmpty(TLSStructure):
pass
You must declare field as static value of the class with the annotation from TLSAnnotation
. The main annotation is TLSField
. The order of the declaration of the field must be the same from the order in which they are serialized.
Example :
from tls_attack.structure.TLSStructure import TLSStructure
from tls_attack.structure.TLSAnnotation import *
class TLSSomething(TLSStructure):
field_name = TLSField(size = 2, type = "bytes")
Parameters of TLSField
- size - Size in byte of the field.
- type - Type that the byte must be interpreted with. Must be : "bytes", "int", "enum" or the class name of an other
TLSStructure
. - (optional) type_ref - To implement switch case type, this value must be an enum class. This enum class will be used at runtime to replace the type parameter with the correct class value.
- (optional) type_list - Represents whether the field is a list or not. When set to
True
, the field is decoded as a list oftype
. - (optional) type_enum - When type is set to "enum", this value must be set to an enum class. This enum class will be used at runtime to replace the decoded value with the corresponding enum element.
- (optional) encryptable - Represents whether the field becomes encrypted when a
ChangeCipherSpec
is sent. - (optional) optional - If no data is remaining this field will stay empty. This is used for structure which have more value in some version of SSL / TLS.
- (optional) default - Default value of the field when no value is provided.
For value which depend on previously decoded value, it's possible to use the TLSFieldRef
class.
Example :
class TLSHeader(TLSStructure):
content_type = TLSField(size = 1, type = "int", default = TLSAuto())
version = TLSField(size = 2, type = "enum", type_enum = TLSVersion)
length = TLSField(size = 2, type = "int", default = TLSAuto())
body = TLSField(
size = TLSFieldRef(name = "length"),
type = TLSFieldRef(name = "content_type"),
type_ref = TLSContentType,
encryptable = True
)
In this case, the size
and the type
will depend on the value of the length
field and the content_type
field.
To simplify the declaration of the structure, it's recommended to use the annotation TLSAuto
for the default value of field which depend on other value. In the previous example, the field length
and content_type
will be automatically filled with the correct value based on the content of the body
.
State
In order to keep state of the connection and have encrypted field properly decoded, you can keep the state of the connection with TLSState
. Once initialized, every decoded structure must be fed to the update
method. This method takes two parameters :
- source - Must be either
TLSSource.CLIENT
orTLSSource.SERVER
- tls_object -
TLSStructure
decoded.
This class also has the following attributes which are updated :
- cipher_suite - Currently negotiated cipher suite. When none are negotiated the value is
TLSCipherSuite.TLS_NULL_WITH_NULL_NULL
- compression - Currently negotiated compression.
- encrypted - Map that indicates if the structure coming from the specified source is encrypted. Keys to this map are
TLSSource.CLIENT
andTLSSource.SERVER
.