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

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

Issue 210323002: Update tlslite to 0.4.6. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Executable bit and --similarity=80 Created 6 years, 8 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/sharedkeydb.py ('k') | third_party/tlslite/tlslite/tlsrecordlayer.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/tlslite/tlslite/tlsconnection.py
diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
index 90449afe13faf78390ad67acfbb0848f68147f8b..20cd85bc90f31b456ec45c5d23a746123b962346 100644
--- a/third_party/tlslite/tlslite/tlsconnection.py
+++ b/third_party/tlslite/tlslite/tlsconnection.py
@@ -1,18 +1,27 @@
+# Authors:
+# Trevor Perrin
+# Google - added reqCAs parameter
+# Google (adapted by Sam Rushing and Marcelo Fernandez) - NPN support
+# Dimitris Moraitis - Anon ciphersuites
+# Martin von Loewis - python 3 port
+#
+# See the LICENSE file for legal information regarding use of this file.
+
"""
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
+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
+from .utils.tackwrapper import *
class TLSConnection(TLSRecordLayer):
@@ -36,11 +45,9 @@ class TLSConnection(TLSRecordLayer):
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}).
+ L{tlslite.integration.tlsasyncdispatchermixin.TLSAsyncDispatcherMixIn}).
"""
-
def __init__(self, sock):
"""Create a new TLSConnection instance.
@@ -52,23 +59,18 @@ class TLSConnection(TLSRecordLayer):
"""
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.
+ #*********************************************************
+ # Client Handshake Functions
+ #*********************************************************
- 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.
+ def handshakeClientAnonymous(self, session=None, settings=None,
+ checker=None, serverName="",
+ async=False):
+ """Perform an anonymous handshake in the role of client.
+ This function performs an SSL or TLS handshake using an
+ anonymous Diffie Hellman ciphersuite.
+
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.
@@ -79,17 +81,10 @@ class TLSConnection(TLSRecordLayer):
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.
+ @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
@@ -100,6 +95,9 @@ class TLSConnection(TLSRecordLayer):
@param checker: A Checker instance. This instance will be
invoked to examine the other party's authentication
credentials, if the handshake completes succesfully.
+
+ @type serverName: string
+ @param serverName: The ServerNameIndication TLS Extension.
@type async: bool
@param async: If False, this function will block until the
@@ -120,35 +118,28 @@ class TLSConnection(TLSRecordLayer):
@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)
+ handshaker = self._handshakeClientAsync(anonParams=(True),
+ session=session,
+ settings=settings,
+ checker=checker,
+ serverName=serverName)
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.
+ def handshakeClientSRP(self, username, password, session=None,
+ settings=None, checker=None,
+ reqTack=True, serverName="",
+ async=False):
+ """Perform an SRP handshake in the role of client.
- 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 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.
If the function completes without raising an exception, the
TLS connection will be open and available for data transfer.
@@ -156,30 +147,35 @@ class TLSConnection(TLSRecordLayer):
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 username: str
+ @param username: The SRP username.
- @type privateKey: L{tlslite.utils.RSAKey.RSAKey}
- @param privateKey: The private key to be used if the server
- requests client authentication.
+ @type password: str
+ @param password: The SRP password.
- @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 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}
+ @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}
+ @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 reqTack: bool
+ @param reqTack: Whether or not to send a "tack" TLS Extension,
+ requesting the server return a TackExtension if it has one.
+
+ @type serverName: string
+ @param serverName: The ServerNameIndication TLS Extension.
+
@type async: bool
@param async: If False, this function will block until the
handshake is completed. If True, this function will return a
@@ -199,68 +195,80 @@ class TLSConnection(TLSRecordLayer):
@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)
+ handshaker = self._handshakeClientAsync(srpParams=(username, password),
+ session=session, settings=settings, checker=checker,
+ reqTack=reqTack, serverName=serverName)
+ # The handshaker is a Python Generator which executes the handshake.
+ # It allows the handshake to be run in a "piecewise", asynchronous
+ # fashion, returning 1 when it is waiting to able to write, 0 when
+ # it is waiting to read.
+ #
+ # If 'async' is True, the generator is returned to the caller,
+ # otherwise it is executed to completion here.
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.
+ def handshakeClientCert(self, certChain=None, privateKey=None,
+ session=None, settings=None, checker=None,
+ nextProtos=None, reqTack=True, serverName="",
+ 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 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.
- 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
+ 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.
- 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 certChain: L{tlslite.x509certchain.X509CertChain}
+ @param certChain: The certificate chain to be used if the
+ server requests client authentication.
- @type certCallback: callable
- @param certCallback: The callback to be used if the server
- requests client certificate 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}
+ @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}
+ @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}
+ @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 nextProtos: list of strings.
+ @param nextProtos: A list of upper layer protocols ordered by
+ preference, to use in the Next-Protocol Negotiation Extension.
+
+ @type reqTack: bool
+ @param reqTack: Whether or not to send a "tack" TLS Extension,
+ requesting the server return a TackExtension if it has one.
+
+ @type serverName: string
+ @param serverName: The ServerNameIndication TLS Extension.
@type async: bool
@param async: If False, this function will block until the
@@ -281,276 +289,261 @@ class TLSConnection(TLSRecordLayer):
@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)
+ handshaker = self._handshakeClientAsync(certParams=(certChain,
+ privateKey), session=session, settings=settings,
+ checker=checker, serverName=serverName,
+ nextProtos=nextProtos, reqTack=reqTack)
+ # The handshaker is a Python Generator which executes the handshake.
+ # It allows the handshake to be run in a "piecewise", asynchronous
+ # fashion, returning 1 when it is waiting to able to write, 0 when
+ # it is waiting to read.
+ #
+ # If 'async' is True, the generator is returned to the caller,
+ # otherwise it is executed to completion here.
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=(),
+ def _handshakeClientAsync(self, srpParams=(), certParams=(), anonParams=(),
session=None, settings=None, checker=None,
- recursive=False):
+ nextProtos=None, serverName="", reqTack=True):
handshaker = self._handshakeClientAsyncHelper(srpParams=srpParams,
- certParams=certParams, unknownParams=unknownParams,
- sharedKeyParams=sharedKeyParams, session=session,
- settings=settings, recursive=recursive)
+ certParams=certParams,
+ anonParams=anonParams,
+ session=session,
+ settings=settings,
+ serverName=serverName,
+ nextProtos=nextProtos,
+ reqTack=reqTack)
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)
+ def _handshakeClientAsyncHelper(self, srpParams, certParams, anonParams,
+ session, settings, serverName, nextProtos, reqTack):
+
+ 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
+ srpUsername = None # srpParams[0]
+ password = None # srpParams[1]
+ clientCertChain = None # certParams[0]
+ privateKey = None # certParams[1]
+ # Allow only one of (srpParams, certParams, anonParams)
if srpParams:
+ assert(not certParams)
+ assert(not anonParams)
srpUsername, password = srpParams
- elif certParams:
+ if certParams:
+ assert(not srpParams)
+ assert(not anonParams)
clientCertChain, privateKey = certParams
- elif unknownParams:
- srpCallback, certCallback = unknownParams
- elif sharedKeyParams:
- session = Session()._createSharedKey(*sharedKeyParams)
-
- if not settings:
- settings = HandshakeSettings()
- settings = settings._filter()
+ if anonParams:
+ assert(not srpParams)
+ assert(not certParams)
#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 reqTack:
+ if not tackpyLoaded:
+ reqTack = False
+ if not settings or not settings.useExperimentalTackExtension:
+ reqTack = False
+ if nextProtos is not None:
+ if len(nextProtos) == 0:
+ raise ValueError("Caller passed no nextProtos")
+
+ # Validates the settings and filters out any unsupported ciphers
+ # or crypto libraries that were requested
+ if not settings:
+ settings = HandshakeSettings()
+ settings = settings._filter()
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:
+ if not isinstance(clientCertChain, X509CertChain):
raise ValueError("Unrecognized certificate type")
-
-
+ if "x509" not in settings.certificateTypes:
+ raise ValueError("Client certificate doesn't match "\
+ "Handshake Settings")
+
if session:
+ # session.valid() ensures session is resumable and has
+ # non-empty sessionID
if not session.valid():
session = None #ignore non-resumable sessions...
- elif session.resumable and \
- (session.srpUsername != srpUsername):
- raise ValueError("Session username doesn't match")
+ elif session.resumable:
+ if session.srpUsername != srpUsername:
+ raise ValueError("Session username doesn't match")
+ if session.serverName != serverName:
+ raise ValueError("Session servername 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)
+ #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
+
+ # OK Start sending messages!
+ # *****************************
+
+ # Send the ClientHello.
+ for result in self._clientSendClientHello(settings, session,
+ srpUsername, srpParams, certParams,
+ anonParams, serverName, nextProtos,
+ reqTack):
+ if result in (0,1): yield result
+ else: break
+ clientHello = result
+
+ #Get the ServerHello.
+ for result in self._clientGetServerHello(settings, clientHello):
+ if result in (0,1): yield result
+ else: break
+ serverHello = result
+ cipherSuite = serverHello.cipher_suite
+
+ # Choose a matching Next Protocol from server list against ours
+ # (string or None)
+ nextProto = self._clientSelectNextProto(nextProtos, serverHello)
+
+ #If the server elected to resume the session, it is handled here.
+ for result in self._clientResume(session, serverHello,
+ clientHello.random,
+ settings.cipherImplementations,
+ nextProto):
+ if result in (0,1): yield result
+ else: break
+ if result == "resumed_and_finished":
+ self._handshakeDone(resumed=True)
+ return
+
+ #If the server selected an SRP ciphersuite, the client finishes
+ #reading the post-ServerHello messages, then derives a
+ #premasterSecret and sends a corresponding ClientKeyExchange.
+ if cipherSuite in CipherSuite.srpAllSuites:
+ for result in self._clientSRPKeyExchange(\
+ settings, cipherSuite, serverHello.certificate_type,
+ srpUsername, password,
+ clientHello.random, serverHello.random,
+ serverHello.tackExt):
+ if result in (0,1): yield result
+ else: break
+ (premasterSecret, serverCertChain, tackExt) = result
+
+ #If the server selected an anonymous ciphersuite, the client
+ #finishes reading the post-ServerHello messages.
+ elif cipherSuite in CipherSuite.anonSuites:
+ for result in self._clientAnonKeyExchange(settings, cipherSuite,
+ clientHello.random, serverHello.random):
+ if result in (0,1): yield result
+ else: break
+ (premasterSecret, serverCertChain, tackExt) = result
+
+ #If the server selected a certificate-based RSA ciphersuite,
+ #the client finishes reading the post-ServerHello messages. If
+ #a CertificateRequest message was sent, the client responds with
+ #a Certificate message containing its certificate chain (if any),
+ #and also produces a CertificateVerify message that signs the
+ #ClientKeyExchange.
+ else:
+ for result in self._clientRSAKeyExchange(settings, cipherSuite,
+ clientCertChain, privateKey,
+ serverHello.certificate_type,
+ clientHello.random, serverHello.random,
+ serverHello.tackExt):
+ if result in (0,1): yield result
+ else: break
+ (premasterSecret, serverCertChain, clientCertChain,
+ tackExt) = result
+
+ #After having previously sent a ClientKeyExchange, the client now
+ #initiates an exchange of Finished messages.
+ for result in self._clientFinished(premasterSecret,
+ clientHello.random,
+ serverHello.random,
+ cipherSuite, settings.cipherImplementations,
+ nextProto):
+ if result in (0,1): yield result
+ else: break
+ masterSecret = result
+
+ # Create the session object which is used for resumptions
+ self.session = Session()
+ self.session.create(masterSecret, serverHello.session_id, cipherSuite,
+ srpUsername, clientCertChain, serverCertChain,
+ tackExt, serverHello.tackExt!=None, serverName)
+ self._handshakeDone(resumed=False)
+
+ def _clientSendClientHello(self, settings, session, srpUsername,
+ srpParams, certParams, anonParams,
+ serverName, nextProtos, reqTack):
#Initialize acceptable ciphersuites
- cipherSuites = []
+ cipherSuites = [CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
if srpParams:
- cipherSuites += CipherSuite.getSrpRsaSuites(settings.cipherNames)
- cipherSuites += CipherSuite.getSrpSuites(settings.cipherNames)
+ cipherSuites += CipherSuite.getSrpAllSuites(settings)
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)
+ cipherSuites += CipherSuite.getCertSuites(settings)
+ elif anonParams:
+ cipherSuites += CipherSuite.getAnonSuites(settings)
else:
- cipherSuites += CipherSuite.getRsaSuites(settings.cipherNames)
+ assert(False)
#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
+ if session and session.sessionID:
+ #If it's resumable, then its
#ciphersuite must be one of the acceptable ciphersuites
- if (not sharedKeyParams) and \
- session.cipherSuite not in cipherSuites:
+ if session.cipherSuite not in cipherSuites:
raise ValueError("Session's cipher suite not consistent "\
"with parameters")
else:
clientHello = ClientHello()
- clientHello.create(settings.maxVersion, clientRandom,
+ clientHello.create(settings.maxVersion, getRandomBytes(32),
session.sessionID, cipherSuites,
- certificateTypes, session.srpUsername)
+ certificateTypes,
+ session.srpUsername,
+ reqTack, nextProtos is not None,
+ session.serverName)
#Or send ClientHello (without)
else:
clientHello = ClientHello()
- clientHello.create(settings.maxVersion, clientRandom,
- createByteArraySequence([]), cipherSuites,
- certificateTypes, srpUsername)
+ clientHello.create(settings.maxVersion, getRandomBytes(32),
+ bytearray(0), cipherSuites,
+ certificateTypes,
+ srpUsername,
+ reqTack, nextProtos is not None,
+ serverName)
for result in self._sendMsg(clientHello):
yield result
+ yield clientHello
- #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
+ def _clientGetServerHello(self, settings, clientHello):
+ for result in self._getMsg(ContentType.handshake,
+ HandshakeType.server_hello):
+ if result in (0,1): yield result
+ else: break
+ serverHello = result
#Get the server version. Do this before anything else, so any
#error alerts will use the server's version
@@ -570,12 +563,12 @@ class TLSConnection(TLSRecordLayer):
AlertDescription.protocol_version,
"Too new version: %s" % str(serverHello.server_version)):
yield result
- if serverHello.cipher_suite not in cipherSuites:
+ if serverHello.cipher_suite not in clientHello.cipher_suites:
for result in self._sendError(\
AlertDescription.illegal_parameter,
"Server responded with incorrect ciphersuite"):
yield result
- if serverHello.certificate_type not in certificateTypes:
+ if serverHello.certificate_type not in clientHello.certificate_types:
for result in self._sendError(\
AlertDescription.illegal_parameter,
"Server responded with incorrect certificate type"):
@@ -585,365 +578,401 @@ class TLSConnection(TLSRecordLayer):
AlertDescription.illegal_parameter,
"Server responded with incorrect compression method"):
yield result
+ if serverHello.tackExt:
+ if not clientHello.tack:
+ for result in self._sendError(\
+ AlertDescription.illegal_parameter,
+ "Server responded with unrequested Tack Extension"):
+ yield result
+ if serverHello.next_protos and not clientHello.supports_npn:
+ for result in self._sendError(\
+ AlertDescription.illegal_parameter,
+ "Server responded with unrequested NPN Extension"):
+ yield result
+ if not serverHello.tackExt.verifySignatures():
+ for result in self._sendError(\
+ AlertDescription.decrypt_error,
+ "TackExtension contains an invalid signature"):
+ yield result
+ yield serverHello
- #Get the server nonce
- serverRandom = serverHello.random
-
+ def _clientSelectNextProto(self, nextProtos, serverHello):
+ # nextProtos is None or non-empty list of strings
+ # serverHello.next_protos is None or possibly-empty list of strings
+ #
+ # !!! We assume the client may have specified nextProtos as a list of
+ # strings so we convert them to bytearrays (it's awkward to require
+ # the user to specify a list of bytearrays or "bytes", and in
+ # Python 2.6 bytes() is just an alias for str() anyways...
+ if nextProtos is not None and serverHello.next_protos is not None:
+ for p in nextProtos:
+ if bytearray(p) in serverHello.next_protos:
+ return bytearray(p)
+ else:
+ # If the client doesn't support any of server's protocols,
+ # or the server doesn't advertise any (next_protos == [])
+ # the client SHOULD select the first protocol it supports.
+ return bytearray(nextProtos[0])
+ return None
+
+ def _clientResume(self, session, serverHello, clientRandom,
+ cipherImplementations, nextProto):
#If the server agrees to resume
if session and session.sessionID and \
- serverHello.session_id == session.sessionID:
+ 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:
+ if serverHello.cipher_suite != session.cipherSuite:
for result in self._sendError(\
AlertDescription.illegal_parameter,\
"Server's ciphersuite doesn't match session"):
yield result
+ #Calculate pending connection states
+ self._calcPendingStates(session.cipherSuite,
+ session.masterSecret,
+ clientRandom, serverHello.random,
+ cipherImplementations)
+
+ #Exchange ChangeCipherSpec and Finished messages
+ for result in self._getFinished(session.masterSecret):
+ yield result
+ for result in self._sendFinished(session.masterSecret, nextProto):
+ yield result
+
#Set the session for this connection
self.session = session
+ yield "resumed_and_finished"
+
+ def _clientSRPKeyExchange(self, settings, cipherSuite, certificateType,
+ srpUsername, password,
+ clientRandom, serverRandom, tackExt):
+
+ #If the server chose an SRP+RSA suite...
+ if cipherSuite in CipherSuite.srpCertSuites:
+ #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
+ else:
+ serverCertificate = None
- #Calculate pending connection states
- self._calcPendingStates(clientRandom, serverRandom,
- settings.cipherImplementations)
+ for result in self._getMsg(ContentType.handshake,
+ HandshakeType.server_key_exchange, cipherSuite):
+ if result in (0,1): yield result
+ else: break
+ serverKeyExchange = result
- #Exchange ChangeCipherSpec and Finished messages
- for result in self._getChangeCipherSpec():
+ for result in self._getMsg(ContentType.handshake,
+ HandshakeType.server_hello_done):
+ if result in (0,1): yield result
+ else: break
+ serverHelloDone = result
+
+ #Calculate SRP premaster secret
+ #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.insufficient_security,
+ "Unknown group parameters"):
+ yield result
+ if numBits(N) < settings.minKeySize:
+ for result in self._sendError(\
+ AlertDescription.insufficient_security,
+ "N value is too small: %d" % numBits(N)):
yield result
- for result in self._getFinished():
+ if numBits(N) > settings.maxKeySize:
+ for result in self._sendError(\
+ AlertDescription.insufficient_security,
+ "N value is too large: %d" % numBits(N)):
yield result
- for result in self._sendFinished():
+ if B % N == 0:
+ for result in self._sendError(\
+ AlertDescription.illegal_parameter,
+ "Suspicious B value"):
yield result
- #Mark the connection as open
- self._handshakeDone(resumed=True)
+ #Check the server's signature, if server chose an
+ #SRP+RSA suite
+ serverCertChain = None
+ if cipherSuite in CipherSuite.srpCertSuites:
+ #Hash ServerKeyExchange/ServerSRPParams
+ hashBytes = serverKeyExchange.hash(clientRandom, serverRandom)
- #If server DOES NOT agree to resume
- else:
+ #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
- if sharedKeyParams:
+ # Get server's public key from the Certificate message
+ # Also validate the chain against the ServerHello's TACKext (if any)
+ # If none, and a TACK cert is present, return its TACKext
+ for result in self._clientGetKeyFromChain(serverCertificate,
+ settings, tackExt):
+ if result in (0,1): yield result
+ else: break
+ publicKey, serverCertChain, tackExt = result
+
+ #Verify signature
+ if not publicKey.verify(sigBytes, hashBytes):
for result in self._sendError(\
- AlertDescription.user_canceled,
- "Was expecting a shared-key resumption"):
+ AlertDescription.decrypt_error,
+ "Signature failed to verify"):
yield result
- #We've already validated these
- cipherSuite = serverHello.cipher_suite
- certificateType = serverHello.certificate_type
+ #Calculate client's ephemeral DH values (a, A)
+ a = bytesToNumber(getRandomBytes(32))
+ A = powMod(g, a, N)
- #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
+ #Calculate client's static DH values (x, v)
+ x = makeX(s, bytearray(srpUsername, "utf-8"),
+ bytearray(password, "utf-8"))
+ v = powMod(g, x, N)
- for result in self._getMsg(ContentType.handshake,
- HandshakeType.server_hello_done):
- if result in (0,1):
- yield result
- else:
- break
- serverHelloDone = result
+ #Calculate u
+ u = makeU(N, A, B)
- #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
+ #Calculate premaster secret
+ k = makeK(N, g)
+ S = powMod((B - (k*v)) % N, a+(u*x), N)
- for result in self._getMsg(ContentType.handshake,
- HandshakeType.server_key_exchange, cipherSuite):
- if result in (0,1):
- yield result
- else:
- break
- serverKeyExchange = result
+ if self.fault == Fault.badA:
+ A = N
+ S = 0
+
+ premasterSecret = numberToByteArray(S)
- for result in self._getMsg(ContentType.handshake,
- HandshakeType.server_hello_done):
- if result in (0,1):
- yield result
- else:
- break
- serverHelloDone = result
+ #Send ClientKeyExchange
+ for result in self._sendMsg(\
+ ClientKeyExchange(cipherSuite).createSRP(A)):
+ yield result
+ yield (premasterSecret, serverCertChain, tackExt)
+
- #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()
+ def _clientRSAKeyExchange(self, settings, cipherSuite,
+ clientCertChain, privateKey,
+ certificateType,
+ clientRandom, serverRandom,
+ tackExt):
+ #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
- #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
+ # Get CertificateRequest or ServerHelloDone
+ 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
+ # We got CertificateRequest, so this must be ServerHelloDone
+ 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
+
+ # Get server's public key from the Certificate message
+ # Also validate the chain against the ServerHello's TACKext (if any)
+ # If none, and a TACK cert is present, return its TACKext
+ for result in self._clientGetKeyFromChain(serverCertificate,
+ settings, tackExt):
+ if result in (0,1): yield result
+ else: break
+ publicKey, serverCertChain, tackExt = 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 (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:
+ 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
+ if wrongType:
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):
+ AlertDescription.handshake_failure,
+ "Client certificate is of wrong type"):
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
+ 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
+ #If client authentication was requested and we have a
+ #private key, send CertificateVerify
+ if certificateRequest and privateKey:
+ if self.version == (3,0):
+ masterSecret = calcMasterSecret(self.version,
+ premasterSecret,
+ clientRandom,
+ serverRandom)
+ verifyBytes = self._calcSSLHandshakeHash(masterSecret, b"")
+ elif self.version in ((3,1), (3,2)):
+ verifyBytes = 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
+ yield (premasterSecret, serverCertChain, clientCertChain, tackExt)
+ def _clientAnonKeyExchange(self, settings, cipherSuite, clientRandom,
+ serverRandom):
+ for result in self._getMsg(ContentType.handshake,
+ HandshakeType.server_key_exchange, cipherSuite):
+ if result in (0,1): yield result
+ else: break
+ serverKeyExchange = 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
+ for result in self._getMsg(ContentType.handshake,
+ HandshakeType.server_hello_done):
+ if result in (0,1): yield result
+ else: break
+ serverHelloDone = result
+
+ #calculate Yc
+ dh_p = serverKeyExchange.dh_p
+ dh_g = serverKeyExchange.dh_g
+ dh_Xc = bytesToNumber(getRandomBytes(32))
+ dh_Ys = serverKeyExchange.dh_Ys
+ dh_Yc = powMod(dh_g, dh_Xc, dh_p)
+
+ #Send ClientKeyExchange
+ for result in self._sendMsg(\
+ ClientKeyExchange(cipherSuite, self.version).createDH(dh_Yc)):
+ yield result
+
+ #Calculate premaster secret
+ S = powMod(dh_Ys, dh_Xc, dh_p)
+ premasterSecret = numberToByteArray(S)
+
+ yield (premasterSecret, None, None)
+
+ def _clientFinished(self, premasterSecret, clientRandom, serverRandom,
+ cipherSuite, cipherImplementations, nextProto):
+
+ masterSecret = calcMasterSecret(self.version, premasterSecret,
+ clientRandom, serverRandom)
+ self._calcPendingStates(cipherSuite, masterSecret,
+ clientRandom, serverRandom,
+ cipherImplementations)
- #Calculate pending connection states
- self._calcPendingStates(clientRandom, serverRandom,
- settings.cipherImplementations)
+ #Exchange ChangeCipherSpec and Finished messages
+ for result in self._sendFinished(masterSecret, nextProto):
+ yield result
+ for result in self._getFinished(masterSecret, nextProto=nextProto):
+ yield result
+ yield masterSecret
- #Exchange ChangeCipherSpec and Finished messages
- for result in self._sendFinished():
+ def _clientGetKeyFromChain(self, certificate, settings, tackExt=None):
+ #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
- for result in self._getChangeCipherSpec():
+
+ #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
- for result in self._getFinished():
+ 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
+
+ # If there's no TLS Extension, look for a TACK cert
+ if tackpyLoaded:
+ if not tackExt:
+ tackExt = certChain.getTackExt()
+
+ # If there's a TACK (whether via TLS or TACK Cert), check that it
+ # matches the cert chain
+ if tackExt and tackExt.tacks:
+ for tack in tackExt.tacks:
+ if not certChain.checkTack(tack):
+ for result in self._sendError(
+ AlertDescription.illegal_parameter,
+ "Other party's TACK doesn't match their public key"):
+ yield result
+
+ yield publicKey, certChain, tackExt
- #Mark the connection as open
- self.session._setResumable(True)
- self._handshakeDone(resumed=False)
+ #*********************************************************
+ # Server Handshake Functions
+ #*********************************************************
- def handshakeServer(self, sharedKeyDB=None, verifierDB=None,
+ def handshakeServer(self, verifierDB=None,
certChain=None, privateKey=None, reqCert=False,
sessionCache=None, settings=None, checker=None,
- reqCAs=None, tlsIntolerant=0,
- signedCertTimestamps=None, fallbackSCSV=False,
- ocspResponse=None):
+ reqCAs = None,
+ tacks=None, activationFlags=0,
+ nextProtos=None, anon=False,
+ tlsIntolerant=None, 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
+ perform an SRP, or certificate-based handshake. It
can also perform a combined SRP and server-certificate
handshake.
@@ -961,67 +990,62 @@ class TLSConnection(TLSRecordLayer):
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}
+ @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}
+ @type certChain: L{tlslite.x509certchain.X509CertChain}
@param certChain: The certificate chain to be used if the
client requests server certificate authentication.
- @type privateKey: L{tlslite.utils.RSAKey.RSAKey}
+ @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
+ certificate authentication; if the client chooses SRP
+ 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}
+ @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}
+ @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}
+ @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
+
+ @type reqCAs: list of L{bytearray} 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.
+ verification.
+
+ @type nextProtos: list of strings.
+ @param nextProtos: A list of upper layer protocols to expose to the
+ clients through the Next-Protocol Negotiation Extension,
+ if they support it.
+
+ @type tlsIntolerant: (int, int) or None
+ @param tlsIntolerant: If tlsIntolerant is not None, the server will
+ simulate TLS version intolerance by returning a fatal handshake_failure
+ alert to all TLS versions tlsIntolerant or higher.
@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
@@ -1044,19 +1068,27 @@ class TLSConnection(TLSRecordLayer):
@raise tlslite.errors.TLSAuthenticationError: If the checker
doesn't like the other party's authentication credentials.
"""
- for result in self.handshakeServerAsync(sharedKeyDB, verifierDB,
+ for result in self.handshakeServerAsync(verifierDB,
certChain, privateKey, reqCert, sessionCache, settings,
- checker, reqCAs, tlsIntolerant, signedCertTimestamps,
- fallbackSCSV, ocspResponse):
+ checker, reqCAs,
+ tacks=tacks, activationFlags=activationFlags,
+ nextProtos=nextProtos, anon=anon, tlsIntolerant=tlsIntolerant,
+ signedCertTimestamps=signedCertTimestamps,
+ fallbackSCSV=fallbackSCSV, ocspResponse=ocspResponse):
pass
- def handshakeServerAsync(self, sharedKeyDB=None, verifierDB=None,
+ def handshakeServerAsync(self, verifierDB=None,
certChain=None, privateKey=None, reqCert=False,
sessionCache=None, settings=None, checker=None,
- reqCAs=None, tlsIntolerant=0,
+ reqCAs=None,
+ tacks=None, activationFlags=0,
+ nextProtos=None, anon=False,
+ tlsIntolerant=None,
signedCertTimestamps=None,
- fallbackSCSV=False, ocspResponse=None):
+ fallbackSCSV=False,
+ ocspResponse=None
+ ):
"""Start a server handshake operation on the TLS connection.
This function returns a generator which behaves similarly to
@@ -1069,35 +1101,47 @@ class TLSConnection(TLSRecordLayer):
@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,
+ sessionCache=sessionCache, settings=settings,
+ reqCAs=reqCAs,
+ tacks=tacks, activationFlags=activationFlags,
+ nextProtos=nextProtos, anon=anon,
tlsIntolerant=tlsIntolerant,
signedCertTimestamps=signedCertTimestamps,
- fallbackSCSV=fallbackSCSV, ocspResponse=ocspResponse)
-
+ 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):
+ def _handshakeServerAsyncHelper(self, verifierDB,
+ certChain, privateKey, reqCert, sessionCache,
+ settings, reqCAs,
+ tacks, activationFlags,
+ nextProtos, anon,
+ tlsIntolerant, signedCertTimestamps, fallbackSCSV,
+ ocspResponse):
self._handshakeStart(client=False)
- if (not sharedKeyDB) and (not verifierDB) and (not certChain):
+ if (not verifierDB) and (not certChain) and not anon:
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")
+ raise ValueError("Caller passed reqCAs but not reqCert")
+ if certChain and not isinstance(certChain, X509CertChain):
+ raise ValueError("Unrecognized certificate type")
+ if activationFlags and not tacks:
+ raise ValueError("Nonzero activationFlags requires tacks")
+ if tacks:
+ if not tackpyLoaded:
+ raise ValueError("tackpy is not loaded")
+ if not settings or not settings.useExperimentalTackExtension:
+ raise ValueError("useExperimentalTackExtension not enabled")
if signedCertTimestamps and not certChain:
raise ValueError("Caller passed signedCertTimestamps but no "
"certChain")
@@ -1105,36 +1149,129 @@ class TLSConnection(TLSRecordLayer):
if not settings:
settings = HandshakeSettings()
settings = settings._filter()
+
+ # OK Start exchanging messages
+ # ******************************
+
+ # Handle ClientHello and resumption
+ for result in self._serverGetClientHello(settings, certChain,\
+ verifierDB, sessionCache,
+ anon, tlsIntolerant, fallbackSCSV):
+ if result in (0,1): yield result
+ elif result == None:
+ self._handshakeDone(resumed=True)
+ return # Handshake was resumed, we're done
+ else: break
+ (clientHello, cipherSuite) = result
+
+ #If not a resumption...
+
+ # Create the ServerHello message
+ if sessionCache:
+ sessionID = getRandomBytes(32)
+ else:
+ sessionID = bytearray(0)
+
+ if not clientHello.supports_npn:
+ nextProtos = None
+
+ # If not doing a certificate-based suite, discard the TACK
+ if not cipherSuite in CipherSuite.certAllSuites:
+ tacks = None
+
+ # Prepare a TACK Extension if requested
+ if clientHello.tack:
+ tackExt = TackExtension.create(tacks, activationFlags)
+ else:
+ tackExt = None
+ serverHello = ServerHello()
+ serverHello.create(self.version, getRandomBytes(32), sessionID, \
+ cipherSuite, CertificateType.x509, tackExt,
+ nextProtos)
+ serverHello.channel_id = clientHello.channel_id
+ if clientHello.support_signed_cert_timestamps:
+ serverHello.signed_cert_timestamps = signedCertTimestamps
+ if clientHello.status_request:
+ serverHello.status_request = ocspResponse
+
+ # Perform the SRP key exchange
+ clientCertChain = None
+ if cipherSuite in CipherSuite.srpAllSuites:
+ for result in self._serverSRPKeyExchange(clientHello, serverHello,
+ verifierDB, cipherSuite,
+ privateKey, certChain):
+ if result in (0,1): yield result
+ else: break
+ premasterSecret = result
+
+ # Perform the RSA key exchange
+ elif cipherSuite in CipherSuite.certSuites:
+ for result in self._serverCertKeyExchange(clientHello, serverHello,
+ certChain, privateKey,
+ reqCert, reqCAs, cipherSuite,
+ settings, ocspResponse):
+ if result in (0,1): yield result
+ else: break
+ (premasterSecret, clientCertChain) = result
+
+ # Perform anonymous Diffie Hellman key exchange
+ elif cipherSuite in CipherSuite.anonSuites:
+ for result in self._serverAnonKeyExchange(clientHello, serverHello,
+ cipherSuite, settings):
+ if result in (0,1): yield result
+ else: break
+ premasterSecret = result
+
+ else:
+ assert(False)
+
+ # Exchange Finished messages
+ for result in self._serverFinished(premasterSecret,
+ clientHello.random, serverHello.random,
+ cipherSuite, settings.cipherImplementations,
+ nextProtos, clientHello.channel_id):
+ if result in (0,1): yield result
+ else: break
+ masterSecret = result
+ #Create the session object
+ self.session = Session()
+ if cipherSuite in CipherSuite.certAllSuites:
+ serverCertChain = certChain
+ else:
+ serverCertChain = None
+ srpUsername = None
+ serverName = None
+ if clientHello.srp_username:
+ srpUsername = clientHello.srp_username.decode("utf-8")
+ if clientHello.server_name:
+ serverName = clientHello.server_name.decode("utf-8")
+ self.session.create(masterSecret, serverHello.session_id, cipherSuite,
+ srpUsername, clientCertChain, serverCertChain,
+ tackExt, serverHello.tackExt!=None, serverName)
+
+ #Add the session object to the session cache
+ if sessionCache and sessionID:
+ sessionCache[sessionID] = self.session
+
+ self._handshakeDone(resumed=False)
+
+
+ def _serverGetClientHello(self, settings, certChain, verifierDB,
+ sessionCache, anon, tlsIntolerant, fallbackSCSV):
#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
+ CipherSuite.getSrpCertSuites(settings)
+ cipherSuites += CipherSuite.getSrpSuites(settings)
+ elif certChain:
+ cipherSuites += CipherSuite.getCertSuites(settings)
+ elif anon:
+ cipherSuites += CipherSuite.getAnonSuites(settings)
+ else:
+ assert(False)
#Tentatively set version to most-desirable version, so if an error
#occurs parsing the ClientHello, this is what we'll use for the
@@ -1144,10 +1281,8 @@ class TLSConnection(TLSRecordLayer):
#Get ClientHello
for result in self._getMsg(ContentType.handshake,
HandshakeType.client_hello):
- if result in (0,1):
- yield result
- else:
- break
+ if result in (0,1): yield result
+ else: break
clientHello = result
#If client's version is too low, reject it
@@ -1158,79 +1293,36 @@ class TLSConnection(TLSRecordLayer):
"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)):
+ #If simulating TLS intolerance, reject certain TLS versions.
+ elif (tlsIntolerant is not None and
+ clientHello.client_version >= tlsIntolerant):
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:
+ elif 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)
+ #Detect if the client performed an inappropriate fallback.
+ elif fallbackSCSV and clientHello.client_version < settings.maxVersion:
+ if CipherSuite.TLS_FALLBACK_SCSV in clientHello.cipher_suites:
+ for result in self._sendError(\
+ AlertDescription.inappropriate_fallback):
+ yield result
- #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
+ #Set the version to the client's version
+ self.version = clientHello.client_version
- #If resumption was requested...
- if clientHello.session_id and (sharedKeyDB or sessionCache):
+ #If resumption was requested and we have a session cache...
+ if clientHello.session_id and 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
+ #Check in the session cache
if sessionCache and not session:
try:
- session = sessionCache[bytesToString(\
- clientHello.session_id)]
- if session.sharedKey:
- raise AssertionError()
+ session = sessionCache[clientHello.session_id]
if not session.resumable:
raise AssertionError()
#Check for consistency with ClientHello
@@ -1243,390 +1335,460 @@ class TLSConnection(TLSRecordLayer):
AlertDescription.handshake_failure):
yield result
if clientHello.srp_username:
- if clientHello.srp_username != session.srpUsername:
+ if not session.srpUsername or \
+ clientHello.srp_username != bytearray(session.srpUsername, "utf-8"):
for result in self._sendError(\
AlertDescription.handshake_failure):
yield result
+ if clientHello.server_name:
+ if not session.serverName or \
+ clientHello.server_name != bytearray(session.serverName, "utf-8"):
+ 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,
+ serverHello.create(self.version, getRandomBytes(32),
session.sessionID, session.cipherSuite,
- certificateType)
- serverHello.channel_id = clientHello.channel_id
- doingChannelID = clientHello.channel_id
+ CertificateType.x509, None, None)
for result in self._sendMsg(serverHello):
yield result
- #From here on, the client's messages must have the right version
+ #From here on, the client's messages must have right version
self._versionCheck = True
#Calculate pending connection states
- self._calcPendingStates(clientRandom, serverRandom,
- settings.cipherImplementations)
+ self._calcPendingStates(session.cipherSuite,
+ session.masterSecret,
+ clientHello.random,
+ serverHello.random,
+ settings.cipherImplementations)
#Exchange ChangeCipherSpec and Finished messages
- for result in self._sendFinished():
+ for result in self._sendFinished(session.masterSecret):
yield result
- for result in self._getChangeCipherSpec():
+ for result in self._getFinished(session.masterSecret):
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
+ #Set the session
+ self.session = session
+
+ yield None # Handshake done!
- #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:
+ #Calculate the first cipher suite intersection.
+ #This is the 'privileged' ciphersuite. We'll use it if we're
+ #doing a new negotiation. In fact,
+ #the only time we won't use it is if we're resuming a
+ #session, in which case we use the ciphersuite from the session.
+ #
+ #Use the client's preferences for now.
+ for cipherSuite in clientHello.cipher_suites:
+ if cipherSuite in cipherSuites:
+ break
+ else:
for result in self._sendError(\
- AlertDescription.handshake_failure):
+ AlertDescription.handshake_failure,
+ "No mutual ciphersuite"):
yield result
-
+ if cipherSuite in CipherSuite.srpAllSuites and \
+ not clientHello.srp_username:
+ for result in self._sendError(\
+ AlertDescription.unknown_psk_identity,
+ "Client sent a hello, but without the SRP username"):
+ 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 cipherSuite in CipherSuite.certAllSuites and CertificateType.x509 \
+ not in clientHello.certificate_types:
+ for result in self._sendError(\
+ AlertDescription.handshake_failure,
+ "the client doesn't support my certificate type"):
+ yield result
- #If we've selected an SRP suite, exchange keys and calculate
- #premaster secret:
- if cipherSuite in CipherSuite.srpSuites + CipherSuite.srpRsaSuites:
+ # If resumption was not requested, or
+ # we have no session cache, or
+ # the client's session_id was not found in cache:
+ yield (clientHello, cipherSuite)
- #If there's no SRP username...
- if not clientHello.srp_username:
+ def _serverSRPKeyExchange(self, clientHello, serverHello, verifierDB,
+ cipherSuite, privateKey, serverCertChain):
- #Ask the client to re-send ClientHello with one
- for result in self._sendMsg(Alert().create(\
- AlertDescription.missing_srp_username,
- AlertLevel.warning)):
- yield result
+ srpUsername = clientHello.srp_username.decode("utf-8")
+ self.allegedSrpUsername = srpUsername
+ #Get parameters from username
+ try:
+ entry = verifierDB[srpUsername]
+ except KeyError:
+ for result in self._sendError(\
+ AlertDescription.unknown_psk_identity):
+ 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, s, B)
+ if cipherSuite in CipherSuite.srpCertSuites:
+ hashBytes = serverKeyExchange.hash(clientHello.random,
+ serverHello.random)
+ serverKeyExchange.signature = privateKey.sign(hashBytes)
+
+ #Send ServerHello[, Certificate], ServerKeyExchange,
+ #ServerHelloDone
+ msgs = []
+ msgs.append(serverHello)
+ if cipherSuite in CipherSuite.srpCertSuites:
+ certificateMsg = Certificate(CertificateType.x509)
+ certificateMsg.create(serverCertChain)
+ msgs.append(certificateMsg)
+ msgs.append(serverKeyExchange)
+ msgs.append(ServerHelloDone())
+ for result in self._sendMsgs(msgs):
+ 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
+ #From here on, the client's messages must have the right version
+ self._versionCheck = True
- #If client's version is too high, propose my highest version
- elif clientHello.client_version > settings.maxVersion:
- self.version = settings.maxVersion
+ #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:
+ for result in self._sendError(AlertDescription.illegal_parameter,
+ "Suspicious A value"):
+ yield result
+ assert(False) # Just to ensure we don't fall through somehow
- 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
+ #Calculate u
+ u = makeU(N, A, B)
- #Get the client nonce; create server nonce
- clientRandom = clientHello.random
- serverRandom = getRandomBytes(32)
+ #Calculate premaster secret
+ S = powMod((A * powMod(v,u,N)) % N, b, N)
+ premasterSecret = numberToByteArray(S)
+
+ yield premasterSecret
- #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
+ def _serverCertKeyExchange(self, clientHello, serverHello,
+ serverCertChain, privateKey,
+ reqCert, reqCAs, cipherSuite,
+ settings, ocspResponse):
+ #Send ServerHello, Certificate[, CertificateRequest],
+ #ServerHelloDone
+ msgs = []
- #Get username
- self.allegedSrpUsername = clientHello.srp_username
+ # If we verify a client cert chain, return it
+ clientCertChain = None
- #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
+ msgs.append(serverHello)
+ msgs.append(Certificate(CertificateType.x509).create(serverCertChain))
+ if serverHello.status_request:
+ msgs.append(CertificateStatus().create(ocspResponse))
+ if reqCert and reqCAs:
+ msgs.append(CertificateRequest().create(\
+ [ClientCertificateType.rsa_sign], 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
+ #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
+ #Get [Certificate,] (if was requested)
+ if reqCert:
+ if self.version == (3,0):
+ for result in self._getMsg((ContentType.handshake,
+ ContentType.alert),
+ HandshakeType.certificate,
+ CertificateType.x509):
+ if result in (0,1): yield result
+ else: break
+ msg = 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 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.x509):
+ 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)
+
+ # On decryption failure randomize premaster secret to avoid
+ # Bleichenbacher's "million message" attack
+ 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 ClientKeyExchange
+ #Get and check CertificateVerify, if relevant
+ if clientCertChain:
+ if self.version == (3,0):
+ masterSecret = calcMasterSecret(self.version, premasterSecret,
+ clientHello.random, serverHello.random)
+ verifyBytes = self._calcSSLHandshakeHash(masterSecret, b"")
+ elif self.version in ((3,1), (3,2)):
+ verifyBytes = self._handshake_md5.digest() + \
+ self._handshake_sha.digest()
for result in self._getMsg(ContentType.handshake,
- HandshakeType.client_key_exchange,
- cipherSuite):
- if result in (0,1):
+ HandshakeType.certificate_verify):
+ if result in (0,1): yield result
+ else: break
+ certificateVerify = result
+ publicKey = clientCertChain.getEndEntityPublicKey()
+ if len(publicKey) < settings.minKeySize:
+ for result in self._sendError(\
+ AlertDescription.handshake_failure,
+ "Client's public key too small: %d" % len(publicKey)):
yield result
- else:
- break
- clientKeyExchange = result
- #Decrypt ClientKeyExchange
- premasterSecret = privateKey.decrypt(\
- clientKeyExchange.encryptedPreMasterSecret)
+ if len(publicKey) > settings.maxKeySize:
+ for result in self._sendError(\
+ AlertDescription.handshake_failure,
+ "Client's public key too large: %d" % len(publicKey)):
+ yield result
- 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
+ if not publicKey.verify(certificateVerify.signature, verifyBytes):
+ for result in self._sendError(\
+ AlertDescription.decrypt_error,
+ "Signature failed to verify"):
+ yield result
+ yield (premasterSecret, clientCertChain)
+
+
+ def _serverAnonKeyExchange(self, clientHello, serverHello, cipherSuite,
+ settings):
+ # Calculate DH p, g, Xs, Ys
+ dh_p = getRandomSafePrime(32, False)
+ dh_g = getRandomNumber(2, dh_p)
+ dh_Xs = bytesToNumber(getRandomBytes(32))
+ dh_Ys = powMod(dh_g, dh_Xs, dh_p)
+
+ #Create ServerKeyExchange
+ serverKeyExchange = ServerKeyExchange(cipherSuite)
+ serverKeyExchange.createDH(dh_p, dh_g, dh_Ys)
+
+ #Send ServerHello[, Certificate], ServerKeyExchange,
+ #ServerHelloDone
+ msgs = []
+ msgs.append(serverHello)
+ 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
+ dh_Yc = clientKeyExchange.dh_Yc
+
+ if dh_Yc % dh_p == 0:
+ for result in self._sendError(AlertDescription.illegal_parameter,
+ "Suspicious dh_Yc value"):
+ yield result
+ assert(False) # Just to ensure we don't fall through somehow
- #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")
+ #Calculate premaster secre
+ S = powMod(dh_Yc,dh_Xs,dh_p)
+ premasterSecret = numberToByteArray(S)
+
+ yield premasterSecret
- #Create the session object
- self.session = Session()
- self.session._calcMasterSecret(self.version, premasterSecret,
+ def _serverFinished(self, premasterSecret, clientRandom, serverRandom,
+ cipherSuite, cipherImplementations, nextProtos,
+ doingChannelID):
+ masterSecret = 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)
+ self._calcPendingStates(cipherSuite, masterSecret,
+ clientRandom, serverRandom,
+ cipherImplementations)
#Exchange ChangeCipherSpec and Finished messages
- for result in self._getChangeCipherSpec():
+ for result in self._getFinished(masterSecret,
+ expect_next_protocol=nextProtos is not None,
+ expect_channel_id=doingChannelID):
yield result
- if doingChannelID:
- for result in self._getEncryptedExtensions():
- yield result
- for result in self._getFinished():
+
+ for result in self._sendFinished(masterSecret):
yield result
+
+ yield masterSecret
- #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):
+
+ #*********************************************************
+ # Shared Handshake Functions
+ #*********************************************************
+
+
+ def _sendFinished(self, masterSecret, nextProto=None):
+ #Send ChangeCipherSpec
+ for result in self._sendMsg(ChangeCipherSpec()):
+ yield result
+
+ #Switch to pending write state
+ self._changeWriteState()
+
+ if nextProto is not None:
+ nextProtoMsg = NextProtocol().create(nextProto)
+ for result in self._sendMsg(nextProtoMsg):
yield result
- for result in self._sendFinished():
+ #Calculate verification data
+ verifyData = self._calcFinished(masterSecret, 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
- #Add the session object to the session cache
- if sessionCache and sessionID:
- sessionCache[bytesToString(sessionID)] = self.session
+ def _getFinished(self, masterSecret, expect_next_protocol=False, nextProto=None,
+ expect_channel_id=False):
+ #Get and check ChangeCipherSpec
+ for result in self._getMsg(ContentType.change_cipher_spec):
+ if result in (0,1):
+ yield result
+ changeCipherSpec = result
- #Mark the connection as open
- self.session._setResumable(True)
- self._handshakeDone(resumed=False)
+ if changeCipherSpec.type != 1:
+ for result in self._sendError(AlertDescription.illegal_parameter,
+ "ChangeCipherSpec type incorrect"):
+ yield result
+
+ #Switch to pending read state
+ self._changeReadState()
+
+ #Server Finish - Are we waiting for a next protocol echo?
+ if expect_next_protocol:
+ for result in self._getMsg(ContentType.handshake, HandshakeType.next_protocol):
+ if result in (0,1):
+ yield result
+ if result is None:
+ for result in self._sendError(AlertDescription.unexpected_message,
+ "Didn't get NextProtocol message"):
+ yield result
+
+ self.next_proto = result.next_proto
+ else:
+ self.next_proto = None
+
+ #Client Finish - Only set the next_protocol selected in the connection
+ if nextProto:
+ self.next_proto = nextProto
+
+ #Server Finish - Are we waiting for a EncryptedExtensions?
+ if expect_channel_id:
+ for result in self._getMsg(ContentType.handshake, HandshakeType.encrypted_extensions):
+ if result in (0,1):
+ yield result
+ if result is None:
+ for result in self._sendError(AlertDescription.unexpected_message,
+ "Didn't get EncryptedExtensions message"):
+ yield result
+ encrypted_extensions = result
+ self.channel_id = result.channel_id_key
+ else:
+ self.channel_id = None
+
+ #Calculate verification data
+ verifyData = self._calcFinished(masterSecret, 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, masterSecret, send=True):
+ if self.version == (3,0):
+ if (self._client and send) or (not self._client and not send):
+ senderStr = b"\x43\x4C\x4E\x54"
+ else:
+ senderStr = b"\x53\x52\x56\x52"
+
+ verifyData = self._calcSSLHandshakeHash(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 = b"client finished"
+ else:
+ label = b"server finished"
+
+ handshakeHashes = self._handshake_md5.digest() + \
+ self._handshake_sha.digest()
+ verifyData = PRF(masterSecret, label, handshakeHashes, 12)
+ return verifyData
+ else:
+ raise AssertionError()
def _handshakeWrapperAsync(self, handshaker, checker):
@@ -1643,27 +1805,11 @@ class TLSConnection(TLSRecordLayer):
for result in self._sendMsg(alert):
yield result
raise
- except:
- self._shutdown(False)
+ except GeneratorExit:
+ raise
+ except TLSAlert as alert:
+ if not self.fault:
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:
@@ -1671,28 +1817,3 @@ class TLSConnection(TLSRecordLayer):
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
« no previous file with comments | « third_party/tlslite/tlslite/sharedkeydb.py ('k') | third_party/tlslite/tlslite/tlsrecordlayer.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698