Package tlslite :: Module extensions
[hide private]
[frames] | no frames]

Source Code for Module tlslite.extensions

   1  # Copyright (c) 2014, 2015 Hubert Kario 
   2  # 
   3  # See the LICENSE file for legal information regarding use of this file. 
   4   
   5  """ Helper package for handling TLS extensions encountered in ClientHello 
   6  and ServerHello messages. 
   7  """ 
   8   
   9  from __future__ import generators 
  10  from .utils.codec import Writer, Parser 
  11  from collections import namedtuple 
  12  from .constants import NameType, ExtensionType, CertificateStatusType 
  13  from .errors import TLSInternalError 
14 15 -class TLSExtension(object):
16 """ 17 Base class for handling handshake protocol hello messages extensions. 18 19 This class handles the generic information about TLS extensions used by 20 both sides of connection in Client Hello and Server Hello messages. 21 See U{RFC 4366<https://tools.ietf.org/html/rfc4366>} for more info. 22 23 It is used as a base class for specific users and as a way to store 24 extensions that are not implemented in library. 25 26 To implement a new extension you will need to create a new class which 27 calls this class contructor (__init__), usually specifying just the 28 extType parameter. The other methods which need to be implemented are: 29 L{extData}, L{create}, L{parse} and L{__repr__}. If the parser can be used 30 for client and optionally server extensions, the extension constructor 31 should be added to L{_universalExtensions}. Otherwise, when the client and 32 server extensions have completely different forms, you should add client 33 form to the L{_universalExtensions} and the server form to 34 L{_serverExtensions}. Since the server MUST NOT send extensions not 35 advertised by client, there are no purely server-side extensions. But 36 if the client side extension is just marked by presence and has no payload, 37 the client side (thus the L{_universalExtensions} may be skipped, then 38 the L{TLSExtension} class will be used for implementing it. See 39 end of the file for type-to-constructor bindings. 40 41 Though please note that subclassing for the purpose of parsing extensions 42 is not an officially supported part of API (just as underscores in their 43 names would indicate. 44 45 @type extType: int 46 @ivar extType: a 2^16-1 limited integer specifying the type of the 47 extension that it contains, e.g. 0 indicates server name extension 48 49 @type extData: bytearray 50 @ivar extData: a byte array containing the value of the extension as 51 to be written on the wire 52 53 @type serverType: boolean 54 @ivar serverType: indicates that the extension was parsed with ServerHello 55 specific parser, otherwise it used universal or ClientHello specific 56 parser 57 58 @type _universalExtensions: dict 59 @cvar _universalExtensions: dictionary with concrete implementations of 60 specific TLS extensions where key is the numeric value of the extension 61 ID. Contains ClientHello version of extensions or universal 62 implementations 63 64 @type _serverExtensions: dict 65 @cvar _serverExtensions: dictionary with concrete implementations of 66 specific TLS extensions where key is the numeric value of the extension 67 ID. Includes only those extensions that require special handlers for 68 ServerHello versions. 69 """ 70 # actual definition at the end of file, after definitions of all classes 71 _universalExtensions = {} 72 _serverExtensions = {} 73
74 - def __init__(self, server=False, extType=None):
75 """ 76 Creates a generic TLS extension. 77 78 You'll need to use L{create} or L{parse} methods to create an extension 79 that is actually usable. 80 81 @type server: boolean 82 @param server: whether to select ClientHello or ServerHello version 83 for parsing 84 @type extType: int 85 @param extType: type of extension encoded as an integer, to be used 86 by subclasses 87 """ 88 self.extType = extType 89 self._extData = bytearray(0) 90 self.serverType = server
91 92 @property
93 - def extData(self):
94 """ 95 Return the on the wire encoding of extension 96 97 Child classes need to override this property so that it returns just 98 the payload of an extension, that is, without the 4 byte generic header 99 common to all extension. In other words, without the extension ID and 100 overall extension length. 101 102 @rtype: bytearray 103 """ 104 return self._extData
105
106 - def _oldCreate(self, extType, data):
107 """Legacy handling of create method""" 108 self.extType = extType 109 self._extData = data
110
111 - def _newCreate(self, data):
112 """New format for create method""" 113 self._extData = data
114
115 - def create(self, *args, **kwargs):
116 """ 117 Initializes a generic TLS extension. 118 119 The extension can carry arbitrary data and have arbitrary payload, can 120 be used in client hello or server hello messages. 121 122 The legacy calling method uses two arguments - the extType and data. 123 If the new calling method is used, only one argument is passed in - 124 data. 125 126 Child classes need to override this method so that it is possible 127 to set values for all fields used by the extension. 128 129 @type extType: int 130 @param extType: if int: type of the extension encoded as an integer 131 between M{0} and M{2^16-1} 132 @type data: bytearray 133 @param data: raw data representing extension on the wire 134 @rtype: L{TLSExtension} 135 """ 136 # old style 137 if len(args) + len(kwargs) == 2: 138 self._oldCreate(*args, **kwargs) 139 # new style 140 elif len(args) + len(kwargs) == 1: 141 self._newCreate(*args, **kwargs) 142 else: 143 raise TypeError("Invalid number of arguments") 144 145 return self
146
147 - def write(self):
148 """Returns encoded extension, as encoded on the wire 149 150 Note that child classes in general don't need to override this method. 151 152 @rtype: bytearray 153 @return: An array of bytes formatted as is supposed to be written on 154 the wire, including the extension_type, length and the extension 155 data 156 157 @raise AssertionError: when the object was not initialized 158 """ 159 assert self.extType is not None 160 161 w = Writer() 162 w.addTwo(self.extType) 163 data = self.extData 164 w.addTwo(len(data)) 165 w.bytes += data 166 return w.bytes
167 168 @staticmethod
169 - def _parseExt(parser, extType, extLength, extList):
170 """Parse a extension using a predefined constructor""" 171 ext = extList[extType]() 172 extParser = Parser(parser.getFixBytes(extLength)) 173 ext = ext.parse(extParser) 174 return ext
175
176 - def parse(self, p):
177 """Parses extension from on the wire format 178 179 Child classes should override this method so that it parses the 180 extension from on the wire data. Note that child class parsers will 181 not receive the generic header of the extension, but just a parser 182 with the payload. In other words, the method should be the exact 183 reverse of the L{extData} property. 184 185 @type p: L{tlslite.util.codec.Parser} 186 @param p: data to be parsed 187 188 @raise SyntaxError: when the size of the passed element doesn't match 189 the internal representation 190 191 @rtype: L{TLSExtension} 192 """ 193 extType = p.get(2) 194 extLength = p.get(2) 195 196 # first check if we shouldn't use server side parser 197 if self.serverType and extType in self._serverExtensions: 198 return self._parseExt(p, extType, extLength, 199 self._serverExtensions) 200 201 # then fallback to universal/ClientHello-specific parsers 202 if extType in self._universalExtensions: 203 return self._parseExt(p, extType, extLength, 204 self._universalExtensions) 205 206 # finally, just save the extension data as there are extensions which 207 # don't require specific handlers and indicate option by mere presence 208 self.extType = extType 209 self._extData = p.getFixBytes(extLength) 210 assert len(self._extData) == extLength 211 return self
212
213 - def __eq__(self, that):
214 """Test if two TLS extensions are effectively the same 215 216 Will check if encoding them will result in the same on the wire 217 representation. 218 219 Will return False for every object that's not an extension. 220 """ 221 if hasattr(that, 'extType') and hasattr(that, 'extData'): 222 return self.extType == that.extType and \ 223 self.extData == that.extData 224 else: 225 return False
226
227 - def __repr__(self):
228 """Output human readable representation of object 229 230 Child classes should override this method to support more appropriate 231 string rendering of the extension. 232 233 @rtype: str 234 """ 235 return "TLSExtension(extType={0!r}, extData={1!r},"\ 236 " serverType={2!r})".format(self.extType, self.extData, 237 self.serverType)
238
239 -class VarListExtension(TLSExtension):
240 """ 241 Abstract extension for handling extensions comprised only of a value list 242 243 Extension for handling arbitrary extensions comprising of just a list 244 of same-sized elementes inside an array 245 """ 246
247 - def __init__(self, elemLength, lengthLength, fieldName, extType):
248 super(VarListExtension, self).__init__(extType=extType) 249 self._fieldName = fieldName 250 self._internalList = None 251 self._elemLength = elemLength 252 self._lengthLength = lengthLength
253 254 @property
255 - def extData(self):
256 """Return raw data encoding of the extension 257 258 @rtype: bytearray 259 """ 260 if self._internalList is None: 261 return bytearray(0) 262 263 writer = Writer() 264 writer.addVarSeq(self._internalList, 265 self._elemLength, 266 self._lengthLength) 267 return writer.bytes
268
269 - def create(self, values):
270 """Set the list to specified values 271 272 @type values: list of int 273 @param values: list of values to save 274 """ 275 self._internalList = values 276 return self
277
278 - def parse(self, parser):
279 """ 280 Deserialise extension from on-the-wire data 281 282 @type parser: L{Parser} 283 @rtype: Extension 284 """ 285 if parser.getRemainingLength() == 0: 286 self._internalList = None 287 return self 288 289 self._internalList = parser.getVarList(self._elemLength, 290 self._lengthLength) 291 return self
292
293 - def __getattr__(self, name):
294 """Return the special field name value""" 295 if name == '_fieldName': 296 raise AttributeError("type object '{0}' has no attribute '{1}'"\ 297 .format(self.__class__.__name__, name)) 298 if name == self._fieldName: 299 return self._internalList 300 raise AttributeError("type object '{0}' has no attribute '{1}'"\ 301 .format(self.__class__.__name__, name))
302
303 - def __setattr__(self, name, value):
304 """Set the special field value""" 305 if name == '_fieldName': 306 super(VarListExtension, self).__setattr__(name, value) 307 return 308 if hasattr(self, '_fieldName') and name == self._fieldName: 309 self._internalList = value 310 return 311 super(VarListExtension, self).__setattr__(name, value)
312
313 - def __repr__(self):
314 return "{0}({1}={2!r})".format(self.__class__.__name__, 315 self._fieldName, 316 self._internalList)
317
318 -class SNIExtension(TLSExtension):
319 """ 320 Class for handling Server Name Indication (server_name) extension from 321 RFC 4366. 322 323 Note that while usually the client does advertise just one name, it is 324 possible to provide a list of names, each of different type. 325 The type is a single byte value (represented by ints), the names are 326 opaque byte strings, in case of DNS host names (records of type 0) they 327 are UTF-8 encoded domain names (without the ending dot). 328 329 @type hostNames: tuple of bytearrays 330 @ivar hostNames: tuple of hostnames (server name records of type 0) 331 advertised in the extension. Note that it may not include all names 332 from client hello as the client can advertise other types. Also note 333 that while it's not possible to change the returned array in place, it 334 is possible to assign a new set of names. IOW, this won't work:: 335 336 sni_extension.hostNames[0] = bytearray(b'example.com') 337 338 while this will work:: 339 340 names = list(sni_extension.hostNames) 341 names[0] = bytearray(b'example.com') 342 sni_extension.hostNames = names 343 344 345 @type serverNames: list of L{ServerName} 346 @ivar serverNames: list of all names advertised in extension. 347 L{ServerName} is a namedtuple with two elements, the first 348 element (type) defines the type of the name (encoded as int) 349 while the other (name) is a bytearray that carries the value. 350 Known types are defined in L{tlslite.constants.NameType}. 351 The list will be empty if the on the wire extension had and empty 352 list while it will be None if the extension was empty. 353 354 @type extType: int 355 @ivar extType: numeric type of SNIExtension, i.e. 0 356 357 @type extData: bytearray 358 @ivar extData: raw representation of the extension 359 """ 360 361 ServerName = namedtuple('ServerName', 'name_type name') 362
363 - def __init__(self):
364 """ 365 Create an instance of SNIExtension. 366 367 See also: L{create} and L{parse}. 368 """ 369 super(SNIExtension, self).__init__(extType=ExtensionType.server_name) 370 self.serverNames = None
371
372 - def __repr__(self):
373 """ 374 Return programmer-readable representation of extension 375 376 @rtype: str 377 """ 378 return "SNIExtension(serverNames={0!r})".format(self.serverNames)
379
380 - def create(self, hostname=None, hostNames=None, serverNames=None):
381 """ 382 Initializes an instance with provided hostname, host names or 383 raw server names. 384 385 Any of the parameters may be None, in that case the list inside the 386 extension won't be defined, if either hostNames or serverNames is 387 an empty list, then the extension will define a list of lenght 0. 388 389 If multiple parameters are specified at the same time, then the 390 resulting list of names will be concatenated in order of hostname, 391 hostNames and serverNames last. 392 393 @type hostname: bytearray 394 @param hostname: raw UTF-8 encoding of the host name 395 396 @type hostNames: list of bytearrays 397 @param hostNames: list of raw UTF-8 encoded host names 398 399 @type serverNames: list of L{ServerName} 400 @param serverNames: pairs of name_type and name encoded as a namedtuple 401 402 @rtype: L{SNIExtension} 403 """ 404 if hostname is None and hostNames is None and serverNames is None: 405 self.serverNames = None 406 return self 407 else: 408 self.serverNames = [] 409 410 if hostname: 411 self.serverNames += [SNIExtension.ServerName(NameType.host_name,\ 412 hostname)] 413 414 if hostNames: 415 self.serverNames +=\ 416 [SNIExtension.ServerName(NameType.host_name, x) for x in\ 417 hostNames] 418 419 if serverNames: 420 self.serverNames += serverNames 421 422 return self
423 424 @property
425 - def hostNames(self):
426 """ Returns a simulated list of hostNames from the extension. 427 428 @rtype: tuple of bytearrays 429 """ 430 # because we can't simulate assignments to array elements we return 431 # an immutable type 432 if self.serverNames is None: 433 return tuple() 434 else: 435 return tuple([x.name for x in self.serverNames if \ 436 x.name_type == NameType.host_name])
437 438 @hostNames.setter
439 - def hostNames(self, hostNames):
440 """ Removes all host names from the extension and replaces them by 441 names in X{hostNames} parameter. 442 443 Newly added parameters will be added at the I{beginning} of the list 444 of extensions. 445 446 @type hostNames: iterable of bytearrays 447 @param hostNames: host names to replace the old server names of type 0 448 """ 449 450 self.serverNames = \ 451 [SNIExtension.ServerName(NameType.host_name, x) for x in \ 452 hostNames] + \ 453 [x for x in self.serverNames if \ 454 x.name_type != NameType.host_name]
455 456 @hostNames.deleter
457 - def hostNames(self):
458 """ Remove all host names from extension, leaves other name types 459 unmodified 460 """ 461 self.serverNames = [x for x in self.serverNames if \ 462 x.name_type != NameType.host_name]
463 464 @property
465 - def extData(self):
466 """ raw encoding of extension data, without type and length header 467 468 @rtype: bytearray 469 """ 470 if self.serverNames is None: 471 return bytearray(0) 472 473 w2 = Writer() 474 for server_name in self.serverNames: 475 w2.add(server_name.name_type, 1) 476 w2.add(len(server_name.name), 2) 477 w2.bytes += server_name.name 478 479 # note that when the array is empty we write it as array of length 0 480 w = Writer() 481 w.add(len(w2.bytes), 2) 482 w.bytes += w2.bytes 483 return w.bytes
484
485 - def write(self):
486 """ Returns encoded extension, as encoded on the wire 487 488 @rtype: bytearray 489 @return: an array of bytes formatted as they are supposed to be written 490 on the wire, including the type, length and extension data 491 """ 492 493 raw_data = self.extData 494 495 w = Writer() 496 w.add(self.extType, 2) 497 w.add(len(raw_data), 2) 498 w.bytes += raw_data 499 500 return w.bytes
501
502 - def parse(self, p):
503 """ 504 Deserialise the extension from on-the-wire data 505 506 The parser should not include the type or length of extension! 507 508 @type p: L{tlslite.util.codec.Parser} 509 @param p: data to be parsed 510 511 @rtype: L{SNIExtension} 512 @raise SyntaxError: when the internal sizes don't match the attached 513 data 514 """ 515 if p.getRemainingLength() == 0: 516 return self 517 518 self.serverNames = [] 519 520 p.startLengthCheck(2) 521 while not p.atLengthCheck(): 522 sn_type = p.get(1) 523 sn_name = p.getVarBytes(2) 524 self.serverNames += [SNIExtension.ServerName(sn_type, sn_name)] 525 p.stopLengthCheck() 526 527 return self
528
529 -class ClientCertTypeExtension(VarListExtension):
530 """ 531 This class handles the (client variant of) Certificate Type extension 532 533 See RFC 6091. 534 535 @type extType: int 536 @ivar extType: numeric type of Certificate Type extension, i.e. 9 537 538 @type extData: bytearray 539 @ivar extData: raw representation of the extension data 540 541 @type certTypes: list of int 542 @ivar certTypes: list of certificate type identifiers (each one byte long) 543 """ 544
545 - def __init__(self):
546 """ 547 Create an instance of ClientCertTypeExtension 548 549 See also: L{create} and L{parse} 550 """ 551 super(ClientCertTypeExtension, self).__init__(1, 1, 'certTypes', \ 552 ExtensionType.cert_type)
553
554 -class ServerCertTypeExtension(TLSExtension):
555 """ 556 This class handles the Certificate Type extension (variant sent by server) 557 defined in RFC 6091. 558 559 @type extType: int 560 @ivar extType: binary type of Certificate Type extension, i.e. 9 561 562 @type extData: bytearray 563 @ivar extData: raw representation of the extension data 564 565 @type cert_type: int 566 @ivar cert_type: the certificate type selected by server 567 """ 568
569 - def __init__(self):
570 """ 571 Create an instance of ServerCertTypeExtension 572 573 See also: L{create} and L{parse} 574 """ 575 super(ServerCertTypeExtension, self).__init__(server=True, \ 576 extType=ExtensionType.cert_type) 577 self.cert_type = None
578
579 - def __repr__(self):
580 """ Return programmer-centric description of object 581 582 @rtype: str 583 """ 584 return "ServerCertTypeExtension(cert_type={0!r})".format(self.cert_type)
585 586 @property
587 - def extData(self):
588 """ 589 Return the raw encoding of the extension data 590 591 @rtype: bytearray 592 """ 593 if self.cert_type is None: 594 return bytearray(0) 595 596 w = Writer() 597 w.add(self.cert_type, 1) 598 599 return w.bytes
600
601 - def create(self, val):
602 """Create an instance for sending the extension to client. 603 604 @type val: int 605 @param val: selected type of certificate 606 """ 607 self.cert_type = val 608 return self
609
610 - def parse(self, p):
611 """Parse the extension from on the wire format 612 613 @type p: L{Parser} 614 @param p: parser with data 615 """ 616 self.cert_type = p.get(1) 617 if p.getRemainingLength() > 0: 618 raise SyntaxError() 619 620 return self
621
622 -class SRPExtension(TLSExtension):
623 """ 624 This class handles the Secure Remote Password protocol TLS extension 625 defined in RFC 5054. 626 627 @type extType: int 628 @ivar extType: numeric type of SRPExtension, i.e. 12 629 630 @type extData: bytearray 631 @ivar extData: raw representation of extension data 632 633 @type identity: bytearray 634 @ivar identity: UTF-8 encoding of user name 635 """ 636
637 - def __init__(self):
638 """ 639 Create an instance of SRPExtension 640 641 See also: L{create} and L{parse} 642 """ 643 super(SRPExtension, self).__init__(extType=ExtensionType.srp) 644 645 self.identity = None
646
647 - def __repr__(self):
648 """ 649 Return programmer-centric description of extension 650 651 @rtype: str 652 """ 653 return "SRPExtension(identity={0!r})".format(self.identity)
654 655 @property
656 - def extData(self):
657 """ 658 Return raw data encoding of the extension 659 660 @rtype: bytearray 661 """ 662 663 if self.identity is None: 664 return bytearray(0) 665 666 w = Writer() 667 w.add(len(self.identity), 1) 668 w.addFixSeq(self.identity, 1) 669 670 return w.bytes
671
672 - def create(self, identity=None):
673 """ Create and instance of SRPExtension with specified protocols 674 675 @type identity: bytearray 676 @param identity: UTF-8 encoded identity (user name) to be provided 677 to user. MUST be shorter than 2^8-1. 678 679 @raise ValueError: when the identity lenght is longer than 2^8-1 680 """ 681 682 if identity is None: 683 return self 684 685 if len(identity) >= 2**8: 686 raise ValueError() 687 688 self.identity = identity 689 return self
690
691 - def parse(self, p):
692 """ 693 Parse the extension from on the wire format 694 695 @type p: L{tlslite.util.codec.Parser} 696 @param p: data to be parsed 697 698 @raise SyntaxError: when the data is internally inconsistent 699 700 @rtype: L{SRPExtension} 701 """ 702 703 self.identity = p.getVarBytes(1) 704 705 return self
706
707 -class NPNExtension(TLSExtension):
708 """ 709 This class handles the unofficial Next Protocol Negotiation TLS extension. 710 711 @type protocols: list of bytearrays 712 @ivar protocols: list of protocol names supported by the server 713 714 @type extType: int 715 @ivar extType: numeric type of NPNExtension, i.e. 13172 716 717 @type extData: bytearray 718 @ivar extData: raw representation of extension data 719 """ 720
721 - def __init__(self):
722 """ 723 Create an instance of NPNExtension 724 725 See also: L{create} and L{parse} 726 """ 727 super(NPNExtension, self).__init__(extType=ExtensionType.supports_npn) 728 729 self.protocols = None
730
731 - def __repr__(self):
732 """ 733 Create programmer-readable version of representation 734 735 @rtype: str 736 """ 737 return "NPNExtension(protocols={0!r})".format(self.protocols)
738 739 @property
740 - def extData(self):
741 """ Return the raw data encoding of the extension 742 743 @rtype: bytearray 744 """ 745 if self.protocols is None: 746 return bytearray(0) 747 748 w = Writer() 749 for prot in self.protocols: 750 w.add(len(prot), 1) 751 w.addFixSeq(prot, 1) 752 753 return w.bytes
754
755 - def create(self, protocols=None):
756 """ Create an instance of NPNExtension with specified protocols 757 758 @type protocols: list of bytearray 759 @param protocols: list of protocol names that are supported 760 """ 761 self.protocols = protocols 762 return self
763
764 - def parse(self, p):
765 """ Parse the extension from on the wire format 766 767 @type p: L{tlslite.util.codec.Parser} 768 @param p: data to be parsed 769 770 @raise SyntaxError: when the size of the passed element doesn't match 771 the internal representation 772 773 @rtype: L{NPNExtension} 774 """ 775 self.protocols = [] 776 777 while p.getRemainingLength() > 0: 778 self.protocols += [p.getVarBytes(1)] 779 780 return self
781
782 -class TACKExtension(TLSExtension):
783 """ 784 This class handles the server side TACK extension (see 785 draft-perrin-tls-tack-02). 786 787 @type tacks: list 788 @ivar tacks: list of L{TACK}'s supported by server 789 790 @type activation_flags: int 791 @ivar activation_flags: activation flags for the tacks 792 """ 793
794 - class TACK(object):
795 """ 796 Implementation of the single TACK 797 """
798 - def __init__(self):
799 """ 800 Create a single TACK object 801 """ 802 self.public_key = bytearray(64) 803 self.min_generation = 0 804 self.generation = 0 805 self.expiration = 0 806 self.target_hash = bytearray(32) 807 self.signature = bytearray(64)
808
809 - def __repr__(self):
810 """ 811 Return programmmer readable representation of TACK object 812 813 @rtype: str 814 """ 815 return "TACK(public_key={0!r}, min_generation={1!r}, "\ 816 "generation={2!r}, expiration={3!r}, target_hash={4!r}, "\ 817 "signature={5!r})".format( 818 self.public_key, self.min_generation, 819 self.generation, self.expiration, self.target_hash, 820 self.signature)
821
822 - def create(self, public_key, min_generation, generation, expiration, 823 target_hash, signature):
824 """ 825 Initialise the TACK with data 826 """ 827 self.public_key = public_key 828 self.min_generation = min_generation 829 self.generation = generation 830 self.expiration = expiration 831 self.target_hash = target_hash 832 self.signature = signature 833 return self
834
835 - def write(self):
836 """ 837 Convert the TACK into on the wire format 838 839 @rtype: bytearray 840 """ 841 w = Writer() 842 if len(self.public_key) != 64: 843 raise TLSInternalError("Public_key must be 64 bytes long") 844 w.bytes += self.public_key 845 w.add(self.min_generation, 1) 846 w.add(self.generation, 1) 847 w.add(self.expiration, 4) 848 if len(self.target_hash) != 32: 849 raise TLSInternalError("Target_hash must be 32 bytes long") 850 w.bytes += self.target_hash 851 if len(self.signature) != 64: 852 raise TLSInternalError("Signature must be 64 bytes long") 853 w.bytes += self.signature 854 return w.bytes
855
856 - def parse(self, p):
857 """ 858 Parse the TACK from on the wire format 859 860 @type p: L{tlslite.util.codec.Parser} 861 @param p: data to be parsed 862 863 @rtype: L{TACK} 864 @raise SyntaxError: when the internal sizes don't match the 865 provided data 866 """ 867 868 self.public_key = p.getFixBytes(64) 869 self.min_generation = p.get(1) 870 self.generation = p.get(1) 871 self.expiration = p.get(4) 872 self.target_hash = p.getFixBytes(32) 873 self.signature = p.getFixBytes(64) 874 return self
875
876 - def __eq__(self, other):
877 """ 878 Tests if the other object is equivalent to this TACK 879 880 Returns False for every object that's not a TACK 881 """ 882 if hasattr(other, 'public_key') and\ 883 hasattr(other, 'min_generation') and\ 884 hasattr(other, 'generation') and\ 885 hasattr(other, 'expiration') and\ 886 hasattr(other, 'target_hash') and\ 887 hasattr(other, 'signature'): 888 if self.public_key == other.public_key and\ 889 self.min_generation == other.min_generation and\ 890 self.generation == other.generation and\ 891 self.expiration == other.expiration and\ 892 self.target_hash == other.target_hash and\ 893 self.signature == other.signature: 894 return True 895 else: 896 return False 897 else: 898 return False
899
900 - def __init__(self):
901 """ 902 Create an instance of TACKExtension 903 904 See also: L{create} and L{parse} 905 """ 906 super(TACKExtension, self).__init__(extType=ExtensionType.tack) 907 908 self.tacks = [] 909 self.activation_flags = 0
910
911 - def __repr__(self):
912 """ 913 Create a programmer readable representation of TACK extension 914 915 @rtype: str 916 """ 917 return "TACKExtension(activation_flags={0!r}, tacks={1!r})".format( 918 self.activation_flags, self.tacks)
919 920 @property
921 - def extData(self):
922 """ 923 Return the raw data encoding of the extension 924 925 @rtype: bytearray 926 """ 927 w2 = Writer() 928 for t in self.tacks: 929 w2.bytes += t.write() 930 931 w = Writer() 932 w.add(len(w2.bytes), 2) 933 w.bytes += w2.bytes 934 w.add(self.activation_flags, 1) 935 return w.bytes
936
937 - def create(self, tacks, activation_flags):
938 """ 939 Initialize the instance of TACKExtension 940 941 @rtype: TACKExtension 942 """ 943 944 self.tacks = tacks 945 self.activation_flags = activation_flags 946 return self
947
948 - def parse(self, p):
949 """ 950 Parse the extension from on the wire format 951 952 @type p: L{tlslite.util.codec.Parser} 953 @param p: data to be parsed 954 955 @rtype: L{TACKExtension} 956 """ 957 self.tacks = [] 958 959 p.startLengthCheck(2) 960 while not p.atLengthCheck(): 961 tack = TACKExtension.TACK().parse(p) 962 self.tacks += [tack] 963 p.stopLengthCheck() 964 self.activation_flags = p.get(1) 965 966 return self
967
968 -class SupportedGroupsExtension(VarListExtension):
969 """ 970 Client side list of supported groups of (EC)DHE key exchage. 971 972 See RFC4492, RFC7027 and RFC-ietf-tls-negotiated-ff-dhe-10 973 974 @type groups: int 975 @ivar groups: list of groups that the client supports 976 """ 977
978 - def __init__(self):
979 """Create instance of class""" 980 super(SupportedGroupsExtension, self).__init__(2, 2, 'groups', \ 981 ExtensionType.supported_groups)
982
983 -class ECPointFormatsExtension(VarListExtension):
984 """ 985 Client side list of supported ECC point formats. 986 987 See RFC4492. 988 989 @type formats: list of int 990 @ivar formats: list of point formats supported by peer 991 """ 992
993 - def __init__(self):
994 """Create instance of class""" 995 super(ECPointFormatsExtension, self).__init__(1, 1, 'formats', \ 996 ExtensionType.ec_point_formats)
997
998 -class SignatureAlgorithmsExtension(TLSExtension):
999 1000 """ 1001 Client side list of supported signature algorithms. 1002 1003 Should be used by server to select certificate and signing method for 1004 Server Key Exchange messages. In practice used only for the latter. 1005 1006 See RFC5246. 1007 """ 1008
1009 - def __init__(self):
1010 """Create instance of class""" 1011 super(SignatureAlgorithmsExtension, self).__init__(extType= 1012 ExtensionType. 1013 signature_algorithms) 1014 self.sigalgs = None
1015 1016 @property
1017 - def extData(self):
1018 """ 1019 Return raw encoding of the extension 1020 1021 @rtype: bytearray 1022 """ 1023 if self.sigalgs is None: 1024 return bytearray(0) 1025 1026 writer = Writer() 1027 # elements 1 byte each, overall length encoded in 2 bytes 1028 writer.addVarTupleSeq(self.sigalgs, 1, 2) 1029 return writer.bytes
1030
1031 - def create(self, sigalgs):
1032 """ 1033 Set the list of supported algorithm types 1034 1035 @type sigalgs: list of tuples 1036 @param sigalgs: list of pairs of a hash algorithm and signature 1037 algorithm 1038 """ 1039 self.sigalgs = sigalgs 1040 return self
1041
1042 - def parse(self, parser):
1043 """ 1044 Deserialise extension from on the wire data 1045 1046 @type parser: L{Parser} 1047 @rtype: SignatureAlgorithmsExtension 1048 """ 1049 if parser.getRemainingLength() == 0: 1050 self.sigalgs = None 1051 return self 1052 1053 self.sigalgs = parser.getVarTupleList(1, 2, 2) 1054 1055 if parser.getRemainingLength() != 0: 1056 raise SyntaxError() 1057 1058 return self
1059
1060 1061 -class PaddingExtension(TLSExtension):
1062 """ 1063 ClientHello message padding with a desired size. 1064 1065 Can be used to pad ClientHello messages to a desired size 1066 in order to avoid implementation bugs caused by certain 1067 ClientHello sizes. 1068 1069 See RFC7685. 1070 """ 1071
1072 - def __init__(self):
1073 """Create instance of class.""" 1074 extType = ExtensionType.client_hello_padding 1075 super(PaddingExtension, self).__init__(extType=extType) 1076 self.paddingData = bytearray(0)
1077 1078 @property
1079 - def extData(self):
1080 """ 1081 Return raw encoding of the extension. 1082 1083 @rtype: bytearray 1084 """ 1085 return self.paddingData
1086
1087 - def create(self, size):
1088 """ 1089 Set the padding size and create null byte padding of defined size. 1090 1091 @type size: int 1092 @param size: required padding size in bytes 1093 """ 1094 self.paddingData = bytearray(size) 1095 return self
1096
1097 - def parse(self, p):
1098 """ 1099 Deserialise extension from on the wire data. 1100 1101 @type p: L{tlslite.util.codec.Parser} 1102 @param p: data to be parsed 1103 1104 @raise SyntaxError: when the size of the passed element doesn't match 1105 the internal representation 1106 1107 @rtype: L{TLSExtension} 1108 """ 1109 self.paddingData = p.getFixBytes(p.getRemainingLength()) 1110 return self
1111
1112 -class RenegotiationInfoExtension(TLSExtension):
1113 """ 1114 Client and Server Hello secure renegotiation extension from RFC 5746 1115 1116 Should have an empty renegotiated_connection field in case of initial 1117 connection 1118 """ 1119
1120 - def __init__(self):
1121 """Create instance""" 1122 extType = ExtensionType.renegotiation_info 1123 super(RenegotiationInfoExtension, self).__init__(extType=extType) 1124 self.renegotiated_connection = None
1125 1126 @property
1127 - def extData(self):
1128 """ 1129 Return raw encoding of the extension. 1130 1131 @rtype: bytearray 1132 """ 1133 if self.renegotiated_connection is None: 1134 return bytearray(0) 1135 writer = Writer() 1136 writer.add(len(self.renegotiated_connection), 1) 1137 writer.bytes += self.renegotiated_connection 1138 return writer.bytes
1139
1140 - def create(self, renegotiated_connection):
1141 """ 1142 Set the finished message payload from previous connection. 1143 1144 @type renegotiated_connection: bytearray 1145 """ 1146 self.renegotiated_connection = renegotiated_connection 1147 return self
1148
1149 - def parse(self, parser):
1150 """ 1151 Deserialise extension from on the wire data. 1152 1153 @type parser: L{tlslite.util.codec.Parser} 1154 @param parser: data to be parsed 1155 1156 @rtype: L{RenegotiationInfoExtension} 1157 """ 1158 if parser.getRemainingLength() == 0: 1159 self.renegotiated_connection = None 1160 else: 1161 self.renegotiated_connection = parser.getVarBytes(1) 1162 1163 return self
1164
1165 1166 -class ALPNExtension(TLSExtension):
1167 """ 1168 Handling of Application Layer Protocol Negotiation extension from RFC 7301. 1169 1170 @type protocol_names: list of bytearrays 1171 @ivar protocol_names: list of protocol names acceptable or selected by peer 1172 1173 @type extType: int 1174 @ivar extType: numberic type of ALPNExtension, i.e. 16 1175 1176 @type extData: bytearray 1177 @ivar extData: raw encoding of the extension data 1178 """ 1179
1180 - def __init__(self):
1181 """ 1182 Create instance of ALPNExtension 1183 1184 See also: L{create} and L{parse} 1185 """ 1186 super(ALPNExtension, self).__init__(extType=ExtensionType.alpn) 1187 1188 self.protocol_names = None
1189
1190 - def __repr__(self):
1191 """ 1192 Create programmer-readable representation of object 1193 1194 @rtype: str 1195 """ 1196 return "ALPNExtension(protocol_names={0!r})".format(self.protocol_names)
1197 1198 @property
1199 - def extData(self):
1200 """ 1201 Return encoded payload of the extension 1202 1203 @rtype: bytearray 1204 """ 1205 if self.protocol_names is None: 1206 return bytearray(0) 1207 1208 writer = Writer() 1209 for prot in self.protocol_names: 1210 writer.add(len(prot), 1) 1211 writer.bytes += prot 1212 1213 writer2 = Writer() 1214 writer2.add(len(writer.bytes), 2) 1215 writer2.bytes += writer.bytes 1216 1217 return writer2.bytes
1218
1219 - def create(self, protocol_names=None):
1220 """ 1221 Create an instance of ALPNExtension with specified protocols 1222 1223 @type protocols: list of bytearray 1224 @param protocols: list of protocol names that are to be sent 1225 """ 1226 self.protocol_names = protocol_names 1227 return self
1228
1229 - def parse(self, parser):
1230 """ 1231 Parse the extension from on the wire format 1232 1233 @type parser: L{tlslite.util.codec.Parser} 1234 @param parser: data to be parsed as extension 1235 1236 @raise SyntaxError: when the encoding of the extension is self 1237 inconsistent 1238 1239 @rtype: L{ALPNExtension} 1240 """ 1241 self.protocol_names = [] 1242 parser.startLengthCheck(2) 1243 while not parser.atLengthCheck(): 1244 name_len = parser.get(1) 1245 self.protocol_names.append(parser.getFixBytes(name_len)) 1246 parser.stopLengthCheck() 1247 if parser.getRemainingLength() != 0: 1248 raise SyntaxError("Trailing data after protocol_name_list") 1249 return self
1250
1251 1252 -class StatusRequestExtension(TLSExtension):
1253 """ 1254 Handling of the Certificate Status Request extension from RFC 6066. 1255 1256 @type status_type: int 1257 @ivar status_type: type of the status request 1258 1259 @type responder_id_list: list of bytearray 1260 @ivar responder_id_list: list of DER encoded OCSP responder identifiers 1261 that the client trusts 1262 1263 @type request_extensions: bytearray 1264 @ivar request_extensions: DER encoded list of OCSP extensions, as defined 1265 in RFC 2560 1266 """ 1267
1268 - def __init__(self):
1269 super(StatusRequestExtension, self).__init__( 1270 extType=ExtensionType.status_request) 1271 """Create instance of StatusRequestExtension.""" 1272 self.status_type = None 1273 self.responder_id_list = [] 1274 self.request_extensions = bytearray()
1275
1276 - def __repr__(self):
1277 """ 1278 Create programmer-readable representation of object 1279 1280 @rtype: str 1281 """ 1282 return ("StatusRequestExtension(status_type={0}, " 1283 "responder_id_list={1!r}, " 1284 "request_extensions={2!r})").format( 1285 self.status_type, self.responder_id_list, 1286 self.request_extensions)
1287 1288 @property
1289 - def extData(self):
1290 """ 1291 Return encoded payload of the extension. 1292 1293 @rtype: bytearray 1294 """ 1295 if self.status_type is None: 1296 return bytearray() 1297 1298 writer = Writer() 1299 writer.add(self.status_type, 1) 1300 writer2 = Writer() 1301 for i in self.responder_id_list: 1302 writer2.add(len(i), 2) 1303 writer2.bytes += i 1304 writer.add(len(writer2.bytes), 2) 1305 writer.bytes += writer2.bytes 1306 writer.add(len(self.request_extensions), 2) 1307 writer.bytes += self.request_extensions 1308 1309 return writer.bytes
1310
1311 - def create(self, status_type=CertificateStatusType.ocsp, 1312 responder_id_list=tuple(), 1313 request_extensions=b''):
1314 """ 1315 Create an instance of StatusRequestExtension with specified options. 1316 1317 @type status_type: int 1318 @param status_type: type of status returned 1319 1320 @type responder_id_list: list 1321 @param responder_id_list: list of encoded OCSP responder identifiers 1322 that the client trusts 1323 1324 @type request_extensions: bytearray 1325 @param request_extensions: DER encoding of requested OCSP extensions 1326 """ 1327 self.status_type = status_type 1328 self.responder_id_list = list(responder_id_list) 1329 self.request_extensions = bytearray(request_extensions) 1330 return self
1331
1332 - def parse(self, parser):
1333 """ 1334 Parse the extension from on the wire format. 1335 1336 @type parser: L{tlslite.util.codec.Parser} 1337 @param parser: data to be parsed as extension 1338 1339 @rtype: L{StatusRequestExtension} 1340 """ 1341 # handling of server side message 1342 if parser.getRemainingLength() == 0: 1343 self.status_type = None 1344 self.responder_id_list = [] 1345 self.request_extensions = bytearray() 1346 return self 1347 1348 self.status_type = parser.get(1) 1349 self.responder_id_list = [] 1350 parser.startLengthCheck(2) 1351 while not parser.atLengthCheck(): 1352 self.responder_id_list.append(parser.getVarBytes(2)) 1353 parser.stopLengthCheck() 1354 self.request_extensions = parser.getVarBytes(2) 1355 if parser.getRemainingLength() != 0: 1356 raise SyntaxError("Trailing data after CertificateStatusRequest") 1357 return self
1358 1359 1360 TLSExtension._universalExtensions = \ 1361 { 1362 ExtensionType.server_name: SNIExtension, 1363 ExtensionType.status_request: StatusRequestExtension, 1364 ExtensionType.cert_type: ClientCertTypeExtension, 1365 ExtensionType.supported_groups: SupportedGroupsExtension, 1366 ExtensionType.ec_point_formats: ECPointFormatsExtension, 1367 ExtensionType.srp: SRPExtension, 1368 ExtensionType.signature_algorithms: SignatureAlgorithmsExtension, 1369 ExtensionType.alpn: ALPNExtension, 1370 ExtensionType.supports_npn: NPNExtension, 1371 ExtensionType.client_hello_padding: PaddingExtension, 1372 ExtensionType.renegotiation_info: RenegotiationInfoExtension} 1373 1374 TLSExtension._serverExtensions = \ 1375 { 1376 ExtensionType.cert_type: ServerCertTypeExtension, 1377 ExtensionType.tack: TACKExtension} 1378