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