Home | History | Annotate | Download | only in tls
      1 ## This file is part of Scapy
      2 ## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard
      3 ##               2015, 2016, 2017 Maxence Tury
      4 ## This program is published under a GPLv2 license
      5 
      6 """
      7 TLS helpers, provided as out-of-context methods.
      8 """
      9 
     10 from scapy.error import warning
     11 from scapy.fields import (ByteEnumField, ShortEnumField,
     12                           FieldLenField, StrLenField)
     13 from scapy.packet import Packet
     14 
     15 from scapy.layers.tls.basefields import _tls_type, _tls_version
     16 
     17 
     18 class TLSPlaintext(Packet):
     19     name = "TLS Plaintext"
     20     fields_desc = [ ByteEnumField("type", None, _tls_type),
     21                     ShortEnumField("version", None, _tls_version),
     22                     FieldLenField("len", None, length_of="fragment",
     23                                   fmt="!H"),
     24                     StrLenField("fragment", "",
     25                                 length_from = lambda pkt: pkt.length) ]
     26 
     27 class TLSCompressed(TLSPlaintext):
     28     name = "TLS Compressed"
     29 
     30 class TLSCiphertext(TLSPlaintext):
     31     name = "TLS Ciphertext"
     32 
     33 
     34 def _tls_compress(alg, p):
     35     """
     36     Compress p (a TLSPlaintext instance) using compression algorithm instance
     37     alg and return a TLSCompressed instance.
     38     """
     39     c = TLSCompressed()
     40     c.type = p.type
     41     c.version = p.version
     42     c.fragment = alg.compress(p.fragment)
     43     c.len = len(c.fragment)
     44     return c
     45 
     46 def _tls_decompress(alg, c):
     47     """
     48     Decompress c (a TLSCompressed instance) using compression algorithm
     49     instance alg and return a TLSPlaintext instance.
     50     """
     51     p = TLSPlaintext()
     52     p.type = c.type
     53     p.version = c.version
     54     p.fragment = alg.decompress(c.fragment)
     55     p.len = len(p.fragment)
     56     return p
     57 
     58 def _tls_mac_add(alg, c, write_seq_num):
     59     """
     60     Compute the MAC using provided MAC alg instance over TLSCiphertext c using
     61     current write sequence number write_seq_num. Computed MAC is then appended
     62     to c.fragment and c.length is updated to reflect that change. It is the
     63     caller responsability to increment the sequence number after the operation.
     64     The function has no return value.
     65     """
     66     write_seq_num = struct.pack("!Q", write_seq_num)
     67     h = alg.digest(write_seq_num + str(c))
     68     c.fragment += h
     69     c.len += alg.hash_len
     70 
     71 def _tls_mac_verify(alg, p, read_seq_num):
     72     """
     73     Verify if the MAC in provided message (message resulting from decryption
     74     and padding removal) is valid. Current read sequence number is used in
     75     the verification process.
     76 
     77     If the MAC is valid:
     78      - The function returns True
     79      - The packet p is updated in the following way: trailing MAC value is
     80        removed from p.fragment and length is updated accordingly.
     81 
     82     In case of error, False is returned, and p may have been modified.
     83 
     84     Also note that it is the caller's responsibility to update the read
     85     sequence number after the operation.
     86     """
     87     h_size = alg.hash_len
     88     if p.len < h_size:
     89         return False
     90     received_h = p.fragment[-h_size:]
     91     p.len -= h_size
     92     p.fragment = p.fragment[:-h_size]
     93 
     94     read_seq_num = struct.pack("!Q", read_seq_num)
     95     h = alg.digest(read_seq_num + str(p))
     96     return h == received_h
     97 
     98 def _tls_add_pad(p, block_size):
     99     """
    100     Provided with cipher block size parameter and current TLSCompressed packet
    101     p (after MAC addition), the function adds required, deterministic padding
    102     to p.fragment before encryption step, as it is defined for TLS (i.e. not
    103     SSL and its allowed random padding). The function has no return value.
    104     """
    105     padlen = block_size - ((p.len + 1) % block_size)
    106     if padlen == block_size:
    107         padlen =  0
    108     padding = chr(padlen) * (padlen + 1)
    109     p.len += len(padding)
    110     p.fragment += padding
    111 
    112 def _tls_del_pad(p):
    113     """
    114     Provided with a just decrypted TLSCiphertext (now a TLSPlaintext instance)
    115     p, the function removes the trailing padding found in p.fragment. It also
    116     performs some sanity checks on the padding (length, content, ...). False
    117     is returned if one of the check fails. Otherwise, True is returned,
    118     indicating that p.fragment and p.len have been updated.
    119     """
    120 
    121     if p.len < 1:
    122         warning("Message format is invalid (padding)")
    123         return False
    124 
    125     padlen = ord(p.fragment[-1]) + 1
    126     if (p.len < padlen):
    127         warning("Invalid padding length")
    128         return False
    129 
    130     if (p.fragment[-padlen:] != p.fragment[-1] * padlen):
    131         warning("Padding content is invalid %s", repr(p.fragment[-padlen:]))
    132         return False
    133 
    134     p.fragment = p.fragment[:-padlen]
    135     p.len -= padlen
    136 
    137     return True
    138 
    139 def _tls_encrypt(alg, p):
    140     """
    141     Provided with an already MACed TLSCompressed packet, and a stream or block
    142     cipher alg, the function converts it into a TLSCiphertext (i.e. encrypts it
    143     and updates length). The function returns a newly created TLSCiphertext
    144     instance.
    145     """
    146     c = TLSCiphertext()
    147     c.type = p.type
    148     c.version = p.version
    149     c.fragment = alg.encrypt(p.fragment)
    150     c.len = len(c.fragment)
    151     return c
    152 
    153 def _tls_decrypt(alg, c):
    154     """
    155     Provided with a TLSCiphertext instance c, and a stream or block cipher alg,
    156     the function decrypts c.fragment and returns a newly created TLSPlaintext.
    157     """
    158     p = TLSPlaintext()
    159     p.type = c.type
    160     p.version = c.version
    161     p.fragment = alg.decrypt(c.fragment)
    162     p.len = len(p.fragment)
    163     return p
    164 
    165 def _tls_aead_auth_encrypt(alg, p, write_seq_num):
    166     """
    167     Provided with a TLSCompressed instance p, the function applies AEAD
    168     cipher alg to p.fragment and builds a new TLSCiphertext instance. Unlike
    169     for block and stream ciphers, for which the authentication step is done
    170     separately, AEAD alg does it simultaneously: this is the reason why
    171     write_seq_num is passed to the function, to be incorporated in
    172     authenticated data. Note that it is the caller's responsibility to increment
    173     write_seq_num afterwards.
    174     """
    175     P = str(p)
    176     write_seq_num = struct.pack("!Q", write_seq_num)
    177     A = write_seq_num + P[:5]
    178 
    179     c = TLCCiphertext()
    180     c.type = p.type
    181     c.version = p.version
    182     c.fragment = alg.auth_encrypt(P, A)
    183     c.len = len(c.fragment)
    184     return c
    185 
    186 def _tls_aead_auth_decrypt(alg, c, read_seq_num):
    187     """
    188     Provided with a TLSCiphertext instance c, the function applies AEAD
    189     cipher alg auth_decrypt function to c.fragment (and additional data)
    190     in order to authenticate the data and decrypt c.fragment. When those
    191     steps succeed, the result is a newly created TLSCompressed instance.
    192     On error, None is returned. Note that it is the caller's responsibility to
    193     increment read_seq_num afterwards.
    194     """
    195     # 'Deduce' TLSCompressed length from TLSCiphertext length
    196     # There is actually no guaranty of this equality, but this is defined as
    197     # such in TLS 1.2 specifications, and it works for GCM and CCM at least.
    198     l = p.len - alg.nonce_explicit_len - alg.tag_len
    199     read_seq_num = struct.pack("!Q", read_seq_num)
    200     A = read_seq_num + struct.pack('!BHH', p.type, p.version, l)
    201 
    202     p = TLSCompressed()
    203     p.type = c.type
    204     p.version = c.version
    205     p.len = l
    206     p.fragment = alg.auth_decrypt(A, c.fragment)
    207 
    208     if p.fragment is None: # Verification failed.
    209         return None
    210     return p
    211 
    212