Source code for flextls.protocol.record

"""
The SSL/TLS Record Protocol
"""
import struct

import six

from flextls.exception import NotEnoughData
from flextls.field import UInt8EnumField, UInt16Field, UInt48Field, VersionField
from flextls.protocol import Protocol
from flextls.protocol.alert import Alert
from flextls.protocol.change_cipher_spec import ChangeCipherSpec
from flextls.protocol.handshake import Handshake, DTLSv10Handshake
from flextls.protocol.handshake import SSLv2ClientHello, SSLv2ServerHello
from flextls.protocol.heartbeat import Heartbeat


class Record(Protocol):
    @classmethod
    def decode(cls, data, connection=None, payload_auto_decode=True):
        if len(data) < 4:
            raise NotEnoughData("Not enough data to decode header")

        if six.indexbytes(data, 3) == 0x00 and six.indexbytes(data, 4) == 0x02:
            obj = SSLv2Record(
                connection=connection
            )
        elif six.indexbytes(data, 1) == 0x03:
            obj = SSLv3Record(
                connection=connection
            )

        data = obj.dissect(data)
        return (obj, data)


[docs]class DTLSv10Record(Protocol): """ Handle DTLS 1.0 and DTLS 1.2 Record layer. """ def __init__(self, **kwargs): Protocol.__init__(self, **kwargs) self.fields = [ UInt8EnumField( "content_type", None, { 20: "change_cipher_spec", 21: "alert", 22: "handshake", 23: "application_data", 255: None } ), VersionField("version"), UInt16Field("epoch", 0), UInt48Field("sequence_number", 0), UInt16Field("length", 0), ] self.payload_identifier_field = "content_type" self.payload_length_field = "length"
[docs]class SSLv2Record(Protocol): """ Handle the SSLv2 Record layer. """ def __init__(self, **kwargs): Protocol.__init__(self, **kwargs) self.length = 0 self.is_escape = None self.padding_length = None self.padding = b"" self.type = None def assemble(self): data = b"" payload = b"" if isinstance(self.payload, Protocol): payload = self.payload.encode() for pay_pattern, pay_class in self.payload_list.items(): if isinstance(self.payload, pay_class): self.type = pay_pattern break elif self.payload is not None: payload = self.payload data = struct.pack("!B", (self.type)) data += payload data += self.padding self.length = len(data) # Is it 2 or 3 bytes header if len(self.padding) > 0: tmp = [0, 0, 0] tmp[0] = (self.length >> 8) & 0x3f tmp[1] = self.length & 0xff tmp[2] = len(self.padding) if self.is_escape == True: tmp[0] = tmp[0] | 0x40 data = struct.pack("!BBB", *tmp) + data else: tmp = [0, 0] tmp[0] = (self.length >> 8) & 0x7f tmp[1] = self.length & 0xff tmp[0] = tmp[0] | 0x80 data = struct.pack("!BB", *tmp) + data return data def dissect(self, data, payload_auto_decode=True): if len(data) < 2: raise NotEnoughData("Not enough data to decode header") # Is it 2 or 3 bytes header if struct.unpack("!B", data[:1])[0] & 0x80 == 0: tmp = struct.unpack("!BBB", data[:3]) data = data[3:] self.length = ((tmp[0] & 0x3f) << 8) | tmp[1] self.is_escape = ((tmp[0] & 0x40) != 0) self.padding_length = tmp[2] else: tmp = struct.unpack("!BB", data[:2]) data = data[2:] self.length = ((tmp[0] & 0x7f) << 8) | tmp[1] if len(data) == 0: raise NotEnoughData("Not enough data to decode header") self.type = struct.unpack("!B", data[:1])[0] data = data[1:] payload_class = self.payload_list.get( self.type, None ) if payload_class is None or payload_auto_decode is False: self.payload = data else: (obj, data) = payload_class.decode( data, connection=self._connection, payload_auto_decode=payload_auto_decode ) self.payload = obj return data
[docs]class SSLv3Record(Protocol): """ Handle the SSLv3 and TLS 1.0, 1.1 and 1.2 Record layer """ def __init__(self, **kwargs): Protocol.__init__(self, **kwargs) self.fields = [ UInt8EnumField( "content_type", None, { 20: "change_cipher_spec", 21: "alert", 22: "handshake", 23: "application_data", 255: None } ), VersionField("version"), UInt16Field("length", 0), ] self.payload_identifier_field = "content_type" self.payload_length_field = "length"
DTLSv10Record.add_payload_type(21, Alert) DTLSv10Record.add_payload_type(22, DTLSv10Handshake) SSLv2Record.add_payload_type(1, SSLv2ClientHello) SSLv2Record.add_payload_type(4, SSLv2ServerHello) SSLv3Record.add_payload_type(20, ChangeCipherSpec) SSLv3Record.add_payload_type(21, Alert) SSLv3Record.add_payload_type(22, Handshake) SSLv3Record.add_payload_type(24, Heartbeat)