• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Authors:
2#   Trevor Perrin
3#   Google - handling CertificateRequest.certificate_types
4#   Google (adapted by Sam Rushing and Marcelo Fernandez) - NPN support
5#   Dimitris Moraitis - Anon ciphersuites
6#
7# See the LICENSE file for legal information regarding use of this file.
8
9"""Classes representing TLS messages."""
10
11from .utils.compat import *
12from .utils.cryptomath import *
13from .errors import *
14from .utils.codec import *
15from .constants import *
16from .x509 import X509
17from .x509certchain import X509CertChain
18from .utils.tackwrapper import *
19
20class RecordHeader3(object):
21    def __init__(self):
22        self.type = 0
23        self.version = (0,0)
24        self.length = 0
25        self.ssl2 = False
26
27    def create(self, version, type, length):
28        self.type = type
29        self.version = version
30        self.length = length
31        return self
32
33    def write(self):
34        w = Writer()
35        w.add(self.type, 1)
36        w.add(self.version[0], 1)
37        w.add(self.version[1], 1)
38        w.add(self.length, 2)
39        return w.bytes
40
41    def parse(self, p):
42        self.type = p.get(1)
43        self.version = (p.get(1), p.get(1))
44        self.length = p.get(2)
45        self.ssl2 = False
46        return self
47
48class RecordHeader2(object):
49    def __init__(self):
50        self.type = 0
51        self.version = (0,0)
52        self.length = 0
53        self.ssl2 = True
54
55    def parse(self, p):
56        if p.get(1)!=128:
57            raise SyntaxError()
58        self.type = ContentType.handshake
59        self.version = (2,0)
60        #We don't support 2-byte-length-headers; could be a problem
61        self.length = p.get(1)
62        return self
63
64
65class Alert(object):
66    def __init__(self):
67        self.contentType = ContentType.alert
68        self.level = 0
69        self.description = 0
70
71    def create(self, description, level=AlertLevel.fatal):
72        self.level = level
73        self.description = description
74        return self
75
76    def parse(self, p):
77        p.setLengthCheck(2)
78        self.level = p.get(1)
79        self.description = p.get(1)
80        p.stopLengthCheck()
81        return self
82
83    def write(self):
84        w = Writer()
85        w.add(self.level, 1)
86        w.add(self.description, 1)
87        return w.bytes
88
89
90class HandshakeMsg(object):
91    def __init__(self, handshakeType):
92        self.contentType = ContentType.handshake
93        self.handshakeType = handshakeType
94
95    def postWrite(self, w):
96        headerWriter = Writer()
97        headerWriter.add(self.handshakeType, 1)
98        headerWriter.add(len(w.bytes), 3)
99        return headerWriter.bytes + w.bytes
100
101class ClientHello(HandshakeMsg):
102    def __init__(self, ssl2=False):
103        HandshakeMsg.__init__(self, HandshakeType.client_hello)
104        self.ssl2 = ssl2
105        self.client_version = (0,0)
106        self.random = bytearray(32)
107        self.session_id = bytearray(0)
108        self.cipher_suites = []         # a list of 16-bit values
109        self.certificate_types = [CertificateType.x509]
110        self.compression_methods = []   # a list of 8-bit values
111        self.srp_username = None        # a string
112        self.tack = False
113        self.supports_npn = False
114        self.server_name = bytearray(0)
115        self.channel_id = False
116        self.support_signed_cert_timestamps = False
117        self.status_request = False
118
119    def create(self, version, random, session_id, cipher_suites,
120               certificate_types=None, srpUsername=None,
121               tack=False, supports_npn=False, serverName=None):
122        self.client_version = version
123        self.random = random
124        self.session_id = session_id
125        self.cipher_suites = cipher_suites
126        self.certificate_types = certificate_types
127        self.compression_methods = [0]
128        if srpUsername:
129            self.srp_username = bytearray(srpUsername, "utf-8")
130        self.tack = tack
131        self.supports_npn = supports_npn
132        if serverName:
133            self.server_name = bytearray(serverName, "utf-8")
134        return self
135
136    def parse(self, p):
137        if self.ssl2:
138            self.client_version = (p.get(1), p.get(1))
139            cipherSpecsLength = p.get(2)
140            sessionIDLength = p.get(2)
141            randomLength = p.get(2)
142            self.cipher_suites = p.getFixList(3, cipherSpecsLength//3)
143            self.session_id = p.getFixBytes(sessionIDLength)
144            self.random = p.getFixBytes(randomLength)
145            if len(self.random) < 32:
146                zeroBytes = 32-len(self.random)
147                self.random = bytearray(zeroBytes) + self.random
148            self.compression_methods = [0]#Fake this value
149
150            #We're not doing a stopLengthCheck() for SSLv2, oh well..
151        else:
152            p.startLengthCheck(3)
153            self.client_version = (p.get(1), p.get(1))
154            self.random = p.getFixBytes(32)
155            self.session_id = p.getVarBytes(1)
156            self.cipher_suites = p.getVarList(2, 2)
157            self.compression_methods = p.getVarList(1, 1)
158            if not p.atLengthCheck():
159                totalExtLength = p.get(2)
160                soFar = 0
161                while soFar != totalExtLength:
162                    extType = p.get(2)
163                    extLength = p.get(2)
164                    index1 = p.index
165                    if extType == ExtensionType.srp:
166                        self.srp_username = p.getVarBytes(1)
167                    elif extType == ExtensionType.cert_type:
168                        self.certificate_types = p.getVarList(1, 1)
169                    elif extType == ExtensionType.tack:
170                        self.tack = True
171                    elif extType == ExtensionType.supports_npn:
172                        self.supports_npn = True
173                    elif extType == ExtensionType.server_name:
174                        serverNameListBytes = p.getFixBytes(extLength)
175                        p2 = Parser(serverNameListBytes)
176                        p2.startLengthCheck(2)
177                        while 1:
178                            if p2.atLengthCheck():
179                                break # no host_name, oh well
180                            name_type = p2.get(1)
181                            hostNameBytes = p2.getVarBytes(2)
182                            if name_type == NameType.host_name:
183                                self.server_name = hostNameBytes
184                                break
185                    elif extType == ExtensionType.channel_id:
186                        self.channel_id = True
187                    elif extType == ExtensionType.signed_cert_timestamps:
188                        if extLength:
189                            raise SyntaxError()
190                        self.support_signed_cert_timestamps = True
191                    elif extType == ExtensionType.status_request:
192                        # Extension contents are currently ignored.
193                        # According to RFC 6066, this is not strictly forbidden
194                        # (although it is suboptimal):
195                        # Servers that receive a client hello containing the
196                        # "status_request" extension MAY return a suitable
197                        # certificate status response to the client along with
198                        # their certificate.  If OCSP is requested, they
199                        # SHOULD use the information contained in the extension
200                        # when selecting an OCSP responder and SHOULD include
201                        # request_extensions in the OCSP request.
202                        p.getFixBytes(extLength)
203                        self.status_request = True
204                    else:
205                        _ = p.getFixBytes(extLength)
206                    index2 = p.index
207                    if index2 - index1 != extLength:
208                        raise SyntaxError("Bad length for extension_data")
209                    soFar += 4 + extLength
210            p.stopLengthCheck()
211        return self
212
213    def write(self):
214        w = Writer()
215        w.add(self.client_version[0], 1)
216        w.add(self.client_version[1], 1)
217        w.addFixSeq(self.random, 1)
218        w.addVarSeq(self.session_id, 1, 1)
219        w.addVarSeq(self.cipher_suites, 2, 2)
220        w.addVarSeq(self.compression_methods, 1, 1)
221
222        w2 = Writer() # For Extensions
223        if self.certificate_types and self.certificate_types != \
224                [CertificateType.x509]:
225            w2.add(ExtensionType.cert_type, 2)
226            w2.add(len(self.certificate_types)+1, 2)
227            w2.addVarSeq(self.certificate_types, 1, 1)
228        if self.srp_username:
229            w2.add(ExtensionType.srp, 2)
230            w2.add(len(self.srp_username)+1, 2)
231            w2.addVarSeq(self.srp_username, 1, 1)
232        if self.supports_npn:
233            w2.add(ExtensionType.supports_npn, 2)
234            w2.add(0, 2)
235        if self.server_name:
236            w2.add(ExtensionType.server_name, 2)
237            w2.add(len(self.server_name)+5, 2)
238            w2.add(len(self.server_name)+3, 2)
239            w2.add(NameType.host_name, 1)
240            w2.addVarSeq(self.server_name, 1, 2)
241        if self.tack:
242            w2.add(ExtensionType.tack, 2)
243            w2.add(0, 2)
244        if len(w2.bytes):
245            w.add(len(w2.bytes), 2)
246            w.bytes += w2.bytes
247        return self.postWrite(w)
248
249class BadNextProtos(Exception):
250    def __init__(self, l):
251        self.length = l
252
253    def __str__(self):
254        return 'Cannot encode a list of next protocols because it contains an element with invalid length %d. Element lengths must be 0 < x < 256' % self.length
255
256class ServerHello(HandshakeMsg):
257    def __init__(self):
258        HandshakeMsg.__init__(self, HandshakeType.server_hello)
259        self.server_version = (0,0)
260        self.random = bytearray(32)
261        self.session_id = bytearray(0)
262        self.cipher_suite = 0
263        self.certificate_type = CertificateType.x509
264        self.compression_method = 0
265        self.tackExt = None
266        self.next_protos_advertised = None
267        self.next_protos = None
268        self.channel_id = False
269        self.signed_cert_timestamps = None
270        self.status_request = False
271
272    def create(self, version, random, session_id, cipher_suite,
273               certificate_type, tackExt, next_protos_advertised):
274        self.server_version = version
275        self.random = random
276        self.session_id = session_id
277        self.cipher_suite = cipher_suite
278        self.certificate_type = certificate_type
279        self.compression_method = 0
280        self.tackExt = tackExt
281        self.next_protos_advertised = next_protos_advertised
282        return self
283
284    def parse(self, p):
285        p.startLengthCheck(3)
286        self.server_version = (p.get(1), p.get(1))
287        self.random = p.getFixBytes(32)
288        self.session_id = p.getVarBytes(1)
289        self.cipher_suite = p.get(2)
290        self.compression_method = p.get(1)
291        if not p.atLengthCheck():
292            totalExtLength = p.get(2)
293            soFar = 0
294            while soFar != totalExtLength:
295                extType = p.get(2)
296                extLength = p.get(2)
297                if extType == ExtensionType.cert_type:
298                    if extLength != 1:
299                        raise SyntaxError()
300                    self.certificate_type = p.get(1)
301                elif extType == ExtensionType.tack and tackpyLoaded:
302                    self.tackExt = TackExtension(p.getFixBytes(extLength))
303                elif extType == ExtensionType.supports_npn:
304                    self.next_protos = self.__parse_next_protos(p.getFixBytes(extLength))
305                else:
306                    p.getFixBytes(extLength)
307                soFar += 4 + extLength
308        p.stopLengthCheck()
309        return self
310
311    def __parse_next_protos(self, b):
312        protos = []
313        while True:
314            if len(b) == 0:
315                break
316            l = b[0]
317            b = b[1:]
318            if len(b) < l:
319                raise BadNextProtos(len(b))
320            protos.append(b[:l])
321            b = b[l:]
322        return protos
323
324    def __next_protos_encoded(self):
325        b = bytearray()
326        for e in self.next_protos_advertised:
327            if len(e) > 255 or len(e) == 0:
328                raise BadNextProtos(len(e))
329            b += bytearray( [len(e)] ) + bytearray(e)
330        return b
331
332    def write(self):
333        w = Writer()
334        w.add(self.server_version[0], 1)
335        w.add(self.server_version[1], 1)
336        w.addFixSeq(self.random, 1)
337        w.addVarSeq(self.session_id, 1, 1)
338        w.add(self.cipher_suite, 2)
339        w.add(self.compression_method, 1)
340
341        w2 = Writer() # For Extensions
342        if self.certificate_type and self.certificate_type != \
343                CertificateType.x509:
344            w2.add(ExtensionType.cert_type, 2)
345            w2.add(1, 2)
346            w2.add(self.certificate_type, 1)
347        if self.tackExt:
348            b = self.tackExt.serialize()
349            w2.add(ExtensionType.tack, 2)
350            w2.add(len(b), 2)
351            w2.bytes += b
352        if self.next_protos_advertised is not None:
353            encoded_next_protos_advertised = self.__next_protos_encoded()
354            w2.add(ExtensionType.supports_npn, 2)
355            w2.add(len(encoded_next_protos_advertised), 2)
356            w2.addFixSeq(encoded_next_protos_advertised, 1)
357        if self.channel_id:
358            w2.add(ExtensionType.channel_id, 2)
359            w2.add(0, 2)
360        if self.signed_cert_timestamps:
361            w2.add(ExtensionType.signed_cert_timestamps, 2)
362            w2.addVarSeq(bytearray(self.signed_cert_timestamps), 1, 2)
363        if self.status_request:
364            w2.add(ExtensionType.status_request, 2)
365            w2.add(0, 2)
366        if len(w2.bytes):
367            w.add(len(w2.bytes), 2)
368            w.bytes += w2.bytes
369        return self.postWrite(w)
370
371
372class Certificate(HandshakeMsg):
373    def __init__(self, certificateType):
374        HandshakeMsg.__init__(self, HandshakeType.certificate)
375        self.certificateType = certificateType
376        self.certChain = None
377
378    def create(self, certChain):
379        self.certChain = certChain
380        return self
381
382    def parse(self, p):
383        p.startLengthCheck(3)
384        if self.certificateType == CertificateType.x509:
385            chainLength = p.get(3)
386            index = 0
387            certificate_list = []
388            while index != chainLength:
389                certBytes = p.getVarBytes(3)
390                x509 = X509()
391                x509.parseBinary(certBytes)
392                certificate_list.append(x509)
393                index += len(certBytes)+3
394            if certificate_list:
395                self.certChain = X509CertChain(certificate_list)
396        else:
397            raise AssertionError()
398
399        p.stopLengthCheck()
400        return self
401
402    def write(self):
403        w = Writer()
404        if self.certificateType == CertificateType.x509:
405            chainLength = 0
406            if self.certChain:
407                certificate_list = self.certChain.x509List
408            else:
409                certificate_list = []
410            #determine length
411            for cert in certificate_list:
412                bytes = cert.writeBytes()
413                chainLength += len(bytes)+3
414            #add bytes
415            w.add(chainLength, 3)
416            for cert in certificate_list:
417                bytes = cert.writeBytes()
418                w.addVarSeq(bytes, 1, 3)
419        else:
420            raise AssertionError()
421        return self.postWrite(w)
422
423class CertificateStatus(HandshakeMsg):
424    def __init__(self):
425        HandshakeMsg.__init__(self, HandshakeType.certificate_status)
426
427    def create(self, ocsp_response):
428        self.ocsp_response = ocsp_response
429        return self
430
431    # Defined for the sake of completeness, even though we currently only
432    # support sending the status message (server-side), not requesting
433    # or receiving it (client-side).
434    def parse(self, p):
435        p.startLengthCheck(3)
436        status_type = p.get(1)
437        # Only one type is specified, so hardwire it.
438        if status_type != CertificateStatusType.ocsp:
439            raise SyntaxError()
440        ocsp_response = p.getVarBytes(3)
441        if not ocsp_response:
442            # Can't be empty
443            raise SyntaxError()
444        self.ocsp_response = ocsp_response
445        p.stopLengthCheck()
446        return self
447
448    def write(self):
449        w = Writer()
450        w.add(CertificateStatusType.ocsp, 1)
451        w.addVarSeq(bytearray(self.ocsp_response), 1, 3)
452        return self.postWrite(w)
453
454class CertificateRequest(HandshakeMsg):
455    def __init__(self):
456        HandshakeMsg.__init__(self, HandshakeType.certificate_request)
457        self.certificate_types = []
458        self.certificate_authorities = []
459
460    def create(self, certificate_types, certificate_authorities):
461        self.certificate_types = certificate_types
462        self.certificate_authorities = certificate_authorities
463        return self
464
465    def parse(self, p):
466        p.startLengthCheck(3)
467        self.certificate_types = p.getVarList(1, 1)
468        ca_list_length = p.get(2)
469        index = 0
470        self.certificate_authorities = []
471        while index != ca_list_length:
472          ca_bytes = p.getVarBytes(2)
473          self.certificate_authorities.append(ca_bytes)
474          index += len(ca_bytes)+2
475        p.stopLengthCheck()
476        return self
477
478    def write(self):
479        w = Writer()
480        w.addVarSeq(self.certificate_types, 1, 1)
481        caLength = 0
482        #determine length
483        for ca_dn in self.certificate_authorities:
484            caLength += len(ca_dn)+2
485        w.add(caLength, 2)
486        #add bytes
487        for ca_dn in self.certificate_authorities:
488            w.addVarSeq(ca_dn, 1, 2)
489        return self.postWrite(w)
490
491class ServerKeyExchange(HandshakeMsg):
492    def __init__(self, cipherSuite):
493        HandshakeMsg.__init__(self, HandshakeType.server_key_exchange)
494        self.cipherSuite = cipherSuite
495        self.srp_N = 0
496        self.srp_g = 0
497        self.srp_s = bytearray(0)
498        self.srp_B = 0
499        # Anon DH params:
500        self.dh_p = 0
501        self.dh_g = 0
502        self.dh_Ys = 0
503        self.signature = bytearray(0)
504
505    def createSRP(self, srp_N, srp_g, srp_s, srp_B):
506        self.srp_N = srp_N
507        self.srp_g = srp_g
508        self.srp_s = srp_s
509        self.srp_B = srp_B
510        return self
511
512    def createDH(self, dh_p, dh_g, dh_Ys):
513        self.dh_p = dh_p
514        self.dh_g = dh_g
515        self.dh_Ys = dh_Ys
516        return self
517
518    def parse(self, p):
519        p.startLengthCheck(3)
520        if self.cipherSuite in CipherSuite.srpAllSuites:
521            self.srp_N = bytesToNumber(p.getVarBytes(2))
522            self.srp_g = bytesToNumber(p.getVarBytes(2))
523            self.srp_s = p.getVarBytes(1)
524            self.srp_B = bytesToNumber(p.getVarBytes(2))
525            if self.cipherSuite in CipherSuite.srpCertSuites:
526                self.signature = p.getVarBytes(2)
527        elif self.cipherSuite in CipherSuite.anonSuites:
528            self.dh_p = bytesToNumber(p.getVarBytes(2))
529            self.dh_g = bytesToNumber(p.getVarBytes(2))
530            self.dh_Ys = bytesToNumber(p.getVarBytes(2))
531        p.stopLengthCheck()
532        return self
533
534    def write_params(self):
535        w = Writer()
536        if self.cipherSuite in CipherSuite.srpAllSuites:
537            w.addVarSeq(numberToByteArray(self.srp_N), 1, 2)
538            w.addVarSeq(numberToByteArray(self.srp_g), 1, 2)
539            w.addVarSeq(self.srp_s, 1, 1)
540            w.addVarSeq(numberToByteArray(self.srp_B), 1, 2)
541        elif self.cipherSuite in CipherSuite.dhAllSuites:
542            w.addVarSeq(numberToByteArray(self.dh_p), 1, 2)
543            w.addVarSeq(numberToByteArray(self.dh_g), 1, 2)
544            w.addVarSeq(numberToByteArray(self.dh_Ys), 1, 2)
545        else:
546            assert(False)
547        return w.bytes
548
549    def write(self):
550        w = Writer()
551        w.bytes += self.write_params()
552        if self.cipherSuite in CipherSuite.certAllSuites:
553            w.addVarSeq(self.signature, 1, 2)
554        return self.postWrite(w)
555
556    def hash(self, clientRandom, serverRandom):
557        bytes = clientRandom + serverRandom + self.write_params()
558        return MD5(bytes) + SHA1(bytes)
559
560class ServerHelloDone(HandshakeMsg):
561    def __init__(self):
562        HandshakeMsg.__init__(self, HandshakeType.server_hello_done)
563
564    def create(self):
565        return self
566
567    def parse(self, p):
568        p.startLengthCheck(3)
569        p.stopLengthCheck()
570        return self
571
572    def write(self):
573        w = Writer()
574        return self.postWrite(w)
575
576class ClientKeyExchange(HandshakeMsg):
577    def __init__(self, cipherSuite, version=None):
578        HandshakeMsg.__init__(self, HandshakeType.client_key_exchange)
579        self.cipherSuite = cipherSuite
580        self.version = version
581        self.srp_A = 0
582        self.encryptedPreMasterSecret = bytearray(0)
583
584    def createSRP(self, srp_A):
585        self.srp_A = srp_A
586        return self
587
588    def createRSA(self, encryptedPreMasterSecret):
589        self.encryptedPreMasterSecret = encryptedPreMasterSecret
590        return self
591
592    def createDH(self, dh_Yc):
593        self.dh_Yc = dh_Yc
594        return self
595
596    def parse(self, p):
597        p.startLengthCheck(3)
598        if self.cipherSuite in CipherSuite.srpAllSuites:
599            self.srp_A = bytesToNumber(p.getVarBytes(2))
600        elif self.cipherSuite in CipherSuite.certSuites:
601            if self.version in ((3,1), (3,2)):
602                self.encryptedPreMasterSecret = p.getVarBytes(2)
603            elif self.version == (3,0):
604                self.encryptedPreMasterSecret = \
605                    p.getFixBytes(len(p.bytes)-p.index)
606            else:
607                raise AssertionError()
608        elif self.cipherSuite in CipherSuite.dhAllSuites:
609            self.dh_Yc = bytesToNumber(p.getVarBytes(2))
610        else:
611            raise AssertionError()
612        p.stopLengthCheck()
613        return self
614
615    def write(self):
616        w = Writer()
617        if self.cipherSuite in CipherSuite.srpAllSuites:
618            w.addVarSeq(numberToByteArray(self.srp_A), 1, 2)
619        elif self.cipherSuite in CipherSuite.certSuites:
620            if self.version in ((3,1), (3,2)):
621                w.addVarSeq(self.encryptedPreMasterSecret, 1, 2)
622            elif self.version == (3,0):
623                w.addFixSeq(self.encryptedPreMasterSecret, 1)
624            else:
625                raise AssertionError()
626        elif self.cipherSuite in CipherSuite.anonSuites:
627            w.addVarSeq(numberToByteArray(self.dh_Yc), 1, 2)
628        else:
629            raise AssertionError()
630        return self.postWrite(w)
631
632class CertificateVerify(HandshakeMsg):
633    def __init__(self):
634        HandshakeMsg.__init__(self, HandshakeType.certificate_verify)
635        self.signature = bytearray(0)
636
637    def create(self, signature):
638        self.signature = signature
639        return self
640
641    def parse(self, p):
642        p.startLengthCheck(3)
643        self.signature = p.getVarBytes(2)
644        p.stopLengthCheck()
645        return self
646
647    def write(self):
648        w = Writer()
649        w.addVarSeq(self.signature, 1, 2)
650        return self.postWrite(w)
651
652class ChangeCipherSpec(object):
653    def __init__(self):
654        self.contentType = ContentType.change_cipher_spec
655        self.type = 1
656
657    def create(self):
658        self.type = 1
659        return self
660
661    def parse(self, p):
662        p.setLengthCheck(1)
663        self.type = p.get(1)
664        p.stopLengthCheck()
665        return self
666
667    def write(self):
668        w = Writer()
669        w.add(self.type,1)
670        return w.bytes
671
672
673class NextProtocol(HandshakeMsg):
674    def __init__(self):
675        HandshakeMsg.__init__(self, HandshakeType.next_protocol)
676        self.next_proto = None
677
678    def create(self, next_proto):
679        self.next_proto = next_proto
680        return self
681
682    def parse(self, p):
683        p.startLengthCheck(3)
684        self.next_proto = p.getVarBytes(1)
685        _ = p.getVarBytes(1)
686        p.stopLengthCheck()
687        return self
688
689    def write(self, trial=False):
690        w = Writer()
691        w.addVarSeq(self.next_proto, 1, 1)
692        paddingLen = 32 - ((len(self.next_proto) + 2) % 32)
693        w.addVarSeq(bytearray(paddingLen), 1, 1)
694        return self.postWrite(w)
695
696class Finished(HandshakeMsg):
697    def __init__(self, version):
698        HandshakeMsg.__init__(self, HandshakeType.finished)
699        self.version = version
700        self.verify_data = bytearray(0)
701
702    def create(self, verify_data):
703        self.verify_data = verify_data
704        return self
705
706    def parse(self, p):
707        p.startLengthCheck(3)
708        if self.version == (3,0):
709            self.verify_data = p.getFixBytes(36)
710        elif self.version in ((3,1), (3,2)):
711            self.verify_data = p.getFixBytes(12)
712        else:
713            raise AssertionError()
714        p.stopLengthCheck()
715        return self
716
717    def write(self):
718        w = Writer()
719        w.addFixSeq(self.verify_data, 1)
720        return self.postWrite(w)
721
722class EncryptedExtensions(HandshakeMsg):
723    def __init__(self):
724        self.channel_id_key = None
725        self.channel_id_proof = None
726
727    def parse(self, p):
728        p.startLengthCheck(3)
729        soFar = 0
730        while soFar != p.lengthCheck:
731            extType = p.get(2)
732            extLength = p.get(2)
733            if extType == ExtensionType.channel_id:
734                if extLength != 32*4:
735                    raise SyntaxError()
736                self.channel_id_key = p.getFixBytes(64)
737                self.channel_id_proof = p.getFixBytes(64)
738            else:
739                p.getFixBytes(extLength)
740            soFar += 4 + extLength
741        p.stopLengthCheck()
742        return self
743
744class ApplicationData(object):
745    def __init__(self):
746        self.contentType = ContentType.application_data
747        self.bytes = bytearray(0)
748
749    def create(self, bytes):
750        self.bytes = bytes
751        return self
752
753    def splitFirstByte(self):
754        newMsg = ApplicationData().create(self.bytes[:1])
755        self.bytes = self.bytes[1:]
756        return newMsg
757
758    def parse(self, p):
759        self.bytes = p.bytes
760        return self
761
762    def write(self):
763        return self.bytes
764