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