scapy.layers.tls.record

Common TLS fields & bindings.

This module covers the record layer, along with the ChangeCipherSpec, Alert and ApplicationData submessages. For the Handshake type, see tls_handshake.py.

See the TLS class documentation for more information.

class scapy.layers.tls.record.TLS(*args, **kargs)

Bases: scapy.layers.tls.session._GenericTLSSessionInheritance

The generic TLS Record message, based on section 6.2 of RFC 5246.

When reading a TLS message, we try to parse as much as we can. In .pre_dissect(), according to the type of the current cipher algorithm (self.tls_session.rcs.cipher.type), we extract the ‘iv’, ‘mac’, ‘pad’ and ‘padlen’. Some of these fields may remain blank: for instance, when using a stream cipher, there is no IV nor any padding. The ‘len’ should always hold the length of the ciphered message; for the plaintext version, you should rely on the additional ‘deciphered_len’ attribute.

XXX Fix ‘deciphered_len’ which should not be defined when failing with AEAD decryption. This is related to the ‘decryption_success’ below. Also, follow this behaviour in record_sslv2.py and record_tls13.py

Once we have isolated the ciphered message aggregate (which should be one or several TLS messages of the same type), we try to decipher it. Either we succeed and store the clear data in ‘msg’, or we graciously fail with a CipherError and store the ciphered data in ‘msg’.

Unless the user manually provides the session secrets through the passing of a ‘tls_session’, obviously the ciphered messages will not be deciphered. Indeed, the need for a proper context may also present itself when trying to parse clear handshake messages.

For instance, suppose you sniffed the beginning of a DHE-RSA negotiation:

t1 = TLS(<client_hello>)
t2 = TLS(<server_hello | certificate | server_key_exchange>)
t3 = TLS(<server_hello | certificate | server_key_exchange>,
         tls_session=t1.tls_session)

(Note that to do things properly, here ‘t1.tls_session’ should actually be ‘t1.tls_session.mirror()’. See session.py for explanations.)

As no context was passed to t2, neither was any client_random. Hence Scapy will not be able to verify the signature of the server_key_exchange inside t2. However, it should be able to do so for t3, thanks to the tls_session. The consequence of not having a complete TLS context is even more obvious when trying to parse ciphered content, as we described before.

Thus, in order to parse TLS-protected communications with Scapy: _either Scapy reads every message from one side of the TLS connection and builds every message from the other side (as such, it should know the secrets needed for the generation of the pre_master_secret), while passing the same tls_session context (this is how our automaton.py mostly works); _or, if Scapy did not build any TLS message, it has to create a TLS context and feed it with secrets retrieved by whatever technique. Note that the knowing the private key of the server certificate will not be sufficient if a PFS ciphersuite was used. However, if you got a master_secret somehow, use it with tls_session.(w|r)cs.derive_keys() and leave the rest to Scapy.

When building a TLS message with raw_stateful, we expect the tls_session to have the right parameters for ciphering. Else, .post_build() might fail.

aliastypes
deciphered_len
classmethod dispatch_hook(_pkt=None, *args, **kargs)

If the TLS class was called on raw SSLv2 data, we want to return an SSLv2 record instance. We acknowledge the risk of SSLv2 packets with a msglen of 0x1403, 0x1503, 0x1603 or 0x1703 which will never be casted as SSLv2 records but TLS ones instead, but hey, we can’t be held responsible for low-minded extensibility choices.

do_dissect_payload(s)

Try to dissect the following data as a TLS message. Note that overloading .guess_payload_class() would not be enough, as the TLS session to be used would get lost.

fields_desc
TLS fields

type

ByteEnumField

None

version

_TLSVersionField

None

len

_TLSLengthField

None

iv

_TLSIVField

None

msg

_TLSMsgListField

[]

mac

_TLSMACField

None

pad

_TLSPadField

None

padlen

_TLSPadLenField

None

post_build(pkt, pay)

Apply the previous methods according to the writing cipher type.

post_dissect(s)

Commit the pending r/w state if it has been triggered (e.g. by an underlying TLSChangeCipherSpec or a SSLv2ClientMasterKey). We update nothing if the prcs was not set, as this probably means that we’re working out-of-context (and we need to keep the default rcs).

pre_dissect(s)

Decrypt, verify and decompress the message, i.e. apply the previous methods according to the reading cipher type. If the decryption was successful, ‘len’ will be the length of the TLSPlaintext.fragment. Else, it should be the length of the _TLSEncryptedContent.

class scapy.layers.tls.record.TLSAlert(_pkt='', post_transform=None, _internal=0, _underlayer=None, tls_session=None, **fields)

Bases: scapy.layers.tls.session._GenericTLSSessionInheritance

aliastypes
fields_desc
TLSAlert fields

level

ByteEnumField

None

descr

ByteEnumField

None

post_build_tls_session_update(msg_str)
post_dissection_tls_session_update(msg_str)
class scapy.layers.tls.record.TLSApplicationData(_pkt='', post_transform=None, _internal=0, _underlayer=None, tls_session=None, **fields)

Bases: scapy.layers.tls.session._GenericTLSSessionInheritance

aliastypes
fields_desc
TLSApplicationData fields

data

StrField

b''

post_build_tls_session_update(msg_str)
post_dissection_tls_session_update(msg_str)
class scapy.layers.tls.record.TLSChangeCipherSpec(_pkt='', post_transform=None, _internal=0, _underlayer=None, tls_session=None, **fields)

Bases: scapy.layers.tls.session._GenericTLSSessionInheritance

Note that, as they are not handshake messages, the ccs messages do not get appended to the list of messages whose integrity gets verified through the Finished messages.

aliastypes
fields_desc
TLSChangeCipherSpec fields

msgtype

ByteEnumField

1

post_build_tls_session_update(msg_str)
post_dissection_tls_session_update(msg_str)