Package tlslite :: Module tlsconnection
[hide private]
[frames] | no frames]

Source Code for Module tlslite.tlsconnection

   1  # Authors: 
   2  #   Trevor Perrin 
   3  #   Google - added reqCAs parameter 
   4  #   Google (adapted by Sam Rushing and Marcelo Fernandez) - NPN support 
   5  #   Google - FALLBACK_SCSV 
   6  #   Dimitris Moraitis - Anon ciphersuites 
   7  #   Martin von Loewis - python 3 port 
   8  #   Yngve Pettersen (ported by Paul Sokolovsky) - TLS 1.2 
   9  #   Hubert Kario - complete refactoring of key exchange methods, addition 
  10  #          of ECDH support 
  11  # 
  12  # See the LICENSE file for legal information regarding use of this file. 
  13   
  14  """ 
  15  MAIN CLASS FOR TLS LITE (START HERE!). 
  16  """ 
  17   
  18  from __future__ import division 
  19  import socket 
  20  from .utils.compat import formatExceptionTrace 
  21  from .tlsrecordlayer import TLSRecordLayer 
  22  from .session import Session 
  23  from .constants import * 
  24  from .utils.cryptomath import getRandomBytes 
  25  from .errors import * 
  26  from .messages import * 
  27  from .mathtls import * 
  28  from .handshakesettings import HandshakeSettings 
  29  from .utils.tackwrapper import * 
  30  from .keyexchange import KeyExchange, RSAKeyExchange, DHE_RSAKeyExchange, \ 
  31          ECDHE_RSAKeyExchange, SRPKeyExchange 
32 33 -class TLSConnection(TLSRecordLayer):
34 """ 35 This class wraps a socket and provides TLS handshaking and data transfer. 36 37 To use this class, create a new instance, passing a connected 38 socket into the constructor. Then call some handshake function. 39 If the handshake completes without raising an exception, then a TLS 40 connection has been negotiated. You can transfer data over this 41 connection as if it were a socket. 42 43 This class provides both synchronous and asynchronous versions of 44 its key functions. The synchronous versions should be used when 45 writing single-or multi-threaded code using blocking sockets. The 46 asynchronous versions should be used when performing asynchronous, 47 event-based I/O with non-blocking sockets. 48 49 Asynchronous I/O is a complicated subject; typically, you should 50 not use the asynchronous functions directly, but should use some 51 framework like asyncore or Twisted which TLS Lite integrates with 52 (see 53 L{tlslite.integration.tlsasyncdispatchermixin.TLSAsyncDispatcherMixIn}). 54 """ 55
56 - def __init__(self, sock):
57 """Create a new TLSConnection instance. 58 59 @param sock: The socket data will be transmitted on. The 60 socket should already be connected. It may be in blocking or 61 non-blocking mode. 62 63 @type sock: L{socket.socket} 64 """ 65 TLSRecordLayer.__init__(self, sock) 66 self.serverSigAlg = None 67 self.ecdhCurve = None 68 self.dhGroupSize = None
69 70 #********************************************************* 71 # Client Handshake Functions 72 #********************************************************* 73
74 - def handshakeClientAnonymous(self, session=None, settings=None, 75 checker=None, serverName=None, 76 async=False):
77 """Perform an anonymous handshake in the role of client. 78 79 This function performs an SSL or TLS handshake using an 80 anonymous Diffie Hellman ciphersuite. 81 82 Like any handshake function, this can be called on a closed 83 TLS connection, or on a TLS connection that is already open. 84 If called on an open connection it performs a re-handshake. 85 86 If the function completes without raising an exception, the 87 TLS connection will be open and available for data transfer. 88 89 If an exception is raised, the connection will have been 90 automatically closed (if it was ever open). 91 92 @type session: L{tlslite.Session.Session} 93 @param session: A TLS session to attempt to resume. If the 94 resumption does not succeed, a full handshake will be 95 performed. 96 97 @type settings: L{tlslite.HandshakeSettings.HandshakeSettings} 98 @param settings: Various settings which can be used to control 99 the ciphersuites, certificate types, and SSL/TLS versions 100 offered by the client. 101 102 @type checker: L{tlslite.Checker.Checker} 103 @param checker: A Checker instance. This instance will be 104 invoked to examine the other party's authentication 105 credentials, if the handshake completes succesfully. 106 107 @type serverName: string 108 @param serverName: The ServerNameIndication TLS Extension. 109 110 @type async: bool 111 @param async: If False, this function will block until the 112 handshake is completed. If True, this function will return a 113 generator. Successive invocations of the generator will 114 return 0 if it is waiting to read from the socket, 1 if it is 115 waiting to write to the socket, or will raise StopIteration if 116 the handshake operation is completed. 117 118 @rtype: None or an iterable 119 @return: If 'async' is True, a generator object will be 120 returned. 121 122 @raise socket.error: If a socket error occurs. 123 @raise tlslite.errors.TLSAbruptCloseError: If the socket is closed 124 without a preceding alert. 125 @raise tlslite.errors.TLSAlert: If a TLS alert is signalled. 126 @raise tlslite.errors.TLSAuthenticationError: If the checker 127 doesn't like the other party's authentication credentials. 128 """ 129 handshaker = self._handshakeClientAsync(anonParams=(True), 130 session=session, 131 settings=settings, 132 checker=checker, 133 serverName=serverName) 134 if async: 135 return handshaker 136 for result in handshaker: 137 pass
138
139 - def handshakeClientSRP(self, username, password, session=None, 140 settings=None, checker=None, 141 reqTack=True, serverName=None, 142 async=False):
143 """Perform an SRP handshake in the role of client. 144 145 This function performs a TLS/SRP handshake. SRP mutually 146 authenticates both parties to each other using only a 147 username and password. This function may also perform a 148 combined SRP and server-certificate handshake, if the server 149 chooses to authenticate itself with a certificate chain in 150 addition to doing SRP. 151 152 If the function completes without raising an exception, the 153 TLS connection will be open and available for data transfer. 154 155 If an exception is raised, the connection will have been 156 automatically closed (if it was ever open). 157 158 @type username: str 159 @param username: The SRP username. 160 161 @type password: str 162 @param password: The SRP password. 163 164 @type session: L{tlslite.session.Session} 165 @param session: A TLS session to attempt to resume. This 166 session must be an SRP session performed with the same username 167 and password as were passed in. If the resumption does not 168 succeed, a full SRP handshake will be performed. 169 170 @type settings: L{tlslite.handshakesettings.HandshakeSettings} 171 @param settings: Various settings which can be used to control 172 the ciphersuites, certificate types, and SSL/TLS versions 173 offered by the client. 174 175 @type checker: L{tlslite.checker.Checker} 176 @param checker: A Checker instance. This instance will be 177 invoked to examine the other party's authentication 178 credentials, if the handshake completes succesfully. 179 180 @type reqTack: bool 181 @param reqTack: Whether or not to send a "tack" TLS Extension, 182 requesting the server return a TackExtension if it has one. 183 184 @type serverName: string 185 @param serverName: The ServerNameIndication TLS Extension. 186 187 @type async: bool 188 @param async: If False, this function will block until the 189 handshake is completed. If True, this function will return a 190 generator. Successive invocations of the generator will 191 return 0 if it is waiting to read from the socket, 1 if it is 192 waiting to write to the socket, or will raise StopIteration if 193 the handshake operation is completed. 194 195 @rtype: None or an iterable 196 @return: If 'async' is True, a generator object will be 197 returned. 198 199 @raise socket.error: If a socket error occurs. 200 @raise tlslite.errors.TLSAbruptCloseError: If the socket is closed 201 without a preceding alert. 202 @raise tlslite.errors.TLSAlert: If a TLS alert is signalled. 203 @raise tlslite.errors.TLSAuthenticationError: If the checker 204 doesn't like the other party's authentication credentials. 205 """ 206 handshaker = self._handshakeClientAsync(srpParams=(username, password), 207 session=session, settings=settings, checker=checker, 208 reqTack=reqTack, serverName=serverName) 209 # The handshaker is a Python Generator which executes the handshake. 210 # It allows the handshake to be run in a "piecewise", asynchronous 211 # fashion, returning 1 when it is waiting to able to write, 0 when 212 # it is waiting to read. 213 # 214 # If 'async' is True, the generator is returned to the caller, 215 # otherwise it is executed to completion here. 216 if async: 217 return handshaker 218 for result in handshaker: 219 pass
220
221 - def handshakeClientCert(self, certChain=None, privateKey=None, 222 session=None, settings=None, checker=None, 223 nextProtos=None, reqTack=True, serverName=None, 224 async=False):
225 """Perform a certificate-based handshake in the role of client. 226 227 This function performs an SSL or TLS handshake. The server 228 will authenticate itself using an X.509 certificate 229 chain. If the handshake succeeds, the server's certificate 230 chain will be stored in the session's serverCertChain attribute. 231 Unless a checker object is passed in, this function does no 232 validation or checking of the server's certificate chain. 233 234 If the server requests client authentication, the 235 client will send the passed-in certificate chain, and use the 236 passed-in private key to authenticate itself. If no 237 certificate chain and private key were passed in, the client 238 will attempt to proceed without client authentication. The 239 server may or may not allow this. 240 241 If the function completes without raising an exception, the 242 TLS connection will be open and available for data transfer. 243 244 If an exception is raised, the connection will have been 245 automatically closed (if it was ever open). 246 247 @type certChain: L{tlslite.x509certchain.X509CertChain} 248 @param certChain: The certificate chain to be used if the 249 server requests client authentication. 250 251 @type privateKey: L{tlslite.utils.rsakey.RSAKey} 252 @param privateKey: The private key to be used if the server 253 requests client authentication. 254 255 @type session: L{tlslite.session.Session} 256 @param session: A TLS session to attempt to resume. If the 257 resumption does not succeed, a full handshake will be 258 performed. 259 260 @type settings: L{tlslite.handshakesettings.HandshakeSettings} 261 @param settings: Various settings which can be used to control 262 the ciphersuites, certificate types, and SSL/TLS versions 263 offered by the client. 264 265 @type checker: L{tlslite.checker.Checker} 266 @param checker: A Checker instance. This instance will be 267 invoked to examine the other party's authentication 268 credentials, if the handshake completes succesfully. 269 270 @type nextProtos: list of strings. 271 @param nextProtos: A list of upper layer protocols ordered by 272 preference, to use in the Next-Protocol Negotiation Extension. 273 274 @type reqTack: bool 275 @param reqTack: Whether or not to send a "tack" TLS Extension, 276 requesting the server return a TackExtension if it has one. 277 278 @type serverName: string 279 @param serverName: The ServerNameIndication TLS Extension. 280 281 @type async: bool 282 @param async: If False, this function will block until the 283 handshake is completed. If True, this function will return a 284 generator. Successive invocations of the generator will 285 return 0 if it is waiting to read from the socket, 1 if it is 286 waiting to write to the socket, or will raise StopIteration if 287 the handshake operation is completed. 288 289 @rtype: None or an iterable 290 @return: If 'async' is True, a generator object will be 291 returned. 292 293 @raise socket.error: If a socket error occurs. 294 @raise tlslite.errors.TLSAbruptCloseError: If the socket is closed 295 without a preceding alert. 296 @raise tlslite.errors.TLSAlert: If a TLS alert is signalled. 297 @raise tlslite.errors.TLSAuthenticationError: If the checker 298 doesn't like the other party's authentication credentials. 299 """ 300 handshaker = \ 301 self._handshakeClientAsync(certParams=(certChain, privateKey), 302 session=session, settings=settings, 303 checker=checker, 304 serverName=serverName, 305 nextProtos=nextProtos, 306 reqTack=reqTack) 307 # The handshaker is a Python Generator which executes the handshake. 308 # It allows the handshake to be run in a "piecewise", asynchronous 309 # fashion, returning 1 when it is waiting to able to write, 0 when 310 # it is waiting to read. 311 # 312 # If 'async' is True, the generator is returned to the caller, 313 # otherwise it is executed to completion here. 314 if async: 315 return handshaker 316 for result in handshaker: 317 pass
318 319
320 - def _handshakeClientAsync(self, srpParams=(), certParams=(), anonParams=(), 321 session=None, settings=None, checker=None, 322 nextProtos=None, serverName=None, reqTack=True):
323 324 handshaker = self._handshakeClientAsyncHelper(srpParams=srpParams, 325 certParams=certParams, 326 anonParams=anonParams, 327 session=session, 328 settings=settings, 329 serverName=serverName, 330 nextProtos=nextProtos, 331 reqTack=reqTack) 332 for result in self._handshakeWrapperAsync(handshaker, checker): 333 yield result
334 335
336 - def _handshakeClientAsyncHelper(self, srpParams, certParams, anonParams, 337 session, settings, serverName, nextProtos, reqTack):
338 339 self._handshakeStart(client=True) 340 341 #Unpack parameters 342 srpUsername = None # srpParams[0] 343 password = None # srpParams[1] 344 clientCertChain = None # certParams[0] 345 privateKey = None # certParams[1] 346 347 # Allow only one of (srpParams, certParams, anonParams) 348 if srpParams: 349 assert(not certParams) 350 assert(not anonParams) 351 srpUsername, password = srpParams 352 if certParams: 353 assert(not srpParams) 354 assert(not anonParams) 355 clientCertChain, privateKey = certParams 356 if anonParams: 357 assert(not srpParams) 358 assert(not certParams) 359 360 #Validate parameters 361 if srpUsername and not password: 362 raise ValueError("Caller passed a username but no password") 363 if password and not srpUsername: 364 raise ValueError("Caller passed a password but no username") 365 if clientCertChain and not privateKey: 366 raise ValueError("Caller passed a certChain but no privateKey") 367 if privateKey and not clientCertChain: 368 raise ValueError("Caller passed a privateKey but no certChain") 369 if reqTack: 370 if not tackpyLoaded: 371 reqTack = False 372 if not settings or not settings.useExperimentalTackExtension: 373 reqTack = False 374 if nextProtos is not None: 375 if len(nextProtos) == 0: 376 raise ValueError("Caller passed no nextProtos") 377 378 # Validates the settings and filters out any unsupported ciphers 379 # or crypto libraries that were requested 380 if not settings: 381 settings = HandshakeSettings() 382 settings = settings.validate() 383 384 if clientCertChain: 385 if not isinstance(clientCertChain, X509CertChain): 386 raise ValueError("Unrecognized certificate type") 387 if "x509" not in settings.certificateTypes: 388 raise ValueError("Client certificate doesn't match "\ 389 "Handshake Settings") 390 391 if session: 392 # session.valid() ensures session is resumable and has 393 # non-empty sessionID 394 if not session.valid(): 395 session = None #ignore non-resumable sessions... 396 elif session.resumable: 397 if session.srpUsername != srpUsername: 398 raise ValueError("Session username doesn't match") 399 if session.serverName != serverName: 400 raise ValueError("Session servername doesn't match") 401 402 #Add Faults to parameters 403 if srpUsername and self.fault == Fault.badUsername: 404 srpUsername += "GARBAGE" 405 if password and self.fault == Fault.badPassword: 406 password += "GARBAGE" 407 408 #Tentatively set the version to the client's minimum version. 409 #We'll use this for the ClientHello, and if an error occurs 410 #parsing the Server Hello, we'll use this version for the response 411 self.version = settings.maxVersion 412 413 # OK Start sending messages! 414 # ***************************** 415 416 # Send the ClientHello. 417 for result in self._clientSendClientHello(settings, session, 418 srpUsername, srpParams, certParams, 419 anonParams, serverName, nextProtos, 420 reqTack): 421 if result in (0,1): yield result 422 else: break 423 clientHello = result 424 425 #Get the ServerHello. 426 for result in self._clientGetServerHello(settings, clientHello): 427 if result in (0,1): yield result 428 else: break 429 serverHello = result 430 cipherSuite = serverHello.cipher_suite 431 432 # Choose a matching Next Protocol from server list against ours 433 # (string or None) 434 nextProto = self._clientSelectNextProto(nextProtos, serverHello) 435 436 # Check if server selected encrypt-then-MAC 437 if serverHello.getExtension(ExtensionType.encrypt_then_mac): 438 self._recordLayer.encryptThenMAC = True 439 440 #If the server elected to resume the session, it is handled here. 441 for result in self._clientResume(session, serverHello, 442 clientHello.random, 443 settings.cipherImplementations, 444 nextProto): 445 if result in (0,1): yield result 446 else: break 447 if result == "resumed_and_finished": 448 self._handshakeDone(resumed=True) 449 return 450 451 #If the server selected an SRP ciphersuite, the client finishes 452 #reading the post-ServerHello messages, then derives a 453 #premasterSecret and sends a corresponding ClientKeyExchange. 454 if cipherSuite in CipherSuite.srpAllSuites: 455 keyExchange = SRPKeyExchange(cipherSuite, clientHello, 456 serverHello, None, None, 457 srpUsername=srpUsername, 458 password=password, 459 settings=settings) 460 461 #If the server selected an anonymous ciphersuite, the client 462 #finishes reading the post-ServerHello messages. 463 elif cipherSuite in CipherSuite.dhAllSuites: 464 keyExchange = DHE_RSAKeyExchange(cipherSuite, clientHello, 465 serverHello, None) 466 467 elif cipherSuite in CipherSuite.ecdhAllSuites: 468 acceptedCurves = self._curveNamesToList(settings) 469 keyExchange = ECDHE_RSAKeyExchange(cipherSuite, clientHello, 470 serverHello, None, 471 acceptedCurves) 472 473 #If the server selected a certificate-based RSA ciphersuite, 474 #the client finishes reading the post-ServerHello messages. If 475 #a CertificateRequest message was sent, the client responds with 476 #a Certificate message containing its certificate chain (if any), 477 #and also produces a CertificateVerify message that signs the 478 #ClientKeyExchange. 479 else: 480 keyExchange = RSAKeyExchange(cipherSuite, clientHello, 481 serverHello, None) 482 483 for result in self._clientKeyExchange(settings, cipherSuite, 484 clientCertChain, 485 privateKey, 486 serverHello.certificate_type, 487 serverHello.tackExt, 488 clientHello.random, 489 serverHello.random, 490 keyExchange): 491 if result in (0, 1): 492 yield result 493 else: break 494 (premasterSecret, serverCertChain, clientCertChain, 495 tackExt) = result 496 497 #After having previously sent a ClientKeyExchange, the client now 498 #initiates an exchange of Finished messages. 499 for result in self._clientFinished(premasterSecret, 500 clientHello.random, 501 serverHello.random, 502 cipherSuite, settings.cipherImplementations, 503 nextProto): 504 if result in (0,1): yield result 505 else: break 506 masterSecret = result 507 508 # Create the session object which is used for resumptions 509 self.session = Session() 510 self.session.create(masterSecret, serverHello.session_id, cipherSuite, 511 srpUsername, clientCertChain, serverCertChain, 512 tackExt, (serverHello.tackExt is not None), 513 serverName, 514 encryptThenMAC=self._recordLayer.encryptThenMAC) 515 self._handshakeDone(resumed=False)
516 517
518 - def _clientSendClientHello(self, settings, session, srpUsername, 519 srpParams, certParams, anonParams, 520 serverName, nextProtos, reqTack):
521 #Initialize acceptable ciphersuites 522 cipherSuites = [CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] 523 if srpParams: 524 cipherSuites += CipherSuite.getSrpAllSuites(settings) 525 elif certParams: 526 cipherSuites += CipherSuite.getEcdheCertSuites(settings) 527 cipherSuites += CipherSuite.getDheCertSuites(settings) 528 cipherSuites += CipherSuite.getCertSuites(settings) 529 elif anonParams: 530 cipherSuites += CipherSuite.getEcdhAnonSuites(settings) 531 cipherSuites += CipherSuite.getAnonSuites(settings) 532 else: 533 assert False 534 535 #Add any SCSVs. These are not real cipher suites, but signaling 536 #values which reuse the cipher suite field in the ClientHello. 537 wireCipherSuites = list(cipherSuites) 538 if settings.sendFallbackSCSV: 539 wireCipherSuites.append(CipherSuite.TLS_FALLBACK_SCSV) 540 541 #Initialize acceptable certificate types 542 certificateTypes = settings.getCertificateTypes() 543 544 extensions = [] 545 546 #Initialize TLS extensions 547 if settings.useEncryptThenMAC: 548 extensions.append(TLSExtension().\ 549 create(ExtensionType.encrypt_then_mac, 550 bytearray(0))) 551 #Send the ECC extensions only if we advertise ECC ciphers 552 if next((cipher for cipher in cipherSuites \ 553 if cipher in CipherSuite.ecdhAllSuites), None) is not None: 554 extensions.append(SupportedGroupsExtension().\ 555 create(self._curveNamesToList(settings))) 556 extensions.append(ECPointFormatsExtension().\ 557 create([ECPointFormat.uncompressed])) 558 # In TLS1.2 advertise support for additional signature types 559 if settings.maxVersion >= (3, 3): 560 sigList = self._sigHashesToList(settings) 561 assert len(sigList) > 0 562 extensions.append(SignatureAlgorithmsExtension().\ 563 create(sigList)) 564 #don't send empty list of extensions 565 if not extensions: 566 extensions = None 567 568 #Either send ClientHello (with a resumable session)... 569 if session and session.sessionID: 570 #If it's resumable, then its 571 #ciphersuite must be one of the acceptable ciphersuites 572 if session.cipherSuite not in cipherSuites: 573 raise ValueError("Session's cipher suite not consistent "\ 574 "with parameters") 575 else: 576 clientHello = ClientHello() 577 clientHello.create(settings.maxVersion, getRandomBytes(32), 578 session.sessionID, wireCipherSuites, 579 certificateTypes, 580 session.srpUsername, 581 reqTack, nextProtos is not None, 582 session.serverName, 583 extensions=extensions) 584 585 #Or send ClientHello (without) 586 else: 587 clientHello = ClientHello() 588 clientHello.create(settings.maxVersion, getRandomBytes(32), 589 bytearray(0), wireCipherSuites, 590 certificateTypes, 591 srpUsername, 592 reqTack, nextProtos is not None, 593 serverName, 594 extensions=extensions) 595 for result in self._sendMsg(clientHello): 596 yield result 597 yield clientHello
598 599
600 - def _clientGetServerHello(self, settings, clientHello):
601 for result in self._getMsg(ContentType.handshake, 602 HandshakeType.server_hello): 603 if result in (0,1): yield result 604 else: break 605 serverHello = result 606 607 #Get the server version. Do this before anything else, so any 608 #error alerts will use the server's version 609 self.version = serverHello.server_version 610 611 #Check ServerHello 612 if serverHello.server_version < settings.minVersion: 613 for result in self._sendError(\ 614 AlertDescription.protocol_version, 615 "Too old version: %s" % str(serverHello.server_version)): 616 yield result 617 if serverHello.server_version > settings.maxVersion: 618 for result in self._sendError(\ 619 AlertDescription.protocol_version, 620 "Too new version: %s" % str(serverHello.server_version)): 621 yield result 622 serverVer = serverHello.server_version 623 cipherSuites = CipherSuite.filterForVersion(clientHello.cipher_suites, 624 minVersion=serverVer, 625 maxVersion=serverVer) 626 if serverHello.cipher_suite not in cipherSuites: 627 for result in self._sendError(\ 628 AlertDescription.illegal_parameter, 629 "Server responded with incorrect ciphersuite"): 630 yield result 631 if serverHello.certificate_type not in clientHello.certificate_types: 632 for result in self._sendError(\ 633 AlertDescription.illegal_parameter, 634 "Server responded with incorrect certificate type"): 635 yield result 636 if serverHello.compression_method != 0: 637 for result in self._sendError(\ 638 AlertDescription.illegal_parameter, 639 "Server responded with incorrect compression method"): 640 yield result 641 if serverHello.tackExt: 642 if not clientHello.tack: 643 for result in self._sendError(\ 644 AlertDescription.illegal_parameter, 645 "Server responded with unrequested Tack Extension"): 646 yield result 647 if not serverHello.tackExt.verifySignatures(): 648 for result in self._sendError(\ 649 AlertDescription.decrypt_error, 650 "TackExtension contains an invalid signature"): 651 yield result 652 if serverHello.next_protos and not clientHello.supports_npn: 653 for result in self._sendError(\ 654 AlertDescription.illegal_parameter, 655 "Server responded with unrequested NPN Extension"): 656 yield result 657 yield serverHello
658
659 - def _clientSelectNextProto(self, nextProtos, serverHello):
660 # nextProtos is None or non-empty list of strings 661 # serverHello.next_protos is None or possibly-empty list of strings 662 # 663 # !!! We assume the client may have specified nextProtos as a list of 664 # strings so we convert them to bytearrays (it's awkward to require 665 # the user to specify a list of bytearrays or "bytes", and in 666 # Python 2.6 bytes() is just an alias for str() anyways... 667 if nextProtos is not None and serverHello.next_protos is not None: 668 for p in nextProtos: 669 if bytearray(p) in serverHello.next_protos: 670 return bytearray(p) 671 else: 672 # If the client doesn't support any of server's protocols, 673 # or the server doesn't advertise any (next_protos == []) 674 # the client SHOULD select the first protocol it supports. 675 return bytearray(nextProtos[0]) 676 return None
677
678 - def _clientResume(self, session, serverHello, clientRandom, 679 cipherImplementations, nextProto):
680 #If the server agrees to resume 681 if session and session.sessionID and \ 682 serverHello.session_id == session.sessionID: 683 684 if serverHello.cipher_suite != session.cipherSuite: 685 for result in self._sendError(\ 686 AlertDescription.illegal_parameter,\ 687 "Server's ciphersuite doesn't match session"): 688 yield result 689 690 #Calculate pending connection states 691 self._calcPendingStates(session.cipherSuite, 692 session.masterSecret, 693 clientRandom, serverHello.random, 694 cipherImplementations) 695 696 #Exchange ChangeCipherSpec and Finished messages 697 for result in self._getFinished(session.masterSecret, 698 session.cipherSuite): 699 yield result 700 for result in self._sendFinished(session.masterSecret, 701 session.cipherSuite, 702 nextProto): 703 yield result 704 705 #Set the session for this connection 706 self.session = session 707 yield "resumed_and_finished"
708
709 - def _clientKeyExchange(self, settings, cipherSuite, 710 clientCertChain, privateKey, 711 certificateType, 712 tackExt, clientRandom, serverRandom, 713 keyExchange):
714 """Perform the client side of key exchange""" 715 # if server chose cipher suite with authentication, get the certificate 716 if cipherSuite in CipherSuite.certAllSuites: 717 for result in self._getMsg(ContentType.handshake, 718 HandshakeType.certificate, 719 certificateType): 720 if result in (0, 1): 721 yield result 722 else: break 723 serverCertificate = result 724 else: 725 serverCertificate = None 726 # if server chose RSA key exchange, we need to skip SKE message 727 if cipherSuite not in CipherSuite.certSuites: 728 for result in self._getMsg(ContentType.handshake, 729 HandshakeType.server_key_exchange, 730 cipherSuite): 731 if result in (0, 1): 732 yield result 733 else: break 734 serverKeyExchange = result 735 else: 736 serverKeyExchange = None 737 738 for result in self._getMsg(ContentType.handshake, 739 (HandshakeType.certificate_request, 740 HandshakeType.server_hello_done)): 741 if result in (0, 1): 742 yield result 743 else: break 744 745 certificateRequest = None 746 if isinstance(result, CertificateRequest): 747 certificateRequest = result 748 749 #abort if Certificate Request with inappropriate ciphersuite 750 if cipherSuite not in CipherSuite.certAllSuites \ 751 or cipherSuite in CipherSuite.srpAllSuites: 752 for result in self._sendError(\ 753 AlertDescription.unexpected_message, 754 "Certificate Request with incompatible cipher suite"): 755 yield result 756 757 # we got CertificateRequest so now we'll get ServerHelloDone 758 for result in self._getMsg(ContentType.handshake, 759 HandshakeType.server_hello_done): 760 if result in (0, 1): 761 yield result 762 else: break 763 serverHelloDone = result 764 765 serverCertChain = None 766 publicKey = None 767 if cipherSuite in CipherSuite.certAllSuites: 768 # get the certificate 769 for result in self._clientGetKeyFromChain(serverCertificate, 770 settings, 771 tackExt): 772 if result in (0, 1): 773 yield result 774 else: break 775 publicKey, serverCertChain, tackExt = result 776 777 #Check the server's signature, if the server chose an authenticated 778 # PFS-enabled ciphersuite 779 if serverKeyExchange: 780 validSigAlgs = self._sigHashesToList(settings) 781 try: 782 KeyExchange.verifyServerKeyExchange(serverKeyExchange, 783 publicKey, 784 clientRandom, 785 serverRandom, 786 validSigAlgs) 787 except TLSIllegalParameterException: 788 for result in self._sendError(AlertDescription.\ 789 illegal_parameter): 790 yield result 791 except TLSDecryptionFailed: 792 for result in self._sendError(\ 793 AlertDescription.decrypt_error): 794 yield result 795 796 if serverKeyExchange: 797 # store key exchange metadata for user applications 798 if self.version >= (3, 3) \ 799 and cipherSuite in CipherSuite.certAllSuites \ 800 and cipherSuite not in CipherSuite.certSuites: 801 self.serverSigAlg = (serverKeyExchange.hashAlg, 802 serverKeyExchange.signAlg) 803 804 if cipherSuite in CipherSuite.dhAllSuites: 805 self.dhGroupSize = numBits(serverKeyExchange.dh_p) 806 if cipherSuite in CipherSuite.ecdhAllSuites: 807 self.ecdhCurve = serverKeyExchange.named_curve 808 809 #Send Certificate if we were asked for it 810 if certificateRequest: 811 812 # if a peer doesn't advertise support for any algorithm in TLSv1.2, 813 # support for SHA1+RSA can be assumed 814 if self.version == (3, 3)\ 815 and not [sig for sig in \ 816 certificateRequest.supported_signature_algs\ 817 if sig[1] == SignatureAlgorithm.rsa]: 818 for result in self._sendError(\ 819 AlertDescription.handshake_failure, 820 "Server doesn't accept any sigalgs we support: " + 821 str(certificateRequest.supported_signature_algs)): 822 yield result 823 clientCertificate = Certificate(certificateType) 824 825 if clientCertChain: 826 #Check to make sure we have the same type of 827 #certificates the server requested 828 if certificateType == CertificateType.x509 \ 829 and not isinstance(clientCertChain, X509CertChain): 830 for result in self._sendError(\ 831 AlertDescription.handshake_failure, 832 "Client certificate is of wrong type"): 833 yield result 834 835 clientCertificate.create(clientCertChain) 836 # we need to send the message even if we don't have a certificate 837 for result in self._sendMsg(clientCertificate): 838 yield result 839 else: 840 #Server didn't ask for cer, zeroise so session doesn't store them 841 privateKey = None 842 clientCertChain = None 843 844 try: 845 ske = serverKeyExchange 846 premasterSecret = keyExchange.processServerKeyExchange(publicKey, 847 ske) 848 except TLSInsufficientSecurity as e: 849 for result in self._sendError(\ 850 AlertDescription.insufficient_security, e): 851 yield result 852 except TLSIllegalParameterException as e: 853 for result in self._sendError(\ 854 AlertDescription.illegal_parameter, e): 855 yield result 856 857 clientKeyExchange = keyExchange.makeClientKeyExchange() 858 859 #Send ClientKeyExchange 860 for result in self._sendMsg(clientKeyExchange): 861 yield result 862 863 #if client auth was requested and we have a private key, send a 864 #CertificateVerify 865 if certificateRequest and privateKey: 866 validSigAlgs = self._sigHashesToList(settings) 867 certificateVerify = KeyExchange.makeCertificateVerify(\ 868 self.version, 869 self._handshake_hash, 870 validSigAlgs, 871 privateKey, 872 certificateRequest, 873 premasterSecret, 874 clientRandom, 875 serverRandom) 876 for result in self._sendMsg(certificateVerify): 877 yield result 878 879 yield (premasterSecret, serverCertChain, clientCertChain, tackExt)
880
881 - def _clientFinished(self, premasterSecret, clientRandom, serverRandom, 882 cipherSuite, cipherImplementations, nextProto):
883 884 masterSecret = calcMasterSecret(self.version, 885 cipherSuite, 886 premasterSecret, 887 clientRandom, 888 serverRandom) 889 self._calcPendingStates(cipherSuite, masterSecret, 890 clientRandom, serverRandom, 891 cipherImplementations) 892 893 #Exchange ChangeCipherSpec and Finished messages 894 for result in self._sendFinished(masterSecret, cipherSuite, nextProto): 895 yield result 896 for result in self._getFinished(masterSecret, 897 cipherSuite, 898 nextProto=nextProto): 899 yield result 900 yield masterSecret
901
902 - def _clientGetKeyFromChain(self, certificate, settings, tackExt=None):
903 #Get and check cert chain from the Certificate message 904 certChain = certificate.certChain 905 if not certChain or certChain.getNumCerts() == 0: 906 for result in self._sendError(AlertDescription.illegal_parameter, 907 "Other party sent a Certificate message without "\ 908 "certificates"): 909 yield result 910 911 #Get and check public key from the cert chain 912 publicKey = certChain.getEndEntityPublicKey() 913 if len(publicKey) < settings.minKeySize: 914 for result in self._sendError(AlertDescription.handshake_failure, 915 "Other party's public key too small: %d" % len(publicKey)): 916 yield result 917 if len(publicKey) > settings.maxKeySize: 918 for result in self._sendError(AlertDescription.handshake_failure, 919 "Other party's public key too large: %d" % len(publicKey)): 920 yield result 921 922 # If there's no TLS Extension, look for a TACK cert 923 if tackpyLoaded: 924 if not tackExt: 925 tackExt = certChain.getTackExt() 926 927 # If there's a TACK (whether via TLS or TACK Cert), check that it 928 # matches the cert chain 929 if tackExt and tackExt.tacks: 930 for tack in tackExt.tacks: 931 if not certChain.checkTack(tack): 932 for result in self._sendError( 933 AlertDescription.illegal_parameter, 934 "Other party's TACK doesn't match their public key"): 935 yield result 936 937 yield publicKey, certChain, tackExt
938 939 940 #********************************************************* 941 # Server Handshake Functions 942 #********************************************************* 943 944
945 - def handshakeServer(self, verifierDB=None, 946 certChain=None, privateKey=None, reqCert=False, 947 sessionCache=None, settings=None, checker=None, 948 reqCAs = None, 949 tacks=None, activationFlags=0, 950 nextProtos=None, anon=False):
951 """Perform a handshake in the role of server. 952 953 This function performs an SSL or TLS handshake. Depending on 954 the arguments and the behavior of the client, this function can 955 perform an SRP, or certificate-based handshake. It 956 can also perform a combined SRP and server-certificate 957 handshake. 958 959 Like any handshake function, this can be called on a closed 960 TLS connection, or on a TLS connection that is already open. 961 If called on an open connection it performs a re-handshake. 962 This function does not send a Hello Request message before 963 performing the handshake, so if re-handshaking is required, 964 the server must signal the client to begin the re-handshake 965 through some other means. 966 967 If the function completes without raising an exception, the 968 TLS connection will be open and available for data transfer. 969 970 If an exception is raised, the connection will have been 971 automatically closed (if it was ever open). 972 973 @type verifierDB: L{tlslite.verifierdb.VerifierDB} 974 @param verifierDB: A database of SRP password verifiers 975 associated with usernames. If the client performs an SRP 976 handshake, the session's srpUsername attribute will be set. 977 978 @type certChain: L{tlslite.x509certchain.X509CertChain} 979 @param certChain: The certificate chain to be used if the 980 client requests server certificate authentication. 981 982 @type privateKey: L{tlslite.utils.rsakey.RSAKey} 983 @param privateKey: The private key to be used if the client 984 requests server certificate authentication. 985 986 @type reqCert: bool 987 @param reqCert: Whether to request client certificate 988 authentication. This only applies if the client chooses server 989 certificate authentication; if the client chooses SRP 990 authentication, this will be ignored. If the client 991 performs a client certificate authentication, the sessions's 992 clientCertChain attribute will be set. 993 994 @type sessionCache: L{tlslite.sessioncache.SessionCache} 995 @param sessionCache: An in-memory cache of resumable sessions. 996 The client can resume sessions from this cache. Alternatively, 997 if the client performs a full handshake, a new session will be 998 added to the cache. 999 1000 @type settings: L{tlslite.handshakesettings.HandshakeSettings} 1001 @param settings: Various settings which can be used to control 1002 the ciphersuites and SSL/TLS version chosen by the server. 1003 1004 @type checker: L{tlslite.checker.Checker} 1005 @param checker: A Checker instance. This instance will be 1006 invoked to examine the other party's authentication 1007 credentials, if the handshake completes succesfully. 1008 1009 @type reqCAs: list of L{bytearray} of unsigned bytes 1010 @param reqCAs: A collection of DER-encoded DistinguishedNames that 1011 will be sent along with a certificate request. This does not affect 1012 verification. 1013 1014 @type nextProtos: list of strings. 1015 @param nextProtos: A list of upper layer protocols to expose to the 1016 clients through the Next-Protocol Negotiation Extension, 1017 if they support it. 1018 1019 @raise socket.error: If a socket error occurs. 1020 @raise tlslite.errors.TLSAbruptCloseError: If the socket is closed 1021 without a preceding alert. 1022 @raise tlslite.errors.TLSAlert: If a TLS alert is signalled. 1023 @raise tlslite.errors.TLSAuthenticationError: If the checker 1024 doesn't like the other party's authentication credentials. 1025 """ 1026 for result in self.handshakeServerAsync(verifierDB, 1027 certChain, privateKey, reqCert, sessionCache, settings, 1028 checker, reqCAs, 1029 tacks=tacks, activationFlags=activationFlags, 1030 nextProtos=nextProtos, anon=anon): 1031 pass
1032 1033
1034 - def handshakeServerAsync(self, verifierDB=None, 1035 certChain=None, privateKey=None, reqCert=False, 1036 sessionCache=None, settings=None, checker=None, 1037 reqCAs=None, 1038 tacks=None, activationFlags=0, 1039 nextProtos=None, anon=False 1040 ):
1041 """Start a server handshake operation on the TLS connection. 1042 1043 This function returns a generator which behaves similarly to 1044 handshakeServer(). Successive invocations of the generator 1045 will return 0 if it is waiting to read from the socket, 1 if it is 1046 waiting to write to the socket, or it will raise StopIteration 1047 if the handshake operation is complete. 1048 1049 @rtype: iterable 1050 @return: A generator; see above for details. 1051 """ 1052 handshaker = self._handshakeServerAsyncHelper(\ 1053 verifierDB=verifierDB, certChain=certChain, 1054 privateKey=privateKey, reqCert=reqCert, 1055 sessionCache=sessionCache, settings=settings, 1056 reqCAs=reqCAs, 1057 tacks=tacks, activationFlags=activationFlags, 1058 nextProtos=nextProtos, anon=anon) 1059 for result in self._handshakeWrapperAsync(handshaker, checker): 1060 yield result
1061 1062
1063 - def _handshakeServerAsyncHelper(self, verifierDB, 1064 certChain, privateKey, reqCert, sessionCache, 1065 settings, reqCAs, 1066 tacks, activationFlags, 1067 nextProtos, anon):
1068 1069 self._handshakeStart(client=False) 1070 1071 if (not verifierDB) and (not certChain) and not anon: 1072 raise ValueError("Caller passed no authentication credentials") 1073 if certChain and not privateKey: 1074 raise ValueError("Caller passed a certChain but no privateKey") 1075 if privateKey and not certChain: 1076 raise ValueError("Caller passed a privateKey but no certChain") 1077 if reqCAs and not reqCert: 1078 raise ValueError("Caller passed reqCAs but not reqCert") 1079 if certChain and not isinstance(certChain, X509CertChain): 1080 raise ValueError("Unrecognized certificate type") 1081 if activationFlags and not tacks: 1082 raise ValueError("Nonzero activationFlags requires tacks") 1083 if tacks: 1084 if not tackpyLoaded: 1085 raise ValueError("tackpy is not loaded") 1086 if not settings or not settings.useExperimentalTackExtension: 1087 raise ValueError("useExperimentalTackExtension not enabled") 1088 1089 if not settings: 1090 settings = HandshakeSettings() 1091 settings = settings.validate() 1092 1093 # OK Start exchanging messages 1094 # ****************************** 1095 1096 # Handle ClientHello and resumption 1097 for result in self._serverGetClientHello(settings, certChain,\ 1098 verifierDB, sessionCache, 1099 anon): 1100 if result in (0,1): yield result 1101 elif result == None: 1102 self._handshakeDone(resumed=True) 1103 return # Handshake was resumed, we're done 1104 else: break 1105 (clientHello, cipherSuite) = result 1106 1107 #If not a resumption... 1108 1109 # Create the ServerHello message 1110 if sessionCache: 1111 sessionID = getRandomBytes(32) 1112 else: 1113 sessionID = bytearray(0) 1114 1115 if not clientHello.supports_npn: 1116 nextProtos = None 1117 1118 # If not doing a certificate-based suite, discard the TACK 1119 if not cipherSuite in CipherSuite.certAllSuites: 1120 tacks = None 1121 1122 # Prepare a TACK Extension if requested 1123 if clientHello.tack: 1124 tackExt = TackExtension.create(tacks, activationFlags) 1125 else: 1126 tackExt = None 1127 1128 # Prepare other extensions if requested 1129 if settings.useEncryptThenMAC and \ 1130 clientHello.getExtension(ExtensionType.encrypt_then_mac) and \ 1131 cipherSuite not in CipherSuite.streamSuites and \ 1132 cipherSuite not in CipherSuite.aeadSuites: 1133 extensions = [TLSExtension().create(ExtensionType.encrypt_then_mac, 1134 bytearray(0))] 1135 self._recordLayer.encryptThenMAC = True 1136 else: 1137 extensions = None 1138 1139 serverHello = ServerHello() 1140 serverHello.create(self.version, getRandomBytes(32), sessionID, \ 1141 cipherSuite, CertificateType.x509, tackExt, 1142 nextProtos, extensions=extensions) 1143 1144 # Perform the SRP key exchange 1145 clientCertChain = None 1146 if cipherSuite in CipherSuite.srpAllSuites: 1147 for result in self._serverSRPKeyExchange(clientHello, serverHello, 1148 verifierDB, cipherSuite, 1149 privateKey, certChain, 1150 settings): 1151 if result in (0, 1): 1152 yield result 1153 else: break 1154 premasterSecret = result 1155 1156 # Perform a certificate-based key exchange 1157 elif (cipherSuite in CipherSuite.certSuites or 1158 cipherSuite in CipherSuite.dheCertSuites or 1159 cipherSuite in CipherSuite.ecdheCertSuites): 1160 if cipherSuite in CipherSuite.certSuites: 1161 keyExchange = RSAKeyExchange(cipherSuite, 1162 clientHello, 1163 serverHello, 1164 privateKey) 1165 elif cipherSuite in CipherSuite.dheCertSuites: 1166 keyExchange = DHE_RSAKeyExchange(cipherSuite, 1167 clientHello, 1168 serverHello, 1169 privateKey) 1170 elif cipherSuite in CipherSuite.ecdheCertSuites: 1171 acceptedCurves = self._curveNamesToList(settings) 1172 keyExchange = ECDHE_RSAKeyExchange(cipherSuite, 1173 clientHello, 1174 serverHello, 1175 privateKey, 1176 acceptedCurves) 1177 else: 1178 assert(False) 1179 for result in self._serverCertKeyExchange(clientHello, serverHello, 1180 certChain, keyExchange, 1181 reqCert, reqCAs, cipherSuite, 1182 settings): 1183 if result in (0,1): yield result 1184 else: break 1185 (premasterSecret, clientCertChain) = result 1186 1187 # Perform anonymous Diffie Hellman key exchange 1188 elif cipherSuite in CipherSuite.anonSuites: 1189 for result in self._serverAnonKeyExchange(clientHello, serverHello, 1190 cipherSuite, settings): 1191 if result in (0,1): yield result 1192 else: break 1193 premasterSecret = result 1194 1195 else: 1196 assert(False) 1197 1198 # Exchange Finished messages 1199 for result in self._serverFinished(premasterSecret, 1200 clientHello.random, serverHello.random, 1201 cipherSuite, settings.cipherImplementations, 1202 nextProtos): 1203 if result in (0,1): yield result 1204 else: break 1205 masterSecret = result 1206 1207 #Create the session object 1208 self.session = Session() 1209 if cipherSuite in CipherSuite.certAllSuites: 1210 serverCertChain = certChain 1211 else: 1212 serverCertChain = None 1213 srpUsername = None 1214 serverName = None 1215 if clientHello.srp_username: 1216 srpUsername = clientHello.srp_username.decode("utf-8") 1217 if clientHello.server_name: 1218 serverName = clientHello.server_name.decode("utf-8") 1219 self.session.create(masterSecret, serverHello.session_id, cipherSuite, 1220 srpUsername, clientCertChain, serverCertChain, 1221 tackExt, (serverHello.tackExt is not None), 1222 serverName, 1223 encryptThenMAC=self._recordLayer.encryptThenMAC) 1224 1225 #Add the session object to the session cache 1226 if sessionCache and sessionID: 1227 sessionCache[sessionID] = self.session 1228 1229 self._handshakeDone(resumed=False)
1230 1231
1232 - def _serverGetClientHello(self, settings, certChain, verifierDB, 1233 sessionCache, anon):
1234 #Tentatively set version to most-desirable version, so if an error 1235 #occurs parsing the ClientHello, this is what we'll use for the 1236 #error alert 1237 self.version = settings.maxVersion 1238 1239 #Get ClientHello 1240 for result in self._getMsg(ContentType.handshake, 1241 HandshakeType.client_hello): 1242 if result in (0,1): yield result 1243 else: break 1244 clientHello = result 1245 1246 #If client's version is too low, reject it 1247 if clientHello.client_version < settings.minVersion: 1248 self.version = settings.minVersion 1249 for result in self._sendError(\ 1250 AlertDescription.protocol_version, 1251 "Too old version: %s" % str(clientHello.client_version)): 1252 yield result 1253 1254 #If client's version is too high, propose my highest version 1255 elif clientHello.client_version > settings.maxVersion: 1256 self.version = settings.maxVersion 1257 1258 else: 1259 #Set the version to the client's version 1260 self.version = clientHello.client_version 1261 1262 #Detect if the client performed an inappropriate fallback. 1263 if clientHello.client_version < settings.maxVersion and \ 1264 CipherSuite.TLS_FALLBACK_SCSV in clientHello.cipher_suites: 1265 for result in self._sendError(\ 1266 AlertDescription.inappropriate_fallback): 1267 yield result 1268 1269 #Check if there's intersection between supported curves by client and 1270 #server 1271 client_groups = clientHello.getExtension(ExtensionType.supported_groups) 1272 group_intersect = [] 1273 if client_groups is not None: 1274 client_groups = client_groups.groups 1275 if client_groups is None: 1276 client_groups = [] 1277 server_groups = self._curveNamesToList(settings) 1278 group_intersect = [x for x in client_groups if x in server_groups] 1279 1280 #Now that the version is known, limit to only the ciphers available to 1281 #that version and client capabilities. 1282 cipherSuites = [] 1283 if verifierDB: 1284 if certChain: 1285 cipherSuites += \ 1286 CipherSuite.getSrpCertSuites(settings, self.version) 1287 cipherSuites += CipherSuite.getSrpSuites(settings, self.version) 1288 elif certChain: 1289 if group_intersect: 1290 cipherSuites += CipherSuite.getEcdheCertSuites(settings, 1291 self.version) 1292 cipherSuites += CipherSuite.getDheCertSuites(settings, self.version) 1293 cipherSuites += CipherSuite.getCertSuites(settings, self.version) 1294 elif anon: 1295 cipherSuites += CipherSuite.getAnonSuites(settings, self.version) 1296 else: 1297 assert(False) 1298 cipherSuites = CipherSuite.filterForVersion(cipherSuites, 1299 minVersion=self.version, 1300 maxVersion=self.version) 1301 1302 #If resumption was requested and we have a session cache... 1303 if clientHello.session_id and sessionCache: 1304 session = None 1305 1306 #Check in the session cache 1307 if sessionCache and not session: 1308 try: 1309 session = sessionCache[clientHello.session_id] 1310 if not session.resumable: 1311 raise AssertionError() 1312 #Check for consistency with ClientHello 1313 if session.cipherSuite not in cipherSuites: 1314 for result in self._sendError(\ 1315 AlertDescription.handshake_failure): 1316 yield result 1317 if session.cipherSuite not in clientHello.cipher_suites: 1318 for result in self._sendError(\ 1319 AlertDescription.handshake_failure): 1320 yield result 1321 if clientHello.srp_username: 1322 if not session.srpUsername or \ 1323 clientHello.srp_username != bytearray(session.srpUsername, "utf-8"): 1324 for result in self._sendError(\ 1325 AlertDescription.handshake_failure): 1326 yield result 1327 if clientHello.server_name: 1328 if not session.serverName or \ 1329 clientHello.server_name != bytearray(session.serverName, "utf-8"): 1330 for result in self._sendError(\ 1331 AlertDescription.handshake_failure): 1332 yield result 1333 if session.encryptThenMAC and \ 1334 not clientHello.getExtension( 1335 ExtensionType.encrypt_then_mac): 1336 for result in self._sendError(\ 1337 AlertDescription.handshake_failure): 1338 yield result 1339 except KeyError: 1340 pass 1341 1342 #If a session is found.. 1343 if session: 1344 #Send ServerHello 1345 if session.encryptThenMAC: 1346 self._recordLayer.encryptThenMAC = True 1347 mte = TLSExtension().create(ExtensionType.encrypt_then_mac, 1348 bytearray(0)) 1349 extensions = [mte] 1350 else: 1351 extensions = None 1352 serverHello = ServerHello() 1353 serverHello.create(self.version, getRandomBytes(32), 1354 session.sessionID, session.cipherSuite, 1355 CertificateType.x509, None, None, 1356 extensions=extensions) 1357 for result in self._sendMsg(serverHello): 1358 yield result 1359 1360 #Calculate pending connection states 1361 self._calcPendingStates(session.cipherSuite, 1362 session.masterSecret, 1363 clientHello.random, 1364 serverHello.random, 1365 settings.cipherImplementations) 1366 1367 #Exchange ChangeCipherSpec and Finished messages 1368 for result in self._sendFinished(session.masterSecret, 1369 session.cipherSuite): 1370 yield result 1371 for result in self._getFinished(session.masterSecret, 1372 session.cipherSuite): 1373 yield result 1374 1375 #Set the session 1376 self.session = session 1377 1378 yield None # Handshake done! 1379 1380 #Calculate the first cipher suite intersection. 1381 #This is the 'privileged' ciphersuite. We'll use it if we're 1382 #doing a new negotiation. In fact, 1383 #the only time we won't use it is if we're resuming a 1384 #session, in which case we use the ciphersuite from the session. 1385 # 1386 #Given the current ciphersuite ordering, this means we prefer SRP 1387 #over non-SRP. 1388 for cipherSuite in cipherSuites: 1389 if cipherSuite in clientHello.cipher_suites: 1390 break 1391 else: 1392 for result in self._sendError(\ 1393 AlertDescription.handshake_failure, 1394 "No mutual ciphersuite"): 1395 yield result 1396 if cipherSuite in CipherSuite.srpAllSuites and \ 1397 not clientHello.srp_username: 1398 for result in self._sendError(\ 1399 AlertDescription.unknown_psk_identity, 1400 "Client sent a hello, but without the SRP username"): 1401 yield result 1402 1403 #If an RSA suite is chosen, check for certificate type intersection 1404 if cipherSuite in CipherSuite.certAllSuites and CertificateType.x509 \ 1405 not in clientHello.certificate_types: 1406 for result in self._sendError(\ 1407 AlertDescription.handshake_failure, 1408 "the client doesn't support my certificate type"): 1409 yield result 1410 1411 # If resumption was not requested, or 1412 # we have no session cache, or 1413 # the client's session_id was not found in cache: 1414 yield (clientHello, cipherSuite)
1415
1416 - def _serverSRPKeyExchange(self, clientHello, serverHello, verifierDB, 1417 cipherSuite, privateKey, serverCertChain, 1418 settings):
1419 """Perform the server side of SRP key exchange""" 1420 keyExchange = SRPKeyExchange(cipherSuite, 1421 clientHello, 1422 serverHello, 1423 privateKey, 1424 verifierDB) 1425 1426 sigHash = self._pickServerKeyExchangeSig(settings, clientHello) 1427 1428 #Create ServerKeyExchange, signing it if necessary 1429 try: 1430 serverKeyExchange = keyExchange.makeServerKeyExchange(sigHash) 1431 except TLSUnknownPSKIdentity: 1432 for result in self._sendError(\ 1433 AlertDescription.unknown_psk_identity): 1434 yield result 1435 1436 #Send ServerHello[, Certificate], ServerKeyExchange, 1437 #ServerHelloDone 1438 msgs = [] 1439 msgs.append(serverHello) 1440 if cipherSuite in CipherSuite.srpCertSuites: 1441 certificateMsg = Certificate(CertificateType.x509) 1442 certificateMsg.create(serverCertChain) 1443 msgs.append(certificateMsg) 1444 msgs.append(serverKeyExchange) 1445 msgs.append(ServerHelloDone()) 1446 for result in self._sendMsgs(msgs): 1447 yield result 1448 1449 #Get and check ClientKeyExchange 1450 for result in self._getMsg(ContentType.handshake, 1451 HandshakeType.client_key_exchange, 1452 cipherSuite): 1453 if result in (0,1): yield result 1454 else: break 1455 try: 1456 premasterSecret = keyExchange.processClientKeyExchange(result) 1457 except TLSIllegalParameterException: 1458 for result in self._sendError(AlertDescription.illegal_parameter, 1459 "Suspicious A value"): 1460 yield result 1461 1462 yield premasterSecret
1463
1464 - def _serverCertKeyExchange(self, clientHello, serverHello, 1465 serverCertChain, keyExchange, 1466 reqCert, reqCAs, cipherSuite, 1467 settings):
1468 #Send ServerHello, Certificate[, ServerKeyExchange] 1469 #[, CertificateRequest], ServerHelloDone 1470 msgs = [] 1471 1472 # If we verify a client cert chain, return it 1473 clientCertChain = None 1474 1475 msgs.append(serverHello) 1476 msgs.append(Certificate(CertificateType.x509).create(serverCertChain)) 1477 sigHashAlg = self._pickServerKeyExchangeSig(settings, clientHello) 1478 serverKeyExchange = keyExchange.makeServerKeyExchange(sigHashAlg) 1479 if serverKeyExchange is not None: 1480 msgs.append(serverKeyExchange) 1481 if reqCert: 1482 certificateRequest = CertificateRequest(self.version) 1483 if not reqCAs: 1484 reqCAs = [] 1485 validSigAlgs = self._sigHashesToList(settings) 1486 certificateRequest.create([ClientCertificateType.rsa_sign], 1487 reqCAs, 1488 validSigAlgs) 1489 msgs.append(certificateRequest) 1490 msgs.append(ServerHelloDone()) 1491 for result in self._sendMsgs(msgs): 1492 yield result 1493 1494 #Get [Certificate,] (if was requested) 1495 if reqCert: 1496 if self.version == (3,0): 1497 for result in self._getMsg((ContentType.handshake, 1498 ContentType.alert), 1499 HandshakeType.certificate, 1500 CertificateType.x509): 1501 if result in (0,1): yield result 1502 else: break 1503 msg = result 1504 1505 if isinstance(msg, Alert): 1506 #If it's not a no_certificate alert, re-raise 1507 alert = msg 1508 if alert.description != \ 1509 AlertDescription.no_certificate: 1510 self._shutdown(False) 1511 raise TLSRemoteAlert(alert) 1512 elif isinstance(msg, Certificate): 1513 clientCertificate = msg 1514 if clientCertificate.certChain and \ 1515 clientCertificate.certChain.getNumCerts()!=0: 1516 clientCertChain = clientCertificate.certChain 1517 else: 1518 raise AssertionError() 1519 elif self.version in ((3,1), (3,2), (3,3)): 1520 for result in self._getMsg(ContentType.handshake, 1521 HandshakeType.certificate, 1522 CertificateType.x509): 1523 if result in (0,1): yield result 1524 else: break 1525 clientCertificate = result 1526 if clientCertificate.certChain and \ 1527 clientCertificate.certChain.getNumCerts()!=0: 1528 clientCertChain = clientCertificate.certChain 1529 else: 1530 raise AssertionError() 1531 1532 #Get ClientKeyExchange 1533 for result in self._getMsg(ContentType.handshake, 1534 HandshakeType.client_key_exchange, 1535 cipherSuite): 1536 if result in (0,1): yield result 1537 else: break 1538 clientKeyExchange = result 1539 1540 #Process ClientKeyExchange 1541 try: 1542 premasterSecret = \ 1543 keyExchange.processClientKeyExchange(clientKeyExchange) 1544 except TLSLocalAlert as alert: 1545 for result in self._sendError(alert.description, alert.message): 1546 yield result 1547 1548 #Get and check CertificateVerify, if relevant 1549 if clientCertChain: 1550 handshakeHash = self._handshake_hash.copy() 1551 for result in self._getMsg(ContentType.handshake, 1552 HandshakeType.certificate_verify): 1553 if result in (0, 1): 1554 yield result 1555 else: break 1556 certificateVerify = result 1557 signatureAlgorithm = None 1558 if self.version == (3, 3): 1559 validSigAlgs = self._sigHashesToList(settings) 1560 if certificateVerify.signatureAlgorithm not in validSigAlgs: 1561 for result in self._sendError(\ 1562 AlertDescription.decryption_failed, 1563 "Invalid signature on Certificate Verify"): 1564 yield result 1565 signatureAlgorithm = certificateVerify.signatureAlgorithm 1566 1567 verifyBytes = KeyExchange.calcVerifyBytes(self.version, 1568 handshakeHash, 1569 signatureAlgorithm, 1570 premasterSecret, 1571 clientHello.random, 1572 serverHello.random) 1573 publicKey = clientCertChain.getEndEntityPublicKey() 1574 if len(publicKey) < settings.minKeySize: 1575 for result in self._sendError(\ 1576 AlertDescription.handshake_failure, 1577 "Client's public key too small: %d" % len(publicKey)): 1578 yield result 1579 1580 if len(publicKey) > settings.maxKeySize: 1581 for result in self._sendError(\ 1582 AlertDescription.handshake_failure, 1583 "Client's public key too large: %d" % len(publicKey)): 1584 yield result 1585 1586 if not publicKey.verify(certificateVerify.signature, verifyBytes): 1587 for result in self._sendError(\ 1588 AlertDescription.decrypt_error, 1589 "Signature failed to verify"): 1590 yield result 1591 yield (premasterSecret, clientCertChain)
1592 1593
1594 - def _serverAnonKeyExchange(self, clientHello, serverHello, cipherSuite, 1595 settings):
1596 # Calculate DH p, g, Xs, Ys 1597 # TODO make configurable 1598 dh_g, dh_p = goodGroupParameters[2] 1599 dh_Xs = bytesToNumber(getRandomBytes(32)) 1600 dh_Ys = powMod(dh_g, dh_Xs, dh_p) 1601 1602 #Create ServerKeyExchange 1603 serverKeyExchange = ServerKeyExchange(cipherSuite, self.version) 1604 serverKeyExchange.createDH(dh_p, dh_g, dh_Ys) 1605 1606 #Send ServerHello[, Certificate], ServerKeyExchange, 1607 #ServerHelloDone 1608 msgs = [] 1609 msgs.append(serverHello) 1610 msgs.append(serverKeyExchange) 1611 msgs.append(ServerHelloDone()) 1612 for result in self._sendMsgs(msgs): 1613 yield result 1614 1615 #Get and check ClientKeyExchange 1616 for result in self._getMsg(ContentType.handshake, 1617 HandshakeType.client_key_exchange, 1618 cipherSuite): 1619 if result in (0,1): 1620 yield result 1621 else: 1622 break 1623 clientKeyExchange = result 1624 dh_Yc = clientKeyExchange.dh_Yc 1625 1626 if dh_Yc % dh_p == 0: 1627 for result in self._sendError(AlertDescription.illegal_parameter, 1628 "Suspicious dh_Yc value"): 1629 yield result 1630 assert(False) # Just to ensure we don't fall through somehow 1631 1632 #Calculate premaster secre 1633 S = powMod(dh_Yc,dh_Xs,dh_p) 1634 premasterSecret = numberToByteArray(S) 1635 1636 yield premasterSecret
1637 1638
1639 - def _serverFinished(self, premasterSecret, clientRandom, serverRandom, 1640 cipherSuite, cipherImplementations, nextProtos):
1641 masterSecret = calcMasterSecret(self.version, 1642 cipherSuite, 1643 premasterSecret, 1644 clientRandom, 1645 serverRandom) 1646 1647 #Calculate pending connection states 1648 self._calcPendingStates(cipherSuite, masterSecret, 1649 clientRandom, serverRandom, 1650 cipherImplementations) 1651 1652 #Exchange ChangeCipherSpec and Finished messages 1653 for result in self._getFinished(masterSecret, 1654 cipherSuite, 1655 expect_next_protocol=nextProtos is not None): 1656 yield result 1657 1658 for result in self._sendFinished(masterSecret, cipherSuite): 1659 yield result 1660 1661 yield masterSecret
1662 1663 1664 #********************************************************* 1665 # Shared Handshake Functions 1666 #********************************************************* 1667 1668
1669 - def _sendFinished(self, masterSecret, cipherSuite=None, nextProto=None):
1670 #Send ChangeCipherSpec 1671 for result in self._sendMsg(ChangeCipherSpec()): 1672 yield result 1673 1674 #Switch to pending write state 1675 self._changeWriteState() 1676 1677 if nextProto is not None: 1678 nextProtoMsg = NextProtocol().create(nextProto) 1679 for result in self._sendMsg(nextProtoMsg): 1680 yield result 1681 1682 #Calculate verification data 1683 verifyData = calcFinished(self.version, 1684 masterSecret, 1685 cipherSuite, 1686 self._handshake_hash, 1687 self._client) 1688 if self.fault == Fault.badFinished: 1689 verifyData[0] = (verifyData[0]+1)%256 1690 1691 #Send Finished message under new state 1692 finished = Finished(self.version).create(verifyData) 1693 for result in self._sendMsg(finished): 1694 yield result
1695
1696 - def _getFinished(self, masterSecret, cipherSuite=None, 1697 expect_next_protocol=False, nextProto=None):
1698 #Get and check ChangeCipherSpec 1699 for result in self._getMsg(ContentType.change_cipher_spec): 1700 if result in (0,1): 1701 yield result 1702 changeCipherSpec = result 1703 1704 if changeCipherSpec.type != 1: 1705 for result in self._sendError(AlertDescription.illegal_parameter, 1706 "ChangeCipherSpec type incorrect"): 1707 yield result 1708 1709 #Switch to pending read state 1710 self._changeReadState() 1711 1712 #Server Finish - Are we waiting for a next protocol echo? 1713 if expect_next_protocol: 1714 for result in self._getMsg(ContentType.handshake, HandshakeType.next_protocol): 1715 if result in (0,1): 1716 yield result 1717 if result is None: 1718 for result in self._sendError(AlertDescription.unexpected_message, 1719 "Didn't get NextProtocol message"): 1720 yield result 1721 1722 self.next_proto = result.next_proto 1723 else: 1724 self.next_proto = None 1725 1726 #Client Finish - Only set the next_protocol selected in the connection 1727 if nextProto: 1728 self.next_proto = nextProto 1729 1730 #Calculate verification data 1731 verifyData = calcFinished(self.version, 1732 masterSecret, 1733 cipherSuite, 1734 self._handshake_hash, 1735 not self._client) 1736 1737 #Get and check Finished message under new state 1738 for result in self._getMsg(ContentType.handshake, 1739 HandshakeType.finished): 1740 if result in (0,1): 1741 yield result 1742 finished = result 1743 if finished.verify_data != verifyData: 1744 for result in self._sendError(AlertDescription.decrypt_error, 1745 "Finished message is incorrect"): 1746 yield result
1747
1748 - def _handshakeWrapperAsync(self, handshaker, checker):
1749 try: 1750 for result in handshaker: 1751 yield result 1752 if checker: 1753 try: 1754 checker(self) 1755 except TLSAuthenticationError: 1756 alert = Alert().create(AlertDescription.close_notify, 1757 AlertLevel.fatal) 1758 for result in self._sendMsg(alert): 1759 yield result 1760 raise 1761 except GeneratorExit: 1762 raise 1763 except TLSAlert as alert: 1764 if not self.fault: 1765 raise 1766 if alert.description not in Fault.faultAlerts[self.fault]: 1767 raise TLSFaultError(str(alert)) 1768 else: 1769 pass 1770 except: 1771 self._shutdown(False) 1772 raise
1773 1774 @staticmethod
1775 - def _pickServerKeyExchangeSig(settings, clientHello):
1776 """Pick a hash that matches most closely the supported ones""" 1777 hashAndAlgsExt = clientHello.getExtension(\ 1778 ExtensionType.signature_algorithms) 1779 1780 if hashAndAlgsExt is None or hashAndAlgsExt.sigalgs is None: 1781 # RFC 5246 states that if there are no hashes advertised, 1782 # sha1 should be picked 1783 return "sha1" 1784 1785 rsaHashes = [alg[0] for alg in hashAndAlgsExt.sigalgs 1786 if alg[1] == SignatureAlgorithm.rsa] 1787 for hashName in settings.rsaSigHashes: 1788 hashID = getattr(HashAlgorithm, hashName) 1789 if hashID in rsaHashes: 1790 return hashName 1791 1792 # if none match, default to sha1 1793 return "sha1"
1794 1795 @staticmethod
1796 - def _sigHashesToList(settings):
1797 """Convert list of valid signature hashes to array of tuples""" 1798 sigAlgs = [] 1799 for hashName in settings.rsaSigHashes: 1800 sigAlgs.append((getattr(HashAlgorithm, hashName), 1801 SignatureAlgorithm.rsa)) 1802 return sigAlgs
1803 1804 @staticmethod
1805 - def _curveNamesToList(settings):
1806 """Convert list of acceptable curves to array identifiers""" 1807 return [getattr(GroupName, val) for val in settings.eccCurves]
1808