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 if p.getRemainingLength(): 528 raise SyntaxError() 529 530 return self
531
532 -class ClientCertTypeExtension(VarListExtension):
533 """ 534 This class handles the (client variant of) Certificate Type extension 535 536 See RFC 6091. 537 538 @type extType: int 539 @ivar extType: numeric type of Certificate Type extension, i.e. 9 540 541 @type extData: bytearray 542 @ivar extData: raw representation of the extension data 543 544 @type certTypes: list of int 545 @ivar certTypes: list of certificate type identifiers (each one byte long) 546 """ 547
548 - def __init__(self):
549 """ 550 Create an instance of ClientCertTypeExtension 551 552 See also: L{create} and L{parse} 553 """ 554 super(ClientCertTypeExtension, self).__init__(1, 1, 'certTypes', \ 555 ExtensionType.cert_type)
556
557 -class ServerCertTypeExtension(TLSExtension):
558 """ 559 This class handles the Certificate Type extension (variant sent by server) 560 defined in RFC 6091. 561 562 @type extType: int 563 @ivar extType: binary type of Certificate Type extension, i.e. 9 564 565 @type extData: bytearray 566 @ivar extData: raw representation of the extension data 567 568 @type cert_type: int 569 @ivar cert_type: the certificate type selected by server 570 """ 571
572 - def __init__(self):
573 """ 574 Create an instance of ServerCertTypeExtension 575 576 See also: L{create} and L{parse} 577 """ 578 super(ServerCertTypeExtension, self).__init__(server=True, \ 579 extType=ExtensionType.cert_type) 580 self.cert_type = None
581
582 - def __repr__(self):
583 """ Return programmer-centric description of object 584 585 @rtype: str 586 """ 587 return "ServerCertTypeExtension(cert_type={0!r})".format(self.cert_type)
588 589 @property
590 - def extData(self):
591 """ 592 Return the raw encoding of the extension data 593 594 @rtype: bytearray 595 """ 596 if self.cert_type is None: 597 return bytearray(0) 598 599 w = Writer() 600 w.add(self.cert_type, 1) 601 602 return w.bytes
603
604 - def create(self, val):
605 """Create an instance for sending the extension to client. 606 607 @type val: int 608 @param val: selected type of certificate 609 """ 610 self.cert_type = val 611 return self
612
613 - def parse(self, p):
614 """Parse the extension from on the wire format 615 616 @type p: L{Parser} 617 @param p: parser with data 618 """ 619 self.cert_type = p.get(1) 620 if p.getRemainingLength() > 0: 621 raise SyntaxError() 622 623 return self
624
625 -class SRPExtension(TLSExtension):
626 """ 627 This class handles the Secure Remote Password protocol TLS extension 628 defined in RFC 5054. 629 630 @type extType: int 631 @ivar extType: numeric type of SRPExtension, i.e. 12 632 633 @type extData: bytearray 634 @ivar extData: raw representation of extension data 635 636 @type identity: bytearray 637 @ivar identity: UTF-8 encoding of user name 638 """ 639
640 - def __init__(self):
641 """ 642 Create an instance of SRPExtension 643 644 See also: L{create} and L{parse} 645 """ 646 super(SRPExtension, self).__init__(extType=ExtensionType.srp) 647 648 self.identity = None
649
650 - def __repr__(self):
651 """ 652 Return programmer-centric description of extension 653 654 @rtype: str 655 """ 656 return "SRPExtension(identity={0!r})".format(self.identity)
657 658 @property
659 - def extData(self):
660 """ 661 Return raw data encoding of the extension 662 663 @rtype: bytearray 664 """ 665 666 if self.identity is None: 667 return bytearray(0) 668 669 w = Writer() 670 w.add(len(self.identity), 1) 671 w.addFixSeq(self.identity, 1) 672 673 return w.bytes
674
675 - def create(self, identity=None):
676 """ Create and instance of SRPExtension with specified protocols 677 678 @type identity: bytearray 679 @param identity: UTF-8 encoded identity (user name) to be provided 680 to user. MUST be shorter than 2^8-1. 681 682 @raise ValueError: when the identity lenght is longer than 2^8-1 683 """ 684 685 if identity is None: 686 return self 687 688 if len(identity) >= 2**8: 689 raise ValueError() 690 691 self.identity = identity 692 return self
693
694 - def parse(self, p):
695 """ 696 Parse the extension from on the wire format 697 698 @type p: L{tlslite.util.codec.Parser} 699 @param p: data to be parsed 700 701 @raise SyntaxError: when the data is internally inconsistent 702 703 @rtype: L{SRPExtension} 704 """ 705 706 self.identity = p.getVarBytes(1) 707 708 return self
709
710 -class NPNExtension(TLSExtension):
711 """ 712 This class handles the unofficial Next Protocol Negotiation TLS extension. 713 714 @type protocols: list of bytearrays 715 @ivar protocols: list of protocol names supported by the server 716 717 @type extType: int 718 @ivar extType: numeric type of NPNExtension, i.e. 13172 719 720 @type extData: bytearray 721 @ivar extData: raw representation of extension data 722 """ 723
724 - def __init__(self):
725 """ 726 Create an instance of NPNExtension 727 728 See also: L{create} and L{parse} 729 """ 730 super(NPNExtension, self).__init__(extType=ExtensionType.supports_npn) 731 732 self.protocols = None
733
734 - def __repr__(self):
735 """ 736 Create programmer-readable version of representation 737 738 @rtype: str 739 """ 740 return "NPNExtension(protocols={0!r})".format(self.protocols)
741 742 @property
743 - def extData(self):
744 """ Return the raw data encoding of the extension 745 746 @rtype: bytearray 747 """ 748 if self.protocols is None: 749 return bytearray(0) 750 751 w = Writer() 752 for prot in self.protocols: 753 w.add(len(prot), 1) 754 w.addFixSeq(prot, 1) 755 756 return w.bytes
757
758 - def create(self, protocols=None):
759 """ Create an instance of NPNExtension with specified protocols 760 761 @type protocols: list of bytearray 762 @param protocols: list of protocol names that are supported 763 """ 764 self.protocols = protocols 765 return self
766
767 - def parse(self, p):
768 """ Parse the extension from on the wire format 769 770 @type p: L{tlslite.util.codec.Parser} 771 @param p: data to be parsed 772 773 @raise SyntaxError: when the size of the passed element doesn't match 774 the internal representation 775 776 @rtype: L{NPNExtension} 777 """ 778 self.protocols = [] 779 780 while p.getRemainingLength() > 0: 781 self.protocols += [p.getVarBytes(1)] 782 783 return self
784
785 -class TACKExtension(TLSExtension):
786 """ 787 This class handles the server side TACK extension (see 788 draft-perrin-tls-tack-02). 789 790 @type tacks: list 791 @ivar tacks: list of L{TACK}'s supported by server 792 793 @type activation_flags: int 794 @ivar activation_flags: activation flags for the tacks 795 """ 796
797 - class TACK(object):
798 """ 799 Implementation of the single TACK 800 """
801 - def __init__(self):
802 """ 803 Create a single TACK object 804 """ 805 self.public_key = bytearray(64) 806 self.min_generation = 0 807 self.generation = 0 808 self.expiration = 0 809 self.target_hash = bytearray(32) 810 self.signature = bytearray(64)
811
812 - def __repr__(self):
813 """ 814 Return programmmer readable representation of TACK object 815 816 @rtype: str 817 """ 818 return "TACK(public_key={0!r}, min_generation={1!r}, "\ 819 "generation={2!r}, expiration={3!r}, target_hash={4!r}, "\ 820 "signature={5!r})".format( 821 self.public_key, self.min_generation, 822 self.generation, self.expiration, self.target_hash, 823 self.signature)
824
825 - def create(self, public_key, min_generation, generation, expiration, 826 target_hash, signature):
827 """ 828 Initialise the TACK with data 829 """ 830 self.public_key = public_key 831 self.min_generation = min_generation 832 self.generation = generation 833 self.expiration = expiration 834 self.target_hash = target_hash 835 self.signature = signature 836 return self
837
838 - def write(self):
839 """ 840 Convert the TACK into on the wire format 841 842 @rtype: bytearray 843 """ 844 w = Writer() 845 if len(self.public_key) != 64: 846 raise TLSInternalError("Public_key must be 64 bytes long") 847 w.bytes += self.public_key 848 w.add(self.min_generation, 1) 849 w.add(self.generation, 1) 850 w.add(self.expiration, 4) 851 if len(self.target_hash) != 32: 852 raise TLSInternalError("Target_hash must be 32 bytes long") 853 w.bytes += self.target_hash 854 if len(self.signature) != 64: 855 raise TLSInternalError("Signature must be 64 bytes long") 856 w.bytes += self.signature 857 return w.bytes
858
859 - def parse(self, p):
860 """ 861 Parse the TACK from on the wire format 862 863 @type p: L{tlslite.util.codec.Parser} 864 @param p: data to be parsed 865 866 @rtype: L{TACK} 867 @raise SyntaxError: when the internal sizes don't match the 868 provided data 869 """ 870 871 self.public_key = p.getFixBytes(64) 872 self.min_generation = p.get(1) 873 self.generation = p.get(1) 874 self.expiration = p.get(4) 875 self.target_hash = p.getFixBytes(32) 876 self.signature = p.getFixBytes(64) 877 return self
878
879 - def __eq__(self, other):
880 """ 881 Tests if the other object is equivalent to this TACK 882 883 Returns False for every object that's not a TACK 884 """ 885 if hasattr(other, 'public_key') and\ 886 hasattr(other, 'min_generation') and\ 887 hasattr(other, 'generation') and\ 888 hasattr(other, 'expiration') and\ 889 hasattr(other, 'target_hash') and\ 890 hasattr(other, 'signature'): 891 if self.public_key == other.public_key and\ 892 self.min_generation == other.min_generation and\ 893 self.generation == other.generation and\ 894 self.expiration == other.expiration and\ 895 self.target_hash == other.target_hash and\ 896 self.signature == other.signature: 897 return True 898 else: 899 return False 900 else: 901 return False
902
903 - def __init__(self):
904 """ 905 Create an instance of TACKExtension 906 907 See also: L{create} and L{parse} 908 """ 909 super(TACKExtension, self).__init__(extType=ExtensionType.tack) 910 911 self.tacks = [] 912 self.activation_flags = 0
913
914 - def __repr__(self):
915 """ 916 Create a programmer readable representation of TACK extension 917 918 @rtype: str 919 """ 920 return "TACKExtension(activation_flags={0!r}, tacks={1!r})".format( 921 self.activation_flags, self.tacks)
922 923 @property
924 - def extData(self):
925 """ 926 Return the raw data encoding of the extension 927 928 @rtype: bytearray 929 """ 930 w2 = Writer() 931 for t in self.tacks: 932 w2.bytes += t.write() 933 934 w = Writer() 935 w.add(len(w2.bytes), 2) 936 w.bytes += w2.bytes 937 w.add(self.activation_flags, 1) 938 return w.bytes
939
940 - def create(self, tacks, activation_flags):
941 """ 942 Initialize the instance of TACKExtension 943 944 @rtype: TACKExtension 945 """ 946 947 self.tacks = tacks 948 self.activation_flags = activation_flags 949 return self
950
951 - def parse(self, p):
952 """ 953 Parse the extension from on the wire format 954 955 @type p: L{tlslite.util.codec.Parser} 956 @param p: data to be parsed 957 958 @rtype: L{TACKExtension} 959 """ 960 self.tacks = [] 961 962 p.startLengthCheck(2) 963 while not p.atLengthCheck(): 964 tack = TACKExtension.TACK().parse(p) 965 self.tacks += [tack] 966 p.stopLengthCheck() 967 self.activation_flags = p.get(1) 968 969 return self
970
971 -class SupportedGroupsExtension(VarListExtension):
972 """ 973 Client side list of supported groups of (EC)DHE key exchage. 974 975 See RFC4492, RFC7027 and RFC-ietf-tls-negotiated-ff-dhe-10 976 977 @type groups: int 978 @ivar groups: list of groups that the client supports 979 """ 980
981 - def __init__(self):
982 """Create instance of class""" 983 super(SupportedGroupsExtension, self).__init__(2, 2, 'groups', \ 984 ExtensionType.supported_groups)
985
986 -class ECPointFormatsExtension(VarListExtension):
987 """ 988 Client side list of supported ECC point formats. 989 990 See RFC4492. 991 992 @type formats: list of int 993 @ivar formats: list of point formats supported by peer 994 """ 995
996 - def __init__(self):
997 """Create instance of class""" 998 super(ECPointFormatsExtension, self).__init__(1, 1, 'formats', \ 999 ExtensionType.ec_point_formats)
1000
1001 -class SignatureAlgorithmsExtension(TLSExtension):
1002 1003 """ 1004 Client side list of supported signature algorithms. 1005 1006 Should be used by server to select certificate and signing method for 1007 Server Key Exchange messages. In practice used only for the latter. 1008 1009 See RFC5246. 1010 """ 1011
1012 - def __init__(self):
1013 """Create instance of class""" 1014 super(SignatureAlgorithmsExtension, self).__init__(extType= 1015 ExtensionType. 1016 signature_algorithms) 1017 self.sigalgs = None
1018 1019 @property
1020 - def extData(self):
1021 """ 1022 Return raw encoding of the extension 1023 1024 @rtype: bytearray 1025 """ 1026 if self.sigalgs is None: 1027 return bytearray(0) 1028 1029 writer = Writer() 1030 # elements 1 byte each, overall length encoded in 2 bytes 1031 writer.addVarTupleSeq(self.sigalgs, 1, 2) 1032 return writer.bytes
1033
1034 - def create(self, sigalgs):
1035 """ 1036 Set the list of supported algorithm types 1037 1038 @type sigalgs: list of tuples 1039 @param sigalgs: list of pairs of a hash algorithm and signature 1040 algorithm 1041 """ 1042 self.sigalgs = sigalgs 1043 return self
1044
1045 - def parse(self, parser):
1046 """ 1047 Deserialise extension from on the wire data 1048 1049 @type parser: L{Parser} 1050 @rtype: SignatureAlgorithmsExtension 1051 """ 1052 if parser.getRemainingLength() == 0: 1053 self.sigalgs = None 1054 return self 1055 1056 self.sigalgs = parser.getVarTupleList(1, 2, 2) 1057 1058 if parser.getRemainingLength() != 0: 1059 raise SyntaxError() 1060 1061 return self
1062
1063 1064 -class PaddingExtension(TLSExtension):
1065 """ 1066 ClientHello message padding with a desired size. 1067 1068 Can be used to pad ClientHello messages to a desired size 1069 in order to avoid implementation bugs caused by certain 1070 ClientHello sizes. 1071 1072 See RFC7685. 1073 """ 1074
1075 - def __init__(self):
1076 """Create instance of class.""" 1077 extType = ExtensionType.client_hello_padding 1078 super(PaddingExtension, self).__init__(extType=extType) 1079 self.paddingData = bytearray(0)
1080 1081 @property
1082 - def extData(self):
1083 """ 1084 Return raw encoding of the extension. 1085 1086 @rtype: bytearray 1087 """ 1088 return self.paddingData
1089
1090 - def create(self, size):
1091 """ 1092 Set the padding size and create null byte padding of defined size. 1093 1094 @type size: int 1095 @param size: required padding size in bytes 1096 """ 1097 self.paddingData = bytearray(size) 1098 return self
1099
1100 - def parse(self, p):
1101 """ 1102 Deserialise extension from on the wire data. 1103 1104 @type p: L{tlslite.util.codec.Parser} 1105 @param p: data to be parsed 1106 1107 @raise SyntaxError: when the size of the passed element doesn't match 1108 the internal representation 1109 1110 @rtype: L{TLSExtension} 1111 """ 1112 self.paddingData = p.getFixBytes(p.getRemainingLength()) 1113 return self
1114
1115 -class RenegotiationInfoExtension(TLSExtension):
1116 """ 1117 Client and Server Hello secure renegotiation extension from RFC 5746 1118 1119 Should have an empty renegotiated_connection field in case of initial 1120 connection 1121 """ 1122
1123 - def __init__(self):
1124 """Create instance""" 1125 extType = ExtensionType.renegotiation_info 1126 super(RenegotiationInfoExtension, self).__init__(extType=extType) 1127 self.renegotiated_connection = None
1128 1129 @property
1130 - def extData(self):
1131 """ 1132 Return raw encoding of the extension. 1133 1134 @rtype: bytearray 1135 """ 1136 if self.renegotiated_connection is None: 1137 return bytearray(0) 1138 writer = Writer() 1139 writer.add(len(self.renegotiated_connection), 1) 1140 writer.bytes += self.renegotiated_connection 1141 return writer.bytes
1142
1143 - def create(self, renegotiated_connection):
1144 """ 1145 Set the finished message payload from previous connection. 1146 1147 @type renegotiated_connection: bytearray 1148 """ 1149 self.renegotiated_connection = renegotiated_connection 1150 return self
1151
1152 - def parse(self, parser):
1153 """ 1154 Deserialise extension from on the wire data. 1155 1156 @type parser: L{tlslite.util.codec.Parser} 1157 @param parser: data to be parsed 1158 1159 @rtype: L{RenegotiationInfoExtension} 1160 """ 1161 if parser.getRemainingLength() == 0: 1162 self.renegotiated_connection = None 1163 else: 1164 self.renegotiated_connection = parser.getVarBytes(1) 1165 1166 return self
1167
1168 1169 -class ALPNExtension(TLSExtension):
1170 """ 1171 Handling of Application Layer Protocol Negotiation extension from RFC 7301. 1172 1173 @type protocol_names: list of bytearrays 1174 @ivar protocol_names: list of protocol names acceptable or selected by peer 1175 1176 @type extType: int 1177 @ivar extType: numberic type of ALPNExtension, i.e. 16 1178 1179 @type extData: bytearray 1180 @ivar extData: raw encoding of the extension data 1181 """ 1182
1183 - def __init__(self):
1184 """ 1185 Create instance of ALPNExtension 1186 1187 See also: L{create} and L{parse} 1188 """ 1189 super(ALPNExtension, self).__init__(extType=ExtensionType.alpn) 1190 1191 self.protocol_names = None
1192
1193 - def __repr__(self):
1194 """ 1195 Create programmer-readable representation of object 1196 1197 @rtype: str 1198 """ 1199 return "ALPNExtension(protocol_names={0!r})".format(self.protocol_names)
1200 1201 @property
1202 - def extData(self):
1203 """ 1204 Return encoded payload of the extension 1205 1206 @rtype: bytearray 1207 """ 1208 if self.protocol_names is None: 1209 return bytearray(0) 1210 1211 writer = Writer() 1212 for prot in self.protocol_names: 1213 writer.add(len(prot), 1) 1214 writer.bytes += prot 1215 1216 writer2 = Writer() 1217 writer2.add(len(writer.bytes), 2) 1218 writer2.bytes += writer.bytes 1219 1220 return writer2.bytes
1221
1222 - def create(self, protocol_names=None):
1223 """ 1224 Create an instance of ALPNExtension with specified protocols 1225 1226 @type protocols: list of bytearray 1227 @param protocols: list of protocol names that are to be sent 1228 """ 1229 self.protocol_names = protocol_names 1230 return self
1231
1232 - def parse(self, parser):
1233 """ 1234 Parse the extension from on the wire format 1235 1236 @type parser: L{tlslite.util.codec.Parser} 1237 @param parser: data to be parsed as extension 1238 1239 @raise SyntaxError: when the encoding of the extension is self 1240 inconsistent 1241 1242 @rtype: L{ALPNExtension} 1243 """ 1244 self.protocol_names = [] 1245 parser.startLengthCheck(2) 1246 while not parser.atLengthCheck(): 1247 name_len = parser.get(1) 1248 self.protocol_names.append(parser.getFixBytes(name_len)) 1249 parser.stopLengthCheck() 1250 if parser.getRemainingLength() != 0: 1251 raise SyntaxError("Trailing data after protocol_name_list") 1252 return self
1253
1254 1255 -class StatusRequestExtension(TLSExtension):
1256 """ 1257 Handling of the Certificate Status Request extension from RFC 6066. 1258 1259 @type status_type: int 1260 @ivar status_type: type of the status request 1261 1262 @type responder_id_list: list of bytearray 1263 @ivar responder_id_list: list of DER encoded OCSP responder identifiers 1264 that the client trusts 1265 1266 @type request_extensions: bytearray 1267 @ivar request_extensions: DER encoded list of OCSP extensions, as defined 1268 in RFC 2560 1269 """ 1270
1271 - def __init__(self):
1272 super(StatusRequestExtension, self).__init__( 1273 extType=ExtensionType.status_request) 1274 """Create instance of StatusRequestExtension.""" 1275 self.status_type = None 1276 self.responder_id_list = [] 1277 self.request_extensions = bytearray()
1278
1279 - def __repr__(self):
1280 """ 1281 Create programmer-readable representation of object 1282 1283 @rtype: str 1284 """ 1285 return ("StatusRequestExtension(status_type={0}, " 1286 "responder_id_list={1!r}, " 1287 "request_extensions={2!r})").format( 1288 self.status_type, self.responder_id_list, 1289 self.request_extensions)
1290 1291 @property
1292 - def extData(self):
1293 """ 1294 Return encoded payload of the extension. 1295 1296 @rtype: bytearray 1297 """ 1298 if self.status_type is None: 1299 return bytearray() 1300 1301 writer = Writer() 1302 writer.add(self.status_type, 1) 1303 writer2 = Writer() 1304 for i in self.responder_id_list: 1305 writer2.add(len(i), 2) 1306 writer2.bytes += i 1307 writer.add(len(writer2.bytes), 2) 1308 writer.bytes += writer2.bytes 1309 writer.add(len(self.request_extensions), 2) 1310 writer.bytes += self.request_extensions 1311 1312 return writer.bytes
1313
1314 - def create(self, status_type=CertificateStatusType.ocsp, 1315 responder_id_list=tuple(), 1316 request_extensions=b''):
1317 """ 1318 Create an instance of StatusRequestExtension with specified options. 1319 1320 @type status_type: int 1321 @param status_type: type of status returned 1322 1323 @type responder_id_list: list 1324 @param responder_id_list: list of encoded OCSP responder identifiers 1325 that the client trusts 1326 1327 @type request_extensions: bytearray 1328 @param request_extensions: DER encoding of requested OCSP extensions 1329 """ 1330 self.status_type = status_type 1331 self.responder_id_list = list(responder_id_list) 1332 self.request_extensions = bytearray(request_extensions) 1333 return self
1334
1335 - def parse(self, parser):
1336 """ 1337 Parse the extension from on the wire format. 1338 1339 @type parser: L{tlslite.util.codec.Parser} 1340 @param parser: data to be parsed as extension 1341 1342 @rtype: L{StatusRequestExtension} 1343 """ 1344 # handling of server side message 1345 if parser.getRemainingLength() == 0: 1346 self.status_type = None 1347 self.responder_id_list = [] 1348 self.request_extensions = bytearray() 1349 return self 1350 1351 self.status_type = parser.get(1) 1352 self.responder_id_list = [] 1353 parser.startLengthCheck(2) 1354 while not parser.atLengthCheck(): 1355 self.responder_id_list.append(parser.getVarBytes(2)) 1356 parser.stopLengthCheck() 1357 self.request_extensions = parser.getVarBytes(2) 1358 if parser.getRemainingLength() != 0: 1359 raise SyntaxError("Trailing data after CertificateStatusRequest") 1360 return self
1361 1362 1363 TLSExtension._universalExtensions = \ 1364 { 1365 ExtensionType.server_name: SNIExtension, 1366 ExtensionType.status_request: StatusRequestExtension, 1367 ExtensionType.cert_type: ClientCertTypeExtension, 1368 ExtensionType.supported_groups: SupportedGroupsExtension, 1369 ExtensionType.ec_point_formats: ECPointFormatsExtension, 1370 ExtensionType.srp: SRPExtension, 1371 ExtensionType.signature_algorithms: SignatureAlgorithmsExtension, 1372 ExtensionType.alpn: ALPNExtension, 1373 ExtensionType.supports_npn: NPNExtension, 1374 ExtensionType.client_hello_padding: PaddingExtension, 1375 ExtensionType.renegotiation_info: RenegotiationInfoExtension} 1376 1377 TLSExtension._serverExtensions = \ 1378 { 1379 ExtensionType.cert_type: ServerCertTypeExtension, 1380 ExtensionType.tack: TACKExtension} 1381