Index: third_party/tlslite/tlslite/TLSConnection.py |
diff --git a/third_party/tlslite/tlslite/TLSConnection.py b/third_party/tlslite/tlslite/TLSConnection.py |
deleted file mode 100644 |
index 0c3453666e4c8af9828938a7d2eece19a18ae978..0000000000000000000000000000000000000000 |
--- a/third_party/tlslite/tlslite/TLSConnection.py |
+++ /dev/null |
@@ -1,1698 +0,0 @@ |
-""" |
-MAIN CLASS FOR TLS LITE (START HERE!). |
-""" |
-from __future__ import generators |
- |
-import socket |
-from utils.compat import formatExceptionTrace |
-from TLSRecordLayer import TLSRecordLayer |
-from Session import Session |
-from constants import * |
-from utils.cryptomath import getRandomBytes |
-from errors import * |
-from messages import * |
-from mathtls import * |
-from HandshakeSettings import HandshakeSettings |
- |
- |
-class TLSConnection(TLSRecordLayer): |
- """ |
- This class wraps a socket and provides TLS handshaking and data |
- transfer. |
- |
- To use this class, create a new instance, passing a connected |
- socket into the constructor. Then call some handshake function. |
- If the handshake completes without raising an exception, then a TLS |
- connection has been negotiated. You can transfer data over this |
- connection as if it were a socket. |
- |
- This class provides both synchronous and asynchronous versions of |
- its key functions. The synchronous versions should be used when |
- writing single-or multi-threaded code using blocking sockets. The |
- asynchronous versions should be used when performing asynchronous, |
- event-based I/O with non-blocking sockets. |
- |
- Asynchronous I/O is a complicated subject; typically, you should |
- not use the asynchronous functions directly, but should use some |
- framework like asyncore or Twisted which TLS Lite integrates with |
- (see |
- L{tlslite.integration.TLSAsyncDispatcherMixIn.TLSAsyncDispatcherMixIn} or |
- L{tlslite.integration.TLSTwistedProtocolWrapper.TLSTwistedProtocolWrapper}). |
- """ |
- |
- |
- def __init__(self, sock): |
- """Create a new TLSConnection instance. |
- |
- @param sock: The socket data will be transmitted on. The |
- socket should already be connected. It may be in blocking or |
- non-blocking mode. |
- |
- @type sock: L{socket.socket} |
- """ |
- TLSRecordLayer.__init__(self, sock) |
- |
- def handshakeClientSRP(self, username, password, session=None, |
- settings=None, checker=None, async=False): |
- """Perform an SRP handshake in the role of client. |
- |
- This function performs a TLS/SRP handshake. SRP mutually |
- authenticates both parties to each other using only a |
- username and password. This function may also perform a |
- combined SRP and server-certificate handshake, if the server |
- chooses to authenticate itself with a certificate chain in |
- addition to doing SRP. |
- |
- TLS/SRP is non-standard. Most TLS implementations don't |
- support it. See |
- U{http://www.ietf.org/html.charters/tls-charter.html} or |
- U{http://trevp.net/tlssrp/} for the latest information on |
- TLS/SRP. |
- |
- Like any handshake function, this can be called on a closed |
- TLS connection, or on a TLS connection that is already open. |
- If called on an open connection it performs a re-handshake. |
- |
- If the function completes without raising an exception, the |
- TLS connection will be open and available for data transfer. |
- |
- If an exception is raised, the connection will have been |
- automatically closed (if it was ever open). |
- |
- @type username: str |
- @param username: The SRP username. |
- |
- @type password: str |
- @param password: The SRP password. |
- |
- @type session: L{tlslite.Session.Session} |
- @param session: A TLS session to attempt to resume. This |
- session must be an SRP session performed with the same username |
- and password as were passed in. If the resumption does not |
- succeed, a full SRP handshake will be performed. |
- |
- @type settings: L{tlslite.HandshakeSettings.HandshakeSettings} |
- @param settings: Various settings which can be used to control |
- the ciphersuites, certificate types, and SSL/TLS versions |
- offered by the client. |
- |
- @type checker: L{tlslite.Checker.Checker} |
- @param checker: A Checker instance. This instance will be |
- invoked to examine the other party's authentication |
- credentials, if the handshake completes succesfully. |
- |
- @type async: bool |
- @param async: If False, this function will block until the |
- handshake is completed. If True, this function will return a |
- generator. 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 handshake operation is completed. |
- |
- @rtype: None or an iterable |
- @return: If 'async' is True, a generator object will 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. |
- @raise tlslite.errors.TLSAuthenticationError: If the checker |
- doesn't like the other party's authentication credentials. |
- """ |
- handshaker = self._handshakeClientAsync(srpParams=(username, password), |
- session=session, settings=settings, checker=checker) |
- if async: |
- return handshaker |
- for result in handshaker: |
- pass |
- |
- def handshakeClientCert(self, certChain=None, privateKey=None, |
- session=None, settings=None, checker=None, |
- async=False): |
- """Perform a certificate-based handshake in the role of client. |
- |
- This function performs an SSL or TLS handshake. The server |
- will authenticate itself using an X.509 or cryptoID certificate |
- chain. If the handshake succeeds, the server's certificate |
- chain will be stored in the session's serverCertChain attribute. |
- Unless a checker object is passed in, this function does no |
- validation or checking of the server's certificate chain. |
- |
- If the server requests client authentication, the |
- client will send the passed-in certificate chain, and use the |
- passed-in private key to authenticate itself. If no |
- certificate chain and private key were passed in, the client |
- will attempt to proceed without client authentication. The |
- server may or may not allow this. |
- |
- Like any handshake function, this can be called on a closed |
- TLS connection, or on a TLS connection that is already open. |
- If called on an open connection it performs a re-handshake. |
- |
- If the function completes without raising an exception, the |
- TLS connection will be open and available for data transfer. |
- |
- If an exception is raised, the connection will have been |
- automatically closed (if it was ever open). |
- |
- @type certChain: L{tlslite.X509CertChain.X509CertChain} or |
- L{cryptoIDlib.CertChain.CertChain} |
- @param certChain: The certificate chain to be used if the |
- server requests client authentication. |
- |
- @type privateKey: L{tlslite.utils.RSAKey.RSAKey} |
- @param privateKey: The private key to be used if the server |
- requests client authentication. |
- |
- @type session: L{tlslite.Session.Session} |
- @param session: A TLS session to attempt to resume. If the |
- resumption does not succeed, a full handshake will be |
- performed. |
- |
- @type settings: L{tlslite.HandshakeSettings.HandshakeSettings} |
- @param settings: Various settings which can be used to control |
- the ciphersuites, certificate types, and SSL/TLS versions |
- offered by the client. |
- |
- @type checker: L{tlslite.Checker.Checker} |
- @param checker: A Checker instance. This instance will be |
- invoked to examine the other party's authentication |
- credentials, if the handshake completes succesfully. |
- |
- @type async: bool |
- @param async: If False, this function will block until the |
- handshake is completed. If True, this function will return a |
- generator. 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 handshake operation is completed. |
- |
- @rtype: None or an iterable |
- @return: If 'async' is True, a generator object will 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. |
- @raise tlslite.errors.TLSAuthenticationError: If the checker |
- doesn't like the other party's authentication credentials. |
- """ |
- handshaker = self._handshakeClientAsync(certParams=(certChain, |
- privateKey), session=session, settings=settings, |
- checker=checker) |
- if async: |
- return handshaker |
- for result in handshaker: |
- pass |
- |
- def handshakeClientUnknown(self, srpCallback=None, certCallback=None, |
- session=None, settings=None, checker=None, |
- async=False): |
- """Perform a to-be-determined type of handshake in the role of client. |
- |
- This function performs an SSL or TLS handshake. If the server |
- requests client certificate authentication, the |
- certCallback will be invoked and should return a (certChain, |
- privateKey) pair. If the callback returns None, the library |
- will attempt to proceed without client authentication. The |
- server may or may not allow this. |
- |
- If the server requests SRP authentication, the srpCallback |
- will be invoked and should return a (username, password) pair. |
- If the callback returns None, the local implementation will |
- signal a user_canceled error alert. |
- |
- After the handshake completes, the client can inspect the |
- connection's session attribute to determine what type of |
- authentication was performed. |
- |
- Like any handshake function, this can be called on a closed |
- TLS connection, or on a TLS connection that is already open. |
- If called on an open connection it performs a re-handshake. |
- |
- If the function completes without raising an exception, the |
- TLS connection will be open and available for data transfer. |
- |
- If an exception is raised, the connection will have been |
- automatically closed (if it was ever open). |
- |
- @type srpCallback: callable |
- @param srpCallback: The callback to be used if the server |
- requests SRP authentication. If None, the client will not |
- offer support for SRP ciphersuites. |
- |
- @type certCallback: callable |
- @param certCallback: The callback to be used if the server |
- requests client certificate authentication. |
- |
- @type session: L{tlslite.Session.Session} |
- @param session: A TLS session to attempt to resume. If the |
- resumption does not succeed, a full handshake will be |
- performed. |
- |
- @type settings: L{tlslite.HandshakeSettings.HandshakeSettings} |
- @param settings: Various settings which can be used to control |
- the ciphersuites, certificate types, and SSL/TLS versions |
- offered by the client. |
- |
- @type checker: L{tlslite.Checker.Checker} |
- @param checker: A Checker instance. This instance will be |
- invoked to examine the other party's authentication |
- credentials, if the handshake completes succesfully. |
- |
- @type async: bool |
- @param async: If False, this function will block until the |
- handshake is completed. If True, this function will return a |
- generator. 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 handshake operation is completed. |
- |
- @rtype: None or an iterable |
- @return: If 'async' is True, a generator object will 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. |
- @raise tlslite.errors.TLSAuthenticationError: If the checker |
- doesn't like the other party's authentication credentials. |
- """ |
- handshaker = self._handshakeClientAsync(unknownParams=(srpCallback, |
- certCallback), session=session, settings=settings, |
- checker=checker) |
- if async: |
- return handshaker |
- for result in handshaker: |
- pass |
- |
- def handshakeClientSharedKey(self, username, sharedKey, settings=None, |
- checker=None, async=False): |
- """Perform a shared-key handshake in the role of client. |
- |
- This function performs a shared-key handshake. Using shared |
- symmetric keys of high entropy (128 bits or greater) mutually |
- authenticates both parties to each other. |
- |
- TLS with shared-keys is non-standard. Most TLS |
- implementations don't support it. See |
- U{http://www.ietf.org/html.charters/tls-charter.html} for the |
- latest information on TLS with shared-keys. If the shared-keys |
- Internet-Draft changes or is superceded, TLS Lite will track |
- those changes, so the shared-key support in later versions of |
- TLS Lite may become incompatible with this version. |
- |
- Like any handshake function, this can be called on a closed |
- TLS connection, or on a TLS connection that is already open. |
- If called on an open connection it performs a re-handshake. |
- |
- If the function completes without raising an exception, the |
- TLS connection will be open and available for data transfer. |
- |
- If an exception is raised, the connection will have been |
- automatically closed (if it was ever open). |
- |
- @type username: str |
- @param username: The shared-key username. |
- |
- @type sharedKey: str |
- @param sharedKey: The shared key. |
- |
- @type settings: L{tlslite.HandshakeSettings.HandshakeSettings} |
- @param settings: Various settings which can be used to control |
- the ciphersuites, certificate types, and SSL/TLS versions |
- offered by the client. |
- |
- @type checker: L{tlslite.Checker.Checker} |
- @param checker: A Checker instance. This instance will be |
- invoked to examine the other party's authentication |
- credentials, if the handshake completes succesfully. |
- |
- @type async: bool |
- @param async: If False, this function will block until the |
- handshake is completed. If True, this function will return a |
- generator. 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 handshake operation is completed. |
- |
- @rtype: None or an iterable |
- @return: If 'async' is True, a generator object will 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. |
- @raise tlslite.errors.TLSAuthenticationError: If the checker |
- doesn't like the other party's authentication credentials. |
- """ |
- handshaker = self._handshakeClientAsync(sharedKeyParams=(username, |
- sharedKey), settings=settings, checker=checker) |
- if async: |
- return handshaker |
- for result in handshaker: |
- pass |
- |
- def _handshakeClientAsync(self, srpParams=(), certParams=(), |
- unknownParams=(), sharedKeyParams=(), |
- session=None, settings=None, checker=None, |
- recursive=False): |
- |
- handshaker = self._handshakeClientAsyncHelper(srpParams=srpParams, |
- certParams=certParams, unknownParams=unknownParams, |
- sharedKeyParams=sharedKeyParams, session=session, |
- settings=settings, recursive=recursive) |
- for result in self._handshakeWrapperAsync(handshaker, checker): |
- yield result |
- |
- |
- def _handshakeClientAsyncHelper(self, srpParams, certParams, unknownParams, |
- sharedKeyParams, session, settings, recursive): |
- if not recursive: |
- self._handshakeStart(client=True) |
- |
- #Unpack parameters |
- srpUsername = None # srpParams |
- password = None # srpParams |
- clientCertChain = None # certParams |
- privateKey = None # certParams |
- srpCallback = None # unknownParams |
- certCallback = None # unknownParams |
- #session # sharedKeyParams (or session) |
- #settings # settings |
- |
- if srpParams: |
- srpUsername, password = srpParams |
- elif certParams: |
- clientCertChain, privateKey = certParams |
- elif unknownParams: |
- srpCallback, certCallback = unknownParams |
- elif sharedKeyParams: |
- session = Session()._createSharedKey(*sharedKeyParams) |
- |
- if not settings: |
- settings = HandshakeSettings() |
- settings = settings._filter() |
- |
- #Validate parameters |
- if srpUsername and not password: |
- raise ValueError("Caller passed a username but no password") |
- if password and not srpUsername: |
- raise ValueError("Caller passed a password but no username") |
- |
- if clientCertChain and not privateKey: |
- raise ValueError("Caller passed a certChain but no privateKey") |
- if privateKey and not clientCertChain: |
- raise ValueError("Caller passed a privateKey but no certChain") |
- |
- if clientCertChain: |
- foundType = False |
- try: |
- import cryptoIDlib.CertChain |
- if isinstance(clientCertChain, cryptoIDlib.CertChain.CertChain): |
- if "cryptoID" not in settings.certificateTypes: |
- raise ValueError("Client certificate doesn't "\ |
- "match Handshake Settings") |
- settings.certificateTypes = ["cryptoID"] |
- foundType = True |
- except ImportError: |
- pass |
- if not foundType and isinstance(clientCertChain, |
- X509CertChain): |
- if "x509" not in settings.certificateTypes: |
- raise ValueError("Client certificate doesn't match "\ |
- "Handshake Settings") |
- settings.certificateTypes = ["x509"] |
- foundType = True |
- if not foundType: |
- raise ValueError("Unrecognized certificate type") |
- |
- |
- if session: |
- if not session.valid(): |
- session = None #ignore non-resumable sessions... |
- elif session.resumable and \ |
- (session.srpUsername != srpUsername): |
- raise ValueError("Session username doesn't match") |
- |
- #Add Faults to parameters |
- if srpUsername and self.fault == Fault.badUsername: |
- srpUsername += "GARBAGE" |
- if password and self.fault == Fault.badPassword: |
- password += "GARBAGE" |
- if sharedKeyParams: |
- identifier = sharedKeyParams[0] |
- sharedKey = sharedKeyParams[1] |
- if self.fault == Fault.badIdentifier: |
- identifier += "GARBAGE" |
- session = Session()._createSharedKey(identifier, sharedKey) |
- elif self.fault == Fault.badSharedKey: |
- sharedKey += "GARBAGE" |
- session = Session()._createSharedKey(identifier, sharedKey) |
- |
- |
- #Initialize locals |
- serverCertChain = None |
- cipherSuite = 0 |
- certificateType = CertificateType.x509 |
- premasterSecret = None |
- |
- #Get client nonce |
- clientRandom = getRandomBytes(32) |
- |
- #Initialize acceptable ciphersuites |
- cipherSuites = [] |
- if srpParams: |
- cipherSuites += CipherSuite.getSrpRsaSuites(settings.cipherNames) |
- cipherSuites += CipherSuite.getSrpSuites(settings.cipherNames) |
- elif certParams: |
- cipherSuites += CipherSuite.getRsaSuites(settings.cipherNames) |
- elif unknownParams: |
- if srpCallback: |
- cipherSuites += \ |
- CipherSuite.getSrpRsaSuites(settings.cipherNames) |
- cipherSuites += \ |
- CipherSuite.getSrpSuites(settings.cipherNames) |
- cipherSuites += CipherSuite.getRsaSuites(settings.cipherNames) |
- elif sharedKeyParams: |
- cipherSuites += CipherSuite.getRsaSuites(settings.cipherNames) |
- else: |
- cipherSuites += CipherSuite.getRsaSuites(settings.cipherNames) |
- |
- #Initialize acceptable certificate types |
- certificateTypes = settings._getCertificateTypes() |
- |
- #Tentatively set the version to the client's minimum version. |
- #We'll use this for the ClientHello, and if an error occurs |
- #parsing the Server Hello, we'll use this version for the response |
- self.version = settings.maxVersion |
- |
- #Either send ClientHello (with a resumable session)... |
- if session: |
- #If it's a resumable (i.e. not a shared-key session), then its |
- #ciphersuite must be one of the acceptable ciphersuites |
- if (not sharedKeyParams) and \ |
- session.cipherSuite not in cipherSuites: |
- raise ValueError("Session's cipher suite not consistent "\ |
- "with parameters") |
- else: |
- clientHello = ClientHello() |
- clientHello.create(settings.maxVersion, clientRandom, |
- session.sessionID, cipherSuites, |
- certificateTypes, session.srpUsername) |
- |
- #Or send ClientHello (without) |
- else: |
- clientHello = ClientHello() |
- clientHello.create(settings.maxVersion, clientRandom, |
- createByteArraySequence([]), cipherSuites, |
- certificateTypes, srpUsername) |
- for result in self._sendMsg(clientHello): |
- yield result |
- |
- #Get ServerHello (or missing_srp_username) |
- for result in self._getMsg((ContentType.handshake, |
- ContentType.alert), |
- HandshakeType.server_hello): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- msg = result |
- |
- if isinstance(msg, ServerHello): |
- serverHello = msg |
- elif isinstance(msg, Alert): |
- alert = msg |
- |
- #If it's not a missing_srp_username, re-raise |
- if alert.description != AlertDescription.missing_srp_username: |
- self._shutdown(False) |
- raise TLSRemoteAlert(alert) |
- |
- #If we're not in SRP callback mode, we won't have offered SRP |
- #without a username, so we shouldn't get this alert |
- if not srpCallback: |
- for result in self._sendError(\ |
- AlertDescription.unexpected_message): |
- yield result |
- srpParams = srpCallback() |
- #If the callback returns None, cancel the handshake |
- if srpParams == None: |
- for result in self._sendError(AlertDescription.user_canceled): |
- yield result |
- |
- #Recursively perform handshake |
- for result in self._handshakeClientAsyncHelper(srpParams, |
- None, None, None, None, settings, True): |
- yield result |
- return |
- |
- #Get the server version. Do this before anything else, so any |
- #error alerts will use the server's version |
- self.version = serverHello.server_version |
- |
- #Future responses from server must use this version |
- self._versionCheck = True |
- |
- #Check ServerHello |
- if serverHello.server_version < settings.minVersion: |
- for result in self._sendError(\ |
- AlertDescription.protocol_version, |
- "Too old version: %s" % str(serverHello.server_version)): |
- yield result |
- if serverHello.server_version > settings.maxVersion: |
- for result in self._sendError(\ |
- AlertDescription.protocol_version, |
- "Too new version: %s" % str(serverHello.server_version)): |
- yield result |
- if serverHello.cipher_suite not in cipherSuites: |
- for result in self._sendError(\ |
- AlertDescription.illegal_parameter, |
- "Server responded with incorrect ciphersuite"): |
- yield result |
- if serverHello.certificate_type not in certificateTypes: |
- for result in self._sendError(\ |
- AlertDescription.illegal_parameter, |
- "Server responded with incorrect certificate type"): |
- yield result |
- if serverHello.compression_method != 0: |
- for result in self._sendError(\ |
- AlertDescription.illegal_parameter, |
- "Server responded with incorrect compression method"): |
- yield result |
- |
- #Get the server nonce |
- serverRandom = serverHello.random |
- |
- #If the server agrees to resume |
- if session and session.sessionID and \ |
- serverHello.session_id == session.sessionID: |
- |
- #If a shared-key, we're flexible about suites; otherwise the |
- #server-chosen suite has to match the session's suite |
- if sharedKeyParams: |
- session.cipherSuite = serverHello.cipher_suite |
- elif serverHello.cipher_suite != session.cipherSuite: |
- for result in self._sendError(\ |
- AlertDescription.illegal_parameter,\ |
- "Server's ciphersuite doesn't match session"): |
- yield result |
- |
- #Set the session for this connection |
- self.session = session |
- |
- #Calculate pending connection states |
- self._calcPendingStates(clientRandom, serverRandom, |
- settings.cipherImplementations) |
- |
- #Exchange ChangeCipherSpec and Finished messages |
- for result in self._getChangeCipherSpec(): |
- yield result |
- for result in self._getFinished(): |
- yield result |
- for result in self._sendFinished(): |
- yield result |
- |
- #Mark the connection as open |
- self._handshakeDone(resumed=True) |
- |
- #If server DOES NOT agree to resume |
- else: |
- |
- if sharedKeyParams: |
- for result in self._sendError(\ |
- AlertDescription.user_canceled, |
- "Was expecting a shared-key resumption"): |
- yield result |
- |
- #We've already validated these |
- cipherSuite = serverHello.cipher_suite |
- certificateType = serverHello.certificate_type |
- |
- #If the server chose an SRP suite... |
- if cipherSuite in CipherSuite.srpSuites: |
- #Get ServerKeyExchange, ServerHelloDone |
- for result in self._getMsg(ContentType.handshake, |
- HandshakeType.server_key_exchange, cipherSuite): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- serverKeyExchange = result |
- |
- for result in self._getMsg(ContentType.handshake, |
- HandshakeType.server_hello_done): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- serverHelloDone = result |
- |
- #If the server chose an SRP+RSA suite... |
- elif cipherSuite in CipherSuite.srpRsaSuites: |
- #Get Certificate, ServerKeyExchange, ServerHelloDone |
- for result in self._getMsg(ContentType.handshake, |
- HandshakeType.certificate, certificateType): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- serverCertificate = result |
- |
- for result in self._getMsg(ContentType.handshake, |
- HandshakeType.server_key_exchange, cipherSuite): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- serverKeyExchange = result |
- |
- for result in self._getMsg(ContentType.handshake, |
- HandshakeType.server_hello_done): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- serverHelloDone = result |
- |
- #If the server chose an RSA suite... |
- elif cipherSuite in CipherSuite.rsaSuites: |
- #Get Certificate[, CertificateRequest], ServerHelloDone |
- for result in self._getMsg(ContentType.handshake, |
- HandshakeType.certificate, certificateType): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- serverCertificate = result |
- |
- for result in self._getMsg(ContentType.handshake, |
- (HandshakeType.server_hello_done, |
- HandshakeType.certificate_request)): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- msg = result |
- |
- certificateRequest = None |
- if isinstance(msg, CertificateRequest): |
- certificateRequest = msg |
- for result in self._getMsg(ContentType.handshake, |
- HandshakeType.server_hello_done): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- serverHelloDone = result |
- elif isinstance(msg, ServerHelloDone): |
- serverHelloDone = msg |
- else: |
- raise AssertionError() |
- |
- |
- #Calculate SRP premaster secret, if server chose an SRP or |
- #SRP+RSA suite |
- if cipherSuite in CipherSuite.srpSuites + \ |
- CipherSuite.srpRsaSuites: |
- #Get and check the server's group parameters and B value |
- N = serverKeyExchange.srp_N |
- g = serverKeyExchange.srp_g |
- s = serverKeyExchange.srp_s |
- B = serverKeyExchange.srp_B |
- |
- if (g,N) not in goodGroupParameters: |
- for result in self._sendError(\ |
- AlertDescription.untrusted_srp_parameters, |
- "Unknown group parameters"): |
- yield result |
- if numBits(N) < settings.minKeySize: |
- for result in self._sendError(\ |
- AlertDescription.untrusted_srp_parameters, |
- "N value is too small: %d" % numBits(N)): |
- yield result |
- if numBits(N) > settings.maxKeySize: |
- for result in self._sendError(\ |
- AlertDescription.untrusted_srp_parameters, |
- "N value is too large: %d" % numBits(N)): |
- yield result |
- if B % N == 0: |
- for result in self._sendError(\ |
- AlertDescription.illegal_parameter, |
- "Suspicious B value"): |
- yield result |
- |
- #Check the server's signature, if server chose an |
- #SRP+RSA suite |
- if cipherSuite in CipherSuite.srpRsaSuites: |
- #Hash ServerKeyExchange/ServerSRPParams |
- hashBytes = serverKeyExchange.hash(clientRandom, |
- serverRandom) |
- |
- #Extract signature bytes from ServerKeyExchange |
- sigBytes = serverKeyExchange.signature |
- if len(sigBytes) == 0: |
- for result in self._sendError(\ |
- AlertDescription.illegal_parameter, |
- "Server sent an SRP ServerKeyExchange "\ |
- "message without a signature"): |
- yield result |
- |
- #Get server's public key from the Certificate message |
- for result in self._getKeyFromChain(serverCertificate, |
- settings): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- publicKey, serverCertChain = result |
- |
- #Verify signature |
- if not publicKey.verify(sigBytes, hashBytes): |
- for result in self._sendError(\ |
- AlertDescription.decrypt_error, |
- "Signature failed to verify"): |
- yield result |
- |
- |
- #Calculate client's ephemeral DH values (a, A) |
- a = bytesToNumber(getRandomBytes(32)) |
- A = powMod(g, a, N) |
- |
- #Calculate client's static DH values (x, v) |
- x = makeX(bytesToString(s), srpUsername, password) |
- v = powMod(g, x, N) |
- |
- #Calculate u |
- u = makeU(N, A, B) |
- |
- #Calculate premaster secret |
- k = makeK(N, g) |
- S = powMod((B - (k*v)) % N, a+(u*x), N) |
- |
- if self.fault == Fault.badA: |
- A = N |
- S = 0 |
- premasterSecret = numberToBytes(S) |
- |
- #Send ClientKeyExchange |
- for result in self._sendMsg(\ |
- ClientKeyExchange(cipherSuite).createSRP(A)): |
- yield result |
- |
- |
- #Calculate RSA premaster secret, if server chose an RSA suite |
- elif cipherSuite in CipherSuite.rsaSuites: |
- |
- #Handle the presence of a CertificateRequest |
- if certificateRequest: |
- if unknownParams and certCallback: |
- certParamsNew = certCallback() |
- if certParamsNew: |
- clientCertChain, privateKey = certParamsNew |
- |
- #Get server's public key from the Certificate message |
- for result in self._getKeyFromChain(serverCertificate, |
- settings): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- publicKey, serverCertChain = result |
- |
- |
- #Calculate premaster secret |
- premasterSecret = getRandomBytes(48) |
- premasterSecret[0] = settings.maxVersion[0] |
- premasterSecret[1] = settings.maxVersion[1] |
- |
- if self.fault == Fault.badPremasterPadding: |
- premasterSecret[0] = 5 |
- if self.fault == Fault.shortPremasterSecret: |
- premasterSecret = premasterSecret[:-1] |
- |
- #Encrypt premaster secret to server's public key |
- encryptedPreMasterSecret = publicKey.encrypt(premasterSecret) |
- |
- #If client authentication was requested, send Certificate |
- #message, either with certificates or empty |
- if certificateRequest: |
- clientCertificate = Certificate(certificateType) |
- |
- if clientCertChain: |
- #Check to make sure we have the same type of |
- #certificates the server requested |
- wrongType = False |
- if certificateType == CertificateType.x509: |
- if not isinstance(clientCertChain, X509CertChain): |
- wrongType = True |
- elif certificateType == CertificateType.cryptoID: |
- if not isinstance(clientCertChain, |
- cryptoIDlib.CertChain.CertChain): |
- wrongType = True |
- if wrongType: |
- for result in self._sendError(\ |
- AlertDescription.handshake_failure, |
- "Client certificate is of wrong type"): |
- yield result |
- |
- clientCertificate.create(clientCertChain) |
- |
- for result in self._sendMsg(clientCertificate): |
- yield result |
- else: |
- #The server didn't request client auth, so we |
- #zeroize these so the clientCertChain won't be |
- #stored in the session. |
- privateKey = None |
- clientCertChain = None |
- |
- #Send ClientKeyExchange |
- clientKeyExchange = ClientKeyExchange(cipherSuite, |
- self.version) |
- clientKeyExchange.createRSA(encryptedPreMasterSecret) |
- for result in self._sendMsg(clientKeyExchange): |
- yield result |
- |
- #If client authentication was requested and we have a |
- #private key, send CertificateVerify |
- if certificateRequest and privateKey: |
- if self.version == (3,0): |
- #Create a temporary session object, just for the |
- #purpose of creating the CertificateVerify |
- session = Session() |
- session._calcMasterSecret(self.version, |
- premasterSecret, |
- clientRandom, |
- serverRandom) |
- verifyBytes = self._calcSSLHandshakeHash(\ |
- session.masterSecret, "") |
- elif self.version in ((3,1), (3,2)): |
- verifyBytes = stringToBytes(\ |
- self._handshake_md5.digest() + \ |
- self._handshake_sha.digest()) |
- if self.fault == Fault.badVerifyMessage: |
- verifyBytes[0] = ((verifyBytes[0]+1) % 256) |
- signedBytes = privateKey.sign(verifyBytes) |
- certificateVerify = CertificateVerify() |
- certificateVerify.create(signedBytes) |
- for result in self._sendMsg(certificateVerify): |
- yield result |
- |
- |
- #Create the session object |
- self.session = Session() |
- self.session._calcMasterSecret(self.version, premasterSecret, |
- clientRandom, serverRandom) |
- self.session.sessionID = serverHello.session_id |
- self.session.cipherSuite = cipherSuite |
- self.session.srpUsername = srpUsername |
- self.session.clientCertChain = clientCertChain |
- self.session.serverCertChain = serverCertChain |
- |
- #Calculate pending connection states |
- self._calcPendingStates(clientRandom, serverRandom, |
- settings.cipherImplementations) |
- |
- #Exchange ChangeCipherSpec and Finished messages |
- for result in self._sendFinished(): |
- yield result |
- for result in self._getChangeCipherSpec(): |
- yield result |
- for result in self._getFinished(): |
- yield result |
- |
- #Mark the connection as open |
- self.session._setResumable(True) |
- self._handshakeDone(resumed=False) |
- |
- |
- |
- def handshakeServer(self, sharedKeyDB=None, verifierDB=None, |
- certChain=None, privateKey=None, reqCert=False, |
- sessionCache=None, settings=None, checker=None, |
- reqCAs=None, tlsIntolerant=0, |
- signedCertTimestamps=None, fallbackSCSV=False, |
- ocspResponse=None): |
- """Perform a handshake in the role of server. |
- |
- This function performs an SSL or TLS handshake. Depending on |
- the arguments and the behavior of the client, this function can |
- perform a shared-key, SRP, or certificate-based handshake. It |
- can also perform a combined SRP and server-certificate |
- handshake. |
- |
- Like any handshake function, this can be called on a closed |
- TLS connection, or on a TLS connection that is already open. |
- If called on an open connection it performs a re-handshake. |
- This function does not send a Hello Request message before |
- performing the handshake, so if re-handshaking is required, |
- the server must signal the client to begin the re-handshake |
- through some other means. |
- |
- If the function completes without raising an exception, the |
- TLS connection will be open and available for data transfer. |
- |
- If an exception is raised, the connection will have been |
- automatically closed (if it was ever open). |
- |
- @type sharedKeyDB: L{tlslite.SharedKeyDB.SharedKeyDB} |
- @param sharedKeyDB: A database of shared symmetric keys |
- associated with usernames. If the client performs a |
- shared-key handshake, the session's sharedKeyUsername |
- attribute will be set. |
- |
- @type verifierDB: L{tlslite.VerifierDB.VerifierDB} |
- @param verifierDB: A database of SRP password verifiers |
- associated with usernames. If the client performs an SRP |
- handshake, the session's srpUsername attribute will be set. |
- |
- @type certChain: L{tlslite.X509CertChain.X509CertChain} or |
- L{cryptoIDlib.CertChain.CertChain} |
- @param certChain: The certificate chain to be used if the |
- client requests server certificate authentication. |
- |
- @type privateKey: L{tlslite.utils.RSAKey.RSAKey} |
- @param privateKey: The private key to be used if the client |
- requests server certificate authentication. |
- |
- @type reqCert: bool |
- @param reqCert: Whether to request client certificate |
- authentication. This only applies if the client chooses server |
- certificate authentication; if the client chooses SRP or |
- shared-key authentication, this will be ignored. If the client |
- performs a client certificate authentication, the sessions's |
- clientCertChain attribute will be set. |
- |
- @type sessionCache: L{tlslite.SessionCache.SessionCache} |
- @param sessionCache: An in-memory cache of resumable sessions. |
- The client can resume sessions from this cache. Alternatively, |
- if the client performs a full handshake, a new session will be |
- added to the cache. |
- |
- @type settings: L{tlslite.HandshakeSettings.HandshakeSettings} |
- @param settings: Various settings which can be used to control |
- the ciphersuites and SSL/TLS version chosen by the server. |
- |
- @type checker: L{tlslite.Checker.Checker} |
- @param checker: A Checker instance. This instance will be |
- invoked to examine the other party's authentication |
- credentials, if the handshake completes succesfully. |
- |
- @type reqCAs: list of L{array.array} of unsigned bytes |
- @param reqCAs: A collection of DER-encoded DistinguishedNames that |
- will be sent along with a certificate request. This does not affect |
- verification. |
- |
- @type signedCertTimestamps: str |
- @param signedCertTimestamps: A SignedCertificateTimestampList (as a |
- binary 8-bit string) that will be sent as a TLS extension whenever |
- the client announces support for the extension. |
- |
- @type tlsIntolerant: int |
- @param tlsIntolerant: if non-zero, the server will simulate TLS |
- version intolerance by returning a fatal, handshake_failure alert. |
- The versions to which it's intolerant vary depending on the value: |
- 1: reject all TLS versions. |
- 2: reject TLS 1.1 or higher. |
- 3: reject TLS 1.2 or higher. |
- |
- @type fallbackSCSV: bool |
- @param fallbackSCSV: if true, the server will implement |
- TLS_FALLBACK_SCSV and thus reject connections using less than the |
- server's maximum TLS version that include this cipher suite. |
- |
- @type ocspResponse: str |
- @param ocspResponse: An OCSP response (as a binary 8-bit string) that |
- will be sent stapled in the handshake whenever the client announces |
- support for the status_request extension. |
- Note that the response is sent independent of the ClientHello |
- status_request extension contents, and is thus only meant for testing |
- environments. Real OCSP stapling is more complicated as it requires |
- choosing a suitable response based on the ClientHello status_request |
- extension contents. |
- |
- @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. |
- @raise tlslite.errors.TLSAuthenticationError: If the checker |
- doesn't like the other party's authentication credentials. |
- """ |
- for result in self.handshakeServerAsync(sharedKeyDB, verifierDB, |
- certChain, privateKey, reqCert, sessionCache, settings, |
- checker, reqCAs, tlsIntolerant, signedCertTimestamps, |
- fallbackSCSV, ocspResponse): |
- pass |
- |
- |
- def handshakeServerAsync(self, sharedKeyDB=None, verifierDB=None, |
- certChain=None, privateKey=None, reqCert=False, |
- sessionCache=None, settings=None, checker=None, |
- reqCAs=None, tlsIntolerant=0, |
- signedCertTimestamps=None, |
- fallbackSCSV=False, ocspResponse=None): |
- """Start a server handshake operation on the TLS connection. |
- |
- This function returns a generator which behaves similarly to |
- handshakeServer(). 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 it will raise StopIteration |
- if the handshake operation is complete. |
- |
- @rtype: iterable |
- @return: A generator; see above for details. |
- """ |
- handshaker = self._handshakeServerAsyncHelper(\ |
- sharedKeyDB=sharedKeyDB, |
- verifierDB=verifierDB, certChain=certChain, |
- privateKey=privateKey, reqCert=reqCert, |
- sessionCache=sessionCache, settings=settings, |
- reqCAs=reqCAs, |
- tlsIntolerant=tlsIntolerant, |
- signedCertTimestamps=signedCertTimestamps, |
- fallbackSCSV=fallbackSCSV, ocspResponse=ocspResponse) |
- |
- for result in self._handshakeWrapperAsync(handshaker, checker): |
- yield result |
- |
- |
- def _handshakeServerAsyncHelper(self, sharedKeyDB, verifierDB, |
- certChain, privateKey, reqCert, |
- sessionCache, settings, reqCAs, |
- tlsIntolerant, signedCertTimestamps, |
- fallbackSCSV, ocspResponse): |
- |
- self._handshakeStart(client=False) |
- |
- if (not sharedKeyDB) and (not verifierDB) and (not certChain): |
- raise ValueError("Caller passed no authentication credentials") |
- if certChain and not privateKey: |
- raise ValueError("Caller passed a certChain but no privateKey") |
- if privateKey and not certChain: |
- raise ValueError("Caller passed a privateKey but no certChain") |
- if reqCAs and not reqCert: |
- raise ValueError("Caller passed reqCAs but not reqCert") |
- if signedCertTimestamps and not certChain: |
- raise ValueError("Caller passed signedCertTimestamps but no " |
- "certChain") |
- |
- if not settings: |
- settings = HandshakeSettings() |
- settings = settings._filter() |
- |
- #Initialize acceptable cipher suites |
- cipherSuites = [] |
- if verifierDB: |
- if certChain: |
- cipherSuites += \ |
- CipherSuite.getSrpRsaSuites(settings.cipherNames) |
- cipherSuites += CipherSuite.getSrpSuites(settings.cipherNames) |
- if sharedKeyDB or certChain: |
- cipherSuites += CipherSuite.getRsaSuites(settings.cipherNames) |
- |
- #Initialize acceptable certificate type |
- certificateType = None |
- if certChain: |
- try: |
- import cryptoIDlib.CertChain |
- if isinstance(certChain, cryptoIDlib.CertChain.CertChain): |
- certificateType = CertificateType.cryptoID |
- except ImportError: |
- pass |
- if isinstance(certChain, X509CertChain): |
- certificateType = CertificateType.x509 |
- if certificateType == None: |
- raise ValueError("Unrecognized certificate type") |
- |
- #Initialize locals |
- clientCertChain = None |
- serverCertChain = None #We may set certChain to this later |
- postFinishedError = None |
- doingChannelID = False |
- |
- #Tentatively set version to most-desirable version, so if an error |
- #occurs parsing the ClientHello, this is what we'll use for the |
- #error alert |
- self.version = settings.maxVersion |
- |
- #Get ClientHello |
- for result in self._getMsg(ContentType.handshake, |
- HandshakeType.client_hello): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- clientHello = result |
- |
- #If client's version is too low, reject it |
- if clientHello.client_version < settings.minVersion: |
- self.version = settings.minVersion |
- for result in self._sendError(\ |
- AlertDescription.protocol_version, |
- "Too old version: %s" % str(clientHello.client_version)): |
- yield result |
- |
- #If tlsIntolerant is nonzero, reject certain TLS versions. |
- #1: reject all TLS versions. |
- #2: reject TLS 1.1 or higher. |
- #3: reject TLS 1.2 or higher. |
- if (tlsIntolerant == 1 and clientHello.client_version > (3, 0) or |
- tlsIntolerant == 2 and clientHello.client_version > (3, 1) or |
- tlsIntolerant == 3 and clientHello.client_version > (3, 2)): |
- for result in self._sendError(\ |
- AlertDescription.handshake_failure): |
- yield result |
- |
- #If client's version is too high, propose my highest version |
- if clientHello.client_version > settings.maxVersion: |
- self.version = settings.maxVersion |
- else: |
- #Set the version to the client's version |
- self.version = clientHello.client_version |
- if (fallbackSCSV and |
- clientHello.client_version < settings.maxVersion): |
- for cipherSuite in clientHello.cipher_suites: |
- if cipherSuite == 0x5600: |
- for result in self._sendError(\ |
- AlertDescription.inappropriate_fallback): |
- yield result |
- |
- #Get the client nonce; create server nonce |
- clientRandom = clientHello.random |
- serverRandom = getRandomBytes(32) |
- |
- #Calculate the first cipher suite intersection. |
- #This is the 'privileged' ciphersuite. We'll use it if we're |
- #doing a shared-key resumption or a new negotiation. In fact, |
- #the only time we won't use it is if we're resuming a non-sharedkey |
- #session, in which case we use the ciphersuite from the session. |
- # |
- #Given the current ciphersuite ordering, this means we prefer SRP |
- #over non-SRP. |
- for cipherSuite in cipherSuites: |
- if cipherSuite in clientHello.cipher_suites: |
- break |
- else: |
- for result in self._sendError(\ |
- AlertDescription.handshake_failure): |
- yield result |
- |
- #If resumption was requested... |
- if clientHello.session_id and (sharedKeyDB or sessionCache): |
- session = None |
- |
- #Check in the sharedKeys container |
- if sharedKeyDB and len(clientHello.session_id)==16: |
- try: |
- #Trim off zero padding, if any |
- for x in range(16): |
- if clientHello.session_id[x]==0: |
- break |
- self.allegedSharedKeyUsername = bytesToString(\ |
- clientHello.session_id[:x]) |
- session = sharedKeyDB[self.allegedSharedKeyUsername] |
- if not session.sharedKey: |
- raise AssertionError() |
- #use privileged ciphersuite |
- session.cipherSuite = cipherSuite |
- except KeyError: |
- pass |
- |
- #Then check in the session cache |
- if sessionCache and not session: |
- try: |
- session = sessionCache[bytesToString(\ |
- clientHello.session_id)] |
- if session.sharedKey: |
- raise AssertionError() |
- if not session.resumable: |
- raise AssertionError() |
- #Check for consistency with ClientHello |
- if session.cipherSuite not in cipherSuites: |
- for result in self._sendError(\ |
- AlertDescription.handshake_failure): |
- yield result |
- if session.cipherSuite not in clientHello.cipher_suites: |
- for result in self._sendError(\ |
- AlertDescription.handshake_failure): |
- yield result |
- if clientHello.srp_username: |
- if clientHello.srp_username != session.srpUsername: |
- for result in self._sendError(\ |
- AlertDescription.handshake_failure): |
- yield result |
- except KeyError: |
- pass |
- |
- #If a session is found.. |
- if session: |
- #Set the session |
- self.session = session |
- |
- #Send ServerHello |
- serverHello = ServerHello() |
- serverHello.create(self.version, serverRandom, |
- session.sessionID, session.cipherSuite, |
- certificateType) |
- serverHello.channel_id = clientHello.channel_id |
- doingChannelID = clientHello.channel_id |
- for result in self._sendMsg(serverHello): |
- yield result |
- |
- #From here on, the client's messages must have the right version |
- self._versionCheck = True |
- |
- #Calculate pending connection states |
- self._calcPendingStates(clientRandom, serverRandom, |
- settings.cipherImplementations) |
- |
- #Exchange ChangeCipherSpec and Finished messages |
- for result in self._sendFinished(): |
- yield result |
- for result in self._getChangeCipherSpec(): |
- yield result |
- if doingChannelID: |
- for result in self._getEncryptedExtensions(): |
- yield result |
- for result in self._getFinished(): |
- yield result |
- |
- #Mark the connection as open |
- self._handshakeDone(resumed=True) |
- return |
- |
- |
- #If not a resumption... |
- |
- #TRICKY: we might have chosen an RSA suite that was only deemed |
- #acceptable because of the shared-key resumption. If the shared- |
- #key resumption failed, because the identifier wasn't recognized, |
- #we might fall through to here, where we have an RSA suite |
- #chosen, but no certificate. |
- if cipherSuite in CipherSuite.rsaSuites and not certChain: |
- for result in self._sendError(\ |
- AlertDescription.handshake_failure): |
- yield result |
- |
- #If an RSA suite is chosen, check for certificate type intersection |
- #(We do this check down here because if the mismatch occurs but the |
- # client is using a shared-key session, it's okay) |
- if cipherSuite in CipherSuite.rsaSuites + \ |
- CipherSuite.srpRsaSuites: |
- if certificateType not in clientHello.certificate_types: |
- for result in self._sendError(\ |
- AlertDescription.handshake_failure, |
- "the client doesn't support my certificate type"): |
- yield result |
- |
- #Move certChain -> serverCertChain, now that we're using it |
- serverCertChain = certChain |
- |
- |
- #Create sessionID |
- if sessionCache: |
- sessionID = getRandomBytes(32) |
- else: |
- sessionID = createByteArraySequence([]) |
- |
- #If we've selected an SRP suite, exchange keys and calculate |
- #premaster secret: |
- if cipherSuite in CipherSuite.srpSuites + CipherSuite.srpRsaSuites: |
- |
- #If there's no SRP username... |
- if not clientHello.srp_username: |
- |
- #Ask the client to re-send ClientHello with one |
- for result in self._sendMsg(Alert().create(\ |
- AlertDescription.missing_srp_username, |
- AlertLevel.warning)): |
- yield result |
- |
- #Get ClientHello |
- for result in self._getMsg(ContentType.handshake, |
- HandshakeType.client_hello): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- clientHello = result |
- |
- #Check ClientHello |
- #If client's version is too low, reject it (COPIED CODE; BAD!) |
- if clientHello.client_version < settings.minVersion: |
- self.version = settings.minVersion |
- for result in self._sendError(\ |
- AlertDescription.protocol_version, |
- "Too old version: %s" % str(clientHello.client_version)): |
- yield result |
- |
- #If client's version is too high, propose my highest version |
- elif clientHello.client_version > settings.maxVersion: |
- self.version = settings.maxVersion |
- |
- else: |
- #Set the version to the client's version |
- self.version = clientHello.client_version |
- |
- #Recalculate the privileged cipher suite, making sure to |
- #pick an SRP suite |
- cipherSuites = [c for c in cipherSuites if c in \ |
- CipherSuite.srpSuites + \ |
- CipherSuite.srpRsaSuites] |
- for cipherSuite in cipherSuites: |
- if cipherSuite in clientHello.cipher_suites: |
- break |
- else: |
- for result in self._sendError(\ |
- AlertDescription.handshake_failure): |
- yield result |
- |
- #Get the client nonce; create server nonce |
- clientRandom = clientHello.random |
- serverRandom = getRandomBytes(32) |
- |
- #The username better be there, this time |
- if not clientHello.srp_username: |
- for result in self._sendError(\ |
- AlertDescription.illegal_parameter, |
- "Client resent a hello, but without the SRP"\ |
- " username"): |
- yield result |
- |
- |
- #Get username |
- self.allegedSrpUsername = clientHello.srp_username |
- |
- #Get parameters from username |
- try: |
- entry = verifierDB[self.allegedSrpUsername] |
- except KeyError: |
- for result in self._sendError(\ |
- AlertDescription.unknown_srp_username): |
- yield result |
- (N, g, s, v) = entry |
- |
- #Calculate server's ephemeral DH values (b, B) |
- b = bytesToNumber(getRandomBytes(32)) |
- k = makeK(N, g) |
- B = (powMod(g, b, N) + (k*v)) % N |
- |
- #Create ServerKeyExchange, signing it if necessary |
- serverKeyExchange = ServerKeyExchange(cipherSuite) |
- serverKeyExchange.createSRP(N, g, stringToBytes(s), B) |
- if cipherSuite in CipherSuite.srpRsaSuites: |
- hashBytes = serverKeyExchange.hash(clientRandom, |
- serverRandom) |
- serverKeyExchange.signature = privateKey.sign(hashBytes) |
- |
- #Send ServerHello[, Certificate], ServerKeyExchange, |
- #ServerHelloDone |
- msgs = [] |
- serverHello = ServerHello() |
- serverHello.create(self.version, serverRandom, sessionID, |
- cipherSuite, certificateType) |
- msgs.append(serverHello) |
- if cipherSuite in CipherSuite.srpRsaSuites: |
- certificateMsg = Certificate(certificateType) |
- certificateMsg.create(serverCertChain) |
- msgs.append(certificateMsg) |
- msgs.append(serverKeyExchange) |
- msgs.append(ServerHelloDone()) |
- for result in self._sendMsgs(msgs): |
- yield result |
- |
- #From here on, the client's messages must have the right version |
- self._versionCheck = True |
- |
- #Get and check ClientKeyExchange |
- for result in self._getMsg(ContentType.handshake, |
- HandshakeType.client_key_exchange, |
- cipherSuite): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- clientKeyExchange = result |
- A = clientKeyExchange.srp_A |
- if A % N == 0: |
- postFinishedError = (AlertDescription.illegal_parameter, |
- "Suspicious A value") |
- #Calculate u |
- u = makeU(N, A, B) |
- |
- #Calculate premaster secret |
- S = powMod((A * powMod(v,u,N)) % N, b, N) |
- premasterSecret = numberToBytes(S) |
- |
- |
- #If we've selected an RSA suite, exchange keys and calculate |
- #premaster secret: |
- elif cipherSuite in CipherSuite.rsaSuites: |
- |
- #Send ServerHello, Certificate[, CertificateRequest], |
- #ServerHelloDone |
- msgs = [] |
- serverHello = ServerHello().create( |
- self.version, serverRandom, |
- sessionID, cipherSuite, certificateType) |
- serverHello.channel_id = clientHello.channel_id |
- if clientHello.support_signed_cert_timestamps: |
- serverHello.signed_cert_timestamps = signedCertTimestamps |
- serverHello.status_request = (clientHello.status_request and |
- ocspResponse) |
- doingChannelID = clientHello.channel_id |
- msgs.append(serverHello) |
- msgs.append(Certificate(certificateType).create(serverCertChain)) |
- if serverHello.status_request: |
- msgs.append(CertificateStatus().create(ocspResponse)) |
- if reqCert and reqCAs: |
- msgs.append(CertificateRequest().create([], reqCAs)) |
- elif reqCert: |
- msgs.append(CertificateRequest()) |
- msgs.append(ServerHelloDone()) |
- for result in self._sendMsgs(msgs): |
- yield result |
- |
- #From here on, the client's messages must have the right version |
- self._versionCheck = True |
- |
- #Get [Certificate,] (if was requested) |
- if reqCert: |
- if self.version == (3,0): |
- for result in self._getMsg((ContentType.handshake, |
- ContentType.alert), |
- HandshakeType.certificate, |
- certificateType): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- msg = result |
- |
- if isinstance(msg, Alert): |
- #If it's not a no_certificate alert, re-raise |
- alert = msg |
- if alert.description != \ |
- AlertDescription.no_certificate: |
- self._shutdown(False) |
- raise TLSRemoteAlert(alert) |
- elif isinstance(msg, Certificate): |
- clientCertificate = msg |
- if clientCertificate.certChain and \ |
- clientCertificate.certChain.getNumCerts()!=0: |
- clientCertChain = clientCertificate.certChain |
- else: |
- raise AssertionError() |
- elif self.version in ((3,1), (3,2)): |
- for result in self._getMsg(ContentType.handshake, |
- HandshakeType.certificate, |
- certificateType): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- clientCertificate = result |
- if clientCertificate.certChain and \ |
- clientCertificate.certChain.getNumCerts()!=0: |
- clientCertChain = clientCertificate.certChain |
- else: |
- raise AssertionError() |
- |
- #Get ClientKeyExchange |
- for result in self._getMsg(ContentType.handshake, |
- HandshakeType.client_key_exchange, |
- cipherSuite): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- clientKeyExchange = result |
- |
- #Decrypt ClientKeyExchange |
- premasterSecret = privateKey.decrypt(\ |
- clientKeyExchange.encryptedPreMasterSecret) |
- |
- randomPreMasterSecret = getRandomBytes(48) |
- versionCheck = (premasterSecret[0], premasterSecret[1]) |
- if not premasterSecret: |
- premasterSecret = randomPreMasterSecret |
- elif len(premasterSecret)!=48: |
- premasterSecret = randomPreMasterSecret |
- elif versionCheck != clientHello.client_version: |
- if versionCheck != self.version: #Tolerate buggy IE clients |
- premasterSecret = randomPreMasterSecret |
- |
- #Get and check CertificateVerify, if relevant |
- if clientCertChain: |
- if self.version == (3,0): |
- #Create a temporary session object, just for the purpose |
- #of checking the CertificateVerify |
- session = Session() |
- session._calcMasterSecret(self.version, premasterSecret, |
- clientRandom, serverRandom) |
- verifyBytes = self._calcSSLHandshakeHash(\ |
- session.masterSecret, "") |
- elif self.version in ((3,1), (3,2)): |
- verifyBytes = stringToBytes(self._handshake_md5.digest() +\ |
- self._handshake_sha.digest()) |
- for result in self._getMsg(ContentType.handshake, |
- HandshakeType.certificate_verify): |
- if result in (0,1): |
- yield result |
- else: |
- break |
- certificateVerify = result |
- publicKey = clientCertChain.getEndEntityPublicKey() |
- if len(publicKey) < settings.minKeySize: |
- postFinishedError = (AlertDescription.handshake_failure, |
- "Client's public key too small: %d" % len(publicKey)) |
- if len(publicKey) > settings.maxKeySize: |
- postFinishedError = (AlertDescription.handshake_failure, |
- "Client's public key too large: %d" % len(publicKey)) |
- |
- if not publicKey.verify(certificateVerify.signature, |
- verifyBytes): |
- postFinishedError = (AlertDescription.decrypt_error, |
- "Signature failed to verify") |
- |
- |
- #Create the session object |
- self.session = Session() |
- self.session._calcMasterSecret(self.version, premasterSecret, |
- clientRandom, serverRandom) |
- self.session.sessionID = sessionID |
- self.session.cipherSuite = cipherSuite |
- self.session.srpUsername = self.allegedSrpUsername |
- self.session.clientCertChain = clientCertChain |
- self.session.serverCertChain = serverCertChain |
- |
- #Calculate pending connection states |
- self._calcPendingStates(clientRandom, serverRandom, |
- settings.cipherImplementations) |
- |
- #Exchange ChangeCipherSpec and Finished messages |
- for result in self._getChangeCipherSpec(): |
- yield result |
- if doingChannelID: |
- for result in self._getEncryptedExtensions(): |
- yield result |
- for result in self._getFinished(): |
- yield result |
- |
- #If we were holding a post-finished error until receiving the client |
- #finished message, send it now. We delay the call until this point |
- #because calling sendError() throws an exception, and our caller might |
- #shut down the socket upon receiving the exception. If he did, and the |
- #client was still sending its ChangeCipherSpec or Finished messages, it |
- #would cause a socket error on the client side. This is a lot of |
- #consideration to show to misbehaving clients, but this would also |
- #cause problems with fault-testing. |
- if postFinishedError: |
- for result in self._sendError(*postFinishedError): |
- yield result |
- |
- for result in self._sendFinished(): |
- yield result |
- |
- #Add the session object to the session cache |
- if sessionCache and sessionID: |
- sessionCache[bytesToString(sessionID)] = self.session |
- |
- #Mark the connection as open |
- self.session._setResumable(True) |
- self._handshakeDone(resumed=False) |
- |
- |
- def _handshakeWrapperAsync(self, handshaker, checker): |
- if not self.fault: |
- try: |
- for result in handshaker: |
- yield result |
- if checker: |
- try: |
- checker(self) |
- except TLSAuthenticationError: |
- alert = Alert().create(AlertDescription.close_notify, |
- AlertLevel.fatal) |
- for result in self._sendMsg(alert): |
- yield result |
- raise |
- except: |
- self._shutdown(False) |
- raise |
- else: |
- try: |
- for result in handshaker: |
- yield result |
- if checker: |
- try: |
- checker(self) |
- except TLSAuthenticationError: |
- alert = Alert().create(AlertDescription.close_notify, |
- AlertLevel.fatal) |
- for result in self._sendMsg(alert): |
- yield result |
- raise |
- except socket.error, e: |
- raise TLSFaultError("socket error!") |
- except TLSAbruptCloseError, e: |
- raise TLSFaultError("abrupt close error!") |
- except TLSAlert, alert: |
- if alert.description not in Fault.faultAlerts[self.fault]: |
- raise TLSFaultError(str(alert)) |
- else: |
- pass |
- except: |
- self._shutdown(False) |
- raise |
- else: |
- raise TLSFaultError("No error!") |
- |
- |
- def _getKeyFromChain(self, certificate, settings): |
- #Get and check cert chain from the Certificate message |
- certChain = certificate.certChain |
- if not certChain or certChain.getNumCerts() == 0: |
- for result in self._sendError(AlertDescription.illegal_parameter, |
- "Other party sent a Certificate message without "\ |
- "certificates"): |
- yield result |
- |
- #Get and check public key from the cert chain |
- publicKey = certChain.getEndEntityPublicKey() |
- if len(publicKey) < settings.minKeySize: |
- for result in self._sendError(AlertDescription.handshake_failure, |
- "Other party's public key too small: %d" % len(publicKey)): |
- yield result |
- if len(publicKey) > settings.maxKeySize: |
- for result in self._sendError(AlertDescription.handshake_failure, |
- "Other party's public key too large: %d" % len(publicKey)): |
- yield result |
- |
- yield publicKey, certChain |