xref: /aosp_15_r20/external/openthread/tests/scripts/thread-cert/dtls.py (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1*cfb92d14SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*cfb92d14SAndroid Build Coastguard Worker#
3*cfb92d14SAndroid Build Coastguard Worker#  Copyright (c) 2019, The OpenThread Authors.
4*cfb92d14SAndroid Build Coastguard Worker#  All rights reserved.
5*cfb92d14SAndroid Build Coastguard Worker#
6*cfb92d14SAndroid Build Coastguard Worker#  Redistribution and use in source and binary forms, with or without
7*cfb92d14SAndroid Build Coastguard Worker#  modification, are permitted provided that the following conditions are met:
8*cfb92d14SAndroid Build Coastguard Worker#  1. Redistributions of source code must retain the above copyright
9*cfb92d14SAndroid Build Coastguard Worker#     notice, this list of conditions and the following disclaimer.
10*cfb92d14SAndroid Build Coastguard Worker#  2. Redistributions in binary form must reproduce the above copyright
11*cfb92d14SAndroid Build Coastguard Worker#     notice, this list of conditions and the following disclaimer in the
12*cfb92d14SAndroid Build Coastguard Worker#     documentation and/or other materials provided with the distribution.
13*cfb92d14SAndroid Build Coastguard Worker#  3. Neither the name of the copyright holder nor the
14*cfb92d14SAndroid Build Coastguard Worker#     names of its contributors may be used to endorse or promote products
15*cfb92d14SAndroid Build Coastguard Worker#     derived from this software without specific prior written permission.
16*cfb92d14SAndroid Build Coastguard Worker#
17*cfb92d14SAndroid Build Coastguard Worker#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18*cfb92d14SAndroid Build Coastguard Worker#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*cfb92d14SAndroid Build Coastguard Worker#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*cfb92d14SAndroid Build Coastguard Worker#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21*cfb92d14SAndroid Build Coastguard Worker#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*cfb92d14SAndroid Build Coastguard Worker#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*cfb92d14SAndroid Build Coastguard Worker#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*cfb92d14SAndroid Build Coastguard Worker#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*cfb92d14SAndroid Build Coastguard Worker#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*cfb92d14SAndroid Build Coastguard Worker#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*cfb92d14SAndroid Build Coastguard Worker#  POSSIBILITY OF SUCH DAMAGE.
28*cfb92d14SAndroid Build Coastguard Worker#
29*cfb92d14SAndroid Build Coastguard Worker
30*cfb92d14SAndroid Build Coastguard Workerfrom enum import IntEnum
31*cfb92d14SAndroid Build Coastguard Workerfrom functools import reduce
32*cfb92d14SAndroid Build Coastguard Workerimport io
33*cfb92d14SAndroid Build Coastguard Workerimport struct
34*cfb92d14SAndroid Build Coastguard Worker
35*cfb92d14SAndroid Build Coastguard Workerfrom ipv6 import BuildableFromBytes
36*cfb92d14SAndroid Build Coastguard Workerfrom ipv6 import ConvertibleToBytes
37*cfb92d14SAndroid Build Coastguard Worker
38*cfb92d14SAndroid Build Coastguard Worker
39*cfb92d14SAndroid Build Coastguard Workerclass HandshakeType(IntEnum):
40*cfb92d14SAndroid Build Coastguard Worker    HELLO_REQUEST = 0
41*cfb92d14SAndroid Build Coastguard Worker    CLIENT_HELLO = 1
42*cfb92d14SAndroid Build Coastguard Worker    SERVER_HELLO = 2
43*cfb92d14SAndroid Build Coastguard Worker    HELLO_VERIFY_REQUEST = 3
44*cfb92d14SAndroid Build Coastguard Worker    CERTIFICATE = 11
45*cfb92d14SAndroid Build Coastguard Worker    SERVER_KEY_EXCHANGE = 12
46*cfb92d14SAndroid Build Coastguard Worker    CERTIFICATE_REQUEST = 13
47*cfb92d14SAndroid Build Coastguard Worker    SERVER_HELLO_DONE = 14
48*cfb92d14SAndroid Build Coastguard Worker    CERTIFICATE_VERIFY = 15
49*cfb92d14SAndroid Build Coastguard Worker    CLIENT_KEY_EXCHANGE = 16
50*cfb92d14SAndroid Build Coastguard Worker    FINISHED = 20
51*cfb92d14SAndroid Build Coastguard Worker
52*cfb92d14SAndroid Build Coastguard Worker
53*cfb92d14SAndroid Build Coastguard Workerclass ContentType(IntEnum):
54*cfb92d14SAndroid Build Coastguard Worker    CHANGE_CIPHER_SPEC = 20
55*cfb92d14SAndroid Build Coastguard Worker    ALERT = 21
56*cfb92d14SAndroid Build Coastguard Worker    HANDSHAKE = 22
57*cfb92d14SAndroid Build Coastguard Worker    APPLICATION_DATA = 23
58*cfb92d14SAndroid Build Coastguard Worker
59*cfb92d14SAndroid Build Coastguard Worker
60*cfb92d14SAndroid Build Coastguard Workerclass AlertLevel(IntEnum):
61*cfb92d14SAndroid Build Coastguard Worker    WARNING = 1
62*cfb92d14SAndroid Build Coastguard Worker    FATAL = 2
63*cfb92d14SAndroid Build Coastguard Worker
64*cfb92d14SAndroid Build Coastguard Worker
65*cfb92d14SAndroid Build Coastguard Workerclass AlertDescription(IntEnum):
66*cfb92d14SAndroid Build Coastguard Worker    CLOSE_NOTIFY = 0
67*cfb92d14SAndroid Build Coastguard Worker    UNEXPECTED_MESSAGE = 10
68*cfb92d14SAndroid Build Coastguard Worker    BAD_RECORD_MAC = 20
69*cfb92d14SAndroid Build Coastguard Worker    DECRYPTION_FAILED_RESERVED = 21
70*cfb92d14SAndroid Build Coastguard Worker    RECORD_OVERFLOW = 22
71*cfb92d14SAndroid Build Coastguard Worker    DECOMPRESSION_FAILURE = 30
72*cfb92d14SAndroid Build Coastguard Worker    HANDSHAKE_FAILURE = 40
73*cfb92d14SAndroid Build Coastguard Worker    NO_CERTIFICATE_RESERVED = 41
74*cfb92d14SAndroid Build Coastguard Worker    BAD_CERTIFICATE = 42
75*cfb92d14SAndroid Build Coastguard Worker    UNSUPPORTED_CERTIFICATE = 43
76*cfb92d14SAndroid Build Coastguard Worker    CERTIFICATE_REVOKED = 44
77*cfb92d14SAndroid Build Coastguard Worker    CERTIFICATE_EXPIRED = 45
78*cfb92d14SAndroid Build Coastguard Worker    CERTIFICATE_UNKNOWN = 46
79*cfb92d14SAndroid Build Coastguard Worker    ILLEGAL_PARAMETER = 47
80*cfb92d14SAndroid Build Coastguard Worker    UNKNOWN_CA = 48
81*cfb92d14SAndroid Build Coastguard Worker    ACCESS_DENIED = 49
82*cfb92d14SAndroid Build Coastguard Worker    DECODE_ERROR = 50
83*cfb92d14SAndroid Build Coastguard Worker    DECRYPT_ERROR = 51
84*cfb92d14SAndroid Build Coastguard Worker    EXPORT_RESTRICTION_RESERVED = 60
85*cfb92d14SAndroid Build Coastguard Worker    PROTOCOL_VERSION = 70
86*cfb92d14SAndroid Build Coastguard Worker    INSUFFICIENT_SECURITY = 71
87*cfb92d14SAndroid Build Coastguard Worker    INTERNAL_ERROR = 80
88*cfb92d14SAndroid Build Coastguard Worker    USER_CANCELED = 90
89*cfb92d14SAndroid Build Coastguard Worker    NO_RENEGOTIATION = 100
90*cfb92d14SAndroid Build Coastguard Worker    UNSUPPORTED_EXTENSION = 110
91*cfb92d14SAndroid Build Coastguard Worker
92*cfb92d14SAndroid Build Coastguard Worker
93*cfb92d14SAndroid Build Coastguard Workerclass Record(ConvertibleToBytes, BuildableFromBytes):
94*cfb92d14SAndroid Build Coastguard Worker
95*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, content_type, version, epoch, sequence_number, length, fragment):
96*cfb92d14SAndroid Build Coastguard Worker        self.content_type = content_type
97*cfb92d14SAndroid Build Coastguard Worker        self.version = version
98*cfb92d14SAndroid Build Coastguard Worker        self.epoch = epoch
99*cfb92d14SAndroid Build Coastguard Worker        self.sequence_number = sequence_number
100*cfb92d14SAndroid Build Coastguard Worker        self.length = length
101*cfb92d14SAndroid Build Coastguard Worker        self.fragment = fragment
102*cfb92d14SAndroid Build Coastguard Worker
103*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
104*cfb92d14SAndroid Build Coastguard Worker        return (struct.pack(">B", self.content_type) + self.version.to_bytes() + struct.pack(">H", self.epoch) +
105*cfb92d14SAndroid Build Coastguard Worker                self.sequence_number.to_bytes(6, byteorder='big') + struct.pack(">H", self.length) + self.fragment)
106*cfb92d14SAndroid Build Coastguard Worker
107*cfb92d14SAndroid Build Coastguard Worker    @classmethod
108*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
109*cfb92d14SAndroid Build Coastguard Worker        content_type = ContentType(struct.unpack(">B", data.read(1))[0])
110*cfb92d14SAndroid Build Coastguard Worker        version = ProtocolVersion.from_bytes(data)
111*cfb92d14SAndroid Build Coastguard Worker        epoch = struct.unpack(">H", data.read(2))[0]
112*cfb92d14SAndroid Build Coastguard Worker        sequence_number = struct.unpack(">Q", b'\x00\x00' + data.read(6))[0]
113*cfb92d14SAndroid Build Coastguard Worker        length = struct.unpack(">H", data.read(2))[0]
114*cfb92d14SAndroid Build Coastguard Worker        fragment = bytes(data.read(length))
115*cfb92d14SAndroid Build Coastguard Worker        return cls(content_type, version, epoch, sequence_number, length, fragment)
116*cfb92d14SAndroid Build Coastguard Worker
117*cfb92d14SAndroid Build Coastguard Worker    def __repr__(self):
118*cfb92d14SAndroid Build Coastguard Worker        return "Record(content_type={}, version={}, epoch={}, sequence_number={}, length={})".format(
119*cfb92d14SAndroid Build Coastguard Worker            str(self.content_type),
120*cfb92d14SAndroid Build Coastguard Worker            self.version,
121*cfb92d14SAndroid Build Coastguard Worker            self.epoch,
122*cfb92d14SAndroid Build Coastguard Worker            self.sequence_number,
123*cfb92d14SAndroid Build Coastguard Worker            self.length,
124*cfb92d14SAndroid Build Coastguard Worker        )
125*cfb92d14SAndroid Build Coastguard Worker
126*cfb92d14SAndroid Build Coastguard Worker
127*cfb92d14SAndroid Build Coastguard Workerclass Message(ConvertibleToBytes, BuildableFromBytes):
128*cfb92d14SAndroid Build Coastguard Worker
129*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, content_type):
130*cfb92d14SAndroid Build Coastguard Worker        self.content_type = content_type
131*cfb92d14SAndroid Build Coastguard Worker
132*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
133*cfb92d14SAndroid Build Coastguard Worker        raise NotImplementedError
134*cfb92d14SAndroid Build Coastguard Worker
135*cfb92d14SAndroid Build Coastguard Worker    @classmethod
136*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
137*cfb92d14SAndroid Build Coastguard Worker        raise NotImplementedError
138*cfb92d14SAndroid Build Coastguard Worker
139*cfb92d14SAndroid Build Coastguard Worker
140*cfb92d14SAndroid Build Coastguard Workerclass HandshakeMessage(Message):
141*cfb92d14SAndroid Build Coastguard Worker
142*cfb92d14SAndroid Build Coastguard Worker    def __init__(
143*cfb92d14SAndroid Build Coastguard Worker        self,
144*cfb92d14SAndroid Build Coastguard Worker        handshake_type,
145*cfb92d14SAndroid Build Coastguard Worker        length,
146*cfb92d14SAndroid Build Coastguard Worker        message_seq,
147*cfb92d14SAndroid Build Coastguard Worker        fragment_offset,
148*cfb92d14SAndroid Build Coastguard Worker        fragment_length,
149*cfb92d14SAndroid Build Coastguard Worker        body,
150*cfb92d14SAndroid Build Coastguard Worker    ):
151*cfb92d14SAndroid Build Coastguard Worker        super(HandshakeMessage, self).__init__(ContentType.HANDSHAKE)
152*cfb92d14SAndroid Build Coastguard Worker        self.handshake_type = handshake_type
153*cfb92d14SAndroid Build Coastguard Worker        self.length = length
154*cfb92d14SAndroid Build Coastguard Worker        self.message_seq = message_seq
155*cfb92d14SAndroid Build Coastguard Worker        self.fragment_offset = fragment_offset
156*cfb92d14SAndroid Build Coastguard Worker        self.fragment_length = fragment_length
157*cfb92d14SAndroid Build Coastguard Worker        self.body = body
158*cfb92d14SAndroid Build Coastguard Worker
159*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
160*cfb92d14SAndroid Build Coastguard Worker        return (struct.pack(">B", self.handshake_type) + struct.pack(">I", self.length)[1:] +
161*cfb92d14SAndroid Build Coastguard Worker                struct.pack(">H", self.message_seq) + struct.pack(">I", self.fragment_offset)[1:] +
162*cfb92d14SAndroid Build Coastguard Worker                struct.pack(">I", self.fragment_length)[1:] + self.body.to_bytes())
163*cfb92d14SAndroid Build Coastguard Worker
164*cfb92d14SAndroid Build Coastguard Worker    @classmethod
165*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
166*cfb92d14SAndroid Build Coastguard Worker        handshake_type = HandshakeType(struct.unpack(">B", data.read(1))[0])
167*cfb92d14SAndroid Build Coastguard Worker        length = struct.unpack(">I", b'\x00' + data.read(3))[0]
168*cfb92d14SAndroid Build Coastguard Worker        message_seq = struct.unpack(">H", data.read(2))[0]
169*cfb92d14SAndroid Build Coastguard Worker        fragment_offset = struct.unpack(">I", b'\x00' + bytes(data.read(3)))[0]
170*cfb92d14SAndroid Build Coastguard Worker        fragment_length = struct.unpack(">I", b'\x00' + bytes(data.read(3)))[0]
171*cfb92d14SAndroid Build Coastguard Worker        end_position = data.tell() + fragment_length
172*cfb92d14SAndroid Build Coastguard Worker        # TODO(wgtdkp): handle fragmentation
173*cfb92d14SAndroid Build Coastguard Worker
174*cfb92d14SAndroid Build Coastguard Worker        message_class, body = handshake_map[handshake_type], None
175*cfb92d14SAndroid Build Coastguard Worker        if message_class:
176*cfb92d14SAndroid Build Coastguard Worker            body = message_class.from_bytes(data)
177*cfb92d14SAndroid Build Coastguard Worker        else:
178*cfb92d14SAndroid Build Coastguard Worker            print("{} messages are not handled".format(str(handshake_type)))
179*cfb92d14SAndroid Build Coastguard Worker            body = bytes(data.read(fragment_length))
180*cfb92d14SAndroid Build Coastguard Worker        assert data.tell() == end_position
181*cfb92d14SAndroid Build Coastguard Worker
182*cfb92d14SAndroid Build Coastguard Worker        return cls(
183*cfb92d14SAndroid Build Coastguard Worker            handshake_type,
184*cfb92d14SAndroid Build Coastguard Worker            length,
185*cfb92d14SAndroid Build Coastguard Worker            message_seq,
186*cfb92d14SAndroid Build Coastguard Worker            fragment_offset,
187*cfb92d14SAndroid Build Coastguard Worker            fragment_length,
188*cfb92d14SAndroid Build Coastguard Worker            body,
189*cfb92d14SAndroid Build Coastguard Worker        )
190*cfb92d14SAndroid Build Coastguard Worker
191*cfb92d14SAndroid Build Coastguard Worker    def __repr__(self):
192*cfb92d14SAndroid Build Coastguard Worker        return "Handshake(type={}, length={})".format(str(self.handshake_type), self.length)
193*cfb92d14SAndroid Build Coastguard Worker
194*cfb92d14SAndroid Build Coastguard Worker
195*cfb92d14SAndroid Build Coastguard Workerclass ProtocolVersion(ConvertibleToBytes, BuildableFromBytes):
196*cfb92d14SAndroid Build Coastguard Worker
197*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, major, minor):
198*cfb92d14SAndroid Build Coastguard Worker        self.major = major
199*cfb92d14SAndroid Build Coastguard Worker        self.minor = minor
200*cfb92d14SAndroid Build Coastguard Worker
201*cfb92d14SAndroid Build Coastguard Worker    def __eq__(self, other):
202*cfb92d14SAndroid Build Coastguard Worker        return (isinstance(self, type(other)) and self.major == other.major and self.minor == other.minor)
203*cfb92d14SAndroid Build Coastguard Worker
204*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
205*cfb92d14SAndroid Build Coastguard Worker        return struct.pack(">BB", self.major, self.minor)
206*cfb92d14SAndroid Build Coastguard Worker
207*cfb92d14SAndroid Build Coastguard Worker    @classmethod
208*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
209*cfb92d14SAndroid Build Coastguard Worker        major, minor = struct.unpack(">BB", data.read(2))
210*cfb92d14SAndroid Build Coastguard Worker        return cls(major, minor)
211*cfb92d14SAndroid Build Coastguard Worker
212*cfb92d14SAndroid Build Coastguard Worker    def __repr__(self):
213*cfb92d14SAndroid Build Coastguard Worker        return "ProtocolVersion(major={}, minor={})".format(self.major, self.minor)
214*cfb92d14SAndroid Build Coastguard Worker
215*cfb92d14SAndroid Build Coastguard Worker
216*cfb92d14SAndroid Build Coastguard Workerclass Random(ConvertibleToBytes, BuildableFromBytes):
217*cfb92d14SAndroid Build Coastguard Worker
218*cfb92d14SAndroid Build Coastguard Worker    random_bytes_length = 28
219*cfb92d14SAndroid Build Coastguard Worker
220*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, gmt_unix_time, random_bytes):
221*cfb92d14SAndroid Build Coastguard Worker        self.gmt_unix_time = gmt_unix_time
222*cfb92d14SAndroid Build Coastguard Worker        self.random_bytes = random_bytes
223*cfb92d14SAndroid Build Coastguard Worker        assert len(self.random_bytes) == Random.random_bytes_length
224*cfb92d14SAndroid Build Coastguard Worker
225*cfb92d14SAndroid Build Coastguard Worker    def __eq__(self, other):
226*cfb92d14SAndroid Build Coastguard Worker        return (isinstance(self, type(other)) and self.gmt_unix_time == other.gmt_unix_time and
227*cfb92d14SAndroid Build Coastguard Worker                self.random_bytes == other.random_bytes)
228*cfb92d14SAndroid Build Coastguard Worker
229*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
230*cfb92d14SAndroid Build Coastguard Worker        return struct.pack(">I", self.gmt_unix_time) + (self.random_bytes)
231*cfb92d14SAndroid Build Coastguard Worker
232*cfb92d14SAndroid Build Coastguard Worker    @classmethod
233*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
234*cfb92d14SAndroid Build Coastguard Worker        gmt_unix_time = struct.unpack(">I", data.read(4))[0]
235*cfb92d14SAndroid Build Coastguard Worker        random_bytes = bytes(data.read(cls.random_bytes_length))
236*cfb92d14SAndroid Build Coastguard Worker        return cls(gmt_unix_time, random_bytes)
237*cfb92d14SAndroid Build Coastguard Worker
238*cfb92d14SAndroid Build Coastguard Worker
239*cfb92d14SAndroid Build Coastguard Workerclass VariableVector(ConvertibleToBytes):
240*cfb92d14SAndroid Build Coastguard Worker
241*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, subrange, ele_cls, elements):
242*cfb92d14SAndroid Build Coastguard Worker        self.subrange = subrange
243*cfb92d14SAndroid Build Coastguard Worker        self.ele_cls = ele_cls
244*cfb92d14SAndroid Build Coastguard Worker        self.elements = elements
245*cfb92d14SAndroid Build Coastguard Worker        assert self.subrange[0] <= len(self.elements) <= self.subrange[1]
246*cfb92d14SAndroid Build Coastguard Worker
247*cfb92d14SAndroid Build Coastguard Worker    def length(self):
248*cfb92d14SAndroid Build Coastguard Worker        return len(self.elements)
249*cfb92d14SAndroid Build Coastguard Worker
250*cfb92d14SAndroid Build Coastguard Worker    def __eq__(self, other):
251*cfb92d14SAndroid Build Coastguard Worker        return (isinstance(self, type(other)) and self.subrange == other.subrange and self.ele_cls == other.ele_cls and
252*cfb92d14SAndroid Build Coastguard Worker                self.elements == other.elements)
253*cfb92d14SAndroid Build Coastguard Worker
254*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
255*cfb92d14SAndroid Build Coastguard Worker        data = reduce(lambda ele, acc: acc + ele.to_bytes(), self.elements)
256*cfb92d14SAndroid Build Coastguard Worker        return VariableVector._encode_length(len(data), self.subrange) + data
257*cfb92d14SAndroid Build Coastguard Worker
258*cfb92d14SAndroid Build Coastguard Worker    @classmethod
259*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, ele_cls, subrange, data):
260*cfb92d14SAndroid Build Coastguard Worker        length = cls._decode_length(subrange, data)
261*cfb92d14SAndroid Build Coastguard Worker        end_position = data.tell() + length
262*cfb92d14SAndroid Build Coastguard Worker        elements = []
263*cfb92d14SAndroid Build Coastguard Worker        while data.tell() < end_position:
264*cfb92d14SAndroid Build Coastguard Worker            elements.append(ele_cls.from_bytes(data))
265*cfb92d14SAndroid Build Coastguard Worker        return cls(subrange, ele_cls, elements)
266*cfb92d14SAndroid Build Coastguard Worker
267*cfb92d14SAndroid Build Coastguard Worker    @classmethod
268*cfb92d14SAndroid Build Coastguard Worker    def _decode_length(cls, subrange, data):
269*cfb92d14SAndroid Build Coastguard Worker        length_in_byte = cls._calc_length_in_byte(subrange[1])
270*cfb92d14SAndroid Build Coastguard Worker        return reduce(
271*cfb92d14SAndroid Build Coastguard Worker            lambda acc, byte: (acc << 8) | byte,
272*cfb92d14SAndroid Build Coastguard Worker            bytearray(data.read(length_in_byte)),
273*cfb92d14SAndroid Build Coastguard Worker            0,
274*cfb92d14SAndroid Build Coastguard Worker        )
275*cfb92d14SAndroid Build Coastguard Worker
276*cfb92d14SAndroid Build Coastguard Worker    @classmethod
277*cfb92d14SAndroid Build Coastguard Worker    def _encode_length(cls, length, subrange):
278*cfb92d14SAndroid Build Coastguard Worker        length_in_byte = cls._calc_length_in_byte(subrange[1])
279*cfb92d14SAndroid Build Coastguard Worker        ret = bytearray([])
280*cfb92d14SAndroid Build Coastguard Worker        while length_in_byte > 0:
281*cfb92d14SAndroid Build Coastguard Worker            ret += bytes(length_in_byte & 0xff)
282*cfb92d14SAndroid Build Coastguard Worker            length_in_byte = length_in_byte >> 8
283*cfb92d14SAndroid Build Coastguard Worker        return ret
284*cfb92d14SAndroid Build Coastguard Worker
285*cfb92d14SAndroid Build Coastguard Worker    @classmethod
286*cfb92d14SAndroid Build Coastguard Worker    def _calc_length_in_byte(cls, ceiling):
287*cfb92d14SAndroid Build Coastguard Worker        return (ceiling.bit_length() + 7) // 8
288*cfb92d14SAndroid Build Coastguard Worker
289*cfb92d14SAndroid Build Coastguard Worker
290*cfb92d14SAndroid Build Coastguard Workerclass Opaque(ConvertibleToBytes, BuildableFromBytes):
291*cfb92d14SAndroid Build Coastguard Worker
292*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, byte):
293*cfb92d14SAndroid Build Coastguard Worker        self.byte = byte
294*cfb92d14SAndroid Build Coastguard Worker
295*cfb92d14SAndroid Build Coastguard Worker    def __eq__(self, other):
296*cfb92d14SAndroid Build Coastguard Worker        return isinstance(self, type(other)) and self.byte == other.byte
297*cfb92d14SAndroid Build Coastguard Worker
298*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
299*cfb92d14SAndroid Build Coastguard Worker        return struct.pack(">B", self.byte)
300*cfb92d14SAndroid Build Coastguard Worker
301*cfb92d14SAndroid Build Coastguard Worker    @classmethod
302*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
303*cfb92d14SAndroid Build Coastguard Worker        return cls(struct.unpack(">B", data.read(1))[0])
304*cfb92d14SAndroid Build Coastguard Worker
305*cfb92d14SAndroid Build Coastguard Worker
306*cfb92d14SAndroid Build Coastguard Workerclass CipherSuite(ConvertibleToBytes, BuildableFromBytes):
307*cfb92d14SAndroid Build Coastguard Worker
308*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, cipher):
309*cfb92d14SAndroid Build Coastguard Worker        self.cipher = cipher
310*cfb92d14SAndroid Build Coastguard Worker
311*cfb92d14SAndroid Build Coastguard Worker    def __eq__(self, other):
312*cfb92d14SAndroid Build Coastguard Worker        return isinstance(self, type(other)) and self.cipher == other.cipher
313*cfb92d14SAndroid Build Coastguard Worker
314*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
315*cfb92d14SAndroid Build Coastguard Worker        return struct.pack(">BB", self.cipher[0], self.cipher[1])
316*cfb92d14SAndroid Build Coastguard Worker
317*cfb92d14SAndroid Build Coastguard Worker    @classmethod
318*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
319*cfb92d14SAndroid Build Coastguard Worker        return cls(struct.unpack(">BB", data.read(2)))
320*cfb92d14SAndroid Build Coastguard Worker
321*cfb92d14SAndroid Build Coastguard Worker    def __repr__(self):
322*cfb92d14SAndroid Build Coastguard Worker        return "CipherSuite({}, {})".format(self.cipher[0], self.cipher[1])
323*cfb92d14SAndroid Build Coastguard Worker
324*cfb92d14SAndroid Build Coastguard Worker
325*cfb92d14SAndroid Build Coastguard Workerclass CompressionMethod(ConvertibleToBytes, BuildableFromBytes):
326*cfb92d14SAndroid Build Coastguard Worker
327*cfb92d14SAndroid Build Coastguard Worker    NULL = 0
328*cfb92d14SAndroid Build Coastguard Worker
329*cfb92d14SAndroid Build Coastguard Worker    def __init__(self):
330*cfb92d14SAndroid Build Coastguard Worker        pass
331*cfb92d14SAndroid Build Coastguard Worker
332*cfb92d14SAndroid Build Coastguard Worker    def __eq__(self, other):
333*cfb92d14SAndroid Build Coastguard Worker        return isinstance(self, type(other))
334*cfb92d14SAndroid Build Coastguard Worker
335*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
336*cfb92d14SAndroid Build Coastguard Worker        return struct.pack(">B", CompressionMethod.NULL)
337*cfb92d14SAndroid Build Coastguard Worker
338*cfb92d14SAndroid Build Coastguard Worker    @classmethod
339*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
340*cfb92d14SAndroid Build Coastguard Worker        method = struct.unpack(">B", data.read(1))[0]
341*cfb92d14SAndroid Build Coastguard Worker        assert method == cls.NULL
342*cfb92d14SAndroid Build Coastguard Worker        return cls()
343*cfb92d14SAndroid Build Coastguard Worker
344*cfb92d14SAndroid Build Coastguard Worker
345*cfb92d14SAndroid Build Coastguard Workerclass Extension(ConvertibleToBytes, BuildableFromBytes):
346*cfb92d14SAndroid Build Coastguard Worker
347*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, extension_type, extension_data):
348*cfb92d14SAndroid Build Coastguard Worker        self.extension_type = extension_type
349*cfb92d14SAndroid Build Coastguard Worker        self.extension_data = extension_data
350*cfb92d14SAndroid Build Coastguard Worker
351*cfb92d14SAndroid Build Coastguard Worker    def __eq__(self, other):
352*cfb92d14SAndroid Build Coastguard Worker        return (isinstance(self, type(other)) and self.extension_type == other.extension_type and
353*cfb92d14SAndroid Build Coastguard Worker                self.extension_data == other.extension_data)
354*cfb92d14SAndroid Build Coastguard Worker
355*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
356*cfb92d14SAndroid Build Coastguard Worker        return (struct.pack(">H", self.extension_type) + self.extension_data.to_bytes())
357*cfb92d14SAndroid Build Coastguard Worker
358*cfb92d14SAndroid Build Coastguard Worker    @classmethod
359*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
360*cfb92d14SAndroid Build Coastguard Worker        extension_type = struct.unpack(">H", data.read(2))[0]
361*cfb92d14SAndroid Build Coastguard Worker        extension_data = VariableVector.from_bytes(Opaque, (0, 2**16 - 1), data)
362*cfb92d14SAndroid Build Coastguard Worker        return cls(extension_type, extension_data)
363*cfb92d14SAndroid Build Coastguard Worker
364*cfb92d14SAndroid Build Coastguard Worker
365*cfb92d14SAndroid Build Coastguard Workerclass ClientHello(HandshakeMessage):
366*cfb92d14SAndroid Build Coastguard Worker
367*cfb92d14SAndroid Build Coastguard Worker    def __init__(
368*cfb92d14SAndroid Build Coastguard Worker        self,
369*cfb92d14SAndroid Build Coastguard Worker        client_version,
370*cfb92d14SAndroid Build Coastguard Worker        random,
371*cfb92d14SAndroid Build Coastguard Worker        session_id,
372*cfb92d14SAndroid Build Coastguard Worker        cookie,
373*cfb92d14SAndroid Build Coastguard Worker        cipher_suites,
374*cfb92d14SAndroid Build Coastguard Worker        compression_methods,
375*cfb92d14SAndroid Build Coastguard Worker        extensions,
376*cfb92d14SAndroid Build Coastguard Worker    ):
377*cfb92d14SAndroid Build Coastguard Worker        self.client_version = client_version
378*cfb92d14SAndroid Build Coastguard Worker        self.random = random
379*cfb92d14SAndroid Build Coastguard Worker        self.session_id = session_id
380*cfb92d14SAndroid Build Coastguard Worker        self.cookie = cookie
381*cfb92d14SAndroid Build Coastguard Worker        self.cipher_suites = cipher_suites
382*cfb92d14SAndroid Build Coastguard Worker        self.compression_methods = compression_methods
383*cfb92d14SAndroid Build Coastguard Worker        self.extensions = extensions
384*cfb92d14SAndroid Build Coastguard Worker
385*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
386*cfb92d14SAndroid Build Coastguard Worker        return (self.client_version.to_bytes() + self.random.to_bytes() + self.session_id.to_bytes() +
387*cfb92d14SAndroid Build Coastguard Worker                self.cookie.to_bytes() + self.cipher_suites.to_bytes() + self.compression_methods.to_bytes() +
388*cfb92d14SAndroid Build Coastguard Worker                self.extensions.to_bytes())
389*cfb92d14SAndroid Build Coastguard Worker
390*cfb92d14SAndroid Build Coastguard Worker    @classmethod
391*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
392*cfb92d14SAndroid Build Coastguard Worker        client_version = ProtocolVersion.from_bytes(data)
393*cfb92d14SAndroid Build Coastguard Worker        random = Random.from_bytes(data)
394*cfb92d14SAndroid Build Coastguard Worker        session_id = VariableVector.from_bytes(Opaque, (0, 32), data)
395*cfb92d14SAndroid Build Coastguard Worker        cookie = VariableVector.from_bytes(Opaque, (0, 2**8 - 1), data)
396*cfb92d14SAndroid Build Coastguard Worker        cipher_suites = VariableVector.from_bytes(CipherSuite, (2, 2**16 - 1), data)
397*cfb92d14SAndroid Build Coastguard Worker        compression_methods = VariableVector.from_bytes(CompressionMethod, (1, 2**8 - 1), data)
398*cfb92d14SAndroid Build Coastguard Worker        extensions = None
399*cfb92d14SAndroid Build Coastguard Worker        if data.tell() < len(data.getvalue()):
400*cfb92d14SAndroid Build Coastguard Worker            extensions = VariableVector.from_bytes(Extension, (0, 2**16 - 1), data)
401*cfb92d14SAndroid Build Coastguard Worker        return cls(
402*cfb92d14SAndroid Build Coastguard Worker            client_version,
403*cfb92d14SAndroid Build Coastguard Worker            random,
404*cfb92d14SAndroid Build Coastguard Worker            session_id,
405*cfb92d14SAndroid Build Coastguard Worker            cookie,
406*cfb92d14SAndroid Build Coastguard Worker            cipher_suites,
407*cfb92d14SAndroid Build Coastguard Worker            compression_methods,
408*cfb92d14SAndroid Build Coastguard Worker            extensions,
409*cfb92d14SAndroid Build Coastguard Worker        )
410*cfb92d14SAndroid Build Coastguard Worker
411*cfb92d14SAndroid Build Coastguard Worker
412*cfb92d14SAndroid Build Coastguard Workerclass HelloVerifyRequest(HandshakeMessage):
413*cfb92d14SAndroid Build Coastguard Worker
414*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, server_version, cookie):
415*cfb92d14SAndroid Build Coastguard Worker        self.server_version = server_version
416*cfb92d14SAndroid Build Coastguard Worker        self.cookie = cookie
417*cfb92d14SAndroid Build Coastguard Worker
418*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
419*cfb92d14SAndroid Build Coastguard Worker        return self.server_version.to_bytes() + self.cookie.to_bytes()
420*cfb92d14SAndroid Build Coastguard Worker
421*cfb92d14SAndroid Build Coastguard Worker    @classmethod
422*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
423*cfb92d14SAndroid Build Coastguard Worker        server_version = ProtocolVersion.from_bytes(data)
424*cfb92d14SAndroid Build Coastguard Worker        cookie = VariableVector.from_bytes(Opaque, (0, 2**8 - 1), data)
425*cfb92d14SAndroid Build Coastguard Worker        return cls(server_version, cookie)
426*cfb92d14SAndroid Build Coastguard Worker
427*cfb92d14SAndroid Build Coastguard Worker
428*cfb92d14SAndroid Build Coastguard Workerclass ServerHello(HandshakeMessage):
429*cfb92d14SAndroid Build Coastguard Worker
430*cfb92d14SAndroid Build Coastguard Worker    def __init__(
431*cfb92d14SAndroid Build Coastguard Worker        self,
432*cfb92d14SAndroid Build Coastguard Worker        server_version,
433*cfb92d14SAndroid Build Coastguard Worker        random,
434*cfb92d14SAndroid Build Coastguard Worker        session_id,
435*cfb92d14SAndroid Build Coastguard Worker        cipher_suite,
436*cfb92d14SAndroid Build Coastguard Worker        compression_method,
437*cfb92d14SAndroid Build Coastguard Worker        extensions,
438*cfb92d14SAndroid Build Coastguard Worker    ):
439*cfb92d14SAndroid Build Coastguard Worker        self.server_version = server_version
440*cfb92d14SAndroid Build Coastguard Worker        self.random = random
441*cfb92d14SAndroid Build Coastguard Worker        self.session_id = session_id
442*cfb92d14SAndroid Build Coastguard Worker        self.cipher_suite = cipher_suite
443*cfb92d14SAndroid Build Coastguard Worker        self.compression_method = compression_method
444*cfb92d14SAndroid Build Coastguard Worker        self.extensions = extensions
445*cfb92d14SAndroid Build Coastguard Worker
446*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
447*cfb92d14SAndroid Build Coastguard Worker        return (self.server_version.to_bytes() + self.random.to_bytes() + self.session_id.to_bytes() +
448*cfb92d14SAndroid Build Coastguard Worker                self.cipher_suite.to_bytes() + self.compression_method.to_bytes() + self.extensions.to_bytes())
449*cfb92d14SAndroid Build Coastguard Worker
450*cfb92d14SAndroid Build Coastguard Worker    @classmethod
451*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
452*cfb92d14SAndroid Build Coastguard Worker        server_version = ProtocolVersion.from_bytes(data)
453*cfb92d14SAndroid Build Coastguard Worker        random = Random.from_bytes(data)
454*cfb92d14SAndroid Build Coastguard Worker        session_id = VariableVector.from_bytes(Opaque, (0, 32), data)
455*cfb92d14SAndroid Build Coastguard Worker        cipher_suite = CipherSuite.from_bytes(data)
456*cfb92d14SAndroid Build Coastguard Worker        compression_method = CompressionMethod.from_bytes(data)
457*cfb92d14SAndroid Build Coastguard Worker        extensions = None
458*cfb92d14SAndroid Build Coastguard Worker        if data.tell() < len(data.getvalue()):
459*cfb92d14SAndroid Build Coastguard Worker            extensions = VariableVector.from_bytes(Extension, (0, 2**16 - 1), data)
460*cfb92d14SAndroid Build Coastguard Worker        return cls(
461*cfb92d14SAndroid Build Coastguard Worker            server_version,
462*cfb92d14SAndroid Build Coastguard Worker            random,
463*cfb92d14SAndroid Build Coastguard Worker            session_id,
464*cfb92d14SAndroid Build Coastguard Worker            cipher_suite,
465*cfb92d14SAndroid Build Coastguard Worker            compression_method,
466*cfb92d14SAndroid Build Coastguard Worker            extensions,
467*cfb92d14SAndroid Build Coastguard Worker        )
468*cfb92d14SAndroid Build Coastguard Worker
469*cfb92d14SAndroid Build Coastguard Worker
470*cfb92d14SAndroid Build Coastguard Workerclass ServerHelloDone(HandshakeMessage):
471*cfb92d14SAndroid Build Coastguard Worker
472*cfb92d14SAndroid Build Coastguard Worker    def __init__(self):
473*cfb92d14SAndroid Build Coastguard Worker        pass
474*cfb92d14SAndroid Build Coastguard Worker
475*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
476*cfb92d14SAndroid Build Coastguard Worker        return bytearray([])
477*cfb92d14SAndroid Build Coastguard Worker
478*cfb92d14SAndroid Build Coastguard Worker    @classmethod
479*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
480*cfb92d14SAndroid Build Coastguard Worker        return cls()
481*cfb92d14SAndroid Build Coastguard Worker
482*cfb92d14SAndroid Build Coastguard Worker
483*cfb92d14SAndroid Build Coastguard Workerclass HelloRequest(HandshakeMessage):
484*cfb92d14SAndroid Build Coastguard Worker
485*cfb92d14SAndroid Build Coastguard Worker    def __init__(self):
486*cfb92d14SAndroid Build Coastguard Worker        raise NotImplementedError
487*cfb92d14SAndroid Build Coastguard Worker
488*cfb92d14SAndroid Build Coastguard Worker
489*cfb92d14SAndroid Build Coastguard Workerclass Certificate(HandshakeMessage):
490*cfb92d14SAndroid Build Coastguard Worker
491*cfb92d14SAndroid Build Coastguard Worker    def __init__(self):
492*cfb92d14SAndroid Build Coastguard Worker        raise NotImplementedError
493*cfb92d14SAndroid Build Coastguard Worker
494*cfb92d14SAndroid Build Coastguard Worker
495*cfb92d14SAndroid Build Coastguard Workerclass ServerKeyExchange(HandshakeMessage):
496*cfb92d14SAndroid Build Coastguard Worker
497*cfb92d14SAndroid Build Coastguard Worker    def __init__(self):
498*cfb92d14SAndroid Build Coastguard Worker        raise NotImplementedError
499*cfb92d14SAndroid Build Coastguard Worker
500*cfb92d14SAndroid Build Coastguard Worker
501*cfb92d14SAndroid Build Coastguard Workerclass CertificateRequest(HandshakeMessage):
502*cfb92d14SAndroid Build Coastguard Worker
503*cfb92d14SAndroid Build Coastguard Worker    def __init__(self):
504*cfb92d14SAndroid Build Coastguard Worker        raise NotImplementedError
505*cfb92d14SAndroid Build Coastguard Worker
506*cfb92d14SAndroid Build Coastguard Worker
507*cfb92d14SAndroid Build Coastguard Workerclass CertificateVerify(HandshakeMessage):
508*cfb92d14SAndroid Build Coastguard Worker
509*cfb92d14SAndroid Build Coastguard Worker    def __init__(self):
510*cfb92d14SAndroid Build Coastguard Worker        raise NotImplementedError
511*cfb92d14SAndroid Build Coastguard Worker
512*cfb92d14SAndroid Build Coastguard Worker
513*cfb92d14SAndroid Build Coastguard Workerclass ClientKeyExchange(HandshakeMessage):
514*cfb92d14SAndroid Build Coastguard Worker
515*cfb92d14SAndroid Build Coastguard Worker    def __init__(self):
516*cfb92d14SAndroid Build Coastguard Worker        raise NotImplementedError
517*cfb92d14SAndroid Build Coastguard Worker
518*cfb92d14SAndroid Build Coastguard Worker
519*cfb92d14SAndroid Build Coastguard Workerclass Finished(HandshakeMessage):
520*cfb92d14SAndroid Build Coastguard Worker
521*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, verify_data):
522*cfb92d14SAndroid Build Coastguard Worker        raise NotImplementedError
523*cfb92d14SAndroid Build Coastguard Worker
524*cfb92d14SAndroid Build Coastguard Worker
525*cfb92d14SAndroid Build Coastguard Workerclass AlertMessage(Message):
526*cfb92d14SAndroid Build Coastguard Worker
527*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, level, description):
528*cfb92d14SAndroid Build Coastguard Worker        super(AlertMessage, self).__init__(ContentType.ALERT)
529*cfb92d14SAndroid Build Coastguard Worker        self.level = level
530*cfb92d14SAndroid Build Coastguard Worker        self.description = description
531*cfb92d14SAndroid Build Coastguard Worker
532*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
533*cfb92d14SAndroid Build Coastguard Worker        struct.pack(">BB", self.level, self.description)
534*cfb92d14SAndroid Build Coastguard Worker
535*cfb92d14SAndroid Build Coastguard Worker    @classmethod
536*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
537*cfb92d14SAndroid Build Coastguard Worker        level, description = struct.unpack(">BB", data.read(2))
538*cfb92d14SAndroid Build Coastguard Worker        try:
539*cfb92d14SAndroid Build Coastguard Worker            return cls(AlertLevel(level), AlertDescription(description))
540*cfb92d14SAndroid Build Coastguard Worker        except BaseException:
541*cfb92d14SAndroid Build Coastguard Worker            data.read()
542*cfb92d14SAndroid Build Coastguard Worker            # An AlertMessage could be encrypted and we can't parsing it.
543*cfb92d14SAndroid Build Coastguard Worker            return cls(None, None)
544*cfb92d14SAndroid Build Coastguard Worker
545*cfb92d14SAndroid Build Coastguard Worker    def __repr__(self):
546*cfb92d14SAndroid Build Coastguard Worker        return "Alert(level={}, description={})".format(str(self.level), str(self.description))
547*cfb92d14SAndroid Build Coastguard Worker
548*cfb92d14SAndroid Build Coastguard Worker
549*cfb92d14SAndroid Build Coastguard Workerclass ChangeCipherSpecMessage(Message):
550*cfb92d14SAndroid Build Coastguard Worker
551*cfb92d14SAndroid Build Coastguard Worker    def __init__(self):
552*cfb92d14SAndroid Build Coastguard Worker        super(ChangeCipherSpecMessage, self).__init__(ContentType.CHANGE_CIPHER_SPEC)
553*cfb92d14SAndroid Build Coastguard Worker
554*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
555*cfb92d14SAndroid Build Coastguard Worker        return struct.pack(">B", 1)
556*cfb92d14SAndroid Build Coastguard Worker
557*cfb92d14SAndroid Build Coastguard Worker    @classmethod
558*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
559*cfb92d14SAndroid Build Coastguard Worker        assert struct.unpack(">B", data.read(1))[0] == 1
560*cfb92d14SAndroid Build Coastguard Worker        return cls()
561*cfb92d14SAndroid Build Coastguard Worker
562*cfb92d14SAndroid Build Coastguard Worker    def __repr__(self):
563*cfb92d14SAndroid Build Coastguard Worker        return "ChangeCipherSpec(value=1)"
564*cfb92d14SAndroid Build Coastguard Worker
565*cfb92d14SAndroid Build Coastguard Worker
566*cfb92d14SAndroid Build Coastguard Workerclass ApplicationDataMessage(Message):
567*cfb92d14SAndroid Build Coastguard Worker
568*cfb92d14SAndroid Build Coastguard Worker    def __init__(self, raw):
569*cfb92d14SAndroid Build Coastguard Worker        super(ApplicationDataMessage, self).__init__(ContentType.APPLICATION_DATA)
570*cfb92d14SAndroid Build Coastguard Worker        self.raw = raw
571*cfb92d14SAndroid Build Coastguard Worker        self.body = None
572*cfb92d14SAndroid Build Coastguard Worker
573*cfb92d14SAndroid Build Coastguard Worker    def to_bytes(self):
574*cfb92d14SAndroid Build Coastguard Worker        return self.raw
575*cfb92d14SAndroid Build Coastguard Worker
576*cfb92d14SAndroid Build Coastguard Worker    @classmethod
577*cfb92d14SAndroid Build Coastguard Worker    def from_bytes(cls, data):
578*cfb92d14SAndroid Build Coastguard Worker        # It is safe to read until the end of this byte stream, because
579*cfb92d14SAndroid Build Coastguard Worker        # there is single application data message in a record.
580*cfb92d14SAndroid Build Coastguard Worker        length = len(data.getvalue()) - data.tell()
581*cfb92d14SAndroid Build Coastguard Worker        return cls(bytes(data.read(length)))
582*cfb92d14SAndroid Build Coastguard Worker
583*cfb92d14SAndroid Build Coastguard Worker    def __repr__(self):
584*cfb92d14SAndroid Build Coastguard Worker        if self.body:
585*cfb92d14SAndroid Build Coastguard Worker            return "ApplicationData(body={})".format(self.body)
586*cfb92d14SAndroid Build Coastguard Worker        else:
587*cfb92d14SAndroid Build Coastguard Worker            return "ApplicationData(raw_length={})".format(len(self.raw))
588*cfb92d14SAndroid Build Coastguard Worker
589*cfb92d14SAndroid Build Coastguard Worker
590*cfb92d14SAndroid Build Coastguard Workerhandshake_map = {
591*cfb92d14SAndroid Build Coastguard Worker    HandshakeType.HELLO_REQUEST: None,  # HelloRequest
592*cfb92d14SAndroid Build Coastguard Worker    HandshakeType.CLIENT_HELLO: ClientHello,
593*cfb92d14SAndroid Build Coastguard Worker    HandshakeType.SERVER_HELLO: ServerHello,
594*cfb92d14SAndroid Build Coastguard Worker    HandshakeType.HELLO_VERIFY_REQUEST: HelloVerifyRequest,
595*cfb92d14SAndroid Build Coastguard Worker    HandshakeType.CERTIFICATE: None,  # Certificate
596*cfb92d14SAndroid Build Coastguard Worker    HandshakeType.SERVER_KEY_EXCHANGE: None,  # ServerKeyExchange
597*cfb92d14SAndroid Build Coastguard Worker    HandshakeType.CERTIFICATE_REQUEST: None,  # CertificateRequest
598*cfb92d14SAndroid Build Coastguard Worker    HandshakeType.SERVER_HELLO_DONE: ServerHelloDone,
599*cfb92d14SAndroid Build Coastguard Worker    HandshakeType.CERTIFICATE_VERIFY: None,  # CertificateVerify
600*cfb92d14SAndroid Build Coastguard Worker    HandshakeType.CLIENT_KEY_EXCHANGE: None,  # ClientKeyExchange
601*cfb92d14SAndroid Build Coastguard Worker    HandshakeType.FINISHED: None,  # Finished
602*cfb92d14SAndroid Build Coastguard Worker}
603*cfb92d14SAndroid Build Coastguard Worker
604*cfb92d14SAndroid Build Coastguard Workercontent_map = {
605*cfb92d14SAndroid Build Coastguard Worker    ContentType.CHANGE_CIPHER_SPEC: ChangeCipherSpecMessage,
606*cfb92d14SAndroid Build Coastguard Worker    ContentType.ALERT: AlertMessage,
607*cfb92d14SAndroid Build Coastguard Worker    ContentType.HANDSHAKE: HandshakeMessage,
608*cfb92d14SAndroid Build Coastguard Worker    ContentType.APPLICATION_DATA: ApplicationDataMessage,
609*cfb92d14SAndroid Build Coastguard Worker}
610*cfb92d14SAndroid Build Coastguard Worker
611*cfb92d14SAndroid Build Coastguard Worker
612*cfb92d14SAndroid Build Coastguard Workerclass MessageFactory(object):
613*cfb92d14SAndroid Build Coastguard Worker
614*cfb92d14SAndroid Build Coastguard Worker    last_msg_is_change_cipher_spec = False
615*cfb92d14SAndroid Build Coastguard Worker
616*cfb92d14SAndroid Build Coastguard Worker    def __init__(self):
617*cfb92d14SAndroid Build Coastguard Worker        pass
618*cfb92d14SAndroid Build Coastguard Worker
619*cfb92d14SAndroid Build Coastguard Worker    def parse(self, data, message_info):
620*cfb92d14SAndroid Build Coastguard Worker        messages = []
621*cfb92d14SAndroid Build Coastguard Worker
622*cfb92d14SAndroid Build Coastguard Worker        # Multiple records could be sent in the same UDP datagram
623*cfb92d14SAndroid Build Coastguard Worker        while data.tell() < len(data.getvalue()):
624*cfb92d14SAndroid Build Coastguard Worker            record = Record.from_bytes(data)
625*cfb92d14SAndroid Build Coastguard Worker
626*cfb92d14SAndroid Build Coastguard Worker            if record.version.major != 0xfe or record.version.minor != 0xFD:
627*cfb92d14SAndroid Build Coastguard Worker                raise ValueError("DTLS version error, expect DTLSv1.2")
628*cfb92d14SAndroid Build Coastguard Worker
629*cfb92d14SAndroid Build Coastguard Worker            last_msg_is_change_cipher_spec = type(self).last_msg_is_change_cipher_spec
630*cfb92d14SAndroid Build Coastguard Worker            type(self).last_msg_is_change_cipher_spec = (record.content_type == ContentType.CHANGE_CIPHER_SPEC)
631*cfb92d14SAndroid Build Coastguard Worker
632*cfb92d14SAndroid Build Coastguard Worker            # FINISHED message immediately follows CHANGE_CIPHER_SPEC message
633*cfb92d14SAndroid Build Coastguard Worker            # We skip FINISHED message as it is encrypted
634*cfb92d14SAndroid Build Coastguard Worker            if last_msg_is_change_cipher_spec:
635*cfb92d14SAndroid Build Coastguard Worker                continue
636*cfb92d14SAndroid Build Coastguard Worker
637*cfb92d14SAndroid Build Coastguard Worker            fragment_data = io.BytesIO(record.fragment)
638*cfb92d14SAndroid Build Coastguard Worker
639*cfb92d14SAndroid Build Coastguard Worker            # Multiple handshake messages could be sent in the same record
640*cfb92d14SAndroid Build Coastguard Worker            while fragment_data.tell() < len(fragment_data.getvalue()):
641*cfb92d14SAndroid Build Coastguard Worker                content_class = content_map[record.content_type]
642*cfb92d14SAndroid Build Coastguard Worker                assert content_class
643*cfb92d14SAndroid Build Coastguard Worker                messages.append(content_class.from_bytes(fragment_data))
644*cfb92d14SAndroid Build Coastguard Worker
645*cfb92d14SAndroid Build Coastguard Worker        return messages
646