Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Unified Diff: third_party/tlslite/tlslite/TLSRecordLayer.py

Issue 211173006: Perform tlslite 0.3.8 -> 0.4.6 renames ahead of time. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Drop the -B Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/tlslite/tlslite/TLSConnection.py ('k') | third_party/tlslite/tlslite/VerifierDB.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/tlslite/tlslite/TLSRecordLayer.py
diff --git a/third_party/tlslite/tlslite/TLSRecordLayer.py b/third_party/tlslite/tlslite/TLSRecordLayer.py
deleted file mode 100644
index 933b95a9de6346998a0644e6f19ed2362b095d2e..0000000000000000000000000000000000000000
--- a/third_party/tlslite/tlslite/TLSRecordLayer.py
+++ /dev/null
@@ -1,1150 +0,0 @@
-"""Helper class for TLSConnection."""
-from __future__ import generators
-
-from utils.compat import *
-from utils.cryptomath import *
-from utils.cipherfactory import createAES, createRC4, createTripleDES
-from utils.codec import *
-from errors import *
-from messages import *
-from mathtls import *
-from constants import *
-from utils.cryptomath import getRandomBytes
-from utils import hmac
-from FileObject import FileObject
-
-# The sha module is deprecated in Python 2.6
-try:
- import sha
-except ImportError:
- from hashlib import sha1 as sha
-
-# The md5 module is deprecated in Python 2.6
-try:
- import md5
-except ImportError:
- from hashlib import md5
-
-import socket
-import errno
-import traceback
-
-class _ConnectionState:
- def __init__(self):
- self.macContext = None
- self.encContext = None
- self.seqnum = 0
-
- def getSeqNumStr(self):
- w = Writer(8)
- w.add(self.seqnum, 8)
- seqnumStr = bytesToString(w.bytes)
- self.seqnum += 1
- return seqnumStr
-
-
-class TLSRecordLayer:
- """
- This class handles data transmission for a TLS connection.
-
- Its only subclass is L{tlslite.TLSConnection.TLSConnection}. We've
- separated the code in this class from TLSConnection to make things
- more readable.
-
-
- @type sock: socket.socket
- @ivar sock: The underlying socket object.
-
- @type session: L{tlslite.Session.Session}
- @ivar session: The session corresponding to this connection.
-
- Due to TLS session resumption, multiple connections can correspond
- to the same underlying session.
-
- @type version: tuple
- @ivar version: The TLS version being used for this connection.
-
- (3,0) means SSL 3.0, and (3,1) means TLS 1.0.
-
- @type closed: bool
- @ivar closed: If this connection is closed.
-
- @type resumed: bool
- @ivar resumed: If this connection is based on a resumed session.
-
- @type allegedSharedKeyUsername: str or None
- @ivar allegedSharedKeyUsername: This is set to the shared-key
- username asserted by the client, whether the handshake succeeded or
- not. If the handshake fails, this can be inspected to
- determine if a guessing attack is in progress against a particular
- user account.
-
- @type allegedSrpUsername: str or None
- @ivar allegedSrpUsername: This is set to the SRP username
- asserted by the client, whether the handshake succeeded or not.
- If the handshake fails, this can be inspected to determine
- if a guessing attack is in progress against a particular user
- account.
-
- @type closeSocket: bool
- @ivar closeSocket: If the socket should be closed when the
- connection is closed (writable).
-
- If you set this to True, TLS Lite will assume the responsibility of
- closing the socket when the TLS Connection is shutdown (either
- through an error or through the user calling close()). The default
- is False.
-
- @type ignoreAbruptClose: bool
- @ivar ignoreAbruptClose: If an abrupt close of the socket should
- raise an error (writable).
-
- If you set this to True, TLS Lite will not raise a
- L{tlslite.errors.TLSAbruptCloseError} exception if the underlying
- socket is unexpectedly closed. Such an unexpected closure could be
- caused by an attacker. However, it also occurs with some incorrect
- TLS implementations.
-
- You should set this to True only if you're not worried about an
- attacker truncating the connection, and only if necessary to avoid
- spurious errors. The default is False.
-
- @sort: __init__, read, readAsync, write, writeAsync, close, closeAsync,
- getCipherImplementation, getCipherName
- """
-
- def __init__(self, sock):
- self.sock = sock
-
- #My session object (Session instance; read-only)
- self.session = None
-
- #Am I a client or server?
- self._client = None
-
- #Buffers for processing messages
- self._handshakeBuffer = []
- self._readBuffer = ""
-
- #Handshake digests
- self._handshake_md5 = md5.md5()
- self._handshake_sha = sha.sha()
-
- #TLS Protocol Version
- self.version = (0,0) #read-only
- self._versionCheck = False #Once we choose a version, this is True
-
- #Current and Pending connection states
- self._writeState = _ConnectionState()
- self._readState = _ConnectionState()
- self._pendingWriteState = _ConnectionState()
- self._pendingReadState = _ConnectionState()
-
- #Is the connection open?
- self.closed = True #read-only
- self._refCount = 0 #Used to trigger closure
-
- #Is this a resumed (or shared-key) session?
- self.resumed = False #read-only
-
- #What username did the client claim in his handshake?
- self.allegedSharedKeyUsername = None
- self.allegedSrpUsername = None
-
- #On a call to close(), do we close the socket? (writeable)
- self.closeSocket = False
-
- #If the socket is abruptly closed, do we ignore it
- #and pretend the connection was shut down properly? (writeable)
- self.ignoreAbruptClose = False
-
- #Fault we will induce, for testing purposes
- self.fault = None
-
- #*********************************************************
- # Public Functions START
- #*********************************************************
-
- def read(self, max=None, min=1):
- """Read some data from the TLS connection.
-
- This function will block until at least 'min' bytes are
- available (or the connection is closed).
-
- If an exception is raised, the connection will have been
- automatically closed.
-
- @type max: int
- @param max: The maximum number of bytes to return.
-
- @type min: int
- @param min: The minimum number of bytes to return
-
- @rtype: str
- @return: A string of no more than 'max' bytes, and no fewer
- than 'min' (unless the connection has been closed, in which
- case fewer than 'min' bytes may be returned).
-
- @raise socket.error: If a socket error occurs.
- @raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
- without a preceding alert.
- @raise tlslite.errors.TLSAlert: If a TLS alert is signalled.
- """
- for result in self.readAsync(max, min):
- pass
- return result
-
- def readAsync(self, max=None, min=1):
- """Start a read operation on the TLS connection.
-
- This function returns a generator which behaves similarly to
- read(). Successive invocations of the generator will return 0
- if it is waiting to read from the socket, 1 if it is waiting
- to write to the socket, or a string if the read operation has
- completed.
-
- @rtype: iterable
- @return: A generator; see above for details.
- """
- try:
- while len(self._readBuffer)<min and not self.closed:
- try:
- for result in self._getMsg(ContentType.application_data):
- if result in (0,1):
- yield result
- applicationData = result
- self._readBuffer += bytesToString(applicationData.write())
- except TLSRemoteAlert, alert:
- if alert.description != AlertDescription.close_notify:
- raise
- except TLSAbruptCloseError:
- if not self.ignoreAbruptClose:
- raise
- else:
- self._shutdown(True)
-
- if max == None:
- max = len(self._readBuffer)
-
- returnStr = self._readBuffer[:max]
- self._readBuffer = self._readBuffer[max:]
- yield returnStr
- except:
- self._shutdown(False)
- raise
-
- def write(self, s):
- """Write some data to the TLS connection.
-
- This function will block until all the data has been sent.
-
- If an exception is raised, the connection will have been
- automatically closed.
-
- @type s: str
- @param s: The data to transmit to the other party.
-
- @raise socket.error: If a socket error occurs.
- """
- for result in self.writeAsync(s):
- pass
-
- def writeAsync(self, s):
- """Start a write operation on the TLS connection.
-
- This function returns a generator which behaves similarly to
- write(). Successive invocations of the generator will return
- 1 if it is waiting to write to the socket, or will raise
- StopIteration if the write operation has completed.
-
- @rtype: iterable
- @return: A generator; see above for details.
- """
- try:
- if self.closed:
- raise ValueError()
-
- index = 0
- blockSize = 16384
- skipEmptyFrag = False
- while 1:
- startIndex = index * blockSize
- endIndex = startIndex + blockSize
- if startIndex >= len(s):
- break
- if endIndex > len(s):
- endIndex = len(s)
- block = stringToBytes(s[startIndex : endIndex])
- applicationData = ApplicationData().create(block)
- for result in self._sendMsg(applicationData, skipEmptyFrag):
- yield result
- skipEmptyFrag = True #only send an empy fragment on 1st message
- index += 1
- except:
- self._shutdown(False)
- raise
-
- def close(self):
- """Close the TLS connection.
-
- This function will block until it has exchanged close_notify
- alerts with the other party. After doing so, it will shut down the
- TLS connection. Further attempts to read through this connection
- will return "". Further attempts to write through this connection
- will raise ValueError.
-
- If makefile() has been called on this connection, the connection
- will be not be closed until the connection object and all file
- objects have been closed.
-
- Even if an exception is raised, the connection will have been
- closed.
-
- @raise socket.error: If a socket error occurs.
- @raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
- without a preceding alert.
- @raise tlslite.errors.TLSAlert: If a TLS alert is signalled.
- """
- if not self.closed:
- for result in self._decrefAsync():
- pass
-
- def closeAsync(self):
- """Start a close operation on the TLS connection.
-
- This function returns a generator which behaves similarly to
- close(). Successive invocations of the generator will return 0
- if it is waiting to read from the socket, 1 if it is waiting
- to write to the socket, or will raise StopIteration if the
- close operation has completed.
-
- @rtype: iterable
- @return: A generator; see above for details.
- """
- if not self.closed:
- for result in self._decrefAsync():
- yield result
-
- def _decrefAsync(self):
- self._refCount -= 1
- if self._refCount == 0 and not self.closed:
- try:
- for result in self._sendMsg(Alert().create(\
- AlertDescription.close_notify, AlertLevel.warning)):
- yield result
- alert = None
- # Forcing a shutdown as WinHTTP does not seem to be
- # responsive to the close notify.
- prevCloseSocket = self.closeSocket
- self.closeSocket = True
- self._shutdown(True)
- self.closeSocket = prevCloseSocket
- while not alert:
- for result in self._getMsg((ContentType.alert, \
- ContentType.application_data)):
- if result in (0,1):
- yield result
- if result.contentType == ContentType.alert:
- alert = result
- if alert.description == AlertDescription.close_notify:
- self._shutdown(True)
- else:
- raise TLSRemoteAlert(alert)
- except (socket.error, TLSAbruptCloseError):
- #If the other side closes the socket, that's okay
- self._shutdown(True)
- except:
- self._shutdown(False)
- raise
-
- def getCipherName(self):
- """Get the name of the cipher used with this connection.
-
- @rtype: str
- @return: The name of the cipher used with this connection.
- Either 'aes128', 'aes256', 'rc4', or '3des'.
- """
- if not self._writeState.encContext:
- return None
- return self._writeState.encContext.name
-
- def getCipherImplementation(self):
- """Get the name of the cipher implementation used with
- this connection.
-
- @rtype: str
- @return: The name of the cipher implementation used with
- this connection. Either 'python', 'cryptlib', 'openssl',
- or 'pycrypto'.
- """
- if not self._writeState.encContext:
- return None
- return self._writeState.encContext.implementation
-
-
-
- #Emulate a socket, somewhat -
- def send(self, s):
- """Send data to the TLS connection (socket emulation).
-
- @raise socket.error: If a socket error occurs.
- """
- self.write(s)
- return len(s)
-
- def sendall(self, s):
- """Send data to the TLS connection (socket emulation).
-
- @raise socket.error: If a socket error occurs.
- """
- self.write(s)
-
- def recv(self, bufsize):
- """Get some data from the TLS connection (socket emulation).
-
- @raise socket.error: If a socket error occurs.
- @raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
- without a preceding alert.
- @raise tlslite.errors.TLSAlert: If a TLS alert is signalled.
- """
- return self.read(bufsize)
-
- def makefile(self, mode='r', bufsize=-1):
- """Create a file object for the TLS connection (socket emulation).
-
- @rtype: L{tlslite.FileObject.FileObject}
- """
- self._refCount += 1
- return FileObject(self, mode, bufsize)
-
- def getsockname(self):
- """Return the socket's own address (socket emulation)."""
- return self.sock.getsockname()
-
- def getpeername(self):
- """Return the remote address to which the socket is connected
- (socket emulation)."""
- return self.sock.getpeername()
-
- def settimeout(self, value):
- """Set a timeout on blocking socket operations (socket emulation)."""
- return self.sock.settimeout(value)
-
- def gettimeout(self):
- """Return the timeout associated with socket operations (socket
- emulation)."""
- return self.sock.gettimeout()
-
- def setsockopt(self, level, optname, value):
- """Set the value of the given socket option (socket emulation)."""
- return self.sock.setsockopt(level, optname, value)
-
-
- #*********************************************************
- # Public Functions END
- #*********************************************************
-
- def _shutdown(self, resumable):
- self._writeState = _ConnectionState()
- self._readState = _ConnectionState()
- #Don't do this: self._readBuffer = ""
- self.version = (0,0)
- self._versionCheck = False
- self.closed = True
- if self.closeSocket:
- self.sock.close()
-
- #Even if resumable is False, we'll never toggle this on
- if not resumable and self.session:
- self.session.resumable = False
-
-
- def _sendError(self, alertDescription, errorStr=None):
- alert = Alert().create(alertDescription, AlertLevel.fatal)
- for result in self._sendMsg(alert):
- yield result
- self._shutdown(False)
- raise TLSLocalAlert(alert, errorStr)
-
- def _sendMsgs(self, msgs):
- skipEmptyFrag = False
- for msg in msgs:
- for result in self._sendMsg(msg, skipEmptyFrag):
- yield result
- skipEmptyFrag = True
-
- def _sendMsg(self, msg, skipEmptyFrag=False):
- bytes = msg.write()
- contentType = msg.contentType
-
- #Whenever we're connected and asked to send a message,
- #we first send an empty Application Data message. This prevents
- #an attacker from launching a chosen-plaintext attack based on
- #knowing the next IV.
- if not self.closed and not skipEmptyFrag and self.version == (3,1):
- if self._writeState.encContext:
- if self._writeState.encContext.isBlockCipher:
- for result in self._sendMsg(ApplicationData(),
- skipEmptyFrag=True):
- yield result
-
- #Update handshake hashes
- if contentType == ContentType.handshake:
- bytesStr = bytesToString(bytes)
- self._handshake_md5.update(bytesStr)
- self._handshake_sha.update(bytesStr)
-
- #Calculate MAC
- if self._writeState.macContext:
- seqnumStr = self._writeState.getSeqNumStr()
- bytesStr = bytesToString(bytes)
- mac = self._writeState.macContext.copy()
- mac.update(seqnumStr)
- mac.update(chr(contentType))
- if self.version == (3,0):
- mac.update( chr( int(len(bytes)/256) ) )
- mac.update( chr( int(len(bytes)%256) ) )
- elif self.version in ((3,1), (3,2)):
- mac.update(chr(self.version[0]))
- mac.update(chr(self.version[1]))
- mac.update( chr( int(len(bytes)/256) ) )
- mac.update( chr( int(len(bytes)%256) ) )
- else:
- raise AssertionError()
- mac.update(bytesStr)
- macString = mac.digest()
- macBytes = stringToBytes(macString)
- if self.fault == Fault.badMAC:
- macBytes[0] = (macBytes[0]+1) % 256
-
- #Encrypt for Block or Stream Cipher
- if self._writeState.encContext:
- #Add padding and encrypt (for Block Cipher):
- if self._writeState.encContext.isBlockCipher:
-
- #Add TLS 1.1 fixed block
- if self.version == (3,2):
- bytes = self.fixedIVBlock + bytes
-
- #Add padding: bytes = bytes + (macBytes + paddingBytes)
- currentLength = len(bytes) + len(macBytes) + 1
- blockLength = self._writeState.encContext.block_size
- paddingLength = blockLength-(currentLength % blockLength)
-
- paddingBytes = createByteArraySequence([paddingLength] * \
- (paddingLength+1))
- if self.fault == Fault.badPadding:
- paddingBytes[0] = (paddingBytes[0]+1) % 256
- endBytes = concatArrays(macBytes, paddingBytes)
- bytes = concatArrays(bytes, endBytes)
- #Encrypt
- plaintext = stringToBytes(bytes)
- ciphertext = self._writeState.encContext.encrypt(plaintext)
- bytes = stringToBytes(ciphertext)
-
- #Encrypt (for Stream Cipher)
- else:
- bytes = concatArrays(bytes, macBytes)
- plaintext = bytesToString(bytes)
- ciphertext = self._writeState.encContext.encrypt(plaintext)
- bytes = stringToBytes(ciphertext)
-
- #Add record header and send
- r = RecordHeader3().create(self.version, contentType, len(bytes))
- s = bytesToString(concatArrays(r.write(), bytes))
- while 1:
- try:
- bytesSent = self.sock.send(s) #Might raise socket.error
- except socket.error, why:
- if why[0] == errno.EWOULDBLOCK:
- yield 1
- continue
- else:
- raise
- if bytesSent == len(s):
- return
- s = s[bytesSent:]
- yield 1
-
-
- def _getMsg(self, expectedType, secondaryType=None, constructorType=None):
- try:
- if not isinstance(expectedType, tuple):
- expectedType = (expectedType,)
-
- #Spin in a loop, until we've got a non-empty record of a type we
- #expect. The loop will be repeated if:
- # - we receive a renegotiation attempt; we send no_renegotiation,
- # then try again
- # - we receive an empty application-data fragment; we try again
- while 1:
- for result in self._getNextRecord():
- if result in (0,1):
- yield result
- recordHeader, p = result
-
- #If this is an empty application-data fragment, try again
- if recordHeader.type == ContentType.application_data:
- if p.index == len(p.bytes):
- continue
-
- #If we received an unexpected record type...
- if recordHeader.type not in expectedType:
-
- #If we received an alert...
- if recordHeader.type == ContentType.alert:
- alert = Alert().parse(p)
-
- #We either received a fatal error, a warning, or a
- #close_notify. In any case, we're going to close the
- #connection. In the latter two cases we respond with
- #a close_notify, but ignore any socket errors, since
- #the other side might have already closed the socket.
- if alert.level == AlertLevel.warning or \
- alert.description == AlertDescription.close_notify:
-
- #If the sendMsg() call fails because the socket has
- #already been closed, we will be forgiving and not
- #report the error nor invalidate the "resumability"
- #of the session.
- try:
- alertMsg = Alert()
- alertMsg.create(AlertDescription.close_notify,
- AlertLevel.warning)
- for result in self._sendMsg(alertMsg):
- yield result
- except socket.error:
- pass
-
- if alert.description == \
- AlertDescription.close_notify:
- self._shutdown(True)
- elif alert.level == AlertLevel.warning:
- self._shutdown(False)
-
- else: #Fatal alert:
- self._shutdown(False)
-
- #Raise the alert as an exception
- raise TLSRemoteAlert(alert)
-
- #If we received a renegotiation attempt...
- if recordHeader.type == ContentType.handshake:
- subType = p.get(1)
- reneg = False
- if self._client:
- if subType == HandshakeType.hello_request:
- reneg = True
- else:
- if subType == HandshakeType.client_hello:
- reneg = True
- #Send no_renegotiation, then try again
- if reneg:
- alertMsg = Alert()
- alertMsg.create(AlertDescription.no_renegotiation,
- AlertLevel.warning)
- for result in self._sendMsg(alertMsg):
- yield result
- continue
-
- #Otherwise: this is an unexpected record, but neither an
- #alert nor renegotiation
- for result in self._sendError(\
- AlertDescription.unexpected_message,
- "received type=%d" % recordHeader.type):
- yield result
-
- break
-
- #Parse based on content_type
- if recordHeader.type == ContentType.change_cipher_spec:
- yield ChangeCipherSpec().parse(p)
- elif recordHeader.type == ContentType.alert:
- yield Alert().parse(p)
- elif recordHeader.type == ContentType.application_data:
- yield ApplicationData().parse(p)
- elif recordHeader.type == ContentType.handshake:
- #Convert secondaryType to tuple, if it isn't already
- if not isinstance(secondaryType, tuple):
- secondaryType = (secondaryType,)
-
- #If it's a handshake message, check handshake header
- if recordHeader.ssl2:
- subType = p.get(1)
- if subType != HandshakeType.client_hello:
- for result in self._sendError(\
- AlertDescription.unexpected_message,
- "Can only handle SSLv2 ClientHello messages"):
- yield result
- if HandshakeType.client_hello not in secondaryType:
- for result in self._sendError(\
- AlertDescription.unexpected_message):
- yield result
- subType = HandshakeType.client_hello
- else:
- subType = p.get(1)
- if subType not in secondaryType:
- for result in self._sendError(\
- AlertDescription.unexpected_message,
- "Expecting %s, got %s" % (str(secondaryType), subType)):
- yield result
-
- #Update handshake hashes
- sToHash = bytesToString(p.bytes)
- self._handshake_md5.update(sToHash)
- self._handshake_sha.update(sToHash)
-
- #Parse based on handshake type
- if subType == HandshakeType.client_hello:
- yield ClientHello(recordHeader.ssl2).parse(p)
- elif subType == HandshakeType.server_hello:
- yield ServerHello().parse(p)
- elif subType == HandshakeType.certificate:
- yield Certificate(constructorType).parse(p)
- elif subType == HandshakeType.certificate_request:
- yield CertificateRequest().parse(p)
- elif subType == HandshakeType.certificate_verify:
- yield CertificateVerify().parse(p)
- elif subType == HandshakeType.server_key_exchange:
- yield ServerKeyExchange(constructorType).parse(p)
- elif subType == HandshakeType.server_hello_done:
- yield ServerHelloDone().parse(p)
- elif subType == HandshakeType.client_key_exchange:
- yield ClientKeyExchange(constructorType, \
- self.version).parse(p)
- elif subType == HandshakeType.finished:
- yield Finished(self.version).parse(p)
- elif subType == HandshakeType.encrypted_extensions:
- yield EncryptedExtensions().parse(p)
- else:
- raise AssertionError()
-
- #If an exception was raised by a Parser or Message instance:
- except SyntaxError, e:
- for result in self._sendError(AlertDescription.decode_error,
- formatExceptionTrace(e)):
- yield result
-
-
- #Returns next record or next handshake message
- def _getNextRecord(self):
-
- #If there's a handshake message waiting, return it
- if self._handshakeBuffer:
- recordHeader, bytes = self._handshakeBuffer[0]
- self._handshakeBuffer = self._handshakeBuffer[1:]
- yield (recordHeader, Parser(bytes))
- return
-
- #Otherwise...
- #Read the next record header
- bytes = createByteArraySequence([])
- recordHeaderLength = 1
- ssl2 = False
- while 1:
- try:
- s = self.sock.recv(recordHeaderLength-len(bytes))
- except socket.error, why:
- if why[0] == errno.EWOULDBLOCK:
- yield 0
- continue
- else:
- raise
-
- #If the connection was abruptly closed, raise an error
- if len(s)==0:
- raise TLSAbruptCloseError()
-
- bytes += stringToBytes(s)
- if len(bytes)==1:
- if bytes[0] in ContentType.all:
- ssl2 = False
- recordHeaderLength = 5
- elif bytes[0] == 128:
- ssl2 = True
- recordHeaderLength = 2
- else:
- raise SyntaxError()
- if len(bytes) == recordHeaderLength:
- break
-
- #Parse the record header
- if ssl2:
- r = RecordHeader2().parse(Parser(bytes))
- else:
- r = RecordHeader3().parse(Parser(bytes))
-
- #Check the record header fields
- if r.length > 18432:
- for result in self._sendError(AlertDescription.record_overflow):
- yield result
-
- #Read the record contents
- bytes = createByteArraySequence([])
- while 1:
- try:
- s = self.sock.recv(r.length - len(bytes))
- except socket.error, why:
- if why[0] == errno.EWOULDBLOCK:
- yield 0
- continue
- else:
- raise
-
- #If the connection is closed, raise a socket error
- if len(s)==0:
- raise TLSAbruptCloseError()
-
- bytes += stringToBytes(s)
- if len(bytes) == r.length:
- break
-
- #Check the record header fields (2)
- #We do this after reading the contents from the socket, so that
- #if there's an error, we at least don't leave extra bytes in the
- #socket..
- #
- # THIS CHECK HAS NO SECURITY RELEVANCE (?), BUT COULD HURT INTEROP.
- # SO WE LEAVE IT OUT FOR NOW.
- #
- #if self._versionCheck and r.version != self.version:
- # for result in self._sendError(AlertDescription.protocol_version,
- # "Version in header field: %s, should be %s" % (str(r.version),
- # str(self.version))):
- # yield result
-
- #Decrypt the record
- for result in self._decryptRecord(r.type, bytes):
- if result in (0,1):
- yield result
- else:
- break
- bytes = result
- p = Parser(bytes)
-
- #If it doesn't contain handshake messages, we can just return it
- if r.type != ContentType.handshake:
- yield (r, p)
- #If it's an SSLv2 ClientHello, we can return it as well
- elif r.ssl2:
- yield (r, p)
- else:
- #Otherwise, we loop through and add the handshake messages to the
- #handshake buffer
- while 1:
- if p.index == len(bytes): #If we're at the end
- if not self._handshakeBuffer:
- for result in self._sendError(\
- AlertDescription.decode_error, \
- "Received empty handshake record"):
- yield result
- break
- #There needs to be at least 4 bytes to get a header
- if p.index+4 > len(bytes):
- for result in self._sendError(\
- AlertDescription.decode_error,
- "A record has a partial handshake message (1)"):
- yield result
- p.get(1) # skip handshake type
- msgLength = p.get(3)
- if p.index+msgLength > len(bytes):
- for result in self._sendError(\
- AlertDescription.decode_error,
- "A record has a partial handshake message (2)"):
- yield result
-
- handshakePair = (r, bytes[p.index-4 : p.index+msgLength])
- self._handshakeBuffer.append(handshakePair)
- p.index += msgLength
-
- #We've moved at least one handshake message into the
- #handshakeBuffer, return the first one
- recordHeader, bytes = self._handshakeBuffer[0]
- self._handshakeBuffer = self._handshakeBuffer[1:]
- yield (recordHeader, Parser(bytes))
-
-
- def _decryptRecord(self, recordType, bytes):
- if self._readState.encContext:
-
- #Decrypt if it's a block cipher
- if self._readState.encContext.isBlockCipher:
- blockLength = self._readState.encContext.block_size
- if len(bytes) % blockLength != 0:
- for result in self._sendError(\
- AlertDescription.decryption_failed,
- "Encrypted data not a multiple of blocksize"):
- yield result
- ciphertext = bytesToString(bytes)
- plaintext = self._readState.encContext.decrypt(ciphertext)
- if self.version == (3,2): #For TLS 1.1, remove explicit IV
- plaintext = plaintext[self._readState.encContext.block_size : ]
- bytes = stringToBytes(plaintext)
-
- #Check padding
- paddingGood = True
- paddingLength = bytes[-1]
- if (paddingLength+1) > len(bytes):
- paddingGood=False
- totalPaddingLength = 0
- else:
- if self.version == (3,0):
- totalPaddingLength = paddingLength+1
- elif self.version in ((3,1), (3,2)):
- totalPaddingLength = paddingLength+1
- paddingBytes = bytes[-totalPaddingLength:-1]
- for byte in paddingBytes:
- if byte != paddingLength:
- paddingGood = False
- totalPaddingLength = 0
- else:
- raise AssertionError()
-
- #Decrypt if it's a stream cipher
- else:
- paddingGood = True
- ciphertext = bytesToString(bytes)
- plaintext = self._readState.encContext.decrypt(ciphertext)
- bytes = stringToBytes(plaintext)
- totalPaddingLength = 0
-
- #Check MAC
- macGood = True
- macLength = self._readState.macContext.digest_size
- endLength = macLength + totalPaddingLength
- if endLength > len(bytes):
- macGood = False
- else:
- #Read MAC
- startIndex = len(bytes) - endLength
- endIndex = startIndex + macLength
- checkBytes = bytes[startIndex : endIndex]
-
- #Calculate MAC
- seqnumStr = self._readState.getSeqNumStr()
- bytes = bytes[:-endLength]
- bytesStr = bytesToString(bytes)
- mac = self._readState.macContext.copy()
- mac.update(seqnumStr)
- mac.update(chr(recordType))
- if self.version == (3,0):
- mac.update( chr( int(len(bytes)/256) ) )
- mac.update( chr( int(len(bytes)%256) ) )
- elif self.version in ((3,1), (3,2)):
- mac.update(chr(self.version[0]))
- mac.update(chr(self.version[1]))
- mac.update( chr( int(len(bytes)/256) ) )
- mac.update( chr( int(len(bytes)%256) ) )
- else:
- raise AssertionError()
- mac.update(bytesStr)
- macString = mac.digest()
- macBytes = stringToBytes(macString)
-
- #Compare MACs
- if macBytes != checkBytes:
- macGood = False
-
- if not (paddingGood and macGood):
- for result in self._sendError(AlertDescription.bad_record_mac,
- "MAC failure (or padding failure)"):
- yield result
-
- yield bytes
-
- def _handshakeStart(self, client):
- self._client = client
- self._handshake_md5 = md5.md5()
- self._handshake_sha = sha.sha()
- self._handshakeBuffer = []
- self.allegedSharedKeyUsername = None
- self.allegedSrpUsername = None
- self._refCount = 1
-
- def _handshakeDone(self, resumed):
- self.resumed = resumed
- self.closed = False
-
- def _calcPendingStates(self, clientRandom, serverRandom, implementations):
- if self.session.cipherSuite in CipherSuite.aes128Suites:
- macLength = 20
- keyLength = 16
- ivLength = 16
- createCipherFunc = createAES
- elif self.session.cipherSuite in CipherSuite.aes256Suites:
- macLength = 20
- keyLength = 32
- ivLength = 16
- createCipherFunc = createAES
- elif self.session.cipherSuite in CipherSuite.rc4Suites:
- macLength = 20
- keyLength = 16
- ivLength = 0
- createCipherFunc = createRC4
- elif self.session.cipherSuite in CipherSuite.tripleDESSuites:
- macLength = 20
- keyLength = 24
- ivLength = 8
- createCipherFunc = createTripleDES
- else:
- raise AssertionError()
-
- if self.version == (3,0):
- createMACFunc = MAC_SSL
- elif self.version in ((3,1), (3,2)):
- createMACFunc = hmac.HMAC
-
- outputLength = (macLength*2) + (keyLength*2) + (ivLength*2)
-
- #Calculate Keying Material from Master Secret
- if self.version == (3,0):
- keyBlock = PRF_SSL(self.session.masterSecret,
- concatArrays(serverRandom, clientRandom),
- outputLength)
- elif self.version in ((3,1), (3,2)):
- keyBlock = PRF(self.session.masterSecret,
- "key expansion",
- concatArrays(serverRandom,clientRandom),
- outputLength)
- else:
- raise AssertionError()
-
- #Slice up Keying Material
- clientPendingState = _ConnectionState()
- serverPendingState = _ConnectionState()
- p = Parser(keyBlock)
- clientMACBlock = bytesToString(p.getFixBytes(macLength))
- serverMACBlock = bytesToString(p.getFixBytes(macLength))
- clientKeyBlock = bytesToString(p.getFixBytes(keyLength))
- serverKeyBlock = bytesToString(p.getFixBytes(keyLength))
- clientIVBlock = bytesToString(p.getFixBytes(ivLength))
- serverIVBlock = bytesToString(p.getFixBytes(ivLength))
- clientPendingState.macContext = createMACFunc(clientMACBlock,
- digestmod=sha)
- serverPendingState.macContext = createMACFunc(serverMACBlock,
- digestmod=sha)
- clientPendingState.encContext = createCipherFunc(clientKeyBlock,
- clientIVBlock,
- implementations)
- serverPendingState.encContext = createCipherFunc(serverKeyBlock,
- serverIVBlock,
- implementations)
-
- #Assign new connection states to pending states
- if self._client:
- self._pendingWriteState = clientPendingState
- self._pendingReadState = serverPendingState
- else:
- self._pendingWriteState = serverPendingState
- self._pendingReadState = clientPendingState
-
- if self.version == (3,2) and ivLength:
- #Choose fixedIVBlock for TLS 1.1 (this is encrypted with the CBC
- #residue to create the IV for each sent block)
- self.fixedIVBlock = getRandomBytes(ivLength)
-
- def _changeWriteState(self):
- self._writeState = self._pendingWriteState
- self._pendingWriteState = _ConnectionState()
-
- def _changeReadState(self):
- self._readState = self._pendingReadState
- self._pendingReadState = _ConnectionState()
-
- def _sendFinished(self):
- #Send ChangeCipherSpec
- for result in self._sendMsg(ChangeCipherSpec()):
- yield result
-
- #Switch to pending write state
- self._changeWriteState()
-
- #Calculate verification data
- verifyData = self._calcFinished(True)
- if self.fault == Fault.badFinished:
- verifyData[0] = (verifyData[0]+1)%256
-
- #Send Finished message under new state
- finished = Finished(self.version).create(verifyData)
- for result in self._sendMsg(finished):
- yield result
-
- def _getChangeCipherSpec(self):
- #Get and check ChangeCipherSpec
- for result in self._getMsg(ContentType.change_cipher_spec):
- if result in (0,1):
- yield result
- changeCipherSpec = result
-
- if changeCipherSpec.type != 1:
- for result in self._sendError(AlertDescription.illegal_parameter,
- "ChangeCipherSpec type incorrect"):
- yield result
-
- #Switch to pending read state
- self._changeReadState()
-
- def _getEncryptedExtensions(self):
- for result in self._getMsg(ContentType.handshake,
- HandshakeType.encrypted_extensions):
- if result in (0,1):
- yield result
- encrypted_extensions = result
- self.channel_id = encrypted_extensions.channel_id_key
-
- def _getFinished(self):
- #Calculate verification data
- verifyData = self._calcFinished(False)
-
- #Get and check Finished message under new state
- for result in self._getMsg(ContentType.handshake,
- HandshakeType.finished):
- if result in (0,1):
- yield result
- finished = result
- if finished.verify_data != verifyData:
- for result in self._sendError(AlertDescription.decrypt_error,
- "Finished message is incorrect"):
- yield result
-
- def _calcFinished(self, send=True):
- if self.version == (3,0):
- if (self._client and send) or (not self._client and not send):
- senderStr = "\x43\x4C\x4E\x54"
- else:
- senderStr = "\x53\x52\x56\x52"
-
- verifyData = self._calcSSLHandshakeHash(self.session.masterSecret,
- senderStr)
- return verifyData
-
- elif self.version in ((3,1), (3,2)):
- if (self._client and send) or (not self._client and not send):
- label = "client finished"
- else:
- label = "server finished"
-
- handshakeHashes = stringToBytes(self._handshake_md5.digest() + \
- self._handshake_sha.digest())
- verifyData = PRF(self.session.masterSecret, label, handshakeHashes,
- 12)
- return verifyData
- else:
- raise AssertionError()
-
- #Used for Finished messages and CertificateVerify messages in SSL v3
- def _calcSSLHandshakeHash(self, masterSecret, label):
- masterSecretStr = bytesToString(masterSecret)
-
- imac_md5 = self._handshake_md5.copy()
- imac_sha = self._handshake_sha.copy()
-
- imac_md5.update(label + masterSecretStr + '\x36'*48)
- imac_sha.update(label + masterSecretStr + '\x36'*40)
-
- md5Str = md5.md5(masterSecretStr + ('\x5c'*48) + \
- imac_md5.digest()).digest()
- shaStr = sha.sha(masterSecretStr + ('\x5c'*40) + \
- imac_sha.digest()).digest()
-
- return stringToBytes(md5Str + shaStr)
« no previous file with comments | « third_party/tlslite/tlslite/TLSConnection.py ('k') | third_party/tlslite/tlslite/VerifierDB.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698