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

Source Code for Module tlslite.recordlayer

  1  # Copyright (c) 2014, Hubert Kario 
  2  # 
  3  # See the LICENSE file for legal information regarding use of this file. 
  4   
  5  """Implementation of the TLS Record Layer protocol""" 
  6   
  7  import socket 
  8  import errno 
  9  from .utils import tlshashlib as hashlib 
 10  from .constants import ContentType, CipherSuite 
 11  from .messages import RecordHeader3, RecordHeader2, Message 
 12  from .utils.cipherfactory import createAESGCM, createAES, createRC4, \ 
 13          createTripleDES, createCHACHA20 
 14  from .utils.codec import Parser, Writer 
 15  from .utils.compat import compatHMAC 
 16  from .utils.cryptomath import getRandomBytes, MD5 
 17  from .utils.constanttime import ct_compare_digest, ct_check_cbc_mac_and_pad 
 18  from .errors import TLSRecordOverflow, TLSIllegalParameterException,\ 
 19          TLSAbruptCloseError, TLSDecryptionFailed, TLSBadRecordMAC 
 20  from .mathtls import createMAC_SSL, createHMAC, PRF_SSL, PRF, PRF_1_2, \ 
 21          PRF_1_2_SHA384 
22 23 -class RecordSocket(object):
24 25 """Socket wrapper for reading and writing TLS Records""" 26
27 - def __init__(self, sock):
28 """ 29 Assign socket to wrapper 30 31 @type sock: socket.socket 32 """ 33 self.sock = sock 34 self.version = (0, 0)
35
36 - def _sockSendAll(self, data):
37 """ 38 Send all data through socket 39 40 @type data: bytearray 41 @param data: data to send 42 @raise socket.error: when write to socket failed 43 """ 44 while 1: 45 try: 46 bytesSent = self.sock.send(data) 47 except socket.error as why: 48 if why.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN): 49 yield 1 50 continue 51 raise 52 53 if bytesSent == len(data): 54 return 55 data = data[bytesSent:] 56 yield 1
57
58 - def send(self, msg, padding=0):
59 """ 60 Send the message through socket. 61 62 @type msg: bytearray 63 @param msg: TLS message to send 64 @type padding: int 65 @param padding: amount of padding to specify for SSLv2 66 @raise socket.error: when write to socket failed 67 """ 68 data = msg.write() 69 70 if self.version in ((2, 0), (0, 2)): 71 header = RecordHeader2().create(len(data), 72 padding) 73 else: 74 header = RecordHeader3().create(self.version, 75 msg.contentType, 76 len(data)) 77 78 data = header.write() + data 79 80 for result in self._sockSendAll(data): 81 yield result
82
83 - def _sockRecvAll(self, length):
84 """ 85 Read exactly the amount of bytes specified in L{length} from raw socket. 86 87 @rtype: generator 88 @return: generator that will return 0 or 1 in case the socket is non 89 blocking and would block and bytearray in case the read finished 90 @raise TLSAbruptCloseError: when the socket closed 91 """ 92 buf = bytearray(0) 93 94 if length == 0: 95 yield buf 96 97 while True: 98 try: 99 socketBytes = self.sock.recv(length - len(buf)) 100 except socket.error as why: 101 if why.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN): 102 yield 0 103 continue 104 else: 105 raise 106 107 #if the connection closed, raise socket error 108 if len(socketBytes) == 0: 109 raise TLSAbruptCloseError() 110 111 buf += bytearray(socketBytes) 112 if len(buf) == length: 113 yield buf
114
115 - def _recvHeader(self):
116 """Read a single record header from socket""" 117 #Read the next record header 118 buf = bytearray(0) 119 ssl2 = False 120 121 result = None 122 for result in self._sockRecvAll(1): 123 if result in (0, 1): 124 yield result 125 else: break 126 assert result is not None 127 128 buf += result 129 130 if buf[0] in ContentType.all: 131 ssl2 = False 132 # SSLv3 record layer header is 5 bytes long, we already read 1 133 result = None 134 for result in self._sockRecvAll(4): 135 if result in (0, 1): 136 yield result 137 else: break 138 assert result is not None 139 buf += result 140 else: 141 # if header has no pading the header is 2 bytes long, 3 otherwise 142 # at the same time we already read 1 byte 143 ssl2 = True 144 if buf[0] & 0x80: 145 readLen = 1 146 else: 147 readLen = 2 148 result = None 149 for result in self._sockRecvAll(readLen): 150 if result in (0, 1): 151 yield result 152 else: break 153 assert result is not None 154 buf += result 155 156 157 #Parse the record header 158 if ssl2: 159 record = RecordHeader2().parse(Parser(buf)) 160 # padding can't be longer than overall length and if it is present 161 # the overall size must be a multiple of cipher block size 162 if ((record.padding > record.length) or 163 (record.padding and record.length % 8)): 164 raise TLSIllegalParameterException(\ 165 "Malformed record layer header") 166 else: 167 record = RecordHeader3().parse(Parser(buf)) 168 169 yield record
170
171 - def recv(self):
172 """ 173 Read a single record from socket, handle SSLv2 and SSLv3 record layer 174 175 @rtype: generator 176 @return: generator that returns 0 or 1 in case the read would be 177 blocking or a tuple containing record header (object) and record 178 data (bytearray) read from socket 179 @raise socket.error: In case of network error 180 @raise TLSAbruptCloseError: When the socket was closed on the other 181 side in middle of record receiving 182 @raise TLSRecordOverflow: When the received record was longer than 183 allowed by TLS 184 @raise TLSIllegalParameterException: When the record header was 185 malformed 186 """ 187 record = None 188 for record in self._recvHeader(): 189 if record in (0, 1): 190 yield record 191 else: break 192 assert record is not None 193 194 #Check the record header fields 195 # 18432 = 2**14 (basic record size limit) + 1024 (maximum compression 196 # overhead) + 1024 (maximum encryption overhead) 197 if record.length > 18432: 198 raise TLSRecordOverflow() 199 200 #Read the record contents 201 buf = bytearray(0) 202 203 result = None 204 for result in self._sockRecvAll(record.length): 205 if result in (0, 1): 206 yield result 207 else: break 208 assert result is not None 209 210 buf += result 211 212 yield (record, buf)
213
214 -class ConnectionState(object):
215 216 """Preserve the connection state for reading and writing data to records""" 217
218 - def __init__(self):
219 """Create an instance with empty encryption and MACing contexts""" 220 self.macContext = None 221 self.encContext = None 222 self.fixedNonce = None 223 self.seqnum = 0
224
225 - def getSeqNumBytes(self):
226 """Return encoded sequence number and increment it.""" 227 writer = Writer() 228 writer.add(self.seqnum, 8) 229 self.seqnum += 1 230 return writer.bytes
231
232 -class RecordLayer(object):
233 234 """ 235 Implementation of TLS record layer protocol 236 237 @ivar version: the TLS version to use (tuple encoded as on the wire) 238 @ivar sock: underlying socket 239 @ivar client: whether the connection should use encryption 240 @ivar encryptThenMAC: use the encrypt-then-MAC mechanism for record 241 integrity 242 @ivar handshake_finished: used in SSL2, True if handshake protocol is over 243 """ 244
245 - def __init__(self, sock):
246 self.sock = sock 247 self._recordSocket = RecordSocket(sock) 248 self._version = (0, 0) 249 250 self.client = True 251 252 self._writeState = ConnectionState() 253 self._readState = ConnectionState() 254 self._pendingWriteState = ConnectionState() 255 self._pendingReadState = ConnectionState() 256 self.fixedIVBlock = None 257 258 self.encryptThenMAC = False 259 260 self.handshake_finished = False
261 262 @property
263 - def blockSize(self):
264 """Return the size of block used by current symmetric cipher (R/O)""" 265 return self._writeState.encContext.block_size
266 267 @property
268 - def version(self):
269 """Return the TLS version used by record layer""" 270 return self._version
271 272 @version.setter
273 - def version(self, val):
274 """Set the TLS version used by record layer""" 275 self._version = val 276 self._recordSocket.version = val
277
278 - def getCipherName(self):
279 """ 280 Return the name of the bulk cipher used by this connection 281 282 @rtype: str 283 @return: The name of the cipher, like 'aes128', 'rc4', etc. 284 """ 285 if self._writeState.encContext is None: 286 return None 287 return self._writeState.encContext.name
288
289 - def getCipherImplementation(self):
290 """ 291 Return the name of the implementation used for the connection 292 293 'python' for tlslite internal implementation, 'openssl' for M2crypto 294 and 'pycrypto' for pycrypto 295 @rtype: str 296 @return: Name of cipher implementation used, None if not initialised 297 """ 298 if self._writeState.encContext is None: 299 return None 300 return self._writeState.encContext.implementation
301
302 - def shutdown(self):
303 """Clear read and write states""" 304 self._writeState = ConnectionState() 305 self._readState = ConnectionState() 306 self._pendingWriteState = ConnectionState() 307 self._pendingReadState = ConnectionState()
308
309 - def isCBCMode(self):
310 """Returns true if cipher uses CBC mode""" 311 if self._writeState and self._writeState.encContext and \ 312 self._writeState.encContext.isBlockCipher: 313 return True 314 else: 315 return False
316 # 317 # sending messages 318 # 319
320 - def addPadding(self, data):
321 """Add padding to data so that it is multiple of block size""" 322 currentLength = len(data) 323 blockLength = self.blockSize 324 paddingLength = blockLength - 1 - (currentLength % blockLength) 325 326 paddingBytes = bytearray([paddingLength] * (paddingLength+1)) 327 data += paddingBytes 328 return data
329
330 - def calculateMAC(self, mac, seqnumBytes, contentType, data):
331 """Calculate the SSL/TLS version of a MAC""" 332 mac.update(compatHMAC(seqnumBytes)) 333 mac.update(compatHMAC(bytearray([contentType]))) 334 assert self.version in ((3, 0), (3, 1), (3, 2), (3, 3)) 335 if self.version != (3, 0): 336 mac.update(compatHMAC(bytearray([self.version[0]]))) 337 mac.update(compatHMAC(bytearray([self.version[1]]))) 338 mac.update(compatHMAC(bytearray([len(data)//256]))) 339 mac.update(compatHMAC(bytearray([len(data)%256]))) 340 mac.update(compatHMAC(data)) 341 return bytearray(mac.digest())
342
343 - def _macThenEncrypt(self, data, contentType):
344 """MAC, pad then encrypt data""" 345 if self._writeState.macContext: 346 seqnumBytes = self._writeState.getSeqNumBytes() 347 mac = self._writeState.macContext.copy() 348 macBytes = self.calculateMAC(mac, seqnumBytes, contentType, data) 349 data += macBytes 350 351 #Encrypt for Block or Stream Cipher 352 if self._writeState.encContext: 353 #Add padding (for Block Cipher): 354 if self._writeState.encContext.isBlockCipher: 355 356 #Add TLS 1.1 fixed block 357 if self.version >= (3, 2): 358 data = self.fixedIVBlock + data 359 360 data = self.addPadding(data) 361 362 #Encrypt 363 data = self._writeState.encContext.encrypt(data) 364 365 return data
366
367 - def _encryptThenMAC(self, buf, contentType):
368 """Pad, encrypt and then MAC the data""" 369 if self._writeState.encContext: 370 # add IV for TLS1.1+ 371 if self.version >= (3, 2): 372 buf = self.fixedIVBlock + buf 373 374 buf = self.addPadding(buf) 375 376 buf = self._writeState.encContext.encrypt(buf) 377 378 # add MAC 379 if self._writeState.macContext: 380 seqnumBytes = self._writeState.getSeqNumBytes() 381 mac = self._writeState.macContext.copy() 382 383 # append MAC 384 macBytes = self.calculateMAC(mac, seqnumBytes, contentType, buf) 385 buf += macBytes 386 387 return buf
388
389 - def _encryptThenSeal(self, buf, contentType):
390 """Encrypt with AEAD cipher""" 391 #Assemble the authenticated data. 392 seqNumBytes = self._writeState.getSeqNumBytes() 393 authData = seqNumBytes + bytearray([contentType, 394 self.version[0], 395 self.version[1], 396 len(buf)//256, 397 len(buf)%256]) 398 399 #The nonce is always the fixed nonce and the sequence number. 400 nonce = self._writeState.fixedNonce + seqNumBytes 401 402 assert len(nonce) == self._writeState.encContext.nonceLength 403 404 buf = self._writeState.encContext.seal(nonce, buf, authData) 405 406 #AES-GCM, has an explicit variable nonce. 407 if "aes" in self._writeState.encContext.name: 408 buf = seqNumBytes + buf 409 410 return buf
411
412 - def _ssl2Encrypt(self, data):
413 """Encrypt in SSL2 mode""" 414 # in SSLv2 sequence numbers are incremented for plaintext records too 415 seqnumBytes = self._writeState.getSeqNumBytes() 416 417 if (self._writeState.encContext and 418 self._writeState.encContext.isBlockCipher): 419 plaintext_len = len(data) 420 data = self.addPadding(data) 421 padding = len(data) - plaintext_len 422 else: 423 padding = 0 424 425 if self._writeState.macContext: 426 mac = self._writeState.macContext.copy() 427 mac.update(compatHMAC(data)) 428 mac.update(compatHMAC(seqnumBytes[-4:])) 429 430 data = bytearray(mac.digest()) + data 431 432 if self._writeState.encContext: 433 data = self._writeState.encContext.encrypt(data) 434 435 return data, padding
436
437 - def sendRecord(self, msg):
438 """ 439 Encrypt, MAC and send arbitrary message as-is through socket. 440 441 Note that if the message was not fragmented to below 2**14 bytes 442 it will be rejected by the other connection side. 443 444 @param msg: TLS message to send 445 @type msg: ApplicationData, HandshakeMessage, etc. 446 """ 447 data = msg.write() 448 contentType = msg.contentType 449 450 padding = 0 451 if self.version in ((0, 2), (2, 0)): 452 data, padding = self._ssl2Encrypt(data) 453 elif self._writeState and \ 454 self._writeState.encContext and \ 455 self._writeState.encContext.isAEAD: 456 data = self._encryptThenSeal(data, contentType) 457 elif self.encryptThenMAC: 458 data = self._encryptThenMAC(data, contentType) 459 else: 460 data = self._macThenEncrypt(data, contentType) 461 462 encryptedMessage = Message(contentType, data) 463 464 for result in self._recordSocket.send(encryptedMessage, padding): 465 yield result
466 467 # 468 # receiving messages 469 # 470
471 - def _decryptStreamThenMAC(self, recordType, data):
472 """Decrypt a stream cipher and check MAC""" 473 if self._readState.encContext: 474 assert self.version in ((3, 0), (3, 1), (3, 2), (3, 3)) 475 476 data = self._readState.encContext.decrypt(data) 477 478 if self._readState.macContext: 479 #Check MAC 480 macGood = True 481 macLength = self._readState.macContext.digest_size 482 endLength = macLength 483 if endLength > len(data): 484 macGood = False 485 else: 486 #Read MAC 487 startIndex = len(data) - endLength 488 endIndex = startIndex + macLength 489 checkBytes = data[startIndex : endIndex] 490 491 #Calculate MAC 492 seqnumBytes = self._readState.getSeqNumBytes() 493 data = data[:-endLength] 494 mac = self._readState.macContext.copy() 495 macBytes = self.calculateMAC(mac, seqnumBytes, recordType, 496 data) 497 498 #Compare MACs 499 if not ct_compare_digest(macBytes, checkBytes): 500 macGood = False 501 502 if not macGood: 503 raise TLSBadRecordMAC() 504 505 return data
506 507
508 - def _decryptThenMAC(self, recordType, data):
509 """Decrypt data, check padding and MAC""" 510 if self._readState.encContext: 511 assert self.version in ((3, 0), (3, 1), (3, 2), (3, 3)) 512 assert self._readState.encContext.isBlockCipher 513 assert self._readState.macContext 514 515 # 516 # decrypt the record 517 # 518 blockLength = self._readState.encContext.block_size 519 if len(data) % blockLength != 0: 520 raise TLSDecryptionFailed() 521 data = self._readState.encContext.decrypt(data) 522 if self.version >= (3, 2): #For TLS 1.1, remove explicit IV 523 data = data[self._readState.encContext.block_size : ] 524 525 # 526 # check padding and MAC 527 # 528 seqnumBytes = self._readState.getSeqNumBytes() 529 530 if not ct_check_cbc_mac_and_pad(data, 531 self._readState.macContext, 532 seqnumBytes, 533 recordType, 534 self.version): 535 raise TLSBadRecordMAC() 536 537 # 538 # strip padding and MAC 539 # 540 541 endLength = data[-1] + 1 + self._readState.macContext.digest_size 542 543 data = data[:-endLength] 544 545 return data
546
547 - def _macThenDecrypt(self, recordType, buf):
548 """ 549 Check MAC of data, then decrypt and remove padding 550 551 @raise TLSBadRecordMAC: when the mac value is invalid 552 @raise TLSDecryptionFailed: when the data to decrypt has invalid size 553 """ 554 if self._readState.macContext: 555 macLength = self._readState.macContext.digest_size 556 if len(buf) < macLength: 557 raise TLSBadRecordMAC("Truncated data") 558 559 checkBytes = buf[-macLength:] 560 buf = buf[:-macLength] 561 562 seqnumBytes = self._readState.getSeqNumBytes() 563 mac = self._readState.macContext.copy() 564 565 macBytes = self.calculateMAC(mac, seqnumBytes, recordType, buf) 566 567 if not ct_compare_digest(macBytes, checkBytes): 568 raise TLSBadRecordMAC("MAC mismatch") 569 570 if self._readState.encContext: 571 blockLength = self._readState.encContext.block_size 572 if len(buf) % blockLength != 0: 573 raise TLSDecryptionFailed("data length not multiple of "\ 574 "block size") 575 576 buf = self._readState.encContext.decrypt(buf) 577 578 # remove explicit IV 579 if self.version >= (3, 2): 580 buf = buf[blockLength:] 581 582 if len(buf) == 0: 583 raise TLSBadRecordMAC("No data left after IV removal") 584 585 # check padding 586 paddingLength = buf[-1] 587 if paddingLength + 1 > len(buf): 588 raise TLSBadRecordMAC("Invalid padding length") 589 590 paddingGood = True 591 totalPaddingLength = paddingLength+1 592 if self.version != (3, 0): 593 paddingBytes = buf[-totalPaddingLength:-1] 594 for byte in paddingBytes: 595 if byte != paddingLength: 596 paddingGood = False 597 598 if not paddingGood: 599 raise TLSBadRecordMAC("Invalid padding byte values") 600 601 # remove padding 602 buf = buf[:-totalPaddingLength] 603 604 return buf
605
606 - def _decryptAndUnseal(self, recordType, buf):
607 """Decrypt AEAD encrypted data""" 608 seqnumBytes = self._readState.getSeqNumBytes() 609 #AES-GCM, has an explicit variable nonce. 610 if "aes" in self._readState.encContext.name: 611 explicitNonceLength = 8 612 if explicitNonceLength > len(buf): 613 #Publicly invalid. 614 raise TLSBadRecordMAC("Truncated nonce") 615 nonce = self._readState.fixedNonce + buf[:explicitNonceLength] 616 buf = buf[8:] 617 else: 618 nonce = self._readState.fixedNonce + seqnumBytes 619 620 if self._readState.encContext.tagLength > len(buf): 621 #Publicly invalid. 622 raise TLSBadRecordMAC("Truncated tag") 623 624 plaintextLen = len(buf) - self._readState.encContext.tagLength 625 authData = seqnumBytes + bytearray([recordType, self.version[0], 626 self.version[1], 627 plaintextLen//256, 628 plaintextLen%256]) 629 630 buf = self._readState.encContext.open(nonce, buf, authData) 631 if buf is None: 632 raise TLSBadRecordMAC("Invalid tag, decryption failure") 633 return buf
634
635 - def _decryptSSL2(self, data, padding):
636 """Decrypt SSL2 encrypted data""" 637 # sequence numbers are incremented for plaintext records too 638 seqnumBytes = self._readState.getSeqNumBytes() 639 640 # 641 # decrypt 642 # 643 if self._readState.encContext: 644 if self._readState.encContext.isBlockCipher: 645 blockLength = self._readState.encContext.block_size 646 if len(data) % blockLength: 647 raise TLSDecryptionFailed() 648 data = self._readState.encContext.decrypt(data) 649 650 # 651 # strip and check MAC 652 # 653 if self._readState.macContext: 654 macBytes = data[:16] 655 data = data[16:] 656 657 mac = self._readState.macContext.copy() 658 mac.update(compatHMAC(data)) 659 mac.update(compatHMAC(seqnumBytes[-4:])) 660 calcMac = bytearray(mac.digest()) 661 if macBytes != calcMac: 662 raise TLSBadRecordMAC() 663 664 # 665 # strip padding 666 # 667 if padding: 668 data = data[:-padding] 669 return data
670
671 - def recvRecord(self):
672 """ 673 Read, decrypt and check integrity of a single record 674 675 @rtype: tuple 676 @return: message header and decrypted message payload 677 @raise TLSDecryptionFailed: when decryption of data failed 678 @raise TLSBadRecordMAC: when record has bad MAC or padding 679 @raise socket.error: when reading from socket was unsuccessful 680 """ 681 result = None 682 for result in self._recordSocket.recv(): 683 if result in (0, 1): 684 yield result 685 else: break 686 assert result is not None 687 688 (header, data) = result 689 690 if isinstance(header, RecordHeader2): 691 data = self._decryptSSL2(data, header.padding) 692 if self.handshake_finished: 693 header.type = ContentType.application_data 694 elif self._readState and \ 695 self._readState.encContext and \ 696 self._readState.encContext.isAEAD: 697 data = self._decryptAndUnseal(header.type, data) 698 elif self.encryptThenMAC: 699 data = self._macThenDecrypt(header.type, data) 700 elif self._readState and \ 701 self._readState.encContext and \ 702 self._readState.encContext.isBlockCipher: 703 data = self._decryptThenMAC(header.type, data) 704 else: 705 data = self._decryptStreamThenMAC(header.type, data) 706 707 yield (header, Parser(data))
708 709 # 710 # cryptography state methods 711 # 712
713 - def changeWriteState(self):
714 """ 715 Change the cipher state to the pending one for write operations. 716 717 This should be done only once after a call to L{calcPendingStates} was 718 performed and directly after sending a L{ChangeCipherSpec} message. 719 """ 720 if self.version in ((0, 2), (2, 0)): 721 # in SSLv2 sequence numbers carry over from plaintext to encrypted 722 # context 723 self._pendingWriteState.seqnum = self._writeState.seqnum 724 self._writeState = self._pendingWriteState 725 self._pendingWriteState = ConnectionState()
726
727 - def changeReadState(self):
728 """ 729 Change the cipher state to the pending one for read operations. 730 731 This should be done only once after a call to L{calcPendingStates} was 732 performed and directly after receiving a L{ChangeCipherSpec} message. 733 """ 734 if self.version in ((0, 2), (2, 0)): 735 # in SSLv2 sequence numbers carry over from plaintext to encrypted 736 # context 737 self._pendingReadState.seqnum = self._readState.seqnum 738 self._readState = self._pendingReadState 739 self._pendingReadState = ConnectionState()
740 741 @staticmethod
742 - def _getCipherSettings(cipherSuite):
743 """Get the settings for cipher suite used""" 744 if cipherSuite in CipherSuite.aes256GcmSuites: 745 keyLength = 32 746 ivLength = 4 747 createCipherFunc = createAESGCM 748 elif cipherSuite in CipherSuite.aes128GcmSuites: 749 keyLength = 16 750 ivLength = 4 751 createCipherFunc = createAESGCM 752 elif cipherSuite in CipherSuite.chacha20Suites: 753 keyLength = 32 754 ivLength = 4 755 createCipherFunc = createCHACHA20 756 elif cipherSuite in CipherSuite.aes128Suites: 757 keyLength = 16 758 ivLength = 16 759 createCipherFunc = createAES 760 elif cipherSuite in CipherSuite.aes256Suites: 761 keyLength = 32 762 ivLength = 16 763 createCipherFunc = createAES 764 elif cipherSuite in CipherSuite.rc4Suites: 765 keyLength = 16 766 ivLength = 0 767 createCipherFunc = createRC4 768 elif cipherSuite in CipherSuite.tripleDESSuites: 769 keyLength = 24 770 ivLength = 8 771 createCipherFunc = createTripleDES 772 elif cipherSuite in CipherSuite.nullSuites: 773 keyLength = 0 774 ivLength = 0 775 createCipherFunc = None 776 else: 777 raise AssertionError() 778 779 return (keyLength, ivLength, createCipherFunc)
780 781 @staticmethod
782 - def _getMacSettings(cipherSuite):
783 """Get settings for HMAC used""" 784 if cipherSuite in CipherSuite.aeadSuites: 785 macLength = 0 786 digestmod = None 787 elif cipherSuite in CipherSuite.shaSuites: 788 macLength = 20 789 digestmod = hashlib.sha1 790 elif cipherSuite in CipherSuite.sha256Suites: 791 macLength = 32 792 digestmod = hashlib.sha256 793 elif cipherSuite in CipherSuite.md5Suites: 794 macLength = 16 795 digestmod = hashlib.md5 796 else: 797 raise AssertionError() 798 799 return macLength, digestmod
800 801 @staticmethod
802 - def _getHMACMethod(version):
803 """Get the HMAC method""" 804 assert version in ((3, 0), (3, 1), (3, 2), (3, 3)) 805 if version == (3, 0): 806 createMACFunc = createMAC_SSL 807 elif version in ((3, 1), (3, 2), (3, 3)): 808 createMACFunc = createHMAC 809 810 return createMACFunc
811
812 - def _calcKeyBlock(self, cipherSuite, masterSecret, clientRandom, 813 serverRandom, outputLength):
814 """Calculate the overall key to slice up""" 815 if self.version == (3, 0): 816 keyBlock = PRF_SSL(masterSecret, 817 serverRandom + clientRandom, 818 outputLength) 819 elif self.version in ((3, 1), (3, 2)): 820 keyBlock = PRF(masterSecret, 821 b"key expansion", 822 serverRandom + clientRandom, 823 outputLength) 824 elif self.version == (3, 3): 825 if cipherSuite in CipherSuite.sha384PrfSuites: 826 keyBlock = PRF_1_2_SHA384(masterSecret, 827 b"key expansion", 828 serverRandom + clientRandom, 829 outputLength) 830 else: 831 keyBlock = PRF_1_2(masterSecret, 832 b"key expansion", 833 serverRandom + clientRandom, 834 outputLength) 835 else: 836 raise AssertionError() 837 838 return keyBlock
839
840 - def calcSSL2PendingStates(self, cipherSuite, masterSecret, clientRandom, 841 serverRandom, implementations):
842 """ 843 Create the keys for encryption and decryption in SSLv2 844 845 While we could reuse calcPendingStates(), we need to provide the 846 key-arg data for the server that needs to be passed up to handshake 847 protocol. 848 """ 849 if cipherSuite in CipherSuite.ssl2_128Key: 850 key_length = 16 851 elif cipherSuite in CipherSuite.ssl2_192Key: 852 key_length = 24 853 elif cipherSuite in CipherSuite.ssl2_64Key: 854 key_length = 8 855 else: 856 raise ValueError("Unknown cipher specified") 857 858 key_material = bytearray(key_length * 2) 859 md5_output_size = 16 860 for i, pos in enumerate(range(0, key_length * 2, md5_output_size)): 861 key_material[pos:pos+md5_output_size] = MD5(\ 862 masterSecret + 863 bytearray(str(i), "ascii") + 864 clientRandom + serverRandom) 865 866 serverWriteKey = key_material[:key_length] 867 clientWriteKey = key_material[key_length:] 868 869 # specification draft says that DES key should not use the 870 # incrementing label but all implementations use it anyway 871 #elif cipherSuite in CipherSuite.ssl2_64Key: 872 # key_material = MD5(masterSecret + clientRandom + serverRandom) 873 # serverWriteKey = key_material[0:8] 874 # clientWriteKey = key_material[8:16] 875 876 # RC4 cannot use initialisation vector 877 if cipherSuite not in CipherSuite.ssl2rc4: 878 iv = getRandomBytes(8) 879 else: 880 iv = bytearray(0) 881 882 clientPendingState = ConnectionState() 883 serverPendingState = ConnectionState() 884 885 # MAC 886 clientPendingState.macContext = hashlib.md5() 887 clientPendingState.macContext.update(compatHMAC(clientWriteKey)) 888 serverPendingState.macContext = hashlib.md5() 889 serverPendingState.macContext.update(compatHMAC(serverWriteKey)) 890 891 # ciphers 892 if cipherSuite in CipherSuite.ssl2rc4: 893 cipherMethod = createRC4 894 elif cipherSuite in CipherSuite.ssl2_3des: 895 cipherMethod = createTripleDES 896 else: 897 raise NotImplementedError("Unknown cipher") 898 899 clientPendingState.encContext = cipherMethod(clientWriteKey, iv, 900 implementations) 901 serverPendingState.encContext = cipherMethod(serverWriteKey, iv, 902 implementations) 903 904 # Assign new connection states to pending states 905 if self.client: 906 self._pendingWriteState = clientPendingState 907 self._pendingReadState = serverPendingState 908 else: 909 self._pendingWriteState = serverPendingState 910 self._pendingReadState = clientPendingState 911 912 return iv
913
914 - def calcPendingStates(self, cipherSuite, masterSecret, clientRandom, 915 serverRandom, implementations):
916 """Create pending states for encryption and decryption.""" 917 keyLength, ivLength, createCipherFunc = \ 918 self._getCipherSettings(cipherSuite) 919 920 macLength, digestmod = self._getMacSettings(cipherSuite) 921 922 if not digestmod: 923 createMACFunc = None 924 else: 925 createMACFunc = self._getHMACMethod(self.version) 926 927 outputLength = (macLength*2) + (keyLength*2) + (ivLength*2) 928 929 #Calculate Keying Material from Master Secret 930 keyBlock = self._calcKeyBlock(cipherSuite, masterSecret, clientRandom, 931 serverRandom, outputLength) 932 933 #Slice up Keying Material 934 clientPendingState = ConnectionState() 935 serverPendingState = ConnectionState() 936 parser = Parser(keyBlock) 937 clientMACBlock = parser.getFixBytes(macLength) 938 serverMACBlock = parser.getFixBytes(macLength) 939 clientKeyBlock = parser.getFixBytes(keyLength) 940 serverKeyBlock = parser.getFixBytes(keyLength) 941 clientIVBlock = parser.getFixBytes(ivLength) 942 serverIVBlock = parser.getFixBytes(ivLength) 943 944 if digestmod: 945 # Legacy cipher 946 clientPendingState.macContext = createMACFunc( 947 compatHMAC(clientMACBlock), digestmod=digestmod) 948 serverPendingState.macContext = createMACFunc( 949 compatHMAC(serverMACBlock), digestmod=digestmod) 950 if createCipherFunc is not None: 951 clientPendingState.encContext = \ 952 createCipherFunc(clientKeyBlock, 953 clientIVBlock, 954 implementations) 955 serverPendingState.encContext = \ 956 createCipherFunc(serverKeyBlock, 957 serverIVBlock, 958 implementations) 959 else: 960 # AEAD 961 clientPendingState.macContext = None 962 serverPendingState.macContext = None 963 clientPendingState.encContext = createCipherFunc(clientKeyBlock, 964 implementations) 965 serverPendingState.encContext = createCipherFunc(serverKeyBlock, 966 implementations) 967 clientPendingState.fixedNonce = clientIVBlock 968 serverPendingState.fixedNonce = serverIVBlock 969 970 #Assign new connection states to pending states 971 if self.client: 972 self._pendingWriteState = clientPendingState 973 self._pendingReadState = serverPendingState 974 else: 975 self._pendingWriteState = serverPendingState 976 self._pendingReadState = clientPendingState 977 978 if self.version >= (3, 2) and ivLength: 979 #Choose fixedIVBlock for TLS 1.1 (this is encrypted with the CBC 980 #residue to create the IV for each sent block) 981 self.fixedIVBlock = getRandomBytes(ivLength)
982