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 elif self.version == (3,3): 864 verifyBytes = self._handshake_sha256.digest() 865 if self.fault == Fault.badVerifyMessage: 866 verifyBytes[0] = ((verifyBytes[0]+1) % 256) 867 signedBytes = privateKey.sign(verifyBytes) 868 certificateVerify = CertificateVerify() 869 certificateVerify.create(signedBytes) 870 for result in self._sendMsg(certificateVerify): 871 yield result 872 yield (premasterSecret, serverCertChain, clientCertChain, tackExt)
873
874 - def _clientAnonKeyExchange(self, settings, cipherSuite, clientRandom, 875 serverRandom):
876 for result in self._getMsg(ContentType.handshake, 877 HandshakeType.server_key_exchange, cipherSuite): 878 if result in (0,1): yield result 879 else: break 880 serverKeyExchange = result 881 882 for result in self._getMsg(ContentType.handshake, 883 HandshakeType.server_hello_done): 884 if result in (0,1): yield result 885 else: break 886 serverHelloDone = result 887 888 #calculate Yc 889 dh_p = serverKeyExchange.dh_p 890 dh_g = serverKeyExchange.dh_g 891 dh_Xc = bytesToNumber(getRandomBytes(32)) 892 dh_Ys = serverKeyExchange.dh_Ys 893 dh_Yc = powMod(dh_g, dh_Xc, dh_p) 894 895 #Send ClientKeyExchange 896 for result in self._sendMsg(\ 897 ClientKeyExchange(cipherSuite, self.version).createDH(dh_Yc)): 898 yield result 899 900 #Calculate premaster secret 901 S = powMod(dh_Ys, dh_Xc, dh_p) 902 premasterSecret = numberToByteArray(S) 903 904 yield (premasterSecret, None, None)
905
906 - def _clientFinished(self, premasterSecret, clientRandom, serverRandom, 907 cipherSuite, cipherImplementations, nextProto):
908 909 masterSecret = calcMasterSecret(self.version, premasterSecret, 910 clientRandom, serverRandom) 911 self._calcPendingStates(cipherSuite, masterSecret, 912 clientRandom, serverRandom, 913 cipherImplementations) 914 915 #Exchange ChangeCipherSpec and Finished messages 916 for result in self._sendFinished(masterSecret, nextProto): 917 yield result 918 for result in self._getFinished(masterSecret, nextProto=nextProto): 919 yield result 920 yield masterSecret
921
922 - def _clientGetKeyFromChain(self, certificate, settings, tackExt=None):
923 #Get and check cert chain from the Certificate message 924 certChain = certificate.certChain 925 if not certChain or certChain.getNumCerts() == 0: 926 for result in self._sendError(AlertDescription.illegal_parameter, 927 "Other party sent a Certificate message without "\ 928 "certificates"): 929 yield result 930 931 #Get and check public key from the cert chain 932 publicKey = certChain.getEndEntityPublicKey() 933 if len(publicKey) < settings.minKeySize: 934 for result in self._sendError(AlertDescription.handshake_failure, 935 "Other party's public key too small: %d" % len(publicKey)): 936 yield result 937 if len(publicKey) > settings.maxKeySize: 938 for result in self._sendError(AlertDescription.handshake_failure, 939 "Other party's public key too large: %d" % len(publicKey)): 940 yield result 941 942 # If there's no TLS Extension, look for a TACK cert 943 if tackpyLoaded: 944 if not tackExt: 945 tackExt = certChain.getTackExt() 946 947 # If there's a TACK (whether via TLS or TACK Cert), check that it 948 # matches the cert chain 949 if tackExt and tackExt.tacks: 950 for tack in tackExt.tacks: 951 if not certChain.checkTack(tack): 952 for result in self._sendError( 953 AlertDescription.illegal_parameter, 954 "Other party's TACK doesn't match their public key"): 955 yield result 956 957 yield publicKey, certChain, tackExt
958 959 960 #********************************************************* 961 # Server Handshake Functions 962 #********************************************************* 963 964
965 - def handshakeServer(self, verifierDB=None, 966 certChain=None, privateKey=None, reqCert=False, 967 sessionCache=None, settings=None, checker=None, 968 reqCAs = None, 969 tacks=None, activationFlags=0, 970 nextProtos=None, anon=False):
971 """Perform a handshake in the role of server. 972 973 This function performs an SSL or TLS handshake. Depending on 974 the arguments and the behavior of the client, this function can 975 perform an SRP, or certificate-based handshake. It 976 can also perform a combined SRP and server-certificate 977 handshake. 978 979 Like any handshake function, this can be called on a closed 980 TLS connection, or on a TLS connection that is already open. 981 If called on an open connection it performs a re-handshake. 982 This function does not send a Hello Request message before 983 performing the handshake, so if re-handshaking is required, 984 the server must signal the client to begin the re-handshake 985 through some other means. 986 987 If the function completes without raising an exception, the 988 TLS connection will be open and available for data transfer. 989 990 If an exception is raised, the connection will have been 991 automatically closed (if it was ever open). 992 993 @type verifierDB: L{tlslite.verifierdb.VerifierDB} 994 @param verifierDB: A database of SRP password verifiers 995 associated with usernames. If the client performs an SRP 996 handshake, the session's srpUsername attribute will be set. 997 998 @type certChain: L{tlslite.x509certchain.X509CertChain} 999 @param certChain: The certificate chain to be used if the 1000 client requests server certificate authentication. 1001 1002 @type privateKey: L{tlslite.utils.rsakey.RSAKey} 1003 @param privateKey: The private key to be used if the client 1004 requests server certificate authentication. 1005 1006 @type reqCert: bool 1007 @param reqCert: Whether to request client certificate 1008 authentication. This only applies if the client chooses server 1009 certificate authentication; if the client chooses SRP 1010 authentication, this will be ignored. If the client 1011 performs a client certificate authentication, the sessions's 1012 clientCertChain attribute will be set. 1013 1014 @type sessionCache: L{tlslite.sessioncache.SessionCache} 1015 @param sessionCache: An in-memory cache of resumable sessions. 1016 The client can resume sessions from this cache. Alternatively, 1017 if the client performs a full handshake, a new session will be 1018 added to the cache. 1019 1020 @type settings: L{tlslite.handshakesettings.HandshakeSettings} 1021 @param settings: Various settings which can be used to control 1022 the ciphersuites and SSL/TLS version chosen by the server. 1023 1024 @type checker: L{tlslite.checker.Checker} 1025 @param checker: A Checker instance. This instance will be 1026 invoked to examine the other party's authentication 1027 credentials, if the handshake completes succesfully. 1028 1029 @type reqCAs: list of L{bytearray} of unsigned bytes 1030 @param reqCAs: A collection of DER-encoded DistinguishedNames that 1031 will be sent along with a certificate request. This does not affect 1032 verification. 1033 1034 @type nextProtos: list of strings. 1035 @param nextProtos: A list of upper layer protocols to expose to the 1036 clients through the Next-Protocol Negotiation Extension, 1037 if they support it. 1038 1039 @raise socket.error: If a socket error occurs. 1040 @raise tlslite.errors.TLSAbruptCloseError: If the socket is closed 1041 without a preceding alert. 1042 @raise tlslite.errors.TLSAlert: If a TLS alert is signalled. 1043 @raise tlslite.errors.TLSAuthenticationError: If the checker 1044 doesn't like the other party's authentication credentials. 1045 """ 1046 for result in self.handshakeServerAsync(verifierDB, 1047 certChain, privateKey, reqCert, sessionCache, settings, 1048 checker, reqCAs, 1049 tacks=tacks, activationFlags=activationFlags, 1050 nextProtos=nextProtos, anon=anon): 1051 pass
1052 1053
1054 - def handshakeServerAsync(self, verifierDB=None, 1055 certChain=None, privateKey=None, reqCert=False, 1056 sessionCache=None, settings=None, checker=None, 1057 reqCAs=None, 1058 tacks=None, activationFlags=0, 1059 nextProtos=None, anon=False 1060 ):
1061 """Start a server handshake operation on the TLS connection. 1062 1063 This function returns a generator which behaves similarly to 1064 handshakeServer(). Successive invocations of the generator 1065 will return 0 if it is waiting to read from the socket, 1 if it is 1066 waiting to write to the socket, or it will raise StopIteration 1067 if the handshake operation is complete. 1068 1069 @rtype: iterable 1070 @return: A generator; see above for details. 1071 """ 1072 handshaker = self._handshakeServerAsyncHelper(\ 1073 verifierDB=verifierDB, certChain=certChain, 1074 privateKey=privateKey, reqCert=reqCert, 1075 sessionCache=sessionCache, settings=settings, 1076 reqCAs=reqCAs, 1077 tacks=tacks, activationFlags=activationFlags, 1078 nextProtos=nextProtos, anon=anon) 1079 for result in self._handshakeWrapperAsync(handshaker, checker): 1080 yield result
1081 1082
1083 - def _handshakeServerAsyncHelper(self, verifierDB, 1084 certChain, privateKey, reqCert, sessionCache, 1085 settings, reqCAs, 1086 tacks, activationFlags, 1087 nextProtos, anon):
1088 1089 self._handshakeStart(client=False) 1090 1091 if (not verifierDB) and (not certChain) and not anon: 1092 raise ValueError("Caller passed no authentication credentials") 1093 if certChain and not privateKey: 1094 raise ValueError("Caller passed a certChain but no privateKey") 1095 if privateKey and not certChain: 1096 raise ValueError("Caller passed a privateKey but no certChain") 1097 if reqCAs and not reqCert: 1098 raise ValueError("Caller passed reqCAs but not reqCert") 1099 if certChain and not isinstance(certChain, X509CertChain): 1100 raise ValueError("Unrecognized certificate type") 1101 if activationFlags and not tacks: 1102 raise ValueError("Nonzero activationFlags requires tacks") 1103 if tacks: 1104 if not tackpyLoaded: 1105 raise ValueError("tackpy is not loaded") 1106 if not settings or not settings.useExperimentalTackExtension: 1107 raise ValueError("useExperimentalTackExtension not enabled") 1108 1109 if not settings: 1110 settings = HandshakeSettings() 1111 settings = settings._filter() 1112 1113 # OK Start exchanging messages 1114 # ****************************** 1115 1116 # Handle ClientHello and resumption 1117 for result in self._serverGetClientHello(settings, certChain,\ 1118 verifierDB, sessionCache, 1119 anon): 1120 if result in (0,1): yield result 1121 elif result == None: 1122 self._handshakeDone(resumed=True) 1123 return # Handshake was resumed, we're done 1124 else: break 1125 (clientHello, cipherSuite) = result 1126 1127 #If not a resumption... 1128 1129 # Create the ServerHello message 1130 if sessionCache: 1131 sessionID = getRandomBytes(32) 1132 else: 1133 sessionID = bytearray(0) 1134 1135 if not clientHello.supports_npn: 1136 nextProtos = None 1137 1138 # If not doing a certificate-based suite, discard the TACK 1139 if not cipherSuite in CipherSuite.certAllSuites: 1140 tacks = None 1141 1142 # Prepare a TACK Extension if requested 1143 if clientHello.tack: 1144 tackExt = TackExtension.create(tacks, activationFlags) 1145 else: 1146 tackExt = None 1147 serverHello = ServerHello() 1148 serverHello.create(self.version, getRandomBytes(32), sessionID, \ 1149 cipherSuite, CertificateType.x509, tackExt, 1150 nextProtos) 1151 1152 # Perform the SRP key exchange 1153 clientCertChain = None 1154 if cipherSuite in CipherSuite.srpAllSuites: 1155 for result in self._serverSRPKeyExchange(clientHello, serverHello, 1156 verifierDB, cipherSuite, 1157 privateKey, certChain): 1158 if result in (0,1): yield result 1159 else: break 1160 premasterSecret = result 1161 1162 # Perform the RSA key exchange 1163 elif cipherSuite in CipherSuite.certSuites: 1164 for result in self._serverCertKeyExchange(clientHello, serverHello, 1165 certChain, privateKey, 1166 reqCert, reqCAs, cipherSuite, 1167 settings): 1168 if result in (0,1): yield result 1169 else: break 1170 (premasterSecret, clientCertChain) = result 1171 1172 # Perform anonymous Diffie Hellman key exchange 1173 elif cipherSuite in CipherSuite.anonSuites: 1174 for result in self._serverAnonKeyExchange(clientHello, serverHello, 1175 cipherSuite, settings): 1176 if result in (0,1): yield result 1177 else: break 1178 premasterSecret = result 1179 1180 else: 1181 assert(False) 1182 1183 # Exchange Finished messages 1184 for result in self._serverFinished(premasterSecret, 1185 clientHello.random, serverHello.random, 1186 cipherSuite, settings.cipherImplementations, 1187 nextProtos): 1188 if result in (0,1): yield result 1189 else: break 1190 masterSecret = result 1191 1192 #Create the session object 1193 self.session = Session() 1194 if cipherSuite in CipherSuite.certAllSuites: 1195 serverCertChain = certChain 1196 else: 1197 serverCertChain = None 1198 srpUsername = None 1199 serverName = None 1200 if clientHello.srp_username: 1201 srpUsername = clientHello.srp_username.decode("utf-8") 1202 if clientHello.server_name: 1203 serverName = clientHello.server_name.decode("utf-8") 1204 self.session.create(masterSecret, serverHello.session_id, cipherSuite, 1205 srpUsername, clientCertChain, serverCertChain, 1206 tackExt, serverHello.tackExt!=None, serverName) 1207 1208 #Add the session object to the session cache 1209 if sessionCache and sessionID: 1210 sessionCache[sessionID] = self.session 1211 1212 self._handshakeDone(resumed=False)
1213 1214
1215 - def _serverGetClientHello(self, settings, certChain, verifierDB, 1216 sessionCache, anon):
1217 #Initialize acceptable cipher suites 1218 cipherSuites = [] 1219 if verifierDB: 1220 if certChain: 1221 cipherSuites += \ 1222 CipherSuite.getSrpCertSuites(settings) 1223 cipherSuites += CipherSuite.getSrpSuites(settings) 1224 elif certChain: 1225 cipherSuites += CipherSuite.getCertSuites(settings) 1226 elif anon: 1227 cipherSuites += CipherSuite.getAnonSuites(settings) 1228 else: 1229 assert(False) 1230 1231 #Tentatively set version to most-desirable version, so if an error 1232 #occurs parsing the ClientHello, this is what we'll use for the 1233 #error alert 1234 self.version = settings.maxVersion 1235 1236 #Get ClientHello 1237 for result in self._getMsg(ContentType.handshake, 1238 HandshakeType.client_hello): 1239 if result in (0,1): yield result 1240 else: break 1241 clientHello = result 1242 1243 #If client's version is too low, reject it 1244 if clientHello.client_version < settings.minVersion: 1245 self.version = settings.minVersion 1246 for result in self._sendError(\ 1247 AlertDescription.protocol_version, 1248 "Too old version: %s" % str(clientHello.client_version)): 1249 yield result 1250 1251 #If client's version is too high, propose my highest version 1252 elif clientHello.client_version > settings.maxVersion: 1253 self.version = settings.maxVersion 1254 1255 else: 1256 #Set the version to the client's version 1257 self.version = clientHello.client_version 1258 1259 #If resumption was requested and we have a session cache... 1260 if clientHello.session_id and sessionCache: 1261 session = None 1262 1263 #Check in the session cache 1264 if sessionCache and not session: 1265 try: 1266 session = sessionCache[clientHello.session_id] 1267 if not session.resumable: 1268 raise AssertionError() 1269 #Check for consistency with ClientHello 1270 if session.cipherSuite not in cipherSuites: 1271 for result in self._sendError(\ 1272 AlertDescription.handshake_failure): 1273 yield result 1274 if session.cipherSuite not in clientHello.cipher_suites: 1275 for result in self._sendError(\ 1276 AlertDescription.handshake_failure): 1277 yield result 1278 if clientHello.srp_username: 1279 if not session.srpUsername or \ 1280 clientHello.srp_username != bytearray(session.srpUsername, "utf-8"): 1281 for result in self._sendError(\ 1282 AlertDescription.handshake_failure): 1283 yield result 1284 if clientHello.server_name: 1285 if not session.serverName or \ 1286 clientHello.server_name != bytearray(session.serverName, "utf-8"): 1287 for result in self._sendError(\ 1288 AlertDescription.handshake_failure): 1289 yield result 1290 except KeyError: 1291 pass 1292 1293 #If a session is found.. 1294 if session: 1295 #Send ServerHello 1296 serverHello = ServerHello() 1297 serverHello.create(self.version, getRandomBytes(32), 1298 session.sessionID, session.cipherSuite, 1299 CertificateType.x509, None, None) 1300 for result in self._sendMsg(serverHello): 1301 yield result 1302 1303 #From here on, the client's messages must have right version 1304 self._versionCheck = True 1305 1306 #Calculate pending connection states 1307 self._calcPendingStates(session.cipherSuite, 1308 session.masterSecret, 1309 clientHello.random, 1310 serverHello.random, 1311 settings.cipherImplementations) 1312 1313 #Exchange ChangeCipherSpec and Finished messages 1314 for result in self._sendFinished(session.masterSecret): 1315 yield result 1316 for result in self._getFinished(session.masterSecret): 1317 yield result 1318 1319 #Set the session 1320 self.session = session 1321 1322 yield None # Handshake done! 1323 1324 #Calculate the first cipher suite intersection. 1325 #This is the 'privileged' ciphersuite. We'll use it if we're 1326 #doing a new negotiation. In fact, 1327 #the only time we won't use it is if we're resuming a 1328 #session, in which case we use the ciphersuite from the session. 1329 # 1330 #Given the current ciphersuite ordering, this means we prefer SRP 1331 #over non-SRP. 1332 for cipherSuite in cipherSuites: 1333 if cipherSuite in clientHello.cipher_suites: 1334 break 1335 else: 1336 for result in self._sendError(\ 1337 AlertDescription.handshake_failure, 1338 "No mutual ciphersuite"): 1339 yield result 1340 if cipherSuite in CipherSuite.srpAllSuites and \ 1341 not clientHello.srp_username: 1342 for result in self._sendError(\ 1343 AlertDescription.unknown_psk_identity, 1344 "Client sent a hello, but without the SRP username"): 1345 yield result 1346 1347 #If an RSA suite is chosen, check for certificate type intersection 1348 if cipherSuite in CipherSuite.certAllSuites and CertificateType.x509 \ 1349 not in clientHello.certificate_types: 1350 for result in self._sendError(\ 1351 AlertDescription.handshake_failure, 1352 "the client doesn't support my certificate type"): 1353 yield result 1354 1355 # If resumption was not requested, or 1356 # we have no session cache, or 1357 # the client's session_id was not found in cache: 1358 yield (clientHello, cipherSuite)
1359
1360 - def _serverSRPKeyExchange(self, clientHello, serverHello, verifierDB, 1361 cipherSuite, privateKey, serverCertChain):
1362 1363 srpUsername = clientHello.srp_username.decode("utf-8") 1364 self.allegedSrpUsername = srpUsername 1365 #Get parameters from username 1366 try: 1367 entry = verifierDB[srpUsername] 1368 except KeyError: 1369 for result in self._sendError(\ 1370 AlertDescription.unknown_psk_identity): 1371 yield result 1372 (N, g, s, v) = entry 1373 1374 #Calculate server's ephemeral DH values (b, B) 1375 b = bytesToNumber(getRandomBytes(32)) 1376 k = makeK(N, g) 1377 B = (powMod(g, b, N) + (k*v)) % N 1378 1379 #Create ServerKeyExchange, signing it if necessary 1380 serverKeyExchange = ServerKeyExchange(cipherSuite) 1381 serverKeyExchange.createSRP(N, g, s, B) 1382 if cipherSuite in CipherSuite.srpCertSuites: 1383 hashBytes = serverKeyExchange.hash(clientHello.random, 1384 serverHello.random) 1385 serverKeyExchange.signature = privateKey.sign(hashBytes) 1386 1387 #Send ServerHello[, Certificate], ServerKeyExchange, 1388 #ServerHelloDone 1389 msgs = [] 1390 msgs.append(serverHello) 1391 if cipherSuite in CipherSuite.srpCertSuites: 1392 certificateMsg = Certificate(CertificateType.x509) 1393 certificateMsg.create(serverCertChain) 1394 msgs.append(certificateMsg) 1395 msgs.append(serverKeyExchange) 1396 msgs.append(ServerHelloDone()) 1397 for result in self._sendMsgs(msgs): 1398 yield result 1399 1400 #From here on, the client's messages must have the right version 1401 self._versionCheck = True 1402 1403 #Get and check ClientKeyExchange 1404 for result in self._getMsg(ContentType.handshake, 1405 HandshakeType.client_key_exchange, 1406 cipherSuite): 1407 if result in (0,1): yield result 1408 else: break 1409 clientKeyExchange = result 1410 A = clientKeyExchange.srp_A 1411 if A % N == 0: 1412 for result in self._sendError(AlertDescription.illegal_parameter, 1413 "Suspicious A value"): 1414 yield result 1415 assert(False) # Just to ensure we don't fall through somehow 1416 1417 #Calculate u 1418 u = makeU(N, A, B) 1419 1420 #Calculate premaster secret 1421 S = powMod((A * powMod(v,u,N)) % N, b, N) 1422 premasterSecret = numberToByteArray(S) 1423 1424 yield premasterSecret
1425 1426
1427 - def _serverCertKeyExchange(self, clientHello, serverHello, 1428 serverCertChain, privateKey, 1429 reqCert, reqCAs, cipherSuite, 1430 settings):
1431 #Send ServerHello, Certificate[, CertificateRequest], 1432 #ServerHelloDone 1433 msgs = [] 1434 1435 # If we verify a client cert chain, return it 1436 clientCertChain = None 1437 1438 msgs.append(serverHello) 1439 msgs.append(Certificate(CertificateType.x509).create(serverCertChain)) 1440 if reqCert and reqCAs: 1441 msgs.append(CertificateRequest().create(\ 1442 [ClientCertificateType.rsa_sign], reqCAs)) 1443 elif reqCert: 1444 msgs.append(CertificateRequest(self.version)) 1445 msgs.append(ServerHelloDone()) 1446 for result in self._sendMsgs(msgs): 1447 yield result 1448 1449 #From here on, the client's messages must have the right version 1450 self._versionCheck = True 1451 1452 #Get [Certificate,] (if was requested) 1453 if reqCert: 1454 if self.version == (3,0): 1455 for result in self._getMsg((ContentType.handshake, 1456 ContentType.alert), 1457 HandshakeType.certificate, 1458 CertificateType.x509): 1459 if result in (0,1): yield result 1460 else: break 1461 msg = result 1462 1463 if isinstance(msg, Alert): 1464 #If it's not a no_certificate alert, re-raise 1465 alert = msg 1466 if alert.description != \ 1467 AlertDescription.no_certificate: 1468 self._shutdown(False) 1469 raise TLSRemoteAlert(alert) 1470 elif isinstance(msg, Certificate): 1471 clientCertificate = msg 1472 if clientCertificate.certChain and \ 1473 clientCertificate.certChain.getNumCerts()!=0: 1474 clientCertChain = clientCertificate.certChain 1475 else: 1476 raise AssertionError() 1477 elif self.version in ((3,1), (3,2), (3,3)): 1478 for result in self._getMsg(ContentType.handshake, 1479 HandshakeType.certificate, 1480 CertificateType.x509): 1481 if result in (0,1): yield result 1482 else: break 1483 clientCertificate = result 1484 if clientCertificate.certChain and \ 1485 clientCertificate.certChain.getNumCerts()!=0: 1486 clientCertChain = clientCertificate.certChain 1487 else: 1488 raise AssertionError() 1489 1490 #Get ClientKeyExchange 1491 for result in self._getMsg(ContentType.handshake, 1492 HandshakeType.client_key_exchange, 1493 cipherSuite): 1494 if result in (0,1): yield result 1495 else: break 1496 clientKeyExchange = result 1497 1498 #Decrypt ClientKeyExchange 1499 premasterSecret = privateKey.decrypt(\ 1500 clientKeyExchange.encryptedPreMasterSecret) 1501 1502 # On decryption failure randomize premaster secret to avoid 1503 # Bleichenbacher's "million message" attack 1504 randomPreMasterSecret = getRandomBytes(48) 1505 versionCheck = (premasterSecret[0], premasterSecret[1]) 1506 if not premasterSecret: 1507 premasterSecret = randomPreMasterSecret 1508 elif len(premasterSecret)!=48: 1509 premasterSecret = randomPreMasterSecret 1510 elif versionCheck != clientHello.client_version: 1511 if versionCheck != self.version: #Tolerate buggy IE clients 1512 premasterSecret = randomPreMasterSecret 1513 1514 #Get and check CertificateVerify, if relevant 1515 if clientCertChain: 1516 if self.version == (3,0): 1517 masterSecret = calcMasterSecret(self.version, premasterSecret, 1518 clientHello.random, serverHello.random) 1519 verifyBytes = self._calcSSLHandshakeHash(masterSecret, b"") 1520 elif self.version in ((3,1), (3,2)): 1521 verifyBytes = self._handshake_md5.digest() + \ 1522 self._handshake_sha.digest() 1523 elif self.version == (3,3): 1524 verifyBytes = self._handshake_sha256.digest() 1525 for result in self._getMsg(ContentType.handshake, 1526 HandshakeType.certificate_verify): 1527 if result in (0,1): yield result 1528 else: break 1529 certificateVerify = result 1530 publicKey = clientCertChain.getEndEntityPublicKey() 1531 if len(publicKey) < settings.minKeySize: 1532 for result in self._sendError(\ 1533 AlertDescription.handshake_failure, 1534 "Client's public key too small: %d" % len(publicKey)): 1535 yield result 1536 1537 if len(publicKey) > settings.maxKeySize: 1538 for result in self._sendError(\ 1539 AlertDescription.handshake_failure, 1540 "Client's public key too large: %d" % len(publicKey)): 1541 yield result 1542 1543 if not publicKey.verify(certificateVerify.signature, verifyBytes): 1544 for result in self._sendError(\ 1545 AlertDescription.decrypt_error, 1546 "Signature failed to verify"): 1547 yield result 1548 yield (premasterSecret, clientCertChain)
1549 1550
1551 - def _serverAnonKeyExchange(self, clientHello, serverHello, cipherSuite, 1552 settings):
1553 # Calculate DH p, g, Xs, Ys 1554 dh_p = getRandomSafePrime(32, False) 1555 dh_g = getRandomNumber(2, dh_p) 1556 dh_Xs = bytesToNumber(getRandomBytes(32)) 1557 dh_Ys = powMod(dh_g, dh_Xs, dh_p) 1558 1559 #Create ServerKeyExchange 1560 serverKeyExchange = ServerKeyExchange(cipherSuite) 1561 serverKeyExchange.createDH(dh_p, dh_g, dh_Ys) 1562 1563 #Send ServerHello[, Certificate], ServerKeyExchange, 1564 #ServerHelloDone 1565 msgs = [] 1566 msgs.append(serverHello) 1567 msgs.append(serverKeyExchange) 1568 msgs.append(ServerHelloDone()) 1569 for result in self._sendMsgs(msgs): 1570 yield result 1571 1572 #From here on, the client's messages must have the right version 1573 self._versionCheck = True 1574 1575 #Get and check ClientKeyExchange 1576 for result in self._getMsg(ContentType.handshake, 1577 HandshakeType.client_key_exchange, 1578 cipherSuite): 1579 if result in (0,1): 1580 yield result 1581 else: 1582 break 1583 clientKeyExchange = result 1584 dh_Yc = clientKeyExchange.dh_Yc 1585 1586 if dh_Yc % dh_p == 0: 1587 for result in self._sendError(AlertDescription.illegal_parameter, 1588 "Suspicious dh_Yc value"): 1589 yield result 1590 assert(False) # Just to ensure we don't fall through somehow 1591 1592 #Calculate premaster secre 1593 S = powMod(dh_Yc,dh_Xs,dh_p) 1594 premasterSecret = numberToByteArray(S) 1595 1596 yield premasterSecret
1597 1598
1599 - def _serverFinished(self, premasterSecret, clientRandom, serverRandom, 1600 cipherSuite, cipherImplementations, nextProtos):
1601 masterSecret = calcMasterSecret(self.version, premasterSecret, 1602 clientRandom, serverRandom) 1603 1604 #Calculate pending connection states 1605 self._calcPendingStates(cipherSuite, masterSecret, 1606 clientRandom, serverRandom, 1607 cipherImplementations) 1608 1609 #Exchange ChangeCipherSpec and Finished messages 1610 for result in self._getFinished(masterSecret, 1611 expect_next_protocol=nextProtos is not None): 1612 yield result 1613 1614 for result in self._sendFinished(masterSecret): 1615 yield result 1616 1617 yield masterSecret
1618 1619 1620 #********************************************************* 1621 # Shared Handshake Functions 1622 #********************************************************* 1623 1624
1625 - def _sendFinished(self, masterSecret, nextProto=None):
1626 #Send ChangeCipherSpec 1627 for result in self._sendMsg(ChangeCipherSpec()): 1628 yield result 1629 1630 #Switch to pending write state 1631 self._changeWriteState() 1632 1633 if nextProto is not None: 1634 nextProtoMsg = NextProtocol().create(nextProto) 1635 for result in self._sendMsg(nextProtoMsg): 1636 yield result 1637 1638 #Calculate verification data 1639 verifyData = self._calcFinished(masterSecret, True) 1640 if self.fault == Fault.badFinished: 1641 verifyData[0] = (verifyData[0]+1)%256 1642 1643 #Send Finished message under new state 1644 finished = Finished(self.version).create(verifyData) 1645 for result in self._sendMsg(finished): 1646 yield result
1647
1648 - def _getFinished(self, masterSecret, expect_next_protocol=False, nextProto=None):
1649 #Get and check ChangeCipherSpec 1650 for result in self._getMsg(ContentType.change_cipher_spec): 1651 if result in (0,1): 1652 yield result 1653 changeCipherSpec = result 1654 1655 if changeCipherSpec.type != 1: 1656 for result in self._sendError(AlertDescription.illegal_parameter, 1657 "ChangeCipherSpec type incorrect"): 1658 yield result 1659 1660 #Switch to pending read state 1661 self._changeReadState() 1662 1663 #Server Finish - Are we waiting for a next protocol echo? 1664 if expect_next_protocol: 1665 for result in self._getMsg(ContentType.handshake, HandshakeType.next_protocol): 1666 if result in (0,1): 1667 yield result 1668 if result is None: 1669 for result in self._sendError(AlertDescription.unexpected_message, 1670 "Didn't get NextProtocol message"): 1671 yield result 1672 1673 self.next_proto = result.next_proto 1674 else: 1675 self.next_proto = None 1676 1677 #Client Finish - Only set the next_protocol selected in the connection 1678 if nextProto: 1679 self.next_proto = nextProto 1680 1681 #Calculate verification data 1682 verifyData = self._calcFinished(masterSecret, False) 1683 1684 #Get and check Finished message under new state 1685 for result in self._getMsg(ContentType.handshake, 1686 HandshakeType.finished): 1687 if result in (0,1): 1688 yield result 1689 finished = result 1690 if finished.verify_data != verifyData: 1691 for result in self._sendError(AlertDescription.decrypt_error, 1692 "Finished message is incorrect"): 1693 yield result
1694
1695 - def _calcFinished(self, masterSecret, send=True):
1696 if self.version == (3,0): 1697 if (self._client and send) or (not self._client and not send): 1698 senderStr = b"\x43\x4C\x4E\x54" 1699 else: 1700 senderStr = b"\x53\x52\x56\x52" 1701 1702 verifyData = self._calcSSLHandshakeHash(masterSecret, senderStr) 1703 return verifyData 1704 1705 elif self.version in ((3,1), (3,2)): 1706 if (self._client and send) or (not self._client and not send): 1707 label = b"client finished" 1708 else: 1709 label = b"server finished" 1710 1711 handshakeHashes = self._handshake_md5.digest() + \ 1712 self._handshake_sha.digest() 1713 verifyData = PRF(masterSecret, label, handshakeHashes, 12) 1714 return verifyData 1715 elif self.version == (3,3): 1716 if (self._client and send) or (not self._client and not send): 1717 label = b"client finished" 1718 else: 1719 label = b"server finished" 1720 1721 handshakeHashes = self._handshake_sha256.digest() 1722 verifyData = PRF_1_2(masterSecret, label, handshakeHashes, 12) 1723 return verifyData 1724 else: 1725 raise AssertionError()
1726 1727
1728 - def _handshakeWrapperAsync(self, handshaker, checker):
1729 if not self.fault: 1730 try: 1731 for result in handshaker: 1732 yield result 1733 if checker: 1734 try: 1735 checker(self) 1736 except TLSAuthenticationError: 1737 alert = Alert().create(AlertDescription.close_notify, 1738 AlertLevel.fatal) 1739 for result in self._sendMsg(alert): 1740 yield result 1741 raise 1742 except GeneratorExit: 1743 raise 1744 except TLSAlert as alert: 1745 if not self.fault: 1746 raise 1747 if alert.description not in Fault.faultAlerts[self.fault]: 1748 raise TLSFaultError(str(alert)) 1749 else: 1750 pass 1751 except: 1752 self._shutdown(False) 1753 raise
1754