1
2
3
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
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
24
25 """Socket wrapper for reading and writing TLS Records"""
26
28 """
29 Assign socket to wrapper
30
31 @type sock: socket.socket
32 """
33 self.sock = sock
34 self.version = (0, 0)
35
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):
59 """
60 Send the message through socket.
61
62 @type msg: bytearray
63 @param msg: TLS message to send
64 @raise socket.error: when write to socket failed
65 """
66 data = msg.write()
67
68 header = RecordHeader3().create(self.version,
69 msg.contentType,
70 len(data))
71
72 data = header.write() + data
73
74 for result in self._sockSendAll(data):
75 yield result
76
78 """
79 Read exactly the amount of bytes specified in L{length} from raw socket.
80
81 @rtype: generator
82 @return: generator that will return 0 or 1 in case the socket is non
83 blocking and would block and bytearray in case the read finished
84 @raise TLSAbruptCloseError: when the socket closed
85 """
86 buf = bytearray(0)
87
88 if length == 0:
89 yield buf
90
91 while True:
92 try:
93 socketBytes = self.sock.recv(length - len(buf))
94 except socket.error as why:
95 if why.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN):
96 yield 0
97 continue
98 else:
99 raise
100
101
102 if len(socketBytes) == 0:
103 raise TLSAbruptCloseError()
104
105 buf += bytearray(socketBytes)
106 if len(buf) == length:
107 yield buf
108
110 """Read a single record header from socket"""
111
112 buf = bytearray(0)
113 ssl2 = False
114
115 result = None
116 for result in self._sockRecvAll(1):
117 if result in (0, 1):
118 yield result
119 else: break
120 assert result is not None
121
122 buf += result
123
124 if buf[0] in ContentType.all:
125 ssl2 = False
126
127 result = None
128 for result in self._sockRecvAll(4):
129 if result in (0, 1):
130 yield result
131 else: break
132 assert result is not None
133 buf += result
134
135
136 elif buf[0] == 128:
137 ssl2 = True
138
139
140 result = None
141 for result in self._sockRecvAll(1):
142 if result in (0, 1):
143 yield result
144 else: break
145 assert result is not None
146 buf += result
147 else:
148 raise TLSIllegalParameterException(
149 "Record header type doesn't specify known type")
150
151
152 if ssl2:
153 record = RecordHeader2().parse(Parser(buf))
154 else:
155 record = RecordHeader3().parse(Parser(buf))
156
157 yield record
158
160 """
161 Read a single record from socket, handle SSLv2 and SSLv3 record layer
162
163 @rtype: generator
164 @return: generator that returns 0 or 1 in case the read would be
165 blocking or a tuple containing record header (object) and record
166 data (bytearray) read from socket
167 @raise socket.error: In case of network error
168 @raise TLSAbruptCloseError: When the socket was closed on the other
169 side in middle of record receiving
170 @raise TLSRecordOverflow: When the received record was longer than
171 allowed by TLS
172 @raise TLSIllegalParameterException: When the record header was
173 malformed
174 """
175 record = None
176 for record in self._recvHeader():
177 if record in (0, 1):
178 yield record
179 else: break
180 assert record is not None
181
182
183
184
185 if record.length > 18432:
186 raise TLSRecordOverflow()
187
188
189 buf = bytearray(0)
190
191 result = None
192 for result in self._sockRecvAll(record.length):
193 if result in (0, 1):
194 yield result
195 else: break
196 assert result is not None
197
198 buf += result
199
200 yield (record, buf)
201
203
204 """Preserve the connection state for reading and writing data to records"""
205
207 """Create an instance with empty encryption and MACing contexts"""
208 self.macContext = None
209 self.encContext = None
210 self.fixedNonce = None
211 self.seqnum = 0
212
214 """Return encoded sequence number and increment it."""
215 writer = Writer()
216 writer.add(self.seqnum, 8)
217 self.seqnum += 1
218 return writer.bytes
219
221
222 """
223 Implementation of TLS record layer protocol
224
225 @ivar version: the TLS version to use (tuple encoded as on the wire)
226 @ivar sock: underlying socket
227 @ivar client: whether the connection should use encryption
228 @ivar encryptThenMAC: use the encrypt-then-MAC mechanism for record
229 integrity
230 """
231
246
247 @property
249 """Return the size of block used by current symmetric cipher (R/O)"""
250 return self._writeState.encContext.block_size
251
252 @property
254 """Return the TLS version used by record layer"""
255 return self._version
256
257 @version.setter
259 """Set the TLS version used by record layer"""
260 self._version = val
261 self._recordSocket.version = val
262
264 """
265 Return the name of the bulk cipher used by this connection
266
267 @rtype: str
268 @return: The name of the cipher, like 'aes128', 'rc4', etc.
269 """
270 if self._writeState.encContext is None:
271 return None
272 return self._writeState.encContext.name
273
275 """
276 Return the name of the implementation used for the connection
277
278 'python' for tlslite internal implementation, 'openssl' for M2crypto
279 and 'pycrypto' for pycrypto
280 @rtype: str
281 @return: Name of cipher implementation used, None if not initialised
282 """
283 if self._writeState.encContext is None:
284 return None
285 return self._writeState.encContext.implementation
286
293
295 """Returns true if cipher uses CBC mode"""
296 if self._writeState and self._writeState.encContext and \
297 self._writeState.encContext.isBlockCipher:
298 return True
299 else:
300 return False
301
302
303
304
306 """Add padding to data so that it is multiple of block size"""
307 currentLength = len(data)
308 blockLength = self.blockSize
309 paddingLength = blockLength - 1 - (currentLength % blockLength)
310
311 paddingBytes = bytearray([paddingLength] * (paddingLength+1))
312 data += paddingBytes
313 return data
314
315 - def calculateMAC(self, mac, seqnumBytes, contentType, data):
327
329 """MAC, pad then encrypt data"""
330 if self._writeState.macContext:
331 seqnumBytes = self._writeState.getSeqNumBytes()
332 mac = self._writeState.macContext.copy()
333 macBytes = self.calculateMAC(mac, seqnumBytes, contentType, data)
334 data += macBytes
335
336
337 if self._writeState.encContext:
338
339 if self._writeState.encContext.isBlockCipher:
340
341
342 if self.version >= (3, 2):
343 data = self.fixedIVBlock + data
344
345 data = self.addPadding(data)
346
347
348 data = self._writeState.encContext.encrypt(data)
349
350 return data
351
353 """Pad, encrypt and then MAC the data"""
354 if self._writeState.encContext:
355
356 if self.version >= (3, 2):
357 buf = self.fixedIVBlock + buf
358
359 buf = self.addPadding(buf)
360
361 buf = self._writeState.encContext.encrypt(buf)
362
363
364 if self._writeState.macContext:
365 seqnumBytes = self._writeState.getSeqNumBytes()
366 mac = self._writeState.macContext.copy()
367
368
369 macBytes = self.calculateMAC(mac, seqnumBytes, contentType, buf)
370 buf += macBytes
371
372 return buf
373
375 """Encrypt with AEAD cipher"""
376
377 seqNumBytes = self._writeState.getSeqNumBytes()
378 authData = seqNumBytes + bytearray([contentType,
379 self.version[0],
380 self.version[1],
381 len(buf)//256,
382 len(buf)%256])
383
384
385 nonce = self._writeState.fixedNonce + seqNumBytes
386
387 assert len(nonce) == self._writeState.encContext.nonceLength
388
389 buf = self._writeState.encContext.seal(nonce, buf, authData)
390
391
392 if "aes" in self._writeState.encContext.name:
393 buf = seqNumBytes + buf
394
395 return buf
396
398 """
399 Encrypt, MAC and send arbitrary message as-is through socket.
400
401 Note that if the message was not fragmented to below 2**14 bytes
402 it will be rejected by the other connection side.
403
404 @param msg: TLS message to send
405 @type msg: ApplicationData, HandshakeMessage, etc.
406 """
407 data = msg.write()
408 contentType = msg.contentType
409
410 if self._writeState and \
411 self._writeState.encContext and \
412 self._writeState.encContext.isAEAD:
413 data = self._encryptThenSeal(data, contentType)
414 elif self.encryptThenMAC:
415 data = self._encryptThenMAC(data, contentType)
416 else:
417 data = self._macThenEncrypt(data, contentType)
418
419 encryptedMessage = Message(contentType, data)
420
421 for result in self._recordSocket.send(encryptedMessage):
422 yield result
423
424
425
426
427
429 """Decrypt a stream cipher and check MAC"""
430 if self._readState.encContext:
431 assert self.version in ((3, 0), (3, 1), (3, 2), (3, 3))
432
433 data = self._readState.encContext.decrypt(data)
434
435 if self._readState.macContext:
436
437 macGood = True
438 macLength = self._readState.macContext.digest_size
439 endLength = macLength
440 if endLength > len(data):
441 macGood = False
442 else:
443
444 startIndex = len(data) - endLength
445 endIndex = startIndex + macLength
446 checkBytes = data[startIndex : endIndex]
447
448
449 seqnumBytes = self._readState.getSeqNumBytes()
450 data = data[:-endLength]
451 mac = self._readState.macContext.copy()
452 macBytes = self.calculateMAC(mac, seqnumBytes, recordType,
453 data)
454
455
456 if not ct_compare_digest(macBytes, checkBytes):
457 macGood = False
458
459 if not macGood:
460 raise TLSBadRecordMAC()
461
462 return data
463
464
466 """Decrypt data, check padding and MAC"""
467 if self._readState.encContext:
468 assert self.version in ((3, 0), (3, 1), (3, 2), (3, 3))
469 assert self._readState.encContext.isBlockCipher
470 assert self._readState.macContext
471
472
473
474
475 blockLength = self._readState.encContext.block_size
476 if len(data) % blockLength != 0:
477 raise TLSDecryptionFailed()
478 data = self._readState.encContext.decrypt(data)
479 if self.version >= (3, 2):
480 data = data[self._readState.encContext.block_size : ]
481
482
483
484
485 seqnumBytes = self._readState.getSeqNumBytes()
486
487 if not ct_check_cbc_mac_and_pad(data,
488 self._readState.macContext,
489 seqnumBytes,
490 recordType,
491 self.version):
492 raise TLSBadRecordMAC()
493
494
495
496
497
498 endLength = data[-1] + 1 + self._readState.macContext.digest_size
499
500 data = data[:-endLength]
501
502 return data
503
505 """
506 Check MAC of data, then decrypt and remove padding
507
508 @raise TLSBadRecordMAC: when the mac value is invalid
509 @raise TLSDecryptionFailed: when the data to decrypt has invalid size
510 """
511 if self._readState.macContext:
512 macLength = self._readState.macContext.digest_size
513 if len(buf) < macLength:
514 raise TLSBadRecordMAC("Truncated data")
515
516 checkBytes = buf[-macLength:]
517 buf = buf[:-macLength]
518
519 seqnumBytes = self._readState.getSeqNumBytes()
520 mac = self._readState.macContext.copy()
521
522 macBytes = self.calculateMAC(mac, seqnumBytes, recordType, buf)
523
524 if not ct_compare_digest(macBytes, checkBytes):
525 raise TLSBadRecordMAC("MAC mismatch")
526
527 if self._readState.encContext:
528 blockLength = self._readState.encContext.block_size
529 if len(buf) % blockLength != 0:
530 raise TLSDecryptionFailed("data length not multiple of "\
531 "block size")
532
533 buf = self._readState.encContext.decrypt(buf)
534
535
536 if self.version >= (3, 2):
537 buf = buf[blockLength:]
538
539 if len(buf) == 0:
540 raise TLSBadRecordMAC("No data left after IV removal")
541
542
543 paddingLength = buf[-1]
544 if paddingLength + 1 > len(buf):
545 raise TLSBadRecordMAC("Invalid padding length")
546
547 paddingGood = True
548 totalPaddingLength = paddingLength+1
549 if self.version != (3, 0):
550 paddingBytes = buf[-totalPaddingLength:-1]
551 for byte in paddingBytes:
552 if byte != paddingLength:
553 paddingGood = False
554
555 if not paddingGood:
556 raise TLSBadRecordMAC("Invalid padding byte values")
557
558
559 buf = buf[:-totalPaddingLength]
560
561 return buf
562
564 """Decrypt AEAD encrypted data"""
565 seqnumBytes = self._readState.getSeqNumBytes()
566
567 if "aes" in self._readState.encContext.name:
568 explicitNonceLength = 8
569 if explicitNonceLength > len(buf):
570
571 raise TLSBadRecordMAC("Truncated nonce")
572 nonce = self._readState.fixedNonce + buf[:explicitNonceLength]
573 buf = buf[8:]
574 else:
575 nonce = self._readState.fixedNonce + seqnumBytes
576
577 if self._readState.encContext.tagLength > len(buf):
578
579 raise TLSBadRecordMAC("Truncated tag")
580
581 plaintextLen = len(buf) - self._readState.encContext.tagLength
582 authData = seqnumBytes + bytearray([recordType, self.version[0],
583 self.version[1],
584 plaintextLen//256,
585 plaintextLen%256])
586
587 buf = self._readState.encContext.open(nonce, buf, authData)
588 if buf is None:
589 raise TLSBadRecordMAC("Invalid tag, decryption failure")
590 return buf
591
593 """
594 Read, decrypt and check integrity of a single record
595
596 @rtype: tuple
597 @return: message header and decrypted message payload
598 @raise TLSDecryptionFailed: when decryption of data failed
599 @raise TLSBadRecordMAC: when record has bad MAC or padding
600 @raise socket.error: when reading from socket was unsuccessful
601 """
602 result = None
603 for result in self._recordSocket.recv():
604 if result in (0, 1):
605 yield result
606 else: break
607 assert result is not None
608
609 (header, data) = result
610
611 if self._readState and \
612 self._readState.encContext and \
613 self._readState.encContext.isAEAD:
614 data = self._decryptAndUnseal(header.type, data)
615 elif self.encryptThenMAC:
616 data = self._macThenDecrypt(header.type, data)
617 elif self._readState and \
618 self._readState.encContext and \
619 self._readState.encContext.isBlockCipher:
620 data = self._decryptThenMAC(header.type, data)
621 else:
622 data = self._decryptStreamThenMAC(header.type, data)
623
624 yield (header, Parser(data))
625
626
627
628
629
631 """
632 Change the cipher state to the pending one for write operations.
633
634 This should be done only once after a call to L{calcPendingStates} was
635 performed and directly after sending a L{ChangeCipherSpec} message.
636 """
637 self._writeState = self._pendingWriteState
638 self._pendingWriteState = ConnectionState()
639
641 """
642 Change the cipher state to the pending one for read operations.
643
644 This should be done only once after a call to L{calcPendingStates} was
645 performed and directly after receiving a L{ChangeCipherSpec} message.
646 """
647 self._readState = self._pendingReadState
648 self._pendingReadState = ConnectionState()
649
650 @staticmethod
689
690 @staticmethod
709
710 @staticmethod
712 """Get the HMAC method"""
713 assert version in ((3, 0), (3, 1), (3, 2), (3, 3))
714 if version == (3, 0):
715 createMACFunc = createMAC_SSL
716 elif version in ((3, 1), (3, 2), (3, 3)):
717 createMACFunc = createHMAC
718
719 return createMACFunc
720
721 - def _calcKeyBlock(self, cipherSuite, masterSecret, clientRandom,
722 serverRandom, outputLength):
723 """Calculate the overall key to slice up"""
724 if self.version == (3, 0):
725 keyBlock = PRF_SSL(masterSecret,
726 serverRandom + clientRandom,
727 outputLength)
728 elif self.version in ((3, 1), (3, 2)):
729 keyBlock = PRF(masterSecret,
730 b"key expansion",
731 serverRandom + clientRandom,
732 outputLength)
733 elif self.version == (3, 3):
734 if cipherSuite in CipherSuite.sha384PrfSuites:
735 keyBlock = PRF_1_2_SHA384(masterSecret,
736 b"key expansion",
737 serverRandom + clientRandom,
738 outputLength)
739 else:
740 keyBlock = PRF_1_2(masterSecret,
741 b"key expansion",
742 serverRandom + clientRandom,
743 outputLength)
744 else:
745 raise AssertionError()
746
747 return keyBlock
748
749 - def calcPendingStates(self, cipherSuite, masterSecret, clientRandom,
750 serverRandom, implementations):
751 """Create pending states for encryption and decryption."""
752 keyLength, ivLength, createCipherFunc = \
753 self._getCipherSettings(cipherSuite)
754
755 macLength, digestmod = self._getMacSettings(cipherSuite)
756
757 if not digestmod:
758 createMACFunc = None
759 else:
760 createMACFunc = self._getHMACMethod(self.version)
761
762 outputLength = (macLength*2) + (keyLength*2) + (ivLength*2)
763
764
765 keyBlock = self._calcKeyBlock(cipherSuite, masterSecret, clientRandom,
766 serverRandom, outputLength)
767
768
769 clientPendingState = ConnectionState()
770 serverPendingState = ConnectionState()
771 parser = Parser(keyBlock)
772 clientMACBlock = parser.getFixBytes(macLength)
773 serverMACBlock = parser.getFixBytes(macLength)
774 clientKeyBlock = parser.getFixBytes(keyLength)
775 serverKeyBlock = parser.getFixBytes(keyLength)
776 clientIVBlock = parser.getFixBytes(ivLength)
777 serverIVBlock = parser.getFixBytes(ivLength)
778
779 if digestmod:
780
781 clientPendingState.macContext = createMACFunc(
782 compatHMAC(clientMACBlock), digestmod=digestmod)
783 serverPendingState.macContext = createMACFunc(
784 compatHMAC(serverMACBlock), digestmod=digestmod)
785 if createCipherFunc is not None:
786 clientPendingState.encContext = \
787 createCipherFunc(clientKeyBlock,
788 clientIVBlock,
789 implementations)
790 serverPendingState.encContext = \
791 createCipherFunc(serverKeyBlock,
792 serverIVBlock,
793 implementations)
794 else:
795
796 clientPendingState.macContext = None
797 serverPendingState.macContext = None
798 clientPendingState.encContext = createCipherFunc(clientKeyBlock,
799 implementations)
800 serverPendingState.encContext = createCipherFunc(serverKeyBlock,
801 implementations)
802 clientPendingState.fixedNonce = clientIVBlock
803 serverPendingState.fixedNonce = serverIVBlock
804
805
806 if self.client:
807 self._pendingWriteState = clientPendingState
808 self._pendingReadState = serverPendingState
809 else:
810 self._pendingWriteState = serverPendingState
811 self._pendingReadState = clientPendingState
812
813 if self.version >= (3, 2) and ivLength:
814
815
816 self.fixedIVBlock = getRandomBytes(ivLength)
817