test_ssl.py 50.6 KB
Newer Older
1 2 3 4 5
# Test the support for SSL and sockets

import sys
import unittest
from test import test_support
6
import asyncore
7
import socket
8
import select
9 10 11
import errno
import subprocess
import time
12
import gc
13
import os
14
import errno
15
import pprint
16
import urllib, urlparse
17 18
import shutil
import traceback
19
import weakref
20

21 22 23
from BaseHTTPServer import HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler

24 25 26 27 28 29 30
# Optionally test SSL support, if we have it in the tested platform
skip_expected = False
try:
    import ssl
except ImportError:
    skip_expected = True

31
HOST = test_support.HOST
32
CERTFILE = None
33
SVN_PYTHON_ORG_ROOT_CERT = None
34

35 36
def handle_error(prefix):
    exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Bill Janssen's avatar
Bill Janssen committed
37 38
    if test_support.verbose:
        sys.stdout.write(prefix + exc_format)
39

40 41 42

class BasicTests(unittest.TestCase):

43
    def test_sslwrap_simple(self):
44
        # A crude test for the legacy API
45 46 47 48 49 50 51 52 53 54 55 56 57 58
        try:
            ssl.sslwrap_simple(socket.socket(socket.AF_INET))
        except IOError, e:
            if e.errno == 32: # broken pipe when ssl_sock.do_handshake(), this test doesn't care about that
                pass
            else:
                raise
        try:
            ssl.sslwrap_simple(socket.socket(socket.AF_INET)._sock)
        except IOError, e:
            if e.errno == 32: # broken pipe when ssl_sock.do_handshake(), this test doesn't care about that
                pass
            else:
                raise
59

60
    def test_constants(self):
Bill Janssen's avatar
Bill Janssen committed
61 62 63 64 65 66 67 68
        ssl.PROTOCOL_SSLv2
        ssl.PROTOCOL_SSLv23
        ssl.PROTOCOL_SSLv3
        ssl.PROTOCOL_TLSv1
        ssl.CERT_NONE
        ssl.CERT_OPTIONAL
        ssl.CERT_REQUIRED

69
    def test_random(self):
Bill Janssen's avatar
Bill Janssen committed
70 71 72 73 74
        v = ssl.RAND_status()
        if test_support.verbose:
            sys.stdout.write("\n RAND_status is %d (%s)\n"
                             % (v, (v and "sufficient randomness") or
                                "insufficient randomness"))
Guido van Rossum's avatar
Guido van Rossum committed
75
        try:
Bill Janssen's avatar
Bill Janssen committed
76 77 78
            ssl.RAND_egd(1)
        except TypeError:
            pass
Guido van Rossum's avatar
Guido van Rossum committed
79
        else:
Bill Janssen's avatar
Bill Janssen committed
80 81 82
            print "didn't raise TypeError"
        ssl.RAND_add("this is a random string", 75.0)

83
    def test_parse_cert(self):
Bill Janssen's avatar
Bill Janssen committed
84 85 86 87 88 89
        # note that this uses an 'unofficial' function in _ssl.c,
        # provided solely for this test, to exercise the certificate
        # parsing code
        p = ssl._ssl._test_decode_cert(CERTFILE, False)
        if test_support.verbose:
            sys.stdout.write("\n" + pprint.pformat(p) + "\n")
90

91 92 93
    def test_DER_to_PEM(self):
        with open(SVN_PYTHON_ORG_ROOT_CERT, 'r') as f:
            pem = f.read()
94 95 96
        d1 = ssl.PEM_cert_to_DER_cert(pem)
        p2 = ssl.DER_cert_to_PEM_cert(d1)
        d2 = ssl.PEM_cert_to_DER_cert(p2)
97
        self.assertEqual(d1, d2)
98 99 100 101
        if not p2.startswith(ssl.PEM_HEADER + '\n'):
            self.fail("DER-to-PEM didn't include correct header:\n%r\n" % p2)
        if not p2.endswith('\n' + ssl.PEM_FOOTER + '\n'):
            self.fail("DER-to-PEM didn't include correct footer:\n%r\n" % p2)
102

103 104 105 106 107 108 109 110 111
    def test_refcycle(self):
        # Issue #7943: an SSL object doesn't create reference cycles with
        # itself.
        s = socket.socket(socket.AF_INET)
        ss = ssl.wrap_socket(s)
        wr = weakref.ref(ss)
        del ss
        self.assertEqual(wr(), None)

112

113
class NetworkedTests(unittest.TestCase):
114

115
    def test_connect(self):
116 117 118 119 120
        s = ssl.wrap_socket(socket.socket(socket.AF_INET),
                            cert_reqs=ssl.CERT_NONE)
        s.connect(("svn.python.org", 443))
        c = s.getpeercert()
        if c:
121
            self.fail("Peer cert %s shouldn't be here!")
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
        s.close()

        # this should fail because we have no verification certs
        s = ssl.wrap_socket(socket.socket(socket.AF_INET),
                            cert_reqs=ssl.CERT_REQUIRED)
        try:
            s.connect(("svn.python.org", 443))
        except ssl.SSLError:
            pass
        finally:
            s.close()

        # this should succeed because we specify the root cert
        s = ssl.wrap_socket(socket.socket(socket.AF_INET),
                            cert_reqs=ssl.CERT_REQUIRED,
                            ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
        try:
            s.connect(("svn.python.org", 443))
        finally:
            s.close()

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
    def test_makefile_close(self):
        # Issue #5238: creating a file-like object with makefile() shouldn't
        # delay closing the underlying "real socket" (here tested with its
        # file descriptor, hence skipping the test under Windows).
        if os.name == "nt":
            if test_support.verbose:
                print "Skipped: can't use a socket as a file under Windows"
            return
        ss = ssl.wrap_socket(socket.socket(socket.AF_INET))
        ss.connect(("svn.python.org", 443))
        fd = ss.fileno()
        f = ss.makefile()
        f.close()
        # The fd is still open
        os.read(fd, 0)
        # Closing the SSL socket should close the fd too
        ss.close()
        gc.collect()
        try:
            os.read(fd, 0)
        except OSError, e:
            self.assertEqual(e.errno, errno.EBADF)
        else:
            self.fail("OSError wasn't raised")
167

168
    def test_non_blocking_handshake(self):
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
        s = socket.socket(socket.AF_INET)
        s.connect(("svn.python.org", 443))
        s.setblocking(False)
        s = ssl.wrap_socket(s,
                            cert_reqs=ssl.CERT_NONE,
                            do_handshake_on_connect=False)
        count = 0
        while True:
            try:
                count += 1
                s.do_handshake()
                break
            except ssl.SSLError, err:
                if err.args[0] == ssl.SSL_ERROR_WANT_READ:
                    select.select([s], [], [])
                elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
                    select.select([], [s], [])
                else:
                    raise
        s.close()
        if test_support.verbose:
            sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)

192
    def test_get_server_certificate(self):
193 194
        pem = ssl.get_server_certificate(("svn.python.org", 443))
        if not pem:
195
            self.fail("No server certificate on svn.python.org:443!")
196 197 198 199 200 201 202

        try:
            pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
        except ssl.SSLError:
            #should fail
            pass
        else:
203
            self.fail("Got server certificate %s for svn.python.org!" % pem)
204 205 206

        pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
        if not pem:
207
            self.fail("No server certificate on svn.python.org:443!")
208 209 210
        if test_support.verbose:
            sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)

211
    # Test disabled: OPENSSL_VERSION* not available in Python 2.6
212
    def test_algorithms(self):
213 214 215 216
        if test_support.verbose:
            sys.stdout.write("test_algorithms disabled, "
                             "as it fails on some old OpenSSL versions")
        return
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
        # Issue #8484: all algorithms should be available when verifying a
        # certificate.
        # NOTE: https://sha256.tbs-internet.com is another possible test host
        remote = ("sha2.hboeck.de", 443)
        sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
        s = ssl.wrap_socket(socket.socket(socket.AF_INET),
                            cert_reqs=ssl.CERT_REQUIRED,
                            ca_certs=sha256_cert,)
        with test_support.transient_internet():
            try:
                s.connect(remote)
                if test_support.verbose:
                    sys.stdout.write("\nCipher with %r is %r\n" %
                                     (remote, s.cipher()))
                    sys.stdout.write("Certificate is:\n%s\n" %
                                     pprint.pformat(s.getpeercert()))
            finally:
                s.close()

236

Bill Janssen's avatar
Bill Janssen committed
237 238 239 240 241 242
try:
    import threading
except ImportError:
    _have_threads = False
else:
    _have_threads = True
243

Bill Janssen's avatar
Bill Janssen committed
244
    class ThreadedEchoServer(threading.Thread):
245

Bill Janssen's avatar
Bill Janssen committed
246
        class ConnectionHandler(threading.Thread):
247

Bill Janssen's avatar
Bill Janssen committed
248 249 250
            """A mildly complicated class, because we want it to work both
            with and without the SSL wrapper around the socket connection, so
            that we can test the STARTTLS functionality."""
251

Bill Janssen's avatar
Bill Janssen committed
252 253
            def __init__(self, server, connsock):
                self.server = server
Guido van Rossum's avatar
Guido van Rossum committed
254
                self.running = False
Bill Janssen's avatar
Bill Janssen committed
255 256 257 258
                self.sock = connsock
                self.sock.setblocking(1)
                self.sslconn = None
                threading.Thread.__init__(self)
259
                self.daemon = True
Guido van Rossum's avatar
Guido van Rossum committed
260

261 262 263 264 265 266 267 268 269 270 271 272
            def show_conn_details(self):
                if self.server.certreqs == ssl.CERT_REQUIRED:
                    cert = self.sslconn.getpeercert()
                    if test_support.verbose and self.server.chatty:
                        sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
                    cert_binary = self.sslconn.getpeercert(True)
                    if test_support.verbose and self.server.chatty:
                        sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
                cipher = self.sslconn.cipher()
                if test_support.verbose and self.server.chatty:
                    sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")

273
            def wrap_conn(self):
274
                try:
Bill Janssen's avatar
Bill Janssen committed
275 276 277 278 279
                    self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
                                                   certfile=self.server.certificate,
                                                   ssl_version=self.server.protocol,
                                                   ca_certs=self.server.cacerts,
                                                   cert_reqs=self.server.certreqs)
280 281 282 283
                except ssl.SSLError:
                    # XXX Various errors can have happened here, for example
                    # a mismatching protocol version, an invalid certificate,
                    # or a low-level bug. This should be made more discriminating.
Bill Janssen's avatar
Bill Janssen committed
284 285 286
                    if self.server.chatty:
                        handle_error("\n server:  bad connection attempt from " +
                                     str(self.sock.getpeername()) + ":\n")
287
                    self.close()
288 289
                    self.running = False
                    self.server.stop()
Bill Janssen's avatar
Bill Janssen committed
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
                    return False
                else:
                    return True

            def read(self):
                if self.sslconn:
                    return self.sslconn.read()
                else:
                    return self.sock.recv(1024)

            def write(self, bytes):
                if self.sslconn:
                    return self.sslconn.write(bytes)
                else:
                    return self.sock.send(bytes)

            def close(self):
                if self.sslconn:
                    self.sslconn.close()
                else:
310
                    self.sock._sock.close()
Bill Janssen's avatar
Bill Janssen committed
311

312
            def run(self):
Bill Janssen's avatar
Bill Janssen committed
313 314
                self.running = True
                if not self.server.starttls_server:
315 316 317
                    if isinstance(self.sock, ssl.SSLSocket):
                        self.sslconn = self.sock
                    elif not self.wrap_conn():
Bill Janssen's avatar
Bill Janssen committed
318
                        return
319
                    self.show_conn_details()
Bill Janssen's avatar
Bill Janssen committed
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
                while self.running:
                    try:
                        msg = self.read()
                        if not msg:
                            # eof, so quit this handler
                            self.running = False
                            self.close()
                        elif msg.strip() == 'over':
                            if test_support.verbose and self.server.connectionchatty:
                                sys.stdout.write(" server: client closed connection\n")
                            self.close()
                            return
                        elif self.server.starttls_server and msg.strip() == 'STARTTLS':
                            if test_support.verbose and self.server.connectionchatty:
                                sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
                            self.write("OK\n")
                            if not self.wrap_conn():
                                return
338 339 340 341 342 343 344 345
                        elif self.server.starttls_server and self.sslconn and msg.strip() == 'ENDTLS':
                            if test_support.verbose and self.server.connectionchatty:
                                sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
                            self.write("OK\n")
                            self.sslconn.unwrap()
                            self.sslconn = None
                            if test_support.verbose and self.server.connectionchatty:
                                sys.stdout.write(" server: connection is now unencrypted...\n")
Bill Janssen's avatar
Bill Janssen committed
346 347 348 349 350 351 352 353 354 355 356
                        else:
                            if (test_support.verbose and
                                self.server.connectionchatty):
                                ctype = (self.sslconn and "encrypted") or "unencrypted"
                                sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
                                                 % (repr(msg), ctype, repr(msg.lower()), ctype))
                            self.write(msg.lower())
                    except ssl.SSLError:
                        if self.server.chatty:
                            handle_error("Test server failure:\n")
                        self.close()
357
                        self.running = False
Bill Janssen's avatar
Bill Janssen committed
358 359 360 361
                        # normally, we'd just stop here, but for the test
                        # harness, we want to stop the server
                        self.server.stop()

362
        def __init__(self, certificate, ssl_version=None,
363
                     certreqs=None, cacerts=None,
364 365 366
                     chatty=True, connectionchatty=False, starttls_server=False,
                     wrap_accepting_socket=False):

Bill Janssen's avatar
Bill Janssen committed
367 368 369 370 371 372 373 374 375 376 377 378 379
            if ssl_version is None:
                ssl_version = ssl.PROTOCOL_TLSv1
            if certreqs is None:
                certreqs = ssl.CERT_NONE
            self.certificate = certificate
            self.protocol = ssl_version
            self.certreqs = certreqs
            self.cacerts = cacerts
            self.chatty = chatty
            self.connectionchatty = connectionchatty
            self.starttls_server = starttls_server
            self.sock = socket.socket()
            self.flag = None
380 381 382 383 384 385 386 387 388
            if wrap_accepting_socket:
                self.sock = ssl.wrap_socket(self.sock, server_side=True,
                                            certfile=self.certificate,
                                            cert_reqs = self.certreqs,
                                            ca_certs = self.cacerts,
                                            ssl_version = self.protocol)
                if test_support.verbose and self.chatty:
                    sys.stdout.write(' server:  wrapped server socket as %s\n' % str(self.sock))
            self.port = test_support.bind_port(self.sock)
Bill Janssen's avatar
Bill Janssen committed
389 390
            self.active = False
            threading.Thread.__init__(self)
391
            self.daemon = True
Bill Janssen's avatar
Bill Janssen committed
392

393
        def start(self, flag=None):
Bill Janssen's avatar
Bill Janssen committed
394 395 396
            self.flag = flag
            threading.Thread.start(self)

397
        def run(self):
398
            self.sock.settimeout(0.05)
Bill Janssen's avatar
Bill Janssen committed
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
            self.sock.listen(5)
            self.active = True
            if self.flag:
                # signal an event
                self.flag.set()
            while self.active:
                try:
                    newconn, connaddr = self.sock.accept()
                    if test_support.verbose and self.chatty:
                        sys.stdout.write(' server:  new connection from '
                                         + str(connaddr) + '\n')
                    handler = self.ConnectionHandler(self, newconn)
                    handler.start()
                except socket.timeout:
                    pass
                except KeyboardInterrupt:
                    self.stop()
416
            self.sock.close()
Bill Janssen's avatar
Bill Janssen committed
417

418
        def stop(self):
Bill Janssen's avatar
Bill Janssen committed
419 420
            self.active = False

421 422
    class AsyncoreEchoServer(threading.Thread):

423
        class EchoServer(asyncore.dispatcher):
424

425
            class ConnectionHandler(asyncore.dispatcher_with_send):
426 427 428 429 430

                def __init__(self, conn, certfile):
                    asyncore.dispatcher_with_send.__init__(self, conn)
                    self.socket = ssl.wrap_socket(conn, server_side=True,
                                                  certfile=certfile,
431 432
                                                  do_handshake_on_connect=False)
                    self._ssl_accepting = True
433 434 435 436 437 438 439

                def readable(self):
                    if isinstance(self.socket, ssl.SSLSocket):
                        while self.socket.pending() > 0:
                            self.handle_read_event()
                    return True

440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
                def _do_ssl_handshake(self):
                    try:
                        self.socket.do_handshake()
                    except ssl.SSLError, err:
                        if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
                                           ssl.SSL_ERROR_WANT_WRITE):
                            return
                        elif err.args[0] == ssl.SSL_ERROR_EOF:
                            return self.handle_close()
                        raise
                    except socket.error, err:
                        if err.args[0] == errno.ECONNABORTED:
                            return self.handle_close()
                    else:
                        self._ssl_accepting = False

456
                def handle_read(self):
457 458 459 460
                    if self._ssl_accepting:
                        self._do_ssl_handshake()
                    else:
                        data = self.recv(1024)
461 462
                        if data and data.strip() != 'over':
                            self.send(data.lower())
463 464

                def handle_close(self):
465
                    self.close()
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
                    if test_support.verbose:
                        sys.stdout.write(" server:  closed connection %s\n" % self.socket)

                def handle_error(self):
                    raise

            def __init__(self, certfile):
                self.certfile = certfile
                asyncore.dispatcher.__init__(self)
                self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
                self.port = test_support.bind_port(self.socket)
                self.listen(5)

            def handle_accept(self):
                sock_obj, addr = self.accept()
                if test_support.verbose:
                    sys.stdout.write(" server:  new connection from %s:%s\n" %addr)
                self.ConnectionHandler(sock_obj, self.certfile)

            def handle_error(self):
                raise

        def __init__(self, certfile):
            self.flag = None
            self.active = False
            self.server = self.EchoServer(certfile)
            self.port = self.server.port
            threading.Thread.__init__(self)
494
            self.daemon = True
495 496 497 498

        def __str__(self):
            return "<%s %s>" % (self.__class__.__name__, self.server)

499
        def start(self, flag=None):
500 501 502
            self.flag = flag
            threading.Thread.start(self)

503
        def run(self):
504 505 506 507
            self.active = True
            if self.flag:
                self.flag.set()
            while self.active:
508
                asyncore.loop(0.05)
509

510
        def stop(self):
511 512
            self.active = False
            self.server.close()
513

514
    class SocketServerHTTPSServer(threading.Thread):
515 516 517 518 519 520 521 522 523

        class HTTPSServer(HTTPServer):

            def __init__(self, server_address, RequestHandlerClass, certfile):
                HTTPServer.__init__(self, server_address, RequestHandlerClass)
                # we assume the certfile contains both private key and certificate
                self.certfile = certfile
                self.allow_reuse_address = True

524 525 526 527 528 529
            def __str__(self):
                return ('<%s %s:%s>' %
                        (self.__class__.__name__,
                         self.server_name,
                         self.server_port))

530
            def get_request(self):
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
                # override this to wrap socket with SSL
                sock, addr = self.socket.accept()
                sslconn = ssl.wrap_socket(sock, server_side=True,
                                          certfile=self.certfile)
                return sslconn, addr

        class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
            # need to override translate_path to get a known root,
            # instead of using os.curdir, since the test could be
            # run from anywhere

            server_version = "TestHTTPS/1.0"

            root = None

            def translate_path(self, path):
                """Translate a /-separated PATH to the local filename syntax.

                Components that mean special things to the local file system
                (e.g. drive or directory names) are ignored.  (XXX They should
                probably be diagnosed.)

                """
                # abandon query parameters
                path = urlparse.urlparse(path)[2]
                path = os.path.normpath(urllib.unquote(path))
                words = path.split('/')
                words = filter(None, words)
                path = self.root
                for word in words:
                    drive, word = os.path.splitdrive(word)
                    head, word = os.path.split(word)
                    if word in self.root: continue
                    path = os.path.join(path, word)
                return path

            def log_message(self, format, *args):

                # we override this to suppress logging unless "verbose"

                if test_support.verbose:
572 573
                    sys.stdout.write(" server (%s:%d %s):\n   [%s] %s\n" %
                                     (self.server.server_address,
574 575 576 577 578 579
                                      self.server.server_port,
                                      self.request.cipher(),
                                      self.log_date_time_string(),
                                      format%args))


580
        def __init__(self, certfile):
581 582 583
            self.flag = None
            self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
            self.server = self.HTTPSServer(
584 585
                (HOST, 0), self.RootedHTTPRequestHandler, certfile)
            self.port = self.server.server_port
586
            threading.Thread.__init__(self)
587
            self.daemon = True
588 589

        def __str__(self):
590
            return "<%s %s>" % (self.__class__.__name__, self.server)
591

592
        def start(self, flag=None):
593 594 595
            self.flag = flag
            threading.Thread.start(self)

596
        def run(self):
597 598
            if self.flag:
                self.flag.set()
599
            self.server.serve_forever(0.05)
600

601
        def stop(self):
602
            self.server.shutdown()
603 604


605 606 607 608 609
    def bad_cert_test(certfile):
        """
        Launch a server with CERT_REQUIRED, and check that trying to
        connect to it with the given client certificate fails.
        """
610
        server = ThreadedEchoServer(CERTFILE,
Bill Janssen's avatar
Bill Janssen committed
611 612 613 614 615 616 617 618
                                    certreqs=ssl.CERT_REQUIRED,
                                    cacerts=CERTFILE, chatty=False)
        flag = threading.Event()
        server.start(flag)
        # wait for it to start
        flag.wait()
        # try to connect
        try:
619
            try:
Bill Janssen's avatar
Bill Janssen committed
620 621 622
                s = ssl.wrap_socket(socket.socket(),
                                    certfile=certfile,
                                    ssl_version=ssl.PROTOCOL_TLSv1)
623
                s.connect((HOST, server.port))
Bill Janssen's avatar
Bill Janssen committed
624
            except ssl.SSLError, x:
625
                if test_support.verbose:
Bill Janssen's avatar
Bill Janssen committed
626
                    sys.stdout.write("\nSSLError is %s\n" % x[1])
627 628 629
            except socket.error, x:
                if test_support.verbose:
                    sys.stdout.write("\nsocket.error is %s\n" % x[1])
Bill Janssen's avatar
Bill Janssen committed
630
            else:
631
                self.fail("Use of invalid cert should have failed!")
Bill Janssen's avatar
Bill Janssen committed
632 633 634 635
        finally:
            server.stop()
            server.join()

636 637 638 639 640 641 642 643
    def server_params_test(certfile, protocol, certreqs, cacertsfile,
                           client_certfile, client_protocol=None, indata="FOO\n",
                           chatty=True, connectionchatty=False,
                           wrap_accepting_socket=False):
        """
        Launch a server, connect a client to it and try various reads
        and writes.
        """
644
        server = ThreadedEchoServer(certfile,
Bill Janssen's avatar
Bill Janssen committed
645 646 647 648
                                    certreqs=certreqs,
                                    ssl_version=protocol,
                                    cacerts=cacertsfile,
                                    chatty=chatty,
649 650
                                    connectionchatty=connectionchatty,
                                    wrap_accepting_socket=wrap_accepting_socket)
Bill Janssen's avatar
Bill Janssen committed
651 652 653 654 655 656 657 658
        flag = threading.Event()
        server.start(flag)
        # wait for it to start
        flag.wait()
        # try to connect
        if client_protocol is None:
            client_protocol = protocol
        try:
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
            s = ssl.wrap_socket(socket.socket(),
                                certfile=client_certfile,
                                ca_certs=cacertsfile,
                                cert_reqs=certreqs,
                                ssl_version=client_protocol)
            s.connect((HOST, server.port))
            if connectionchatty:
                if test_support.verbose:
                    sys.stdout.write(
                        " client:  sending %s...\n" % (repr(indata)))
            s.write(indata)
            outdata = s.read()
            if connectionchatty:
                if test_support.verbose:
                    sys.stdout.write(" client:  read %s\n" % repr(outdata))
            if outdata != indata.lower():
                self.fail(
                    "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
                    % (outdata[:min(len(outdata),20)], len(outdata),
                       indata[:min(len(indata),20)].lower(), len(indata)))
            s.write("over\n")
            if connectionchatty:
                if test_support.verbose:
                    sys.stdout.write(" client:  closing connection.\n")
            s.close()
Bill Janssen's avatar
Bill Janssen committed
684 685 686 687
        finally:
            server.stop()
            server.join()

688 689 690 691
    def try_protocol_combo(server_protocol,
                           client_protocol,
                           expect_success,
                           certsreqs=None):
692
        if certsreqs is None:
693
            certsreqs = ssl.CERT_NONE
694 695 696 697 698
        certtype = {
            ssl.CERT_NONE: "CERT_NONE",
            ssl.CERT_OPTIONAL: "CERT_OPTIONAL",
            ssl.CERT_REQUIRED: "CERT_REQUIRED",
        }[certsreqs]
Bill Janssen's avatar
Bill Janssen committed
699
        if test_support.verbose:
700
            formatstr = (expect_success and " %s->%s %s\n") or " {%s->%s} %s\n"
Bill Janssen's avatar
Bill Janssen committed
701 702 703 704 705
            sys.stdout.write(formatstr %
                             (ssl.get_protocol_name(client_protocol),
                              ssl.get_protocol_name(server_protocol),
                              certtype))
        try:
706 707 708
            server_params_test(CERTFILE, server_protocol, certsreqs,
                               CERTFILE, CERTFILE, client_protocol,
                               chatty=False)
709 710 711
        # Protocol mismatch can result in either an SSLError, or a
        # "Connection reset by peer" error.
        except ssl.SSLError:
712
            if expect_success:
Bill Janssen's avatar
Bill Janssen committed
713
                raise
714
        except socket.error as e:
715
            if expect_success or e.errno != errno.ECONNRESET:
716
                raise
Bill Janssen's avatar
Bill Janssen committed
717
        else:
718
            if not expect_success:
719
                raise AssertionError(
Bill Janssen's avatar
Bill Janssen committed
720 721 722 723 724
                    "Client protocol %s succeeded with server protocol %s!"
                    % (ssl.get_protocol_name(client_protocol),
                       ssl.get_protocol_name(server_protocol)))


725
    class ThreadedTests(unittest.TestCase):
Bill Janssen's avatar
Bill Janssen committed
726

727 728 729 730
        def test_rude_shutdown(self):
            """A brutal shutdown of an SSL server should raise an IOError
            in the client when attempting handshake.
            """
Bill Janssen's avatar
Bill Janssen committed
731 732 733
            listener_ready = threading.Event()
            listener_gone = threading.Event()

734 735 736 737 738 739 740
            s = socket.socket()
            port = test_support.bind_port(s, HOST)

            # `listener` runs in a thread.  It sits in an accept() until
            # the main thread connects.  Then it rudely closes the socket,
            # and sets Event `listener_gone` to let the main thread know
            # the socket is gone.
Bill Janssen's avatar
Bill Janssen committed
741 742 743 744
            def listener():
                s.listen(5)
                listener_ready.set()
                s.accept()
745
                s.close()
Bill Janssen's avatar
Bill Janssen committed
746 747 748 749
                listener_gone.set()

            def connector():
                listener_ready.wait()
750 751
                c = socket.socket()
                c.connect((HOST, port))
Bill Janssen's avatar
Bill Janssen committed
752 753
                listener_gone.wait()
                try:
754
                    ssl_sock = ssl.wrap_socket(c)
755
                except IOError:
Bill Janssen's avatar
Bill Janssen committed
756 757
                    pass
                else:
758
                    self.fail('connecting to closed SSL socket should have failed')
Bill Janssen's avatar
Bill Janssen committed
759 760 761

            t = threading.Thread(target=listener)
            t.start()
762 763 764 765
            try:
                connector()
            finally:
                t.join()
Bill Janssen's avatar
Bill Janssen committed
766

767 768
        def test_echo(self):
            """Basic test of an SSL client connecting to a server"""
Bill Janssen's avatar
Bill Janssen committed
769 770
            if test_support.verbose:
                sys.stdout.write("\n")
771 772 773
            server_params_test(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
                               CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
                               chatty=True, connectionchatty=True)
Bill Janssen's avatar
Bill Janssen committed
774

775
        def test_getpeercert(self):
Bill Janssen's avatar
Bill Janssen committed
776 777 778
            if test_support.verbose:
                sys.stdout.write("\n")
            s2 = socket.socket()
779
            server = ThreadedEchoServer(CERTFILE,
Bill Janssen's avatar
Bill Janssen committed
780 781 782 783 784 785 786 787 788 789
                                        certreqs=ssl.CERT_NONE,
                                        ssl_version=ssl.PROTOCOL_SSLv23,
                                        cacerts=CERTFILE,
                                        chatty=False)
            flag = threading.Event()
            server.start(flag)
            # wait for it to start
            flag.wait()
            # try to connect
            try:
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
                s = ssl.wrap_socket(socket.socket(),
                                    certfile=CERTFILE,
                                    ca_certs=CERTFILE,
                                    cert_reqs=ssl.CERT_REQUIRED,
                                    ssl_version=ssl.PROTOCOL_SSLv23)
                s.connect((HOST, server.port))
                cert = s.getpeercert()
                self.assertTrue(cert, "Can't get peer certificate.")
                cipher = s.cipher()
                if test_support.verbose:
                    sys.stdout.write(pprint.pformat(cert) + '\n')
                    sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
                if 'subject' not in cert:
                    self.fail("No subject field in certificate: %s." %
                              pprint.pformat(cert))
                if ((('organizationName', 'Python Software Foundation'),)
                    not in cert['subject']):
                    self.fail(
                        "Missing or invalid 'organizationName' field in certificate subject; "
                        "should be 'Python Software Foundation'.")
                s.close()
Bill Janssen's avatar
Bill Janssen committed
811 812 813 814
            finally:
                server.stop()
                server.join()

815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
        def test_empty_cert(self):
            """Connecting with an empty cert file"""
            bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
                                      "nullcert.pem"))
        def test_malformed_cert(self):
            """Connecting with a badly formatted certificate (syntax error)"""
            bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
                                       "badcert.pem"))
        def test_nonexisting_cert(self):
            """Connecting with a non-existing cert file"""
            bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
                                       "wrongcert.pem"))
        def test_malformed_key(self):
            """Connecting with a badly formatted key (syntax error)"""
            bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
                                       "badkey.pem"))

        def test_protocol_sslv2(self):
            """Connecting to an SSLv2 server with various client options"""
Bill Janssen's avatar
Bill Janssen committed
834
            if test_support.verbose:
835 836 837
                sys.stdout.write("\ntest_protocol_sslv2 disabled, "
                                 "as it fails on OpenSSL 1.0.0+")
            return
838 839 840 841 842 843 844 845 846
            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)

        def test_protocol_sslv23(self):
            """Connecting to an SSLv23 server with various client options"""
Bill Janssen's avatar
Bill Janssen committed
847
            if test_support.verbose:
848 849 850
                sys.stdout.write("\ntest_protocol_sslv23 disabled, "
                                 "as it fails on OpenSSL 1.0.0+")
            return
Bill Janssen's avatar
Bill Janssen committed
851
            try:
852
                try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
853
            except (ssl.SSLError, socket.error), x:
Bill Janssen's avatar
Bill Janssen committed
854 855 856 857 858
                # this fails on some older versions of OpenSSL (0.9.7l, for instance)
                if test_support.verbose:
                    sys.stdout.write(
                        " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
                        % str(x))
859 860 861
            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
Bill Janssen's avatar
Bill Janssen committed
862

863 864 865
            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
Bill Janssen's avatar
Bill Janssen committed
866

867 868 869
            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
Bill Janssen's avatar
Bill Janssen committed
870

871 872
        def test_protocol_sslv3(self):
            """Connecting to an SSLv3 server with various client options"""
Bill Janssen's avatar
Bill Janssen committed
873
            if test_support.verbose:
874 875 876
                sys.stdout.write("\ntest_protocol_sslv3 disabled, "
                                 "as it fails on OpenSSL 1.0.0+")
            return
877 878 879 880 881 882 883 884 885
            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)

        def test_protocol_tlsv1(self):
            """Connecting to a TLSv1 server with various client options"""
Bill Janssen's avatar
Bill Janssen committed
886
            if test_support.verbose:
887 888 889
                sys.stdout.write("\ntest_protocol_tlsv1 disabled, "
                                 "as it fails on OpenSSL 1.0.0+")
            return
890 891 892 893 894 895 896 897 898
            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)

        def test_starttls(self):
            """Switching from clear text to encrypted and back again."""
899
            msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Bill Janssen's avatar
Bill Janssen committed
900

901
            server = ThreadedEchoServer(CERTFILE,
Bill Janssen's avatar
Bill Janssen committed
902 903 904 905 906 907 908 909 910 911 912
                                        ssl_version=ssl.PROTOCOL_TLSv1,
                                        starttls_server=True,
                                        chatty=True,
                                        connectionchatty=True)
            flag = threading.Event()
            server.start(flag)
            # wait for it to start
            flag.wait()
            # try to connect
            wrapped = False
            try:
913 914 915 916 917 918
                s = socket.socket()
                s.setblocking(1)
                s.connect((HOST, server.port))
                if test_support.verbose:
                    sys.stdout.write("\n")
                for indata in msgs:
Bill Janssen's avatar
Bill Janssen committed
919
                    if test_support.verbose:
920 921 922 923 924 925 926 927 928 929
                        sys.stdout.write(
                            " client:  sending %s...\n" % repr(indata))
                    if wrapped:
                        conn.write(indata)
                        outdata = conn.read()
                    else:
                        s.send(indata)
                        outdata = s.recv(1024)
                    if (indata == "STARTTLS" and
                        outdata.strip().lower().startswith("ok")):
930
                        # STARTTLS ok, switch to secure mode
Bill Janssen's avatar
Bill Janssen committed
931
                        if test_support.verbose:
932
                            sys.stdout.write(
933 934 935 936 937 938
                                " client:  read %s from server, starting TLS...\n"
                                % repr(outdata))
                        conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
                        wrapped = True
                    elif (indata == "ENDTLS" and
                        outdata.strip().lower().startswith("ok")):
939
                        # ENDTLS ok, switch back to clear text
940 941 942 943 944 945
                        if test_support.verbose:
                            sys.stdout.write(
                                " client:  read %s from server, ending TLS...\n"
                                % repr(outdata))
                        s = conn.unwrap()
                        wrapped = False
Bill Janssen's avatar
Bill Janssen committed
946
                    else:
947 948 949 950 951 952 953 954 955 956
                        if test_support.verbose:
                            sys.stdout.write(
                                " client:  read %s from server\n" % repr(outdata))
                if test_support.verbose:
                    sys.stdout.write(" client:  closing connection.\n")
                if wrapped:
                    conn.write("over\n")
                else:
                    s.send("over\n")
                s.close()
Bill Janssen's avatar
Bill Janssen committed
957 958 959
            finally:
                server.stop()
                server.join()
960

961 962
        def test_socketserver(self):
            """Using a SocketServer to create and manage SSL connections."""
963
            server = SocketServerHTTPSServer(CERTFILE)
964 965 966 967 968 969 970 971
            flag = threading.Event()
            server.start(flag)
            # wait for it to start
            flag.wait()
            # try to connect
            try:
                if test_support.verbose:
                    sys.stdout.write('\n')
972 973
                with open(CERTFILE, 'rb') as f:
                    d1 = f.read()
974 975
                d2 = ''
                # now fetch the same data from the HTTPS server
976 977
                url = 'https://127.0.0.1:%d/%s' % (
                    server.port, os.path.split(CERTFILE)[1])
978 979 980 981 982 983 984 985 986
                f = urllib.urlopen(url)
                dlen = f.info().getheader("content-length")
                if dlen and (int(dlen) > 0):
                    d2 = f.read(int(dlen))
                    if test_support.verbose:
                        sys.stdout.write(
                            " client: read %d bytes from remote server '%s'\n"
                            % (len(d2), server))
                f.close()
987
                self.assertEqual(d1, d2)
988 989 990
            finally:
                server.stop()
                server.join()
991

992 993
        def test_wrapped_accept(self):
            """Check the accept() method on SSL sockets."""
994 995
            if test_support.verbose:
                sys.stdout.write("\n")
996 997 998 999
            server_params_test(CERTFILE, ssl.PROTOCOL_SSLv23, ssl.CERT_REQUIRED,
                               CERTFILE, CERTFILE, ssl.PROTOCOL_SSLv23,
                               chatty=True, connectionchatty=True,
                               wrap_accepting_socket=True)
1000

1001 1002
        def test_asyncore_server(self):
            """Check the example asyncore integration."""
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
            indata = "TEST MESSAGE of mixed case\n"

            if test_support.verbose:
                sys.stdout.write("\n")
            server = AsyncoreEchoServer(CERTFILE)
            flag = threading.Event()
            server.start(flag)
            # wait for it to start
            flag.wait()
            # try to connect
            try:
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
                s = ssl.wrap_socket(socket.socket())
                s.connect(('127.0.0.1', server.port))
                if test_support.verbose:
                    sys.stdout.write(
                        " client:  sending %s...\n" % (repr(indata)))
                s.write(indata)
                outdata = s.read()
                if test_support.verbose:
                    sys.stdout.write(" client:  read %s\n" % repr(outdata))
                if outdata != indata.lower():
                    self.fail(
                        "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
                        % (outdata[:min(len(outdata),20)], len(outdata),
                           indata[:min(len(indata),20)].lower(), len(indata)))
                s.write("over\n")
                if test_support.verbose:
                    sys.stdout.write(" client:  closing connection.\n")
                s.close()
1032 1033 1034 1035 1036
            finally:
                server.stop()
                # wait for server thread to end
                server.join()

1037 1038
        def test_recv_send(self):
            """Test recv(), send() and friends."""
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
            if test_support.verbose:
                sys.stdout.write("\n")

            server = ThreadedEchoServer(CERTFILE,
                                        certreqs=ssl.CERT_NONE,
                                        ssl_version=ssl.PROTOCOL_TLSv1,
                                        cacerts=CERTFILE,
                                        chatty=True,
                                        connectionchatty=False)
            flag = threading.Event()
            server.start(flag)
            # wait for it to start
            flag.wait()
            # try to connect
1053 1054 1055 1056 1057 1058 1059
            s = ssl.wrap_socket(socket.socket(),
                                server_side=False,
                                certfile=CERTFILE,
                                ca_certs=CERTFILE,
                                cert_reqs=ssl.CERT_NONE,
                                ssl_version=ssl.PROTOCOL_TLSv1)
            s.connect((HOST, server.port))
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
            try:
                # helper methods for standardising recv* method signatures
                def _recv_into():
                    b = bytearray("\0"*100)
                    count = s.recv_into(b)
                    return b[:count]

                def _recvfrom_into():
                    b = bytearray("\0"*100)
                    count, addr = s.recvfrom_into(b)
                    return b[:count]

                # (name, method, whether to expect success, *args)
                send_methods = [
                    ('send', s.send, True, []),
                    ('sendto', s.sendto, False, ["some.address"]),
                    ('sendall', s.sendall, True, []),
                ]
                recv_methods = [
                    ('recv', s.recv, True, []),
                    ('recvfrom', s.recvfrom, False, ["some.address"]),
                    ('recv_into', _recv_into, True, []),
                    ('recvfrom_into', _recvfrom_into, False, []),
                ]
                data_prefix = u"PREFIX_"

                for meth_name, send_meth, expect_success, args in send_methods:
                    indata = data_prefix + meth_name
                    try:
                        send_meth(indata.encode('ASCII', 'strict'), *args)
                        outdata = s.read()
                        outdata = outdata.decode('ASCII', 'strict')
                        if outdata != indata.lower():
                            raise support.TestFailed(
                                "While sending with <<%s>> bad data "
                                "<<%r>> (%d) received; "
                                "expected <<%r>> (%d)\n" % (
                                    meth_name, outdata[:20], len(outdata),
                                    indata[:20], len(indata)
                                )
                            )
                    except ValueError as e:
                        if expect_success:
                            raise support.TestFailed(
                                "Failed to send with method <<%s>>; "
                                "expected to succeed.\n" % (meth_name,)
                            )
                        if not str(e).startswith(meth_name):
                            raise support.TestFailed(
                                "Method <<%s>> failed with unexpected "
                                "exception message: %s\n" % (
                                    meth_name, e
                                )
                            )

                for meth_name, recv_meth, expect_success, args in recv_methods:
                    indata = data_prefix + meth_name
                    try:
                        s.send(indata.encode('ASCII', 'strict'))
                        outdata = recv_meth(*args)
                        outdata = outdata.decode('ASCII', 'strict')
                        if outdata != indata.lower():
                            raise support.TestFailed(
                                "While receiving with <<%s>> bad data "
                                "<<%r>> (%d) received; "
                                "expected <<%r>> (%d)\n" % (
                                    meth_name, outdata[:20], len(outdata),
                                    indata[:20], len(indata)
                                )
                            )
                    except ValueError as e:
                        if expect_success:
                            raise support.TestFailed(
                                "Failed to receive with method <<%s>>; "
                                "expected to succeed.\n" % (meth_name,)
                            )
                        if not str(e).startswith(meth_name):
                            raise support.TestFailed(
                                "Method <<%s>> failed with unexpected "
                                "exception message: %s\n" % (
                                    meth_name, e
                                )
                            )
                        # consume data
                        s.read()

                s.write("over\n".encode("ASCII", "strict"))
                s.close()
            finally:
                server.stop()
                server.join()

1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
        def test_handshake_timeout(self):
            # Issue #5103: SSL handshake must respect the socket timeout
            server = socket.socket(socket.AF_INET)
            host = "127.0.0.1"
            port = test_support.bind_port(server)
            started = threading.Event()
            finish = False

            def serve():
                server.listen(5)
                started.set()
                conns = []
                while not finish:
                    r, w, e = select.select([server], [], [], 0.1)
                    if server in r:
                        # Let the socket hang around rather than having
                        # it closed by garbage collection.
                        conns.append(server.accept()[0])

            t = threading.Thread(target=serve)
            t.start()
            started.wait()

            try:
                try:
                    c = socket.socket(socket.AF_INET)
                    c.settimeout(0.2)
                    c.connect((host, port))
                    # Will attempt handshake and time out
                    try:
                        ssl.wrap_socket(c)
                    except ssl.SSLError, e:
                        self.assertTrue("timed out" in str(e), str(e))
                    else:
                        self.fail("SSLError wasn't raised")
                finally:
                    c.close()
                try:
                    c = socket.socket(socket.AF_INET)
                    c.settimeout(0.2)
                    c = ssl.wrap_socket(c)
                    # Will attempt handshake and time out
                    try:
                        c.connect((host, port))
                    except ssl.SSLError, e:
                        self.assertTrue("timed out" in str(e), str(e))
                    else:
                        self.fail("SSLError wasn't raised")
                finally:
                    c.close()
            finally:
                finish = True
                t.join()
                server.close()

1207

1208
def test_main(verbose=False):
1209
    if skip_expected:
1210
        raise test_support.TestSkipped("No SSL support")
1211

1212
    global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
1213
    CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1214 1215 1216 1217 1218 1219 1220
                            "keycert.pem")
    SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
        os.path.dirname(__file__) or os.curdir,
        "https_svn_python_org_root.pem")

    if (not os.path.exists(CERTFILE) or
        not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Bill Janssen's avatar
Bill Janssen committed
1221
        raise test_support.TestFailed("Can't read certificate files!")
1222 1223 1224

    tests = [BasicTests]

1225
    if test_support.is_resource_enabled('network'):
1226
        tests.append(NetworkedTests)
1227

Bill Janssen's avatar
Bill Janssen committed
1228 1229
    if _have_threads:
        thread_info = test_support.threading_setup()
1230
        if thread_info and test_support.is_resource_enabled('network'):
1231
            tests.append(ThreadedTests)
1232

1233 1234 1235 1236 1237
    try:
        test_support.run_unittest(*tests)
    finally:
        if _have_threads:
            test_support.threading_cleanup(*thread_info)
1238 1239 1240

if __name__ == "__main__":
    test_main()