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