1*7dc08ffcSJunyu Lai## This file is part of Scapy 2*7dc08ffcSJunyu Lai## Copyright (C) 2007, 2008, 2009 Arnaud Ebalard 3*7dc08ffcSJunyu Lai## 2015, 2016, 2017 Maxence Tury 4*7dc08ffcSJunyu Lai## This program is published under a GPLv2 license 5*7dc08ffcSJunyu Lai 6*7dc08ffcSJunyu Lai""" 7*7dc08ffcSJunyu LaiThe _TLSAutomaton class provides methods common to both TLS client and server. 8*7dc08ffcSJunyu Lai""" 9*7dc08ffcSJunyu Lai 10*7dc08ffcSJunyu Laiimport struct 11*7dc08ffcSJunyu Lai 12*7dc08ffcSJunyu Laifrom scapy.automaton import Automaton 13*7dc08ffcSJunyu Laifrom scapy.error import log_interactive 14*7dc08ffcSJunyu Laifrom scapy.packet import Raw 15*7dc08ffcSJunyu Laifrom scapy.layers.tls.basefields import _tls_type 16*7dc08ffcSJunyu Laifrom scapy.layers.tls.cert import Cert, PrivKey 17*7dc08ffcSJunyu Laifrom scapy.layers.tls.record import TLS 18*7dc08ffcSJunyu Laifrom scapy.layers.tls.record_sslv2 import SSLv2 19*7dc08ffcSJunyu Laifrom scapy.layers.tls.record_tls13 import TLS13 20*7dc08ffcSJunyu Lai 21*7dc08ffcSJunyu Lai 22*7dc08ffcSJunyu Laiclass _TLSAutomaton(Automaton): 23*7dc08ffcSJunyu Lai """ 24*7dc08ffcSJunyu Lai SSLv3 and TLS 1.0-1.2 typically need a 2-RTT handshake: 25*7dc08ffcSJunyu Lai 26*7dc08ffcSJunyu Lai Client Server 27*7dc08ffcSJunyu Lai | --------->>> | C1 - ClientHello 28*7dc08ffcSJunyu Lai | <<<--------- | S1 - ServerHello 29*7dc08ffcSJunyu Lai | <<<--------- | S1 - Certificate 30*7dc08ffcSJunyu Lai | <<<--------- | S1 - ServerKeyExchange 31*7dc08ffcSJunyu Lai | <<<--------- | S1 - ServerHelloDone 32*7dc08ffcSJunyu Lai | --------->>> | C2 - ClientKeyExchange 33*7dc08ffcSJunyu Lai | --------->>> | C2 - ChangeCipherSpec 34*7dc08ffcSJunyu Lai | --------->>> | C2 - Finished [encrypted] 35*7dc08ffcSJunyu Lai | <<<--------- | S2 - ChangeCipherSpec 36*7dc08ffcSJunyu Lai | <<<--------- | S2 - Finished [encrypted] 37*7dc08ffcSJunyu Lai 38*7dc08ffcSJunyu Lai We call these successive groups of messages: 39*7dc08ffcSJunyu Lai ClientFlight1, ServerFlight1, ClientFlight2 and ServerFlight2. 40*7dc08ffcSJunyu Lai 41*7dc08ffcSJunyu Lai We want to send our messages from the same flight all at once through the 42*7dc08ffcSJunyu Lai socket. This is achieved by managing a list of records in 'buffer_out'. 43*7dc08ffcSJunyu Lai We may put several messages (i.e. what RFC 5246 calls the record fragments) 44*7dc08ffcSJunyu Lai in the same record when possible, but we may need several records for the 45*7dc08ffcSJunyu Lai same flight, as with ClientFlight2. 46*7dc08ffcSJunyu Lai 47*7dc08ffcSJunyu Lai However, note that the flights from the opposite side may be spread wildly 48*7dc08ffcSJunyu Lai accross TLS records and TCP packets. This is why we use a 'get_next_msg' 49*7dc08ffcSJunyu Lai method for feeding a list of received messages, 'buffer_in'. Raw data 50*7dc08ffcSJunyu Lai which has not yet been interpreted as a TLS record is kept in 'remain_in'. 51*7dc08ffcSJunyu Lai """ 52*7dc08ffcSJunyu Lai def parse_args(self, mycert=None, mykey=None, **kargs): 53*7dc08ffcSJunyu Lai 54*7dc08ffcSJunyu Lai super(_TLSAutomaton, self).parse_args(**kargs) 55*7dc08ffcSJunyu Lai 56*7dc08ffcSJunyu Lai self.socket = None 57*7dc08ffcSJunyu Lai self.remain_in = b"" 58*7dc08ffcSJunyu Lai self.buffer_in = [] # these are 'fragments' inside records 59*7dc08ffcSJunyu Lai self.buffer_out = [] # these are records 60*7dc08ffcSJunyu Lai 61*7dc08ffcSJunyu Lai self.cur_session = None 62*7dc08ffcSJunyu Lai self.cur_pkt = None # this is usually the latest parsed packet 63*7dc08ffcSJunyu Lai 64*7dc08ffcSJunyu Lai if mycert: 65*7dc08ffcSJunyu Lai self.mycert = Cert(mycert) 66*7dc08ffcSJunyu Lai else: 67*7dc08ffcSJunyu Lai self.mycert = None 68*7dc08ffcSJunyu Lai 69*7dc08ffcSJunyu Lai if mykey: 70*7dc08ffcSJunyu Lai self.mykey = PrivKey(mykey) 71*7dc08ffcSJunyu Lai else: 72*7dc08ffcSJunyu Lai self.mykey = None 73*7dc08ffcSJunyu Lai 74*7dc08ffcSJunyu Lai self.verbose = kargs.get("verbose", True) 75*7dc08ffcSJunyu Lai 76*7dc08ffcSJunyu Lai 77*7dc08ffcSJunyu Lai def get_next_msg(self, socket_timeout=2, retry=2): 78*7dc08ffcSJunyu Lai """ 79*7dc08ffcSJunyu Lai The purpose of the function is to make next message(s) available in 80*7dc08ffcSJunyu Lai self.buffer_in. If the list is not empty, nothing is done. If not, in 81*7dc08ffcSJunyu Lai order to fill it, the function uses the data already available in 82*7dc08ffcSJunyu Lai self.remain_in from a previous call and waits till there are enough to 83*7dc08ffcSJunyu Lai dissect a TLS packet. Once dissected, the content of the TLS packet 84*7dc08ffcSJunyu Lai (carried messages, or 'fragments') is appended to self.buffer_in. 85*7dc08ffcSJunyu Lai 86*7dc08ffcSJunyu Lai We have to grab enough data to dissect a TLS packet. We start by 87*7dc08ffcSJunyu Lai reading the first 2 bytes. Unless we get anything different from 88*7dc08ffcSJunyu Lai \\x14\\x03, \\x15\\x03, \\x16\\x03 or \\x17\\x03 (which might indicate 89*7dc08ffcSJunyu Lai an SSLv2 record, whose first 2 bytes encode the length), we retrieve 90*7dc08ffcSJunyu Lai 3 more bytes in order to get the length of the TLS record, and 91*7dc08ffcSJunyu Lai finally we can retrieve the remaining of the record. 92*7dc08ffcSJunyu Lai """ 93*7dc08ffcSJunyu Lai if self.buffer_in: 94*7dc08ffcSJunyu Lai # A message is already available. 95*7dc08ffcSJunyu Lai return 96*7dc08ffcSJunyu Lai 97*7dc08ffcSJunyu Lai self.socket.settimeout(socket_timeout) 98*7dc08ffcSJunyu Lai is_sslv2_msg = False 99*7dc08ffcSJunyu Lai still_getting_len = True 100*7dc08ffcSJunyu Lai grablen = 2 101*7dc08ffcSJunyu Lai while retry and (still_getting_len or len(self.remain_in) < grablen): 102*7dc08ffcSJunyu Lai if not is_sslv2_msg and grablen == 5 and len(self.remain_in) >= 5: 103*7dc08ffcSJunyu Lai grablen = struct.unpack('!H', self.remain_in[3:5])[0] + 5 104*7dc08ffcSJunyu Lai still_getting_len = False 105*7dc08ffcSJunyu Lai elif grablen == 2 and len(self.remain_in) >= 2: 106*7dc08ffcSJunyu Lai byte0 = struct.unpack("B", self.remain_in[:1])[0] 107*7dc08ffcSJunyu Lai byte1 = struct.unpack("B", self.remain_in[1:2])[0] 108*7dc08ffcSJunyu Lai if (byte0 in _tls_type) and (byte1 == 3): 109*7dc08ffcSJunyu Lai # Retry following TLS scheme. This will cause failure 110*7dc08ffcSJunyu Lai # for SSLv2 packets with length 0x1{4-7}03. 111*7dc08ffcSJunyu Lai grablen = 5 112*7dc08ffcSJunyu Lai else: 113*7dc08ffcSJunyu Lai # Extract the SSLv2 length. 114*7dc08ffcSJunyu Lai is_sslv2_msg = True 115*7dc08ffcSJunyu Lai still_getting_len = False 116*7dc08ffcSJunyu Lai if byte0 & 0x80: 117*7dc08ffcSJunyu Lai grablen = 2 + 0 + ((byte0 & 0x7f) << 8) + byte1 118*7dc08ffcSJunyu Lai else: 119*7dc08ffcSJunyu Lai grablen = 2 + 1 + ((byte0 & 0x3f) << 8) + byte1 120*7dc08ffcSJunyu Lai elif not is_sslv2_msg and grablen == 5 and len(self.remain_in) >= 5: 121*7dc08ffcSJunyu Lai grablen = struct.unpack('!H', self.remain_in[3:5])[0] + 5 122*7dc08ffcSJunyu Lai 123*7dc08ffcSJunyu Lai if grablen == len(self.remain_in): 124*7dc08ffcSJunyu Lai break 125*7dc08ffcSJunyu Lai 126*7dc08ffcSJunyu Lai try: 127*7dc08ffcSJunyu Lai tmp = self.socket.recv(grablen - len(self.remain_in)) 128*7dc08ffcSJunyu Lai if not tmp: 129*7dc08ffcSJunyu Lai retry -= 1 130*7dc08ffcSJunyu Lai else: 131*7dc08ffcSJunyu Lai self.remain_in += tmp 132*7dc08ffcSJunyu Lai except: 133*7dc08ffcSJunyu Lai self.vprint("Could not join host ! Retrying...") 134*7dc08ffcSJunyu Lai retry -= 1 135*7dc08ffcSJunyu Lai 136*7dc08ffcSJunyu Lai if len(self.remain_in) < 2 or len(self.remain_in) != grablen: 137*7dc08ffcSJunyu Lai # Remote peer is not willing to respond 138*7dc08ffcSJunyu Lai return 139*7dc08ffcSJunyu Lai 140*7dc08ffcSJunyu Lai p = TLS(self.remain_in, tls_session=self.cur_session) 141*7dc08ffcSJunyu Lai self.cur_session = p.tls_session 142*7dc08ffcSJunyu Lai self.remain_in = b"" 143*7dc08ffcSJunyu Lai if isinstance(p, SSLv2) and not p.msg: 144*7dc08ffcSJunyu Lai p.msg = Raw("") 145*7dc08ffcSJunyu Lai if self.cur_session.tls_version is None or \ 146*7dc08ffcSJunyu Lai self.cur_session.tls_version < 0x0304: 147*7dc08ffcSJunyu Lai self.buffer_in += p.msg 148*7dc08ffcSJunyu Lai else: 149*7dc08ffcSJunyu Lai if isinstance(p, TLS13): 150*7dc08ffcSJunyu Lai self.buffer_in += p.inner.msg 151*7dc08ffcSJunyu Lai else: 152*7dc08ffcSJunyu Lai # should be TLS13ServerHello only 153*7dc08ffcSJunyu Lai self.buffer_in += p.msg 154*7dc08ffcSJunyu Lai 155*7dc08ffcSJunyu Lai while p.payload: 156*7dc08ffcSJunyu Lai if isinstance(p.payload, Raw): 157*7dc08ffcSJunyu Lai self.remain_in += p.payload.load 158*7dc08ffcSJunyu Lai p = p.payload 159*7dc08ffcSJunyu Lai elif isinstance(p.payload, TLS): 160*7dc08ffcSJunyu Lai p = p.payload 161*7dc08ffcSJunyu Lai if self.cur_session.tls_version is None or \ 162*7dc08ffcSJunyu Lai self.cur_session.tls_version < 0x0304: 163*7dc08ffcSJunyu Lai self.buffer_in += p.msg 164*7dc08ffcSJunyu Lai else: 165*7dc08ffcSJunyu Lai self.buffer_in += p.inner.msg 166*7dc08ffcSJunyu Lai 167*7dc08ffcSJunyu Lai def raise_on_packet(self, pkt_cls, state, get_next_msg=True): 168*7dc08ffcSJunyu Lai """ 169*7dc08ffcSJunyu Lai If the next message to be processed has type 'pkt_cls', raise 'state'. 170*7dc08ffcSJunyu Lai If there is no message waiting to be processed, we try to get one with 171*7dc08ffcSJunyu Lai the default 'get_next_msg' parameters. 172*7dc08ffcSJunyu Lai """ 173*7dc08ffcSJunyu Lai # Maybe we already parsed the expected packet, maybe not. 174*7dc08ffcSJunyu Lai if get_next_msg: 175*7dc08ffcSJunyu Lai self.get_next_msg() 176*7dc08ffcSJunyu Lai if (not self.buffer_in or 177*7dc08ffcSJunyu Lai not isinstance(self.buffer_in[0], pkt_cls)): 178*7dc08ffcSJunyu Lai return 179*7dc08ffcSJunyu Lai self.cur_pkt = self.buffer_in[0] 180*7dc08ffcSJunyu Lai self.buffer_in = self.buffer_in[1:] 181*7dc08ffcSJunyu Lai raise state() 182*7dc08ffcSJunyu Lai 183*7dc08ffcSJunyu Lai def add_record(self, is_sslv2=None, is_tls13=None): 184*7dc08ffcSJunyu Lai """ 185*7dc08ffcSJunyu Lai Add a new TLS or SSLv2 or TLS 1.3 record to the packets buffered out. 186*7dc08ffcSJunyu Lai """ 187*7dc08ffcSJunyu Lai if is_sslv2 is None and is_tls13 is None: 188*7dc08ffcSJunyu Lai v = (self.cur_session.tls_version or 189*7dc08ffcSJunyu Lai self.cur_session.advertised_tls_version) 190*7dc08ffcSJunyu Lai if v in [0x0200, 0x0002]: 191*7dc08ffcSJunyu Lai is_sslv2 = True 192*7dc08ffcSJunyu Lai elif v >= 0x0304: 193*7dc08ffcSJunyu Lai is_tls13 = True 194*7dc08ffcSJunyu Lai if is_sslv2: 195*7dc08ffcSJunyu Lai self.buffer_out.append(SSLv2(tls_session=self.cur_session)) 196*7dc08ffcSJunyu Lai elif is_tls13: 197*7dc08ffcSJunyu Lai self.buffer_out.append(TLS13(tls_session=self.cur_session)) 198*7dc08ffcSJunyu Lai else: 199*7dc08ffcSJunyu Lai self.buffer_out.append(TLS(tls_session=self.cur_session)) 200*7dc08ffcSJunyu Lai 201*7dc08ffcSJunyu Lai def add_msg(self, pkt): 202*7dc08ffcSJunyu Lai """ 203*7dc08ffcSJunyu Lai Add a TLS message (e.g. TLSClientHello or TLSApplicationData) 204*7dc08ffcSJunyu Lai inside the latest record to be sent through the socket. 205*7dc08ffcSJunyu Lai We believe a good automaton should not use the first test. 206*7dc08ffcSJunyu Lai """ 207*7dc08ffcSJunyu Lai if not self.buffer_out: 208*7dc08ffcSJunyu Lai self.add_record() 209*7dc08ffcSJunyu Lai r = self.buffer_out[-1] 210*7dc08ffcSJunyu Lai if isinstance(r, TLS13): 211*7dc08ffcSJunyu Lai self.buffer_out[-1].inner.msg.append(pkt) 212*7dc08ffcSJunyu Lai else: 213*7dc08ffcSJunyu Lai self.buffer_out[-1].msg.append(pkt) 214*7dc08ffcSJunyu Lai 215*7dc08ffcSJunyu Lai def flush_records(self): 216*7dc08ffcSJunyu Lai """ 217*7dc08ffcSJunyu Lai Send all buffered records and update the session accordingly. 218*7dc08ffcSJunyu Lai """ 219*7dc08ffcSJunyu Lai s = b"".join(p.raw_stateful() for p in self.buffer_out) 220*7dc08ffcSJunyu Lai self.socket.send(s) 221*7dc08ffcSJunyu Lai self.buffer_out = [] 222*7dc08ffcSJunyu Lai 223*7dc08ffcSJunyu Lai def vprint(self, s=""): 224*7dc08ffcSJunyu Lai if self.verbose: 225*7dc08ffcSJunyu Lai log_interactive.info("> %s", s) 226*7dc08ffcSJunyu Lai 227