1
2
3
4
5 """Implementation of the TLS Record Layer protocol"""
6
7 import socket
8 import errno
9 import hashlib
10 from .constants import ContentType, CipherSuite
11 from .messages import RecordHeader3, RecordHeader2, Message
12 from .utils.cipherfactory import createAESGCM, createAES, createRC4, \
13 createTripleDES
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 TLS version used by record layer"""
250 return self._version
251
252 @version.setter
254 """Set the TLS version used by record layer"""
255 self._version = val
256 self._recordSocket.version = val
257
259 """
260 Return the name of the bulk cipher used by this connection
261
262 @rtype: str
263 @return: The name of the cipher, like 'aes128', 'rc4', etc.
264 """
265 if self._writeState.encContext is None:
266 return None
267 return self._writeState.encContext.name
268
270 """
271 Return the name of the implementation used for the connection
272
273 'python' for tlslite internal implementation, 'openssl' for M2crypto
274 and 'pycrypto' for pycrypto
275 @rtype: str
276 @return: Name of cipher implementation used, None if not initialised
277 """
278 if self._writeState.encContext is None:
279 return None
280 return self._writeState.encContext.implementation
281
288
290 """Returns true if cipher uses CBC mode"""
291 if self._writeState and self._writeState.encContext and \
292 self._writeState.encContext.isBlockCipher:
293 return True
294 else:
295 return False
296
297
298
299
301 """Add padding to data so that it is multiple of block size"""
302 currentLength = len(data)
303 blockLength = self._writeState.encContext.block_size
304 paddingLength = blockLength - 1 - (currentLength % blockLength)
305
306 paddingBytes = bytearray([paddingLength] * (paddingLength+1))
307 data += paddingBytes
308 return data
309
322
324 """MAC, pad then encrypt data"""
325 if self._writeState.macContext:
326 seqnumBytes = self._writeState.getSeqNumBytes()
327 mac = self._writeState.macContext.copy()
328 macBytes = self._calculateMAC(mac, seqnumBytes, contentType, data)
329 data += macBytes
330
331
332 if self._writeState.encContext:
333
334 if self._writeState.encContext.isBlockCipher:
335
336
337 if self.version >= (3, 2):
338 data = self.fixedIVBlock + data
339
340 data = self._addPadding(data)
341
342
343 data = self._writeState.encContext.encrypt(data)
344
345 return data
346
348 """Pad, encrypt and then MAC the data"""
349 if self._writeState.encContext:
350
351 if self.version >= (3, 2):
352 buf = self.fixedIVBlock + buf
353
354 buf = self._addPadding(buf)
355
356 buf = self._writeState.encContext.encrypt(buf)
357
358
359 if self._writeState.macContext:
360 seqnumBytes = self._writeState.getSeqNumBytes()
361 mac = self._writeState.macContext.copy()
362
363
364 macBytes = self._calculateMAC(mac, seqnumBytes, contentType, buf)
365 buf += macBytes
366
367 return buf
368
370 """Encrypt with AEAD cipher"""
371
372 seqNumBytes = self._writeState.getSeqNumBytes()
373 authData = seqNumBytes + bytearray([contentType,
374 self.version[0],
375 self.version[1],
376 len(buf)//256,
377 len(buf)%256])
378
379
380 nonce = self._writeState.fixedNonce + seqNumBytes
381 assert len(nonce) == self._writeState.encContext.nonceLength
382
383 buf = self._writeState.encContext.seal(nonce, buf, authData)
384
385
386
387 buf = seqNumBytes + buf
388
389 return buf
390
392 """
393 Encrypt, MAC and send arbitrary message as-is through socket.
394
395 Note that if the message was not fragmented to below 2**14 bytes
396 it will be rejected by the other connection side.
397
398 @param msg: TLS message to send
399 @type msg: ApplicationData, HandshakeMessage, etc.
400 """
401 data = msg.write()
402 contentType = msg.contentType
403
404 if self._writeState and \
405 self._writeState.encContext and \
406 self._writeState.encContext.isAEAD:
407 data = self._encryptThenSeal(data, contentType)
408 elif self.encryptThenMAC:
409 data = self._encryptThenMAC(data, contentType)
410 else:
411 data = self._macThenEncrypt(data, contentType)
412
413 encryptedMessage = Message(contentType, data)
414
415 for result in self._recordSocket.send(encryptedMessage):
416 yield result
417
418
419
420
421
423 """Decrypt a stream cipher and check MAC"""
424 if self._readState.encContext:
425 assert self.version in ((3, 0), (3, 1), (3, 2), (3, 3))
426
427 data = self._readState.encContext.decrypt(data)
428
429 if self._readState.macContext:
430
431 macGood = True
432 macLength = self._readState.macContext.digest_size
433 endLength = macLength
434 if endLength > len(data):
435 macGood = False
436 else:
437
438 startIndex = len(data) - endLength
439 endIndex = startIndex + macLength
440 checkBytes = data[startIndex : endIndex]
441
442
443 seqnumBytes = self._readState.getSeqNumBytes()
444 data = data[:-endLength]
445 mac = self._readState.macContext.copy()
446 macBytes = self._calculateMAC(mac, seqnumBytes, recordType,
447 data)
448
449
450 if not ct_compare_digest(macBytes, checkBytes):
451 macGood = False
452
453 if not macGood:
454 raise TLSBadRecordMAC()
455
456 return data
457
458
460 """Decrypt data, check padding and MAC"""
461 if self._readState.encContext:
462 assert self.version in ((3, 0), (3, 1), (3, 2), (3, 3))
463 assert self._readState.encContext.isBlockCipher
464 assert self._readState.macContext
465
466
467
468
469 blockLength = self._readState.encContext.block_size
470 if len(data) % blockLength != 0:
471 raise TLSDecryptionFailed()
472 data = self._readState.encContext.decrypt(data)
473 if self.version >= (3, 2):
474 data = data[self._readState.encContext.block_size : ]
475
476
477
478
479 seqnumBytes = self._readState.getSeqNumBytes()
480
481 if not ct_check_cbc_mac_and_pad(data,
482 self._readState.macContext,
483 seqnumBytes,
484 recordType,
485 self.version):
486 raise TLSBadRecordMAC()
487
488
489
490
491
492 endLength = data[-1] + 1 + self._readState.macContext.digest_size
493
494 data = data[:-endLength]
495
496 return data
497
499 """
500 Check MAC of data, then decrypt and remove padding
501
502 @raise TLSBadRecordMAC: when the mac value is invalid
503 @raise TLSDecryptionFailed: when the data to decrypt has invalid size
504 """
505 if self._readState.macContext:
506 macLength = self._readState.macContext.digest_size
507 if len(buf) < macLength:
508 raise TLSBadRecordMAC("Truncated data")
509
510 checkBytes = buf[-macLength:]
511 buf = buf[:-macLength]
512
513 seqnumBytes = self._readState.getSeqNumBytes()
514 mac = self._readState.macContext.copy()
515
516 macBytes = self._calculateMAC(mac, seqnumBytes, recordType, buf)
517
518 if not ct_compare_digest(macBytes, checkBytes):
519 raise TLSBadRecordMAC("MAC mismatch")
520
521 if self._readState.encContext:
522 blockLength = self._readState.encContext.block_size
523 if len(buf) % blockLength != 0:
524 raise TLSDecryptionFailed("data length not multiple of "\
525 "block size")
526
527 buf = self._readState.encContext.decrypt(buf)
528
529
530 if self.version >= (3, 2):
531 buf = buf[blockLength:]
532
533 if len(buf) == 0:
534 raise TLSBadRecordMAC("No data left after IV removal")
535
536
537 paddingLength = buf[-1]
538 if paddingLength + 1 > len(buf):
539 raise TLSBadRecordMAC("Invalid padding length")
540
541 paddingGood = True
542 totalPaddingLength = paddingLength+1
543 if self.version != (3, 0):
544 paddingBytes = buf[-totalPaddingLength:-1]
545 for byte in paddingBytes:
546 if byte != paddingLength:
547 paddingGood = False
548
549 if not paddingGood:
550 raise TLSBadRecordMAC("Invalid padding byte values")
551
552
553 buf = buf[:-totalPaddingLength]
554
555 return buf
556
558 """Decrypt AEAD encrypted data"""
559
560
561 explicitNonceLength = 8
562 if explicitNonceLength > len(buf):
563
564 raise TLSBadRecordMAC("Truncated nonce")
565 nonce = self._readState.fixedNonce + buf[:explicitNonceLength]
566 buf = buf[8:]
567
568 if self._readState.encContext.tagLength > len(buf):
569
570 raise TLSBadRecordMAC("Truncated tag")
571
572
573 seqnumBytes = self._readState.getSeqNumBytes()
574 plaintextLen = len(buf) - self._readState.encContext.tagLength
575 authData = seqnumBytes + bytearray([recordType, self.version[0],
576 self.version[1],
577 plaintextLen//256,
578 plaintextLen%256])
579
580 buf = self._readState.encContext.open(nonce, buf, authData)
581 if buf is None:
582 raise TLSBadRecordMAC("Invalid tag, decryption failure")
583 return buf
584
586 """
587 Read, decrypt and check integrity of a single record
588
589 @rtype: tuple
590 @return: message header and decrypted message payload
591 @raise TLSDecryptionFailed: when decryption of data failed
592 @raise TLSBadRecordMAC: when record has bad MAC or padding
593 @raise socket.error: when reading from socket was unsuccessful
594 """
595 result = None
596 for result in self._recordSocket.recv():
597 if result in (0, 1):
598 yield result
599 else: break
600 assert result is not None
601
602 (header, data) = result
603
604 if self._readState and \
605 self._readState.encContext and \
606 self._readState.encContext.isAEAD:
607 data = self._decryptAndUnseal(header.type, data)
608 elif self.encryptThenMAC:
609 data = self._macThenDecrypt(header.type, data)
610 elif self._readState and \
611 self._readState.encContext and \
612 self._readState.encContext.isBlockCipher:
613 data = self._decryptThenMAC(header.type, data)
614 else:
615 data = self._decryptStreamThenMAC(header.type, data)
616
617 yield (header, Parser(data))
618
619
620
621
622
624 """
625 Change the cipher state to the pending one for write operations.
626
627 This should be done only once after a call to L{calcPendingStates} was
628 performed and directly after sending a L{ChangeCipherSpec} message.
629 """
630 self._writeState = self._pendingWriteState
631 self._pendingWriteState = ConnectionState()
632
634 """
635 Change the cipher state to the pending one for read operations.
636
637 This should be done only once after a call to L{calcPendingStates} was
638 performed and directly after receiving a L{ChangeCipherSpec} message.
639 """
640 self._readState = self._pendingReadState
641 self._pendingReadState = ConnectionState()
642
643 @staticmethod
678
679 @staticmethod
698
699 @staticmethod
701 """Get the HMAC method"""
702 assert version in ((3, 0), (3, 1), (3, 2), (3, 3))
703 if version == (3, 0):
704 createMACFunc = createMAC_SSL
705 elif version in ((3, 1), (3, 2), (3, 3)):
706 createMACFunc = createHMAC
707
708 return createMACFunc
709
710 - def _calcKeyBlock(self, cipherSuite, masterSecret, clientRandom,
711 serverRandom, outputLength):
712 """Calculate the overall key to slice up"""
713 if self.version == (3, 0):
714 keyBlock = PRF_SSL(masterSecret,
715 serverRandom + clientRandom,
716 outputLength)
717 elif self.version in ((3, 1), (3, 2)):
718 keyBlock = PRF(masterSecret,
719 b"key expansion",
720 serverRandom + clientRandom,
721 outputLength)
722 elif self.version == (3, 3):
723 if cipherSuite in CipherSuite.sha384PrfSuites:
724 keyBlock = PRF_1_2_SHA384(masterSecret,
725 b"key expansion",
726 serverRandom + clientRandom,
727 outputLength)
728 else:
729 keyBlock = PRF_1_2(masterSecret,
730 b"key expansion",
731 serverRandom + clientRandom,
732 outputLength)
733 else:
734 raise AssertionError()
735
736 return keyBlock
737
738 - def calcPendingStates(self, cipherSuite, masterSecret, clientRandom,
739 serverRandom, implementations):
740 """Create pending states for encryption and decryption."""
741 keyLength, ivLength, createCipherFunc = \
742 self._getCipherSettings(cipherSuite)
743
744 macLength, digestmod = self._getMacSettings(cipherSuite)
745
746 if not digestmod:
747 createMACFunc = None
748 else:
749 createMACFunc = self._getHMACMethod(self.version)
750
751 outputLength = (macLength*2) + (keyLength*2) + (ivLength*2)
752
753
754 keyBlock = self._calcKeyBlock(cipherSuite, masterSecret, clientRandom,
755 serverRandom, outputLength)
756
757
758 clientPendingState = ConnectionState()
759 serverPendingState = ConnectionState()
760 parser = Parser(keyBlock)
761 clientMACBlock = parser.getFixBytes(macLength)
762 serverMACBlock = parser.getFixBytes(macLength)
763 clientKeyBlock = parser.getFixBytes(keyLength)
764 serverKeyBlock = parser.getFixBytes(keyLength)
765 clientIVBlock = parser.getFixBytes(ivLength)
766 serverIVBlock = parser.getFixBytes(ivLength)
767
768 if digestmod:
769
770 clientPendingState.macContext = createMACFunc(
771 compatHMAC(clientMACBlock), digestmod=digestmod)
772 serverPendingState.macContext = createMACFunc(
773 compatHMAC(serverMACBlock), digestmod=digestmod)
774 if createCipherFunc is not None:
775 clientPendingState.encContext = \
776 createCipherFunc(clientKeyBlock,
777 clientIVBlock,
778 implementations)
779 serverPendingState.encContext = \
780 createCipherFunc(serverKeyBlock,
781 serverIVBlock,
782 implementations)
783 else:
784
785 clientPendingState.macContext = None
786 serverPendingState.macContext = None
787 clientPendingState.encContext = createCipherFunc(clientKeyBlock,
788 implementations)
789 serverPendingState.encContext = createCipherFunc(serverKeyBlock,
790 implementations)
791 clientPendingState.fixedNonce = clientIVBlock
792 serverPendingState.fixedNonce = serverIVBlock
793
794
795 if self.client:
796 self._pendingWriteState = clientPendingState
797 self._pendingReadState = serverPendingState
798 else:
799 self._pendingWriteState = serverPendingState
800 self._pendingReadState = clientPendingState
801
802 if self.version >= (3, 2) and ivLength:
803
804
805 self.fixedIVBlock = getRandomBytes(ivLength)
806