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
534 paddingLength = buf[-1]
535 if paddingLength + 1 > len(buf):
536 raise TLSBadRecordMAC("Invalid padding length")
537
538 paddingGood = True
539 totalPaddingLength = paddingLength+1
540 if self.version != (3, 0):
541 paddingBytes = buf[-totalPaddingLength:-1]
542 for byte in paddingBytes:
543 if byte != paddingLength:
544 paddingGood = False
545
546 if not paddingGood:
547 raise TLSBadRecordMAC("Invalid padding byte values")
548
549
550 buf = buf[:-totalPaddingLength]
551
552 return buf
553
555 """Decrypt AEAD encrypted data"""
556
557
558 explicitNonceLength = 8
559 if explicitNonceLength > len(buf):
560
561 raise TLSBadRecordMAC("Truncated nonce")
562 nonce = self._readState.fixedNonce + buf[:explicitNonceLength]
563 buf = buf[8:]
564
565 if self._readState.encContext.tagLength > len(buf):
566
567 raise TLSBadRecordMAC("Truncated tag")
568
569
570 seqnumBytes = self._readState.getSeqNumBytes()
571 plaintextLen = len(buf) - self._readState.encContext.tagLength
572 authData = seqnumBytes + bytearray([recordType, self.version[0],
573 self.version[1],
574 plaintextLen//256,
575 plaintextLen%256])
576
577 buf = self._readState.encContext.open(nonce, buf, authData)
578 if buf is None:
579 raise TLSBadRecordMAC("Invalid tag, decryption failure")
580 return buf
581
583 """
584 Read, decrypt and check integrity of a single record
585
586 @rtype: tuple
587 @return: message header and decrypted message payload
588 @raise TLSDecryptionFailed: when decryption of data failed
589 @raise TLSBadRecordMAC: when record has bad MAC or padding
590 @raise socket.error: when reading from socket was unsuccessful
591 """
592 result = None
593 for result in self._recordSocket.recv():
594 if result in (0, 1):
595 yield result
596 else: break
597 assert result is not None
598
599 (header, data) = result
600
601 if self._readState and \
602 self._readState.encContext and \
603 self._readState.encContext.isAEAD:
604 data = self._decryptAndUnseal(header.type, data)
605 elif self.encryptThenMAC:
606 data = self._macThenDecrypt(header.type, data)
607 elif self._readState and \
608 self._readState.encContext and \
609 self._readState.encContext.isBlockCipher:
610 data = self._decryptThenMAC(header.type, data)
611 else:
612 data = self._decryptStreamThenMAC(header.type, data)
613
614 yield (header, Parser(data))
615
616
617
618
619
621 """
622 Change the cipher state to the pending one for write operations.
623
624 This should be done only once after a call to L{calcPendingStates} was
625 performed and directly after sending a L{ChangeCipherSpec} message.
626 """
627 self._writeState = self._pendingWriteState
628 self._pendingWriteState = ConnectionState()
629
631 """
632 Change the cipher state to the pending one for read operations.
633
634 This should be done only once after a call to L{calcPendingStates} was
635 performed and directly after receiving a L{ChangeCipherSpec} message.
636 """
637 self._readState = self._pendingReadState
638 self._pendingReadState = ConnectionState()
639
640 @staticmethod
675
676 @staticmethod
695
696 @staticmethod
698 """Get the HMAC method"""
699 assert version in ((3, 0), (3, 1), (3, 2), (3, 3))
700 if version == (3, 0):
701 createMACFunc = createMAC_SSL
702 elif version in ((3, 1), (3, 2), (3, 3)):
703 createMACFunc = createHMAC
704
705 return createMACFunc
706
707 - def _calcKeyBlock(self, cipherSuite, masterSecret, clientRandom,
708 serverRandom, outputLength):
709 """Calculate the overall key to slice up"""
710 if self.version == (3, 0):
711 keyBlock = PRF_SSL(masterSecret,
712 serverRandom + clientRandom,
713 outputLength)
714 elif self.version in ((3, 1), (3, 2)):
715 keyBlock = PRF(masterSecret,
716 b"key expansion",
717 serverRandom + clientRandom,
718 outputLength)
719 elif self.version == (3, 3):
720 if cipherSuite in CipherSuite.sha384PrfSuites:
721 keyBlock = PRF_1_2_SHA384(masterSecret,
722 b"key expansion",
723 serverRandom + clientRandom,
724 outputLength)
725 else:
726 keyBlock = PRF_1_2(masterSecret,
727 b"key expansion",
728 serverRandom + clientRandom,
729 outputLength)
730 else:
731 raise AssertionError()
732
733 return keyBlock
734
735 - def calcPendingStates(self, cipherSuite, masterSecret, clientRandom,
736 serverRandom, implementations):
737 """Create pending states for encryption and decryption."""
738 keyLength, ivLength, createCipherFunc = \
739 self._getCipherSettings(cipherSuite)
740
741 macLength, digestmod = self._getMacSettings(cipherSuite)
742
743 if not digestmod:
744 createMACFunc = None
745 else:
746 createMACFunc = self._getHMACMethod(self.version)
747
748 outputLength = (macLength*2) + (keyLength*2) + (ivLength*2)
749
750
751 keyBlock = self._calcKeyBlock(cipherSuite, masterSecret, clientRandom,
752 serverRandom, outputLength)
753
754
755 clientPendingState = ConnectionState()
756 serverPendingState = ConnectionState()
757 parser = Parser(keyBlock)
758 clientMACBlock = parser.getFixBytes(macLength)
759 serverMACBlock = parser.getFixBytes(macLength)
760 clientKeyBlock = parser.getFixBytes(keyLength)
761 serverKeyBlock = parser.getFixBytes(keyLength)
762 clientIVBlock = parser.getFixBytes(ivLength)
763 serverIVBlock = parser.getFixBytes(ivLength)
764
765 if digestmod:
766
767 clientPendingState.macContext = createMACFunc(
768 compatHMAC(clientMACBlock), digestmod=digestmod)
769 serverPendingState.macContext = createMACFunc(
770 compatHMAC(serverMACBlock), digestmod=digestmod)
771 if createCipherFunc is not None:
772 clientPendingState.encContext = \
773 createCipherFunc(clientKeyBlock,
774 clientIVBlock,
775 implementations)
776 serverPendingState.encContext = \
777 createCipherFunc(serverKeyBlock,
778 serverIVBlock,
779 implementations)
780 else:
781
782 clientPendingState.macContext = None
783 serverPendingState.macContext = None
784 clientPendingState.encContext = createCipherFunc(clientKeyBlock,
785 implementations)
786 serverPendingState.encContext = createCipherFunc(serverKeyBlock,
787 implementations)
788 clientPendingState.fixedNonce = clientIVBlock
789 serverPendingState.fixedNonce = serverIVBlock
790
791
792 if self.client:
793 self._pendingWriteState = clientPendingState
794 self._pendingReadState = serverPendingState
795 else:
796 self._pendingWriteState = serverPendingState
797 self._pendingReadState = clientPendingState
798
799 if self.version >= (3, 2) and ivLength:
800
801
802 self.fixedIVBlock = getRandomBytes(ivLength)
803