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