1# $Id: ssl.py 90 2014-04-02 22:06:23Z andrewflnr@gmail.com $
2# Portion Copyright 2012 Google Inc. All rights reserved.
3# -*- coding: utf-8 -*-
4"""Secure Sockets Layer / Transport Layer Security."""
5from __future__ import absolute_import
6
7import struct
8import binascii
9
10from . import dpkt
11from . import ssl_ciphersuites
12from .compat import compat_ord
13
14#
15# Note from April 2011: cde...@gmail.com added code that parses SSL3/TLS messages more in depth.
16#
17# Jul 2012: afleenor@google.com modified and extended SSL support further.
18#
19
20
21# SSL 2.0 is deprecated in RFC 6176
22class SSL2(dpkt.Packet):
23    __hdr__ = (
24        ('len', 'H', 0),
25    )
26
27    def unpack(self, buf):
28        dpkt.Packet.unpack(self, buf)
29        # In SSL, all data sent is encapsulated in a record, an object which is
30        # composed of a header and some non-zero amount of data. Each record header
31        # contains a two or three byte length code. If the most significant bit is
32        # set in the first byte of the record length code then the record has
33        # no padding and the total header length will be 2 bytes, otherwise the
34        # record has padding and the total header length will be 3 bytes. The
35        # record header is transmitted before the data portion of the record.
36        if self.len & 0x8000:
37            n = self.len = self.len & 0x7FFF
38            self.msg, self.data = self.data[:n], self.data[n:]
39        else:
40            # Note that in the long header case (3 bytes total), the second most
41            # significant bit in the first byte has special meaning. When zero,
42            # the record being sent is a data record. When one, the record
43            # being sent is a security escape (there are currently no examples
44            # of security escapes; this is reserved for future versions of the
45            # protocol). In either case, the length code describes how much
46            # data is in the record.
47            n = self.len = self.len & 0x3FFF
48            padlen = compat_ord(self.data[0])
49
50            self.msg = self.data[1:1 + n]
51            self.pad = self.data[1 + n:1 + n + padlen]
52            self.data = self.data[1 + n + padlen:]
53
54
55# SSL 3.0 is deprecated in RFC 7568
56# Use class TLS for >= SSL 3.0
57class TLS(dpkt.Packet):
58    __hdr__ = (
59        ('type', 'B', ''),
60        ('version', 'H', ''),
61        ('len', 'H', ''),
62    )
63
64    def __init__(self, *args, **kwargs):
65        self.records = []
66        dpkt.Packet.__init__(self, *args, **kwargs)
67
68    def unpack(self, buf):
69        dpkt.Packet.unpack(self, buf)
70        pointer = 0
71        while len(self.data[pointer:]) > 0:
72            end = pointer + 5 + struct.unpack("!H", buf[pointer + 3:pointer + 5])[0]
73            self.records.append(TLSRecord(buf[pointer:end]))
74            pointer = end
75            self.data = self.data[pointer:]
76
77
78# SSLv3/TLS versions
79SSL3_V = 0x0300
80TLS1_V = 0x0301
81TLS11_V = 0x0302
82TLS12_V = 0x0303
83
84ssl3_versions_str = {
85    SSL3_V: 'SSL3',
86    TLS1_V: 'TLS 1.0',
87    TLS11_V: 'TLS 1.1',
88    TLS12_V: 'TLS 1.2'
89}
90
91SSL3_VERSION_BYTES = set((b'\x03\x00', b'\x03\x01', b'\x03\x02', b'\x03\x03'))
92
93
94# Alert levels
95SSL3_AD_WARNING = 1
96SSL3_AD_FATAL = 2
97alert_level_str = {
98    SSL3_AD_WARNING: 'SSL3_AD_WARNING',
99    SSL3_AD_FATAL: 'SSL3_AD_FATAL'
100}
101
102# SSL3 alert descriptions
103SSL3_AD_CLOSE_NOTIFY = 0
104SSL3_AD_UNEXPECTED_MESSAGE = 10  # fatal
105SSL3_AD_BAD_RECORD_MAC = 20  # fatal
106SSL3_AD_DECOMPRESSION_FAILURE = 30  # fatal
107SSL3_AD_HANDSHAKE_FAILURE = 40  # fatal
108SSL3_AD_NO_CERTIFICATE = 41
109SSL3_AD_BAD_CERTIFICATE = 42
110SSL3_AD_UNSUPPORTED_CERTIFICATE = 43
111SSL3_AD_CERTIFICATE_REVOKED = 44
112SSL3_AD_CERTIFICATE_EXPIRED = 45
113SSL3_AD_CERTIFICATE_UNKNOWN = 46
114SSL3_AD_ILLEGAL_PARAMETER = 47  # fatal
115
116# TLS1 alert descriptions
117TLS1_AD_DECRYPTION_FAILED = 21
118TLS1_AD_RECORD_OVERFLOW = 22
119TLS1_AD_UNKNOWN_CA = 48  # fatal
120TLS1_AD_ACCESS_DENIED = 49  # fatal
121TLS1_AD_DECODE_ERROR = 50  # fatal
122TLS1_AD_DECRYPT_ERROR = 51
123TLS1_AD_EXPORT_RESTRICTION = 60  # fatal
124TLS1_AD_PROTOCOL_VERSION = 70  # fatal
125TLS1_AD_INSUFFICIENT_SECURITY = 71  # fatal
126TLS1_AD_INTERNAL_ERROR = 80  # fatal
127TLS1_AD_USER_CANCELLED = 90
128TLS1_AD_NO_RENEGOTIATION = 100
129# /* codes 110-114 are from RFC3546 */
130TLS1_AD_UNSUPPORTED_EXTENSION = 110
131TLS1_AD_CERTIFICATE_UNOBTAINABLE = 111
132TLS1_AD_UNRECOGNIZED_NAME = 112
133TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE = 113
134TLS1_AD_BAD_CERTIFICATE_HASH_VALUE = 114
135TLS1_AD_UNKNOWN_PSK_IDENTITY = 115  # fatal
136
137
138# Mapping alert types to strings
139alert_description_str = {
140    SSL3_AD_CLOSE_NOTIFY: 'SSL3_AD_CLOSE_NOTIFY',
141    SSL3_AD_UNEXPECTED_MESSAGE: 'SSL3_AD_UNEXPECTED_MESSAGE',
142    SSL3_AD_BAD_RECORD_MAC: 'SSL3_AD_BAD_RECORD_MAC',
143    SSL3_AD_DECOMPRESSION_FAILURE: 'SSL3_AD_DECOMPRESSION_FAILURE',
144    SSL3_AD_HANDSHAKE_FAILURE: 'SSL3_AD_HANDSHAKE_FAILURE',
145    SSL3_AD_NO_CERTIFICATE: 'SSL3_AD_NO_CERTIFICATE',
146    SSL3_AD_BAD_CERTIFICATE: 'SSL3_AD_BAD_CERTIFICATE',
147    SSL3_AD_UNSUPPORTED_CERTIFICATE: 'SSL3_AD_UNSUPPORTED_CERTIFICATE',
148    SSL3_AD_CERTIFICATE_REVOKED: 'SSL3_AD_CERTIFICATE_REVOKED',
149    SSL3_AD_CERTIFICATE_EXPIRED: 'SSL3_AD_CERTIFICATE_EXPIRED',
150    SSL3_AD_CERTIFICATE_UNKNOWN: 'SSL3_AD_CERTIFICATE_UNKNOWN',
151    SSL3_AD_ILLEGAL_PARAMETER: 'SSL3_AD_ILLEGAL_PARAMETER',
152    TLS1_AD_DECRYPTION_FAILED: 'TLS1_AD_DECRYPTION_FAILED',
153    TLS1_AD_RECORD_OVERFLOW: 'TLS1_AD_RECORD_OVERFLOW',
154    TLS1_AD_UNKNOWN_CA: 'TLS1_AD_UNKNOWN_CA',
155    TLS1_AD_ACCESS_DENIED: 'TLS1_AD_ACCESS_DENIED',
156    TLS1_AD_DECODE_ERROR: 'TLS1_AD_DECODE_ERROR',
157    TLS1_AD_DECRYPT_ERROR: 'TLS1_AD_DECRYPT_ERROR',
158    TLS1_AD_EXPORT_RESTRICTION: 'TLS1_AD_EXPORT_RESTRICTION',
159    TLS1_AD_PROTOCOL_VERSION: 'TLS1_AD_PROTOCOL_VERSION',
160    TLS1_AD_INSUFFICIENT_SECURITY: 'TLS1_AD_INSUFFICIENT_SECURITY',
161    TLS1_AD_INTERNAL_ERROR: 'TLS1_AD_INTERNAL_ERROR',
162    TLS1_AD_USER_CANCELLED: 'TLS1_AD_USER_CANCELLED',
163    TLS1_AD_NO_RENEGOTIATION: 'TLS1_AD_NO_RENEGOTIATION',
164    TLS1_AD_UNSUPPORTED_EXTENSION: 'TLS1_AD_UNSUPPORTED_EXTENSION',
165    TLS1_AD_CERTIFICATE_UNOBTAINABLE: 'TLS1_AD_CERTIFICATE_UNOBTAINABLE',
166    TLS1_AD_UNRECOGNIZED_NAME: 'TLS1_AD_UNRECOGNIZED_NAME',
167    TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE: 'TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE',
168    TLS1_AD_BAD_CERTIFICATE_HASH_VALUE: 'TLS1_AD_BAD_CERTIFICATE_HASH_VALUE',
169    TLS1_AD_UNKNOWN_PSK_IDENTITY: 'TLS1_AD_UNKNOWN_PSK_IDENTITY'
170}
171
172
173# struct format strings for parsing buffer lengths
174# don't forget, you have to pad a 3-byte value with \x00
175_SIZE_FORMATS = ['!B', '!H', '!I', '!I']
176
177
178def parse_variable_array(buf, lenbytes):
179    """
180    Parse an array described using the 'Type name<x..y>' syntax from the spec
181    Read a length at the start of buf, and returns that many bytes
182    after, in a tuple with the TOTAL bytes consumed (including the size). This
183    does not check that the array is the right length for any given datatype.
184    """
185    # first have to figure out how to parse length
186    assert lenbytes <= 4  # pretty sure 4 is impossible, too
187    size_format = _SIZE_FORMATS[lenbytes - 1]
188    padding = b'\x00' if lenbytes == 3 else b''
189    # read off the length
190    size = struct.unpack(size_format, padding + buf[:lenbytes])[0]
191    # read the actual data
192    data = buf[lenbytes:lenbytes + size]
193    # if len(data) != size: insufficient data
194    return data, size + lenbytes
195
196
197def parse_extensions(buf):
198    """
199    Parse TLS extensions in passed buf. Returns an ordered list of extension tuples with
200    ordinal extension type as first value and extension data as second value.
201    Passed buf must start with the 2-byte extensions length TLV.
202    http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
203    """
204    extensions_length = struct.unpack('!H', buf[:2])[0]
205    extensions = []
206
207    pointer = 2
208    while pointer < extensions_length:
209        ext_type = struct.unpack('!H', buf[pointer:pointer + 2])[0]
210        pointer += 2
211        ext_data, parsed = parse_variable_array(buf[pointer:], 2)
212        extensions.append((ext_type, ext_data))
213        pointer += parsed
214    return extensions
215
216
217class SSL3Exception(Exception):
218    pass
219
220
221class TLSRecord(dpkt.Packet):
222    """
223    SSLv3 or TLSv1+ packet.
224
225    In addition to the fields specified in the header, there are
226    compressed and decrypted fields, indicating whether, in the language
227    of the spec, this is a TLSPlaintext, TLSCompressed, or
228    TLSCiphertext. The application will have to figure out when it's
229    appropriate to change these values.
230    """
231
232    __hdr__ = (
233        ('type', 'B', 0),
234        ('version', 'H', 0),
235        ('length', 'H', 0),
236    )
237
238    def __init__(self, *args, **kwargs):
239        # assume plaintext unless specified otherwise in arguments
240        self.compressed = kwargs.pop('compressed', False)
241        self.encrypted = kwargs.pop('encrypted', False)
242        # parent constructor
243        dpkt.Packet.__init__(self, *args, **kwargs)
244        # make sure length and data are consistent
245        self.length = len(self.data)
246
247    def unpack(self, buf):
248        dpkt.Packet.unpack(self, buf)
249        header_length = self.__hdr_len__
250        self.data = buf[header_length:header_length + self.length]
251        # make sure buffer was long enough
252        if len(self.data) != self.length:
253            raise dpkt.NeedData('TLSRecord data was too short.')
254        # assume compressed and encrypted when it's been parsed from
255        # raw data
256        self.compressed = True
257        self.encrypted = True
258
259
260class TLSChangeCipherSpec(dpkt.Packet):
261    """
262    ChangeCipherSpec message is just a single byte with value 1
263    """
264    __hdr__ = (('type', 'B', 1),)
265
266
267class TLSAppData(str):
268    """
269    As far as TLSRecord is concerned, AppData is just an opaque blob.
270    """
271    pass
272
273
274class TLSAlert(dpkt.Packet):
275    __hdr__ = (
276        ('level', 'B', 1),
277        ('description', 'B', 0),
278    )
279
280
281class TLSHelloRequest(dpkt.Packet):
282    __hdr__ = tuple()
283
284
285class TLSClientHello(dpkt.Packet):
286    __hdr__ = (
287        ('version', 'H', 0x0301),
288        ('random', '32s', '\x00' * 32),
289    )  # the rest is variable-length and has to be done manually
290
291    def unpack(self, buf):
292        dpkt.Packet.unpack(self, buf)
293        # now session, cipher suites, extensions are in self.data
294        self.session_id, pointer = parse_variable_array(self.data, 1)
295        # print 'pointer',pointer
296        # handle ciphersuites
297        ciphersuites, parsed = parse_variable_array(self.data[pointer:], 2)
298        pointer += parsed
299        num_ciphersuites = int(len(ciphersuites) / 2)
300        try:
301            self.ciphersuites = [
302                ssl_ciphersuites.BY_CODE[code] for code in struct.unpack('!' + num_ciphersuites * 'H', ciphersuites)]
303        except KeyError as e:
304            raise SSL3Exception('Unknown or invalid cipher suite type %x' % int(e.args[0]))
305        # check len(ciphersuites) % 2 == 0 ?
306        # compression methods
307        compression_methods, parsed = parse_variable_array(self.data[pointer:], 1)
308        pointer += parsed
309        self.compression_methods = struct.unpack('{0}B'.format(len(compression_methods)), compression_methods)
310        # Parse extensions if present
311        if len(self.data[pointer:]) >= 6:
312            self.extensions = parse_extensions(self.data[pointer:])
313
314
315class TLSServerHello(dpkt.Packet):
316    __hdr__ = (
317        ('version', 'H', '0x0301'),
318        ('random', '32s', '\x00' * 32),
319    )  # session is variable, forcing rest to be manual
320
321    def unpack(self, buf):
322        try:
323            dpkt.Packet.unpack(self, buf)
324            self.session_id, pointer = parse_variable_array(self.data, 1)
325            # single cipher suite
326            try:
327                code = struct.unpack('!H', self.data[pointer:pointer + 2])[0]
328                self.cipher_suite = ssl_ciphersuites.BY_CODE[code]
329            except KeyError as e:
330                raise SSL3Exception('Unknown or invalid cipher suite type %x' % int(e.args[0]))
331            pointer += 2
332            # single compression method
333            self.compression = struct.unpack('!B', self.data[pointer:pointer + 1])[0]
334            pointer += 1
335            # Parse extensions if present
336            if len(self.data[pointer:]) >= 6:
337                self.extensions = parse_extensions(self.data[pointer:])
338        except struct.error:
339            # probably data too short
340            raise dpkt.NeedData
341
342
343class TLSCertificate(dpkt.Packet):
344    __hdr__ = tuple()
345
346    def unpack(self, buf):
347        try:
348            dpkt.Packet.unpack(self, buf)
349            all_certs, all_certs_len = parse_variable_array(self.data, 3)
350            self.certificates = []
351            pointer = 3
352            while pointer < all_certs_len:
353                cert, parsed = parse_variable_array(self.data[pointer:], 3)
354                self.certificates.append((cert))
355                pointer += parsed
356        except struct.error:
357            raise dpkt.NeedData
358
359
360class TLSUnknownHandshake(dpkt.Packet):
361    __hdr__ = tuple()
362
363
364TLSNewSessionTicket = TLSUnknownHandshake
365TLSServerKeyExchange = TLSUnknownHandshake
366TLSCertificateRequest = TLSUnknownHandshake
367TLSServerHelloDone = TLSUnknownHandshake
368TLSCertificateVerify = TLSUnknownHandshake
369TLSClientKeyExchange = TLSUnknownHandshake
370TLSFinished = TLSUnknownHandshake
371
372
373# mapping of handshake type ids to their names
374# and the classes that implement them
375HANDSHAKE_TYPES = {
376    0: ('HelloRequest', TLSHelloRequest),
377    1: ('ClientHello', TLSClientHello),
378    2: ('ServerHello', TLSServerHello),
379    4: ('NewSessionTicket', TLSNewSessionTicket),
380    11: ('Certificate', TLSCertificate),
381    12: ('ServerKeyExchange', TLSServerKeyExchange),
382    13: ('CertificateRequest', TLSCertificateRequest),
383    14: ('ServerHelloDone', TLSServerHelloDone),
384    15: ('CertificateVerify', TLSCertificateVerify),
385    16: ('ClientKeyExchange', TLSClientKeyExchange),
386    20: ('Finished', TLSFinished),
387}
388
389
390class TLSHandshake(dpkt.Packet):
391    """
392    A TLS Handshake message
393
394    This goes for all messages encapsulated in the Record layer, but especially
395    important for handshakes and app data: A message may be spread across a
396    number of TLSRecords, in addition to the possibility of there being more
397    than one in a given Record. You have to put together the contents of
398    TLSRecord's yourself.
399    """
400
401    # struct.unpack can't handle the 3-byte int, so we parse it as bytes
402    # (and store it as bytes so dpkt doesn't get confused), and turn it into
403    # an int in a user-facing property
404    __hdr__ = (
405        ('type', 'B', 0),
406        ('length_bytes', '3s', 0),
407    )
408
409    def unpack(self, buf):
410        dpkt.Packet.unpack(self, buf)
411        # Wait, might there be more than one message of self.type?
412        embedded_type = HANDSHAKE_TYPES.get(self.type, None)
413        if embedded_type is None:
414            raise SSL3Exception('Unknown or invalid handshake type %d' %
415                                self.type)
416        # only take the right number of bytes
417        self.data = self.data[:self.length]
418        if len(self.data) != self.length:
419            raise dpkt.NeedData
420        # get class out of embedded_type tuple
421        self.data = embedded_type[1](self.data)
422
423    @property
424    def length(self):
425        return struct.unpack('!I', b'\x00' + self.length_bytes)[0]
426
427
428RECORD_TYPES = {
429    20: TLSChangeCipherSpec,
430    21: TLSAlert,
431    22: TLSHandshake,
432    23: TLSAppData,
433}
434
435
436class SSLFactory(object):
437    def __new__(cls, buf):
438        v = buf[1:3]
439        if v in SSL3_VERSION_BYTES:
440            return TLSRecord(buf)
441        # SSL2 has no characteristic header or magic bytes, so we just assume
442        # that the msg is an SSL2 msg if it is not detected as SSL3+
443        return SSL2(buf)
444
445
446def tls_multi_factory(buf):
447    """
448    Attempt to parse one or more TLSRecord's out of buf
449
450    Args:
451      buf: string containing SSL/TLS messages. May have an incomplete record
452        on the end
453
454    Returns:
455      [TLSRecord]
456      int, total bytes consumed, != len(buf) if an incomplete record was left at
457        the end.
458
459    Raises SSL3Exception.
460    """
461    i, n = 0, len(buf)
462    msgs = []
463    while i + 5 <= n:
464        v = buf[i + 1:i + 3]
465        if v in SSL3_VERSION_BYTES:
466            try:
467                msg = TLSRecord(buf[i:])
468                msgs.append(msg)
469            except dpkt.NeedData:
470                break
471        else:
472            raise SSL3Exception('Bad TLS version in buf: %r' % buf[i:i + 5])
473        i += len(msg)
474    return msgs, i
475
476
477_hexdecode = binascii.a2b_hex
478
479
480class TestTLS(object):
481    """
482    Test basic TLS functionality.
483    Test that each TLSRecord is correctly discovered and added to TLS.records
484    """
485
486    @classmethod
487    def setup_class(cls):
488        cls.p = TLS(
489            b'\x16\x03\x00\x02\x06\x01\x00\x02\x02\x03\x03\x58\x5c\x2f\xf7\x2a\x65\x99\x49\x87\x71\xf5'
490            b'\x95\x14\xf1\x0a\xf6\x8c\x68\xf9\xef\x30\xd0\xda\xdc\x9e\x1a\xf6\x4d\x10\x91\x47\x6a\x00'
491            b'\x00\x84\xc0\x2b\xc0\x2c\xc0\x86\xc0\x87\xc0\x09\xc0\x23\xc0\x0a\xc0\x24\xc0\x72\xc0\x73'
492            b'\xc0\x08\xc0\x07\xc0\x2f\xc0\x30\xc0\x8a\xc0\x8b\xc0\x13\xc0\x27\xc0\x14\xc0\x28\xc0\x76'
493            b'\xc0\x77\xc0\x12\xc0\x11\x00\x9c\x00\x9d\xc0\x7a\xc0\x7b\x00\x2f\x00\x3c\x00\x35\x00\x3d'
494            b'\x00\x41\x00\xba\x00\x84\x00\xc0\x00\x0a\x00\x05\x00\x04\x00\x9e\x00\x9f\xc0\x7c\xc0\x7d'
495            b'\x00\x33\x00\x67\x00\x39\x00\x6b\x00\x45\x00\xbe\x00\x88\x00\xc4\x00\x16\x00\xa2\x00\xa3'
496            b'\xc0\x80\xc0\x81\x00\x32\x00\x40\x00\x38\x00\x6a\x00\x44\x00\xbd\x00\x87\x00\xc3\x00\x13'
497            b'\x00\x66\x01\x00\x01\x55\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\x00\x00\x11\x00\x0f\x00'
498            b'\x00\x0c\x77\x77\x77\x2e\x69\x61\x6e\x61\x2e\x6f\x72\x67\xff\x01\x00\x01\x00\x00\x23\x00'
499            b'\x00\x00\x0a\x00\x0c\x00\x0a\x00\x13\x00\x15\x00\x17\x00\x18\x00\x19\x00\x0b\x00\x02\x01'
500            b'\x00\x00\x0d\x00\x1c\x00\x1a\x04\x01\x04\x02\x04\x03\x05\x01\x05\x03\x06\x01\x06\x03\x03'
501            b'\x01\x03\x02\x03\x03\x02\x01\x02\x02\x02\x03\x00\x15\x00\xf4\x00\xf2\x00\x00\x00\x00\x00'
502            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
503            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
504            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
505            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
506            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
507            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
508            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
509            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
510            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
511            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
512            b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
513        )
514
515    def test_records_length(self):
516        assert (len(self.p.records) == 1)
517
518    def test_record_type(self):
519        assert (self.p.records[0].type == 22)
520
521    def test_record_version(self):
522        assert (self.p.records[0].version == 768)
523
524
525class TestTLSRecord(object):
526    """
527    Test basic TLSRecord functionality
528    For this test, the contents of the record doesn't matter, since we're not parsing the next layer.
529    """
530
531    @classmethod
532    def setup_class(cls):
533        # add some extra data, to make sure length is parsed correctly
534        cls.p = TLSRecord(b'\x17\x03\x01\x00\x08abcdefghzzzzzzzzzzz')
535
536    def test_content_type(self):
537        assert (self.p.type == 23)
538
539    def test_version(self):
540        assert (self.p.version == 0x0301)
541
542    def test_length(self):
543        assert (self.p.length == 8)
544
545    def test_data(self):
546        assert (self.p.data == b'abcdefgh')
547
548    def test_initial_flags(self):
549        assert (self.p.compressed is True)
550        assert (self.p.encrypted is True)
551
552    def test_repack(self):
553        p2 = TLSRecord(type=23, version=0x0301, data=b'abcdefgh')
554        assert (p2.type == 23)
555        assert (p2.version == 0x0301)
556        assert (p2.length == 8)
557        assert (p2.data == b'abcdefgh')
558        assert (p2.pack() == self.p.pack())
559
560    def test_total_length(self):
561        # that len(p) includes header
562        assert (len(self.p) == 13)
563
564    def test_raises_need_data_when_buf_is_short(self):
565        import pytest
566        pytest.raises(dpkt.NeedData, TLSRecord, b'\x16\x03\x01\x00\x10abc')
567
568
569class TestTLSChangeCipherSpec(object):
570    """It's just a byte. This will be quick, I promise"""
571
572    @classmethod
573    def setup_class(cls):
574        cls.p = TLSChangeCipherSpec(b'\x01')
575
576    def test_parses(self):
577        assert (self.p.type == 1)
578
579    def test_total_length(self):
580        assert (len(self.p) == 1)
581
582
583class TestTLSAppData(object):
584    """AppData is basically just a string"""
585
586    def test_value(self):
587        d = TLSAppData('abcdefgh')
588        assert (d == 'abcdefgh')
589
590
591class TestTLSHandshake(object):
592    @classmethod
593    def setup_class(cls):
594        cls.h = TLSHandshake(b'\x00\x00\x00\x01\xff')
595
596    def test_created_inside_message(self):
597        assert (isinstance(self.h.data, TLSHelloRequest) is True)
598
599    def test_length(self):
600        assert (self.h.length == 0x01)
601
602    def test_raises_need_data(self):
603        import pytest
604        pytest.raises(dpkt.NeedData, TLSHandshake, b'\x00\x00\x01\x01')
605
606
607class TestClientHello(object):
608    """This data is extracted from and verified by Wireshark"""
609
610    @classmethod
611    def setup_class(cls):
612        cls.data = _hexdecode(
613            b"01000199"  # handshake header
614            b"0301"  # version
615            b"5008220ce5e0e78b6891afe204498c9363feffbe03235a2d9e05b7d990eb708d"  # rand
616            b"2009bc0192e008e6fa8fe47998fca91311ba30ddde14a9587dc674b11c3d3e5ed1"  # session id
617            # cipher suites
618            b"005200ffc00ac0140088008700390038c00fc00500840035c007c009c011c0130045004400330032"
619            b"c00cc00ec002c0040096004100050004002fc008c01200160013c00dc003000ac006c010c00bc00100020001"
620            b"0100"  # compresssion methods
621            # extensions
622            b"00fc0000000e000c0000096c6f63616c686f7374000a00080006001700180019000b000201000023"
623            b"00d0a50b2e9f618a9ea9bf493ef49b421835cd2f6b05bbe1179d8edf70d58c33d656e8696d36d7e7"
624            b"e0b9d3ecc0e4de339552fa06c64c0fcb550a334bc43944e2739ca342d15a9ebbe981ac87a0d38160"
625            b"507d47af09bdc16c5f0ee4cdceea551539382333226048a026d3a90a0535f4a64236467db8fee22b"
626            b"041af986ad0f253bc369137cd8d8cd061925461d7f4d7895ca9a4181ab554dad50360ac31860e971"
627            b"483877c9335ac1300c5e78f3e56f3b8e0fc16358fcaceefd5c8d8aaae7b35be116f8832856ca6114"
628            b"4fcdd95e071b94d0cf7233740000"
629            b"FFFFFFFFFFFFFFFF")  # random garbage
630        cls.p = TLSHandshake(cls.data)
631
632    def test_client_hello_constructed(self):
633        """Make sure the correct class was constructed"""
634        # print self.p
635        assert (isinstance(self.p.data, TLSClientHello) is True)
636
637    #   def testClientDateCorrect(self):
638    #       self.assertEqual(self.p.random_unixtime, 1342710284)
639
640    def test_client_random_correct(self):
641        assert (self.p.data.random == _hexdecode(b'5008220ce5e0e78b6891afe204498c9363feffbe03235a2d9e05b7d990eb708d'))
642
643    def test_cipher_suite(self):
644        assert (tuple([c.code for c in self.p.data.ciphersuites]) == struct.unpack('!{0}H'.format(
645            len(self.p.data.ciphersuites)), _hexdecode(
646            b'00ffc00ac0140088008700390038c00fc00500840035c007c009c011c0130045004400330032c00c'
647            b'c00ec002c0040096004100050004002fc008c01200160013c00dc003000ac006c010c00bc00100020001')))
648        assert (len(self.p.data.ciphersuites) == 41)
649
650    def test_session_id(self):
651        assert (self.p.data.session_id == _hexdecode(b'09bc0192e008e6fa8fe47998fca91311ba30ddde14a9587dc674b11c3d3e5ed1'))
652
653    def test_compression_methods(self):
654        assert (list(self.p.data.compression_methods) == [0x00, ])
655
656    def test_total_length(self):
657        assert (len(self.p) == 413)
658
659
660class TestServerHello(object):
661    """Again, from Wireshark"""
662
663    @classmethod
664    def setup_class(cls):
665        cls.data = _hexdecode(
666            b'0200004d03015008220c8ec43c5462315a7c99f5d5b6bff009ad285b51dc18485f352e9fdecd2009'
667            b'bc0192e008e6fa8fe47998fca91311ba30ddde14a9587dc674b11c3d3e5ed10002000005ff01000100')
668        cls.p = TLSHandshake(cls.data)
669
670    def test_constructed(self):
671        assert (isinstance(self.p.data, TLSServerHello) is True)
672
673    #    def testDateCorrect(self):
674    #        self.assertEqual(self.p.random_unixtime, 1342710284)
675
676    def test_random_correct(self):
677        assert (self.p.data.random == _hexdecode(b'5008220c8ec43c5462315a7c99f5d5b6bff009ad285b51dc18485f352e9fdecd'))
678
679    def test_cipher_suite(self):
680        assert (self.p.data.cipher_suite.name == 'TLS_RSA_WITH_NULL_SHA')
681
682    def test_total_length(self):
683        assert (len(self.p) == 81)
684
685
686class TestTLSCertificate(object):
687    """We use a 2016 certificate record from iana.org as test data."""
688
689    @classmethod
690    def setup_class(cls):
691        cls.p = TLSHandshake(
692            b'\x0b\x00\x0b\x45\x00\x0b\x42\x00\x06\x87\x30\x82\x06\x83\x30\x82\x05\x6b\xa0\x03\x02\x01\x02\x02\x10\x09\xca'
693            b'\xbb\xe2\x19\x1c\x8f\x56\x9d\xd4\xb6\xdd\x25\x0f\x21\xd8\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b'
694            b'\x05\x00\x30\x70\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x15\x30\x13\x06\x03\x55\x04\x0a\x13'
695            b'\x0c\x44\x69\x67\x69\x43\x65\x72\x74\x20\x49\x6e\x63\x31\x19\x30\x17\x06\x03\x55\x04\x0b\x13\x10\x77\x77\x77'
696            b'\x2e\x64\x69\x67\x69\x63\x65\x72\x74\x2e\x63\x6f\x6d\x31\x2f\x30\x2d\x06\x03\x55\x04\x03\x13\x26\x44\x69\x67'
697            b'\x69\x43\x65\x72\x74\x20\x53\x48\x41\x32\x20\x48\x69\x67\x68\x20\x41\x73\x73\x75\x72\x61\x6e\x63\x65\x20\x53'
698            b'\x65\x72\x76\x65\x72\x20\x43\x41\x30\x1e\x17\x0d\x31\x34\x31\x30\x32\x37\x30\x30\x30\x30\x30\x30\x5a\x17\x0d'
699            b'\x31\x38\x30\x31\x30\x33\x31\x32\x30\x30\x30\x30\x5a\x30\x81\xa3\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02'
700            b'\x55\x53\x31\x13\x30\x11\x06\x03\x55\x04\x08\x13\x0a\x43\x61\x6c\x69\x66\x6f\x72\x6e\x69\x61\x31\x14\x30\x12'
701            b'\x06\x03\x55\x04\x07\x13\x0b\x4c\x6f\x73\x20\x41\x6e\x67\x65\x6c\x65\x73\x31\x3c\x30\x3a\x06\x03\x55\x04\x0a'
702            b'\x13\x33\x49\x6e\x74\x65\x72\x6e\x65\x74\x20\x43\x6f\x72\x70\x6f\x72\x61\x74\x69\x6f\x6e\x20\x66\x6f\x72\x20'
703            b'\x41\x73\x73\x69\x67\x6e\x65\x64\x20\x4e\x61\x6d\x65\x73\x20\x61\x6e\x64\x20\x4e\x75\x6d\x62\x65\x72\x73\x31'
704            b'\x16\x30\x14\x06\x03\x55\x04\x0b\x13\x0d\x49\x54\x20\x4f\x70\x65\x72\x61\x74\x69\x6f\x6e\x73\x31\x13\x30\x11'
705            b'\x06\x03\x55\x04\x03\x0c\x0a\x2a\x2e\x69\x61\x6e\x61\x2e\x6f\x72\x67\x30\x82\x02\x22\x30\x0d\x06\x09\x2a\x86'
706            b'\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x02\x0f\x00\x30\x82\x02\x0a\x02\x82\x02\x01\x00\x9d\xbd\xfd\xde'
707            b'\xb5\xca\xe5\x3a\x55\x97\x47\xe2\xfd\xa6\x37\x28\xe4\xab\xa6\x0f\x18\xb7\x9a\x69\xf0\x33\x10\xbf\x01\x64\xe5'
708            b'\xee\x7d\xb6\xb1\x5b\xf5\x6d\xf2\x3f\xdd\xba\xe6\xa1\xbb\x38\x44\x9b\x8c\x88\x3f\x18\x10\x2b\xbd\x8b\xb6\x55'
709            b'\xac\x0e\x2d\xac\x2e\xe3\xed\x5c\xf4\x31\x58\x68\xd2\xc5\x98\x06\x82\x84\x85\x4b\x24\x89\x4d\xcd\x4b\xd3\x78'
710            b'\x11\xf0\xad\x3a\x28\x2c\xd4\xb4\xe5\x99\xff\xd0\x7d\x8d\x2d\x3f\x24\x78\x55\x4f\x81\x02\x0b\x32\x0e\xe1\x2f'
711            b'\x44\x94\x8e\x2e\xa1\xed\xbc\x99\x0b\x83\x0c\xa5\xcc\xa6\xb4\xa8\x39\xfb\x27\xb5\x18\x50\xc9\x84\x7e\xac\x74'
712            b'\xf2\x66\x09\xeb\x24\x36\x5b\x97\x51\xfb\x1c\x32\x08\xf5\x69\x13\xba\xcb\xca\xe4\x92\x01\x34\x7c\x78\xb7\xe5'
713            b'\x4a\x9d\x99\x97\x94\x04\xc3\x7f\x00\xfb\x65\xdb\x84\x9f\xd7\x5e\x3a\x68\x77\x0c\x30\xf2\xab\xe6\x5b\x33\x25'
714            b'\x6f\xb5\x9b\x45\x00\x50\xb0\x0d\x81\x39\xd4\xd8\x0d\x36\xf7\xbc\x46\xda\xf3\x03\xe4\x8f\x0f\x07\x91\xb2\xfd'
715            b'\xd7\x2e\xc6\x0b\x2c\xb3\xad\x53\x3c\x3f\x28\x8c\x9c\x19\x4e\x49\x33\x7a\x69\xc4\x96\x73\x1f\x08\x6d\x4f\x1f'
716            b'\x98\x25\x90\x07\x13\xe2\xa5\x51\xd0\x5c\xb6\x05\x75\x67\x85\x0d\x91\xe6\x00\x1c\x4c\xe2\x71\x76\xf0\x95\x78'
717            b'\x73\xa9\x5b\x88\x0a\xcb\xec\x19\xe7\xbd\x9b\xcf\x12\x86\xd0\x45\x2b\x73\x78\x9c\x41\x90\x5d\xd4\x70\x97\x1c'
718            b'\xd7\x3a\xea\x52\xc7\x7b\x08\x0c\xd7\x79\xaf\x58\x23\x4f\x33\x72\x25\xc2\x6f\x87\xa8\xc1\x3e\x2a\x65\xe9\xdd'
719            b'\x4e\x03\xa5\xb4\x1d\x7e\x06\xb3\x35\x3f\x38\x12\x9b\x23\x27\xa5\x31\xec\x96\x27\xa2\x1d\xc4\x23\x73\x3a\xa0'
720            b'\x29\xd4\x98\x94\x48\xba\x33\x22\x89\x1c\x1a\x56\x90\xdd\xf2\xd2\x5c\x8e\xc8\xaa\xa8\x94\xb1\x4a\xa9\x21\x30'
721            b'\xc6\xb6\xd9\x69\xa2\x1f\xf6\x71\xb6\x0c\x4c\x92\x3a\x94\xa9\x3e\xa1\xdd\x04\x92\xc9\x33\x93\xca\x6e\xdd\x61'
722            b'\xf3\x3c\xa7\x7e\x92\x08\xd0\x1d\x6b\xd1\x51\x07\x66\x2e\xc0\x88\x73\x3d\xf4\xc8\x76\xa7\xe1\x60\x8b\x82\x97'
723            b'\x3a\x0f\x75\x92\xe8\x4e\xd1\x55\x79\xd1\x81\xe7\x90\x24\xae\x8a\x7e\x4b\x9f\x00\x78\xeb\x20\x05\xb2\x3f\x9d'
724            b'\x09\xa1\xdf\x1b\xbc\x7d\xe2\xa5\xa6\x08\x5a\x36\x46\xd9\xfa\xdb\x0e\x9d\xa2\x73\xa5\xf4\x03\xcd\xd4\x28\x31'
725            b'\xce\x6f\x0c\xa4\x68\x89\x58\x56\x02\xbb\x8b\xc3\x6b\xb3\xbe\x86\x1f\xf6\xd1\xa6\x2e\x35\x02\x03\x01\x00\x01'
726            b'\xa3\x82\x01\xe3\x30\x82\x01\xdf\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x51\x68\xff\x90\xaf\x02'
727            b'\x07\x75\x3c\xcc\xd9\x65\x64\x62\xa2\x12\xb8\x59\x72\x3b\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\xc7\xd0'
728            b'\xac\xef\x89\x8b\x20\xe4\xb9\x14\x66\x89\x33\x03\x23\x94\xf6\xbf\x3a\x61\x30\x1f\x06\x03\x55\x1d\x11\x04\x18'
729            b'\x30\x16\x82\x0a\x2a\x2e\x69\x61\x6e\x61\x2e\x6f\x72\x67\x82\x08\x69\x61\x6e\x61\x2e\x6f\x72\x67\x30\x0e\x06'
730            b'\x03\x55\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x05\xa0\x30\x1d\x06\x03\x55\x1d\x25\x04\x16\x30\x14\x06\x08\x2b'
731            b'\x06\x01\x05\x05\x07\x03\x01\x06\x08\x2b\x06\x01\x05\x05\x07\x03\x02\x30\x75\x06\x03\x55\x1d\x1f\x04\x6e\x30'
732            b'\x6c\x30\x34\xa0\x32\xa0\x30\x86\x2e\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\x6c\x33\x2e\x64\x69\x67\x69\x63\x65'
733            b'\x72\x74\x2e\x63\x6f\x6d\x2f\x73\x68\x61\x32\x2d\x68\x61\x2d\x73\x65\x72\x76\x65\x72\x2d\x67\x33\x2e\x63\x72'
734            b'\x6c\x30\x34\xa0\x32\xa0\x30\x86\x2e\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\x6c\x34\x2e\x64\x69\x67\x69\x63\x65'
735            b'\x72\x74\x2e\x63\x6f\x6d\x2f\x73\x68\x61\x32\x2d\x68\x61\x2d\x73\x65\x72\x76\x65\x72\x2d\x67\x33\x2e\x63\x72'
736            b'\x6c\x30\x42\x06\x03\x55\x1d\x20\x04\x3b\x30\x39\x30\x37\x06\x09\x60\x86\x48\x01\x86\xfd\x6c\x01\x01\x30\x2a'
737            b'\x30\x28\x06\x08\x2b\x06\x01\x05\x05\x07\x02\x01\x16\x1c\x68\x74\x74\x70\x73\x3a\x2f\x2f\x77\x77\x77\x2e\x64'
738            b'\x69\x67\x69\x63\x65\x72\x74\x2e\x63\x6f\x6d\x2f\x43\x50\x53\x30\x81\x83\x06\x08\x2b\x06\x01\x05\x05\x07\x01'
739            b'\x01\x04\x77\x30\x75\x30\x24\x06\x08\x2b\x06\x01\x05\x05\x07\x30\x01\x86\x18\x68\x74\x74\x70\x3a\x2f\x2f\x6f'
740            b'\x63\x73\x70\x2e\x64\x69\x67\x69\x63\x65\x72\x74\x2e\x63\x6f\x6d\x30\x4d\x06\x08\x2b\x06\x01\x05\x05\x07\x30'
741            b'\x02\x86\x41\x68\x74\x74\x70\x3a\x2f\x2f\x63\x61\x63\x65\x72\x74\x73\x2e\x64\x69\x67\x69\x63\x65\x72\x74\x2e'
742            b'\x63\x6f\x6d\x2f\x44\x69\x67\x69\x43\x65\x72\x74\x53\x48\x41\x32\x48\x69\x67\x68\x41\x73\x73\x75\x72\x61\x6e'
743            b'\x63\x65\x53\x65\x72\x76\x65\x72\x43\x41\x2e\x63\x72\x74\x30\x0c\x06\x03\x55\x1d\x13\x01\x01\xff\x04\x02\x30'
744            b'\x00\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x70\x31\x4c\x38\xe7\xc0'
745            b'\x2f\xd8\x08\x10\x50\x0b\x9d\xf6\xda\xe8\x5d\xe9\xb2\x3e\x29\xfb\xd6\x8b\xfd\xb5\xf2\x34\x11\xc8\x9a\xcf\xaf'
746            b'\x9a\xe0\x5a\xf9\x12\x3a\x8a\xa6\xbc\xe6\x95\x4a\x4e\x68\xdc\x7c\xfc\x48\x0a\x65\xd7\x6f\x22\x9c\x4b\xd5\xf5'
747            b'\x67\x4b\x0c\x9a\xc6\xd0\x6a\x37\xa1\xa1\xc1\x45\xc3\x95\x61\x20\xb8\xef\xe6\x7c\x88\x7a\xb4\xff\x7d\x6a\xa9'
748            b'\x50\xff\x36\x98\xf2\x7c\x4a\x19\xd5\x9d\x93\xa3\x9a\xca\x5a\x7b\x6d\x6c\x75\xe3\x49\x74\xe5\x0f\x5a\x59\x00'
749            b'\x05\xb3\xcb\x66\x5d\xdb\xd7\x07\x4f\x9f\xcb\xcb\xf9\xc5\x02\x28\xd5\xe2\x55\x96\xb6\x4a\xda\x16\x0b\x48\xf7'
750            b'\x7a\x93\xaa\xce\xd2\x26\x17\xbf\xe0\x05\xe0\x0f\xe2\x0a\x53\x2a\x0a\xdc\xb8\x18\xc8\x78\xdc\x5d\x66\x49\x27'
751            b'\x77\x77\xca\x1a\x81\x4e\x21\xd0\xb5\x33\x08\xaf\x40\x78\xbe\x45\x54\x71\x5e\x4c\xe4\x82\x8b\x01\x2f\x25\xff'
752            b'\xa1\x3a\x6c\xeb\x30\xd2\x0a\x75\xde\xba\x8a\x34\x4e\x41\xd6\x27\xfa\x63\x8f\xef\xf3\x8a\x30\x63\xa0\x18\x75'
753            b'\x19\xb3\x9b\x05\x3f\x71\x34\xd9\xcd\x83\xe6\x09\x1a\xcc\xf5\xd2\xe3\xa0\x5e\xdf\xa1\xdf\xbe\x18\x1a\x87\xad'
754            b'\x86\xba\x24\xfe\x6b\x97\xfe\x00\x04\xb5\x30\x82\x04\xb1\x30\x82\x03\x99\xa0\x03\x02\x01\x02\x02\x10\x04\xe1'
755            b'\xe7\xa4\xdc\x5c\xf2\xf3\x6d\xc0\x2b\x42\xb8\x5d\x15\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0b'
756            b'\x05\x00\x30\x6c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x15\x30\x13\x06\x03\x55\x04\x0a\x13'
757            b'\x0c\x44\x69\x67\x69\x43\x65\x72\x74\x20\x49\x6e\x63\x31\x19\x30\x17\x06\x03\x55\x04\x0b\x13\x10\x77\x77\x77'
758            b'\x2e\x64\x69\x67\x69\x63\x65\x72\x74\x2e\x63\x6f\x6d\x31\x2b\x30\x29\x06\x03\x55\x04\x03\x13\x22\x44\x69\x67'
759            b'\x69\x43\x65\x72\x74\x20\x48\x69\x67\x68\x20\x41\x73\x73\x75\x72\x61\x6e\x63\x65\x20\x45\x56\x20\x52\x6f\x6f'
760            b'\x74\x20\x43\x41\x30\x1e\x17\x0d\x31\x33\x31\x30\x32\x32\x31\x32\x30\x30\x30\x30\x5a\x17\x0d\x32\x38\x31\x30'
761            b'\x32\x32\x31\x32\x30\x30\x30\x30\x5a\x30\x70\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31\x15\x30'
762            b'\x13\x06\x03\x55\x04\x0a\x13\x0c\x44\x69\x67\x69\x43\x65\x72\x74\x20\x49\x6e\x63\x31\x19\x30\x17\x06\x03\x55'
763            b'\x04\x0b\x13\x10\x77\x77\x77\x2e\x64\x69\x67\x69\x63\x65\x72\x74\x2e\x63\x6f\x6d\x31\x2f\x30\x2d\x06\x03\x55'
764            b'\x04\x03\x13\x26\x44\x69\x67\x69\x43\x65\x72\x74\x20\x53\x48\x41\x32\x20\x48\x69\x67\x68\x20\x41\x73\x73\x75'
765            b'\x72\x61\x6e\x63\x65\x20\x53\x65\x72\x76\x65\x72\x20\x43\x41\x30\x82\x01\x22\x30\x0d\x06\x09\x2a\x86\x48\x86'
766            b'\xf7\x0d\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x00\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xb6\xe0\x2f\xc2\x24\x06'
767            b'\xc8\x6d\x04\x5f\xd7\xef\x0a\x64\x06\xb2\x7d\x22\x26\x65\x16\xae\x42\x40\x9b\xce\xdc\x9f\x9f\x76\x07\x3e\xc3'
768            b'\x30\x55\x87\x19\xb9\x4f\x94\x0e\x5a\x94\x1f\x55\x56\xb4\xc2\x02\x2a\xaf\xd0\x98\xee\x0b\x40\xd7\xc4\xd0\x3b'
769            b'\x72\xc8\x14\x9e\xef\x90\xb1\x11\xa9\xae\xd2\xc8\xb8\x43\x3a\xd9\x0b\x0b\xd5\xd5\x95\xf5\x40\xaf\xc8\x1d\xed'
770            b'\x4d\x9c\x5f\x57\xb7\x86\x50\x68\x99\xf5\x8a\xda\xd2\xc7\x05\x1f\xa8\x97\xc9\xdc\xa4\xb1\x82\x84\x2d\xc6\xad'
771            b'\xa5\x9c\xc7\x19\x82\xa6\x85\x0f\x5e\x44\x58\x2a\x37\x8f\xfd\x35\xf1\x0b\x08\x27\x32\x5a\xf5\xbb\x8b\x9e\xa4'
772            b'\xbd\x51\xd0\x27\xe2\xdd\x3b\x42\x33\xa3\x05\x28\xc4\xbb\x28\xcc\x9a\xac\x2b\x23\x0d\x78\xc6\x7b\xe6\x5e\x71'
773            b'\xb7\x4a\x3e\x08\xfb\x81\xb7\x16\x16\xa1\x9d\x23\x12\x4d\xe5\xd7\x92\x08\xac\x75\xa4\x9c\xba\xcd\x17\xb2\x1e'
774            b'\x44\x35\x65\x7f\x53\x25\x39\xd1\x1c\x0a\x9a\x63\x1b\x19\x92\x74\x68\x0a\x37\xc2\xc2\x52\x48\xcb\x39\x5a\xa2'
775            b'\xb6\xe1\x5d\xc1\xdd\xa0\x20\xb8\x21\xa2\x93\x26\x6f\x14\x4a\x21\x41\xc7\xed\x6d\x9b\xf2\x48\x2f\xf3\x03\xf5'
776            b'\xa2\x68\x92\x53\x2f\x5e\xe3\x02\x03\x01\x00\x01\xa3\x82\x01\x49\x30\x82\x01\x45\x30\x12\x06\x03\x55\x1d\x13'
777            b'\x01\x01\xff\x04\x08\x30\x06\x01\x01\xff\x02\x01\x00\x30\x0e\x06\x03\x55\x1d\x0f\x01\x01\xff\x04\x04\x03\x02'
778            b'\x01\x86\x30\x1d\x06\x03\x55\x1d\x25\x04\x16\x30\x14\x06\x08\x2b\x06\x01\x05\x05\x07\x03\x01\x06\x08\x2b\x06'
779            b'\x01\x05\x05\x07\x03\x02\x30\x34\x06\x08\x2b\x06\x01\x05\x05\x07\x01\x01\x04\x28\x30\x26\x30\x24\x06\x08\x2b'
780            b'\x06\x01\x05\x05\x07\x30\x01\x86\x18\x68\x74\x74\x70\x3a\x2f\x2f\x6f\x63\x73\x70\x2e\x64\x69\x67\x69\x63\x65'
781            b'\x72\x74\x2e\x63\x6f\x6d\x30\x4b\x06\x03\x55\x1d\x1f\x04\x44\x30\x42\x30\x40\xa0\x3e\xa0\x3c\x86\x3a\x68\x74'
782            b'\x74\x70\x3a\x2f\x2f\x63\x72\x6c\x34\x2e\x64\x69\x67\x69\x63\x65\x72\x74\x2e\x63\x6f\x6d\x2f\x44\x69\x67\x69'
783            b'\x43\x65\x72\x74\x48\x69\x67\x68\x41\x73\x73\x75\x72\x61\x6e\x63\x65\x45\x56\x52\x6f\x6f\x74\x43\x41\x2e\x63'
784            b'\x72\x6c\x30\x3d\x06\x03\x55\x1d\x20\x04\x36\x30\x34\x30\x32\x06\x04\x55\x1d\x20\x00\x30\x2a\x30\x28\x06\x08'
785            b'\x2b\x06\x01\x05\x05\x07\x02\x01\x16\x1c\x68\x74\x74\x70\x73\x3a\x2f\x2f\x77\x77\x77\x2e\x64\x69\x67\x69\x63'
786            b'\x65\x72\x74\x2e\x63\x6f\x6d\x2f\x43\x50\x53\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x51\x68\xff\x90\xaf'
787            b'\x02\x07\x75\x3c\xcc\xd9\x65\x64\x62\xa2\x12\xb8\x59\x72\x3b\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80'
788            b'\x14\xb1\x3e\xc3\x69\x03\xf8\xbf\x47\x01\xd4\x98\x26\x1a\x08\x02\xef\x63\x64\x2b\xc3\x30\x0d\x06\x09\x2a\x86'
789            b'\x48\x86\xf7\x0d\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x18\x8a\x95\x89\x03\xe6\x6d\xdf\x5c\xfc\x1d\x68\xea'
790            b'\x4a\x8f\x83\xd6\x51\x2f\x8d\x6b\x44\x16\x9e\xac\x63\xf5\xd2\x6e\x6c\x84\x99\x8b\xaa\x81\x71\x84\x5b\xed\x34'
791            b'\x4e\xb0\xb7\x79\x92\x29\xcc\x2d\x80\x6a\xf0\x8e\x20\xe1\x79\xa4\xfe\x03\x47\x13\xea\xf5\x86\xca\x59\x71\x7d'
792            b'\xf4\x04\x96\x6b\xd3\x59\x58\x3d\xfe\xd3\x31\x25\x5c\x18\x38\x84\xa3\xe6\x9f\x82\xfd\x8c\x5b\x98\x31\x4e\xcd'
793            b'\x78\x9e\x1a\xfd\x85\xcb\x49\xaa\xf2\x27\x8b\x99\x72\xfc\x3e\xaa\xd5\x41\x0b\xda\xd5\x36\xa1\xbf\x1c\x6e\x47'
794            b'\x49\x7f\x5e\xd9\x48\x7c\x03\xd9\xfd\x8b\x49\xa0\x98\x26\x42\x40\xeb\xd6\x92\x11\xa4\x64\x0a\x57\x54\xc4\xf5'
795            b'\x1d\xd6\x02\x5e\x6b\xac\xee\xc4\x80\x9a\x12\x72\xfa\x56\x93\xd7\xff\xbf\x30\x85\x06\x30\xbf\x0b\x7f\x4e\xff'
796            b'\x57\x05\x9d\x24\xed\x85\xc3\x2b\xfb\xa6\x75\xa8\xac\x2d\x16\xef\x7d\x79\x27\xb2\xeb\xc2\x9d\x0b\x07\xea\xaa'
797            b'\x85\xd3\x01\xa3\x20\x28\x41\x59\x43\x28\xd2\x81\xe3\xaa\xf6\xec\x7b\x3b\x77\xb6\x40\x62\x80\x05\x41\x45\x01'
798            b'\xef\x17\x06\x3e\xde\xc0\x33\x9b\x67\xd3\x61\x2e\x72\x87\xe4\x69\xfc\x12\x00\x57\x40\x1e\x70\xf5\x1e\xc9\xb4'
799        )
800
801    def test_num_certs(self):
802        assert (len(self.p.data.certificates) == 2)
803
804
805class TestTLSMultiFactory(object):
806    """Made up test data"""
807    @classmethod
808    def setup_class(cls):
809        cls.data = _hexdecode(b'1703010010'  # header 1
810                              b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'  # data 1
811                              b'1703010010'  # header 2
812                              b'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB'  # data 2
813                              b'1703010010'  # header 3
814                              b'CCCCCCCC')  # data 3 (incomplete)
815        cls.msgs, cls.bytes_parsed = tls_multi_factory(cls.data)
816
817    def test_num_messages(self):
818        # only complete messages should be parsed, incomplete ones left
819        # in buffer
820        assert (len(self.msgs) == 2)
821
822    def test_bytes_parsed(self):
823        assert (self.bytes_parsed == (5 + 16) * 2)
824
825    def test_first_msg_data(self):
826        assert (self.msgs[0].data == _hexdecode(b'AA' * 16))
827
828    def test_second_msg_data(self):
829        assert (self.msgs[1].data == _hexdecode(b'BB' * 16))
830
831    def test_incomplete(self):
832        import pytest
833
834        msgs, n = tls_multi_factory(_hexdecode(b'17'))
835        assert (len(msgs) == 0)
836        assert (n == 0)
837        msgs, n = tls_multi_factory(_hexdecode(b'1703'))
838        assert (len(msgs) == 0)
839        assert (n == 0)
840        msgs, n = tls_multi_factory(_hexdecode(b'170301'))
841        assert (len(msgs) == 0)
842        assert (n == 0)
843        msgs, n = tls_multi_factory(_hexdecode(b'17030100'))
844        assert (len(msgs) == 0)
845        assert (n == 0)
846        msgs, n = tls_multi_factory(_hexdecode(b'1703010000'))
847        assert (len(msgs) == 1)
848        assert (n == 5)
849
850        with pytest.raises(SSL3Exception, match='Bad TLS version in buf: '):
851            tls_multi_factory(_hexdecode(b'000000000000'))
852
853
854def test_ssl2():
855    from binascii import unhexlify
856    buf_padding = unhexlify(
857        '0001'  # len
858        '02'    # padlen
859        '03'    # msg
860        '0405'  # pad
861        '0607'  # data
862    )
863    ssl2 = SSL2(buf_padding)
864    assert ssl2.len == 1
865    assert ssl2.msg == b'\x03'
866    assert ssl2.pad == b'\x04\x05'
867    assert ssl2.data == b'\x06\x07'
868
869    buf_no_padding = unhexlify(
870        '8001'  # len
871        '03'    # msg
872        '0607'  # data
873    )
874    ssl2 = SSL2(buf_no_padding)
875    assert ssl2.len == 1
876    assert ssl2.msg == b'\x03'
877    assert ssl2.data == b'\x06\x07'
878
879
880def test_clienthello_invalidcipher():
881    # NOTE: this test relies on ciphersuite 0x001c not being in ssl_ciphersuites.py CIPHERSUITES.
882    # IANA has reserved this value to avoid conflict with SSLv3, but if it gets reassigned,
883    # a new value should be chosen to fix this test.
884    import pytest
885    from binascii import unhexlify
886
887    buf = unhexlify(
888        '0301'  # version
889        '0000000000000000000000000000000000000000000000000000000000000000'  # random
890        '01'    # session_id length
891        '02'    # session_id
892        '0002'  # ciphersuites len
893        '001c'  # ciphersuite (reserved; not implemented
894    )
895    with pytest.raises(SSL3Exception, match='Unknown or invalid cipher suite type 1c'):
896        TLSClientHello(buf)
897
898
899def test_serverhello_invalidcipher():
900    # NOTE: this test relies on ciphersuite 0x001c not being in ssl_ciphersuites.py CIPHERSUITES.
901    # IANA has reserved this value to avoid conflict with SSLv3, but if it gets reassigned,
902    # a new value should be chosen to fix this test.
903    import pytest
904    from binascii import unhexlify
905
906    buf = unhexlify(
907        '0301'  # version
908        '0000000000000000000000000000000000000000000000000000000000000000'  # random
909        '01'    # session_id length
910        '02'    # session_id
911        '001c'  # ciphersuite (reserved; not implemented
912    )
913    with pytest.raises(SSL3Exception, match='Unknown or invalid cipher suite type 1c'):
914        TLSServerHello(buf)
915
916    # remove the final byte from the ciphersuite so it will fail unpacking
917    buf = buf[:-1]
918    with pytest.raises(dpkt.NeedData):
919        TLSServerHello(buf)
920
921
922def test_tlscertificate_unpacking_error():
923    import pytest
924    from binascii import unhexlify
925    buf = unhexlify(
926        '000003'  # certs len
927        '0000'    # certs (invalid, as size < 3)
928    )
929    with pytest.raises(dpkt.NeedData):
930        TLSCertificate(buf)
931
932
933def test_tlshandshake_invalid_type():
934    import pytest
935    from binascii import unhexlify
936    buf = unhexlify(
937        '7b'      # type (invalid)
938        '000000'  # length_bytes
939    )
940    with pytest.raises(SSL3Exception, match='Unknown or invalid handshake type 123'):
941        TLSHandshake(buf)
942
943
944def test_sslfactory():
945    from binascii import unhexlify
946    buf_tls31 = unhexlify(
947        '00'     # type
948        '0301'   # version
949        '0000'   # length
950    )
951    tls = SSLFactory(buf_tls31)
952    assert isinstance(tls, TLSRecord)
953
954    buf_ssl2 = unhexlify(
955        '00'    # type
956        '0000'  # not an SSL3+ version
957    )
958    ssl2 = SSLFactory(buf_ssl2)
959    assert isinstance(ssl2, SSL2)
960