1# SPDX-License-Identifier: GPL-2.0-only 2# This file is part of Scapy 3# See https://scapy.net/ for more information 4# Copyright (C) 2007, 2008, 2009 Arnaud Ebalard 5# 2015, 2016, 2017 Maxence Tury 6 7""" 8TLS base fields, used for record parsing/building. As several operations depend 9upon the TLS version or ciphersuite, the packet has to provide a TLS context. 10""" 11import struct 12 13from scapy.fields import ByteField, ShortEnumField, ShortField, StrField 14from scapy.compat import orb 15 16_tls_type = {20: "change_cipher_spec", 17 21: "alert", 18 22: "handshake", 19 23: "application_data"} 20 21_tls_version = {0x0002: "SSLv2", 22 0x0200: "SSLv2", 23 0x0300: "SSLv3", 24 0x0301: "TLS 1.0", 25 0x0302: "TLS 1.1", 26 0x0303: "TLS 1.2", 27 0x7f12: "TLS 1.3-d18", 28 0x7f13: "TLS 1.3-d19", 29 0x0304: "TLS 1.3"} 30 31_tls_version_options = {"sslv2": 0x0002, 32 "sslv3": 0x0300, 33 "tls1": 0x0301, 34 "tls10": 0x0301, 35 "tls11": 0x0302, 36 "tls12": 0x0303, 37 "tls13-d18": 0x7f12, 38 "tls13-d19": 0x7f13, 39 "tls13": 0x0304} 40 41 42def _tls13_version_filter(version, legacy_version): 43 if version < 0x0304: 44 return version 45 else: 46 return legacy_version 47 48 49class _TLSClientVersionField(ShortEnumField): 50 """ 51 We use the advertised_tls_version if it has been defined, 52 and the legacy 0x0303 for TLS 1.3 packets. 53 """ 54 55 def i2h(self, pkt, x): 56 if x is None: 57 v = pkt.tls_session.advertised_tls_version 58 if v: 59 return _tls13_version_filter(v, 0x0303) 60 return "" 61 return x 62 63 def i2m(self, pkt, x): 64 if x is None: 65 v = pkt.tls_session.advertised_tls_version 66 if v: 67 return _tls13_version_filter(v, 0x0303) 68 return b"" 69 return x 70 71 72class _TLSVersionField(ShortEnumField): 73 """ 74 We use the tls_version if it has been defined, else the advertised version. 75 Also, the legacy 0x0301 is used for TLS 1.3 packets. 76 """ 77 78 def i2h(self, pkt, x): 79 if x is None: 80 v = pkt.tls_session.tls_version 81 if v: 82 return _tls13_version_filter(v, 0x0301) 83 else: 84 adv_v = pkt.tls_session.advertised_tls_version 85 return _tls13_version_filter(adv_v, 0x0301) 86 return x 87 88 def i2m(self, pkt, x): 89 if x is None: 90 v = pkt.tls_session.tls_version 91 if v: 92 return _tls13_version_filter(v, 0x0301) 93 else: 94 adv_v = pkt.tls_session.advertised_tls_version 95 return _tls13_version_filter(adv_v, 0x0301) 96 return x 97 98 99class _TLSLengthField(ShortField): 100 def i2repr(self, pkt, x): 101 s = super(_TLSLengthField, self).i2repr(pkt, x) 102 if pkt.deciphered_len is not None: 103 dx = pkt.deciphered_len 104 ds = super(_TLSLengthField, self).i2repr(pkt, dx) 105 s += " [deciphered_len= %s]" % ds 106 return s 107 108 109class _TLSIVField(StrField): 110 """ 111 As stated in Section 6.2.3.2. RFC 4346, TLS 1.1 implements an explicit IV 112 mechanism. For that reason, the behavior of the field is dependent on the 113 TLS version found in the packet if available or otherwise (on build, if 114 not overloaded, it is provided by the session). The size of the IV and 115 its value are obviously provided by the session. As a side note, for the 116 first packets exchanged by peers, NULL being the default enc alg, it is 117 empty (except if forced to a specific value). Also note that the field is 118 kept empty (unless forced to a specific value) when the cipher is a stream 119 cipher (and NULL is considered a stream cipher). 120 """ 121 122 def i2len(self, pkt, i): 123 if i is not None: 124 return len(i) 125 tmp_len = 0 126 cipher_type = pkt.tls_session.rcs.cipher.type 127 if cipher_type == "block": 128 if pkt.tls_session.tls_version >= 0x0302: 129 tmp_len = pkt.tls_session.rcs.cipher.block_size 130 elif cipher_type == "aead": 131 tmp_len = pkt.tls_session.rcs.cipher.nonce_explicit_len 132 return tmp_len 133 134 def i2m(self, pkt, x): 135 return x or b"" 136 137 def addfield(self, pkt, s, val): 138 return s + self.i2m(pkt, val) 139 140 def getfield(self, pkt, s): 141 tmp_len = 0 142 cipher_type = pkt.tls_session.rcs.cipher.type 143 if cipher_type == "block": 144 if pkt.tls_session.tls_version >= 0x0302: 145 tmp_len = pkt.tls_session.rcs.cipher.block_size 146 elif cipher_type == "aead": 147 tmp_len = pkt.tls_session.rcs.cipher.nonce_explicit_len 148 return s[tmp_len:], self.m2i(pkt, s[:tmp_len]) 149 150 def i2repr(self, pkt, x): 151 return repr(self.i2m(pkt, x)) 152 153 154class _TLSMACField(StrField): 155 def i2len(self, pkt, i): 156 if i is not None: 157 return len(i) 158 return pkt.tls_session.wcs.mac_len 159 160 def i2m(self, pkt, x): 161 if x is None: 162 return b"" 163 return x 164 165 def addfield(self, pkt, s, val): 166 # We add nothing here. This is done in .post_build() if needed. 167 return s 168 169 def getfield(self, pkt, s): 170 if ( 171 pkt.tls_session.rcs.cipher.type != "aead" and 172 False in pkt.tls_session.rcs.cipher.ready.values() 173 ): 174 # XXX Find a more proper way to handle the still-encrypted case 175 return s, b"" 176 tmp_len = pkt.tls_session.rcs.mac_len 177 return s[tmp_len:], self.m2i(pkt, s[:tmp_len]) 178 179 def i2repr(self, pkt, x): 180 # XXX Provide status when dissection has been performed successfully? 181 return repr(self.i2m(pkt, x)) 182 183 184class _TLSPadField(StrField): 185 def i2len(self, pkt, i): 186 if i is not None: 187 return len(i) 188 return 0 189 190 def i2m(self, pkt, x): 191 if x is None: 192 return b"" 193 return x 194 195 def addfield(self, pkt, s, val): 196 # We add nothing here. This is done in .post_build() if needed. 197 return s 198 199 def getfield(self, pkt, s): 200 if pkt.tls_session.consider_read_padding(): 201 # This should work with SSLv3 and also TLS versions. 202 # Note that we need to retrieve pkt.padlen beforehand, 203 # because it's possible that the padding is followed by some data 204 # from another TLS record (hence the last byte from s would not be 205 # the last byte from the current record padding). 206 tmp_len = orb(s[pkt.padlen - 1]) 207 return s[tmp_len:], self.m2i(pkt, s[:tmp_len]) 208 return s, None 209 210 def i2repr(self, pkt, x): 211 # XXX Provide status when dissection has been performed successfully? 212 return repr(self.i2m(pkt, x)) 213 214 215class _TLSPadLenField(ByteField): 216 def addfield(self, pkt, s, val): 217 # We add nothing here. This is done in .post_build() if needed. 218 return s 219 220 def getfield(self, pkt, s): 221 if pkt.tls_session.consider_read_padding(): 222 return ByteField.getfield(self, pkt, s) 223 return s, None 224 225 226# SSLv2 fields 227 228class _SSLv2LengthField(_TLSLengthField): 229 def i2repr(self, pkt, x): 230 s = super(_SSLv2LengthField, self).i2repr(pkt, x) 231 if pkt.with_padding: 232 x |= 0x8000 233 # elif pkt.with_escape: #XXX no complete support for 'escape' yet 234 # x |= 0x4000 235 s += " [with padding: %s]" % hex(x) 236 return s 237 238 def getfield(self, pkt, s): 239 msglen = struct.unpack('!H', s[:2])[0] 240 pkt.with_padding = (msglen & 0x8000) == 0 241 if pkt.with_padding: 242 msglen_clean = msglen & 0x3fff 243 else: 244 msglen_clean = msglen & 0x7fff 245 return s[2:], msglen_clean 246 247 248class _SSLv2MACField(_TLSMACField): 249 pass 250 251 252class _SSLv2PadField(_TLSPadField): 253 def getfield(self, pkt, s): 254 if pkt.padlen is not None: 255 tmp_len = pkt.padlen 256 return s[tmp_len:], self.m2i(pkt, s[:tmp_len]) 257 return s, None 258 259 260class _SSLv2PadLenField(_TLSPadLenField): 261 def getfield(self, pkt, s): 262 if pkt.with_padding: 263 return ByteField.getfield(self, pkt, s) 264 return s, None 265