PageRenderTime 111ms CodeModel.GetById 3ms app.highlight 98ms RepoModel.GetById 1ms app.codeStats 0ms

/dj14_py27/mac/lib/python2.7/test/test_ssl.py

https://bitbucket.org/kenial/portable-django
Python | 1370 lines | 1179 code | 102 blank | 89 comment | 137 complexity | d6755c6c8d9def10f9e1318bf9a86a9b MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1# Test the support for SSL and sockets
   2
   3import sys
   4import unittest
   5from test import test_support
   6import asyncore
   7import socket
   8import select
   9import time
  10import gc
  11import os
  12import errno
  13import pprint
  14import urllib, urlparse
  15import traceback
  16import weakref
  17import functools
  18import platform
  19
  20from BaseHTTPServer import HTTPServer
  21from SimpleHTTPServer import SimpleHTTPRequestHandler
  22
  23ssl = test_support.import_module("ssl")
  24
  25HOST = test_support.HOST
  26CERTFILE = None
  27SVN_PYTHON_ORG_ROOT_CERT = None
  28
  29def handle_error(prefix):
  30    exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
  31    if test_support.verbose:
  32        sys.stdout.write(prefix + exc_format)
  33
  34
  35class BasicTests(unittest.TestCase):
  36
  37    def test_sslwrap_simple(self):
  38        # A crude test for the legacy API
  39        try:
  40            ssl.sslwrap_simple(socket.socket(socket.AF_INET))
  41        except IOError, e:
  42            if e.errno == 32: # broken pipe when ssl_sock.do_handshake(), this test doesn't care about that
  43                pass
  44            else:
  45                raise
  46        try:
  47            ssl.sslwrap_simple(socket.socket(socket.AF_INET)._sock)
  48        except IOError, e:
  49            if e.errno == 32: # broken pipe when ssl_sock.do_handshake(), this test doesn't care about that
  50                pass
  51            else:
  52                raise
  53
  54# Issue #9415: Ubuntu hijacks their OpenSSL and forcefully disables SSLv2
  55def skip_if_broken_ubuntu_ssl(func):
  56    if hasattr(ssl, 'PROTOCOL_SSLv2'):
  57        # We need to access the lower-level wrapper in order to create an
  58        # implicit SSL context without trying to connect or listen.
  59        try:
  60            import _ssl
  61        except ImportError:
  62            # The returned function won't get executed, just ignore the error
  63            pass
  64        @functools.wraps(func)
  65        def f(*args, **kwargs):
  66            try:
  67                s = socket.socket(socket.AF_INET)
  68                _ssl.sslwrap(s._sock, 0, None, None,
  69                             ssl.CERT_NONE, ssl.PROTOCOL_SSLv2, None, None)
  70            except ssl.SSLError as e:
  71                if (ssl.OPENSSL_VERSION_INFO == (0, 9, 8, 15, 15) and
  72                    platform.linux_distribution() == ('debian', 'squeeze/sid', '')
  73                    and 'Invalid SSL protocol variant specified' in str(e)):
  74                    raise unittest.SkipTest("Patched Ubuntu OpenSSL breaks behaviour")
  75            return func(*args, **kwargs)
  76        return f
  77    else:
  78        return func
  79
  80
  81class BasicSocketTests(unittest.TestCase):
  82
  83    def test_constants(self):
  84        #ssl.PROTOCOL_SSLv2
  85        ssl.PROTOCOL_SSLv23
  86        ssl.PROTOCOL_SSLv3
  87        ssl.PROTOCOL_TLSv1
  88        ssl.CERT_NONE
  89        ssl.CERT_OPTIONAL
  90        ssl.CERT_REQUIRED
  91
  92    def test_random(self):
  93        v = ssl.RAND_status()
  94        if test_support.verbose:
  95            sys.stdout.write("\n RAND_status is %d (%s)\n"
  96                             % (v, (v and "sufficient randomness") or
  97                                "insufficient randomness"))
  98        try:
  99            ssl.RAND_egd(1)
 100        except TypeError:
 101            pass
 102        else:
 103            print "didn't raise TypeError"
 104        ssl.RAND_add("this is a random string", 75.0)
 105
 106    def test_parse_cert(self):
 107        # note that this uses an 'unofficial' function in _ssl.c,
 108        # provided solely for this test, to exercise the certificate
 109        # parsing code
 110        p = ssl._ssl._test_decode_cert(CERTFILE, False)
 111        if test_support.verbose:
 112            sys.stdout.write("\n" + pprint.pformat(p) + "\n")
 113        self.assertEqual(p['subject'],
 114                         ((('countryName', u'US'),),
 115                          (('stateOrProvinceName', u'Delaware'),),
 116                          (('localityName', u'Wilmington'),),
 117                          (('organizationName', u'Python Software Foundation'),),
 118                          (('organizationalUnitName', u'SSL'),),
 119                          (('commonName', u'somemachine.python.org'),)),
 120                        )
 121        # Issue #13034: the subjectAltName in some certificates
 122        # (notably projects.developer.nokia.com:443) wasn't parsed
 123        p = ssl._ssl._test_decode_cert(NOKIACERT)
 124        if test_support.verbose:
 125            sys.stdout.write("\n" + pprint.pformat(p) + "\n")
 126        self.assertEqual(p['subjectAltName'],
 127                         (('DNS', 'projects.developer.nokia.com'),
 128                          ('DNS', 'projects.forum.nokia.com'))
 129                        )
 130
 131    def test_DER_to_PEM(self):
 132        with open(SVN_PYTHON_ORG_ROOT_CERT, 'r') as f:
 133            pem = f.read()
 134        d1 = ssl.PEM_cert_to_DER_cert(pem)
 135        p2 = ssl.DER_cert_to_PEM_cert(d1)
 136        d2 = ssl.PEM_cert_to_DER_cert(p2)
 137        self.assertEqual(d1, d2)
 138        if not p2.startswith(ssl.PEM_HEADER + '\n'):
 139            self.fail("DER-to-PEM didn't include correct header:\n%r\n" % p2)
 140        if not p2.endswith('\n' + ssl.PEM_FOOTER + '\n'):
 141            self.fail("DER-to-PEM didn't include correct footer:\n%r\n" % p2)
 142
 143    def test_openssl_version(self):
 144        n = ssl.OPENSSL_VERSION_NUMBER
 145        t = ssl.OPENSSL_VERSION_INFO
 146        s = ssl.OPENSSL_VERSION
 147        self.assertIsInstance(n, (int, long))
 148        self.assertIsInstance(t, tuple)
 149        self.assertIsInstance(s, str)
 150        # Some sanity checks follow
 151        # >= 0.9
 152        self.assertGreaterEqual(n, 0x900000)
 153        # < 2.0
 154        self.assertLess(n, 0x20000000)
 155        major, minor, fix, patch, status = t
 156        self.assertGreaterEqual(major, 0)
 157        self.assertLess(major, 2)
 158        self.assertGreaterEqual(minor, 0)
 159        self.assertLess(minor, 256)
 160        self.assertGreaterEqual(fix, 0)
 161        self.assertLess(fix, 256)
 162        self.assertGreaterEqual(patch, 0)
 163        self.assertLessEqual(patch, 26)
 164        self.assertGreaterEqual(status, 0)
 165        self.assertLessEqual(status, 15)
 166        # Version string as returned by OpenSSL, the format might change
 167        self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),
 168                        (s, t))
 169
 170    def test_ciphers(self):
 171        if not test_support.is_resource_enabled('network'):
 172            return
 173        remote = ("svn.python.org", 443)
 174        with test_support.transient_internet(remote[0]):
 175            s = ssl.wrap_socket(socket.socket(socket.AF_INET),
 176                                cert_reqs=ssl.CERT_NONE, ciphers="ALL")
 177            s.connect(remote)
 178            s = ssl.wrap_socket(socket.socket(socket.AF_INET),
 179                                cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT")
 180            s.connect(remote)
 181            # Error checking occurs when connecting, because the SSL context
 182            # isn't created before.
 183            s = ssl.wrap_socket(socket.socket(socket.AF_INET),
 184                                cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
 185            with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"):
 186                s.connect(remote)
 187
 188    @test_support.cpython_only
 189    def test_refcycle(self):
 190        # Issue #7943: an SSL object doesn't create reference cycles with
 191        # itself.
 192        s = socket.socket(socket.AF_INET)
 193        ss = ssl.wrap_socket(s)
 194        wr = weakref.ref(ss)
 195        del ss
 196        self.assertEqual(wr(), None)
 197
 198    def test_wrapped_unconnected(self):
 199        # The _delegate_methods in socket.py are correctly delegated to by an
 200        # unconnected SSLSocket, so they will raise a socket.error rather than
 201        # something unexpected like TypeError.
 202        s = socket.socket(socket.AF_INET)
 203        ss = ssl.wrap_socket(s)
 204        self.assertRaises(socket.error, ss.recv, 1)
 205        self.assertRaises(socket.error, ss.recv_into, bytearray(b'x'))
 206        self.assertRaises(socket.error, ss.recvfrom, 1)
 207        self.assertRaises(socket.error, ss.recvfrom_into, bytearray(b'x'), 1)
 208        self.assertRaises(socket.error, ss.send, b'x')
 209        self.assertRaises(socket.error, ss.sendto, b'x', ('0.0.0.0', 0))
 210
 211
 212class NetworkedTests(unittest.TestCase):
 213
 214    def test_connect(self):
 215        with test_support.transient_internet("svn.python.org"):
 216            s = ssl.wrap_socket(socket.socket(socket.AF_INET),
 217                                cert_reqs=ssl.CERT_NONE)
 218            s.connect(("svn.python.org", 443))
 219            c = s.getpeercert()
 220            if c:
 221                self.fail("Peer cert %s shouldn't be here!")
 222            s.close()
 223
 224            # this should fail because we have no verification certs
 225            s = ssl.wrap_socket(socket.socket(socket.AF_INET),
 226                                cert_reqs=ssl.CERT_REQUIRED)
 227            try:
 228                s.connect(("svn.python.org", 443))
 229            except ssl.SSLError:
 230                pass
 231            finally:
 232                s.close()
 233
 234            # this should succeed because we specify the root cert
 235            s = ssl.wrap_socket(socket.socket(socket.AF_INET),
 236                                cert_reqs=ssl.CERT_REQUIRED,
 237                                ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
 238            try:
 239                s.connect(("svn.python.org", 443))
 240            finally:
 241                s.close()
 242
 243    def test_connect_ex(self):
 244        # Issue #11326: check connect_ex() implementation
 245        with test_support.transient_internet("svn.python.org"):
 246            s = ssl.wrap_socket(socket.socket(socket.AF_INET),
 247                                cert_reqs=ssl.CERT_REQUIRED,
 248                                ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
 249            try:
 250                self.assertEqual(0, s.connect_ex(("svn.python.org", 443)))
 251                self.assertTrue(s.getpeercert())
 252            finally:
 253                s.close()
 254
 255    def test_non_blocking_connect_ex(self):
 256        # Issue #11326: non-blocking connect_ex() should allow handshake
 257        # to proceed after the socket gets ready.
 258        with test_support.transient_internet("svn.python.org"):
 259            s = ssl.wrap_socket(socket.socket(socket.AF_INET),
 260                                cert_reqs=ssl.CERT_REQUIRED,
 261                                ca_certs=SVN_PYTHON_ORG_ROOT_CERT,
 262                                do_handshake_on_connect=False)
 263            try:
 264                s.setblocking(False)
 265                rc = s.connect_ex(('svn.python.org', 443))
 266                # EWOULDBLOCK under Windows, EINPROGRESS elsewhere
 267                self.assertIn(rc, (0, errno.EINPROGRESS, errno.EWOULDBLOCK))
 268                # Wait for connect to finish
 269                select.select([], [s], [], 5.0)
 270                # Non-blocking handshake
 271                while True:
 272                    try:
 273                        s.do_handshake()
 274                        break
 275                    except ssl.SSLError as err:
 276                        if err.args[0] == ssl.SSL_ERROR_WANT_READ:
 277                            select.select([s], [], [], 5.0)
 278                        elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
 279                            select.select([], [s], [], 5.0)
 280                        else:
 281                            raise
 282                # SSL established
 283                self.assertTrue(s.getpeercert())
 284            finally:
 285                s.close()
 286
 287    @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
 288    def test_makefile_close(self):
 289        # Issue #5238: creating a file-like object with makefile() shouldn't
 290        # delay closing the underlying "real socket" (here tested with its
 291        # file descriptor, hence skipping the test under Windows).
 292        with test_support.transient_internet("svn.python.org"):
 293            ss = ssl.wrap_socket(socket.socket(socket.AF_INET))
 294            ss.connect(("svn.python.org", 443))
 295            fd = ss.fileno()
 296            f = ss.makefile()
 297            f.close()
 298            # The fd is still open
 299            os.read(fd, 0)
 300            # Closing the SSL socket should close the fd too
 301            ss.close()
 302            gc.collect()
 303            with self.assertRaises(OSError) as e:
 304                os.read(fd, 0)
 305            self.assertEqual(e.exception.errno, errno.EBADF)
 306
 307    def test_non_blocking_handshake(self):
 308        with test_support.transient_internet("svn.python.org"):
 309            s = socket.socket(socket.AF_INET)
 310            s.connect(("svn.python.org", 443))
 311            s.setblocking(False)
 312            s = ssl.wrap_socket(s,
 313                                cert_reqs=ssl.CERT_NONE,
 314                                do_handshake_on_connect=False)
 315            count = 0
 316            while True:
 317                try:
 318                    count += 1
 319                    s.do_handshake()
 320                    break
 321                except ssl.SSLError, err:
 322                    if err.args[0] == ssl.SSL_ERROR_WANT_READ:
 323                        select.select([s], [], [])
 324                    elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
 325                        select.select([], [s], [])
 326                    else:
 327                        raise
 328            s.close()
 329            if test_support.verbose:
 330                sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
 331
 332    def test_get_server_certificate(self):
 333        with test_support.transient_internet("svn.python.org"):
 334            pem = ssl.get_server_certificate(("svn.python.org", 443))
 335            if not pem:
 336                self.fail("No server certificate on svn.python.org:443!")
 337
 338            try:
 339                pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
 340            except ssl.SSLError:
 341                #should fail
 342                pass
 343            else:
 344                self.fail("Got server certificate %s for svn.python.org!" % pem)
 345
 346            pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
 347            if not pem:
 348                self.fail("No server certificate on svn.python.org:443!")
 349            if test_support.verbose:
 350                sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
 351
 352    def test_algorithms(self):
 353        # Issue #8484: all algorithms should be available when verifying a
 354        # certificate.
 355        # SHA256 was added in OpenSSL 0.9.8
 356        if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
 357            self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
 358        # NOTE: https://sha256.tbs-internet.com is another possible test host
 359        remote = ("sha256.tbs-internet.com", 443)
 360        sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
 361        with test_support.transient_internet("sha256.tbs-internet.com"):
 362            s = ssl.wrap_socket(socket.socket(socket.AF_INET),
 363                                cert_reqs=ssl.CERT_REQUIRED,
 364                                ca_certs=sha256_cert,)
 365            try:
 366                s.connect(remote)
 367                if test_support.verbose:
 368                    sys.stdout.write("\nCipher with %r is %r\n" %
 369                                     (remote, s.cipher()))
 370                    sys.stdout.write("Certificate is:\n%s\n" %
 371                                     pprint.pformat(s.getpeercert()))
 372            finally:
 373                s.close()
 374
 375
 376try:
 377    import threading
 378except ImportError:
 379    _have_threads = False
 380else:
 381    _have_threads = True
 382
 383    class ThreadedEchoServer(threading.Thread):
 384
 385        class ConnectionHandler(threading.Thread):
 386
 387            """A mildly complicated class, because we want it to work both
 388            with and without the SSL wrapper around the socket connection, so
 389            that we can test the STARTTLS functionality."""
 390
 391            def __init__(self, server, connsock):
 392                self.server = server
 393                self.running = False
 394                self.sock = connsock
 395                self.sock.setblocking(1)
 396                self.sslconn = None
 397                threading.Thread.__init__(self)
 398                self.daemon = True
 399
 400            def show_conn_details(self):
 401                if self.server.certreqs == ssl.CERT_REQUIRED:
 402                    cert = self.sslconn.getpeercert()
 403                    if test_support.verbose and self.server.chatty:
 404                        sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
 405                    cert_binary = self.sslconn.getpeercert(True)
 406                    if test_support.verbose and self.server.chatty:
 407                        sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
 408                cipher = self.sslconn.cipher()
 409                if test_support.verbose and self.server.chatty:
 410                    sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
 411
 412            def wrap_conn(self):
 413                try:
 414                    self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
 415                                                   certfile=self.server.certificate,
 416                                                   ssl_version=self.server.protocol,
 417                                                   ca_certs=self.server.cacerts,
 418                                                   cert_reqs=self.server.certreqs,
 419                                                   ciphers=self.server.ciphers)
 420                except ssl.SSLError as e:
 421                    # XXX Various errors can have happened here, for example
 422                    # a mismatching protocol version, an invalid certificate,
 423                    # or a low-level bug. This should be made more discriminating.
 424                    self.server.conn_errors.append(e)
 425                    if self.server.chatty:
 426                        handle_error("\n server:  bad connection attempt from " +
 427                                     str(self.sock.getpeername()) + ":\n")
 428                    self.close()
 429                    self.running = False
 430                    self.server.stop()
 431                    return False
 432                else:
 433                    return True
 434
 435            def read(self):
 436                if self.sslconn:
 437                    return self.sslconn.read()
 438                else:
 439                    return self.sock.recv(1024)
 440
 441            def write(self, bytes):
 442                if self.sslconn:
 443                    return self.sslconn.write(bytes)
 444                else:
 445                    return self.sock.send(bytes)
 446
 447            def close(self):
 448                if self.sslconn:
 449                    self.sslconn.close()
 450                else:
 451                    self.sock._sock.close()
 452
 453            def run(self):
 454                self.running = True
 455                if not self.server.starttls_server:
 456                    if isinstance(self.sock, ssl.SSLSocket):
 457                        self.sslconn = self.sock
 458                    elif not self.wrap_conn():
 459                        return
 460                    self.show_conn_details()
 461                while self.running:
 462                    try:
 463                        msg = self.read()
 464                        if not msg:
 465                            # eof, so quit this handler
 466                            self.running = False
 467                            self.close()
 468                        elif msg.strip() == 'over':
 469                            if test_support.verbose and self.server.connectionchatty:
 470                                sys.stdout.write(" server: client closed connection\n")
 471                            self.close()
 472                            return
 473                        elif self.server.starttls_server and msg.strip() == 'STARTTLS':
 474                            if test_support.verbose and self.server.connectionchatty:
 475                                sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
 476                            self.write("OK\n")
 477                            if not self.wrap_conn():
 478                                return
 479                        elif self.server.starttls_server and self.sslconn and msg.strip() == 'ENDTLS':
 480                            if test_support.verbose and self.server.connectionchatty:
 481                                sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
 482                            self.write("OK\n")
 483                            self.sslconn.unwrap()
 484                            self.sslconn = None
 485                            if test_support.verbose and self.server.connectionchatty:
 486                                sys.stdout.write(" server: connection is now unencrypted...\n")
 487                        else:
 488                            if (test_support.verbose and
 489                                self.server.connectionchatty):
 490                                ctype = (self.sslconn and "encrypted") or "unencrypted"
 491                                sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
 492                                                 % (repr(msg), ctype, repr(msg.lower()), ctype))
 493                            self.write(msg.lower())
 494                    except ssl.SSLError:
 495                        if self.server.chatty:
 496                            handle_error("Test server failure:\n")
 497                        self.close()
 498                        self.running = False
 499                        # normally, we'd just stop here, but for the test
 500                        # harness, we want to stop the server
 501                        self.server.stop()
 502
 503        def __init__(self, certificate, ssl_version=None,
 504                     certreqs=None, cacerts=None,
 505                     chatty=True, connectionchatty=False, starttls_server=False,
 506                     wrap_accepting_socket=False, ciphers=None):
 507
 508            if ssl_version is None:
 509                ssl_version = ssl.PROTOCOL_TLSv1
 510            if certreqs is None:
 511                certreqs = ssl.CERT_NONE
 512            self.certificate = certificate
 513            self.protocol = ssl_version
 514            self.certreqs = certreqs
 515            self.cacerts = cacerts
 516            self.ciphers = ciphers
 517            self.chatty = chatty
 518            self.connectionchatty = connectionchatty
 519            self.starttls_server = starttls_server
 520            self.sock = socket.socket()
 521            self.flag = None
 522            if wrap_accepting_socket:
 523                self.sock = ssl.wrap_socket(self.sock, server_side=True,
 524                                            certfile=self.certificate,
 525                                            cert_reqs = self.certreqs,
 526                                            ca_certs = self.cacerts,
 527                                            ssl_version = self.protocol,
 528                                            ciphers = self.ciphers)
 529                if test_support.verbose and self.chatty:
 530                    sys.stdout.write(' server:  wrapped server socket as %s\n' % str(self.sock))
 531            self.port = test_support.bind_port(self.sock)
 532            self.active = False
 533            self.conn_errors = []
 534            threading.Thread.__init__(self)
 535            self.daemon = True
 536
 537        def __enter__(self):
 538            self.start(threading.Event())
 539            self.flag.wait()
 540            return self
 541
 542        def __exit__(self, *args):
 543            self.stop()
 544            self.join()
 545
 546        def start(self, flag=None):
 547            self.flag = flag
 548            threading.Thread.start(self)
 549
 550        def run(self):
 551            self.sock.settimeout(0.05)
 552            self.sock.listen(5)
 553            self.active = True
 554            if self.flag:
 555                # signal an event
 556                self.flag.set()
 557            while self.active:
 558                try:
 559                    newconn, connaddr = self.sock.accept()
 560                    if test_support.verbose and self.chatty:
 561                        sys.stdout.write(' server:  new connection from '
 562                                         + str(connaddr) + '\n')
 563                    handler = self.ConnectionHandler(self, newconn)
 564                    handler.start()
 565                    handler.join()
 566                except socket.timeout:
 567                    pass
 568                except KeyboardInterrupt:
 569                    self.stop()
 570            self.sock.close()
 571
 572        def stop(self):
 573            self.active = False
 574
 575    class AsyncoreEchoServer(threading.Thread):
 576
 577        class EchoServer(asyncore.dispatcher):
 578
 579            class ConnectionHandler(asyncore.dispatcher_with_send):
 580
 581                def __init__(self, conn, certfile):
 582                    asyncore.dispatcher_with_send.__init__(self, conn)
 583                    self.socket = ssl.wrap_socket(conn, server_side=True,
 584                                                  certfile=certfile,
 585                                                  do_handshake_on_connect=False)
 586                    self._ssl_accepting = True
 587
 588                def readable(self):
 589                    if isinstance(self.socket, ssl.SSLSocket):
 590                        while self.socket.pending() > 0:
 591                            self.handle_read_event()
 592                    return True
 593
 594                def _do_ssl_handshake(self):
 595                    try:
 596                        self.socket.do_handshake()
 597                    except ssl.SSLError, err:
 598                        if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
 599                                           ssl.SSL_ERROR_WANT_WRITE):
 600                            return
 601                        elif err.args[0] == ssl.SSL_ERROR_EOF:
 602                            return self.handle_close()
 603                        raise
 604                    except socket.error, err:
 605                        if err.args[0] == errno.ECONNABORTED:
 606                            return self.handle_close()
 607                    else:
 608                        self._ssl_accepting = False
 609
 610                def handle_read(self):
 611                    if self._ssl_accepting:
 612                        self._do_ssl_handshake()
 613                    else:
 614                        data = self.recv(1024)
 615                        if data and data.strip() != 'over':
 616                            self.send(data.lower())
 617
 618                def handle_close(self):
 619                    self.close()
 620                    if test_support.verbose:
 621                        sys.stdout.write(" server:  closed connection %s\n" % self.socket)
 622
 623                def handle_error(self):
 624                    raise
 625
 626            def __init__(self, certfile):
 627                self.certfile = certfile
 628                asyncore.dispatcher.__init__(self)
 629                self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
 630                self.port = test_support.bind_port(self.socket)
 631                self.listen(5)
 632
 633            def handle_accept(self):
 634                sock_obj, addr = self.accept()
 635                if test_support.verbose:
 636                    sys.stdout.write(" server:  new connection from %s:%s\n" %addr)
 637                self.ConnectionHandler(sock_obj, self.certfile)
 638
 639            def handle_error(self):
 640                raise
 641
 642        def __init__(self, certfile):
 643            self.flag = None
 644            self.active = False
 645            self.server = self.EchoServer(certfile)
 646            self.port = self.server.port
 647            threading.Thread.__init__(self)
 648            self.daemon = True
 649
 650        def __str__(self):
 651            return "<%s %s>" % (self.__class__.__name__, self.server)
 652
 653        def __enter__(self):
 654            self.start(threading.Event())
 655            self.flag.wait()
 656            return self
 657
 658        def __exit__(self, *args):
 659            if test_support.verbose:
 660                sys.stdout.write(" cleanup: stopping server.\n")
 661            self.stop()
 662            if test_support.verbose:
 663                sys.stdout.write(" cleanup: joining server thread.\n")
 664            self.join()
 665            if test_support.verbose:
 666                sys.stdout.write(" cleanup: successfully joined.\n")
 667
 668        def start(self, flag=None):
 669            self.flag = flag
 670            threading.Thread.start(self)
 671
 672        def run(self):
 673            self.active = True
 674            if self.flag:
 675                self.flag.set()
 676            while self.active:
 677                asyncore.loop(0.05)
 678
 679        def stop(self):
 680            self.active = False
 681            self.server.close()
 682
 683    class SocketServerHTTPSServer(threading.Thread):
 684
 685        class HTTPSServer(HTTPServer):
 686
 687            def __init__(self, server_address, RequestHandlerClass, certfile):
 688                HTTPServer.__init__(self, server_address, RequestHandlerClass)
 689                # we assume the certfile contains both private key and certificate
 690                self.certfile = certfile
 691                self.allow_reuse_address = True
 692
 693            def __str__(self):
 694                return ('<%s %s:%s>' %
 695                        (self.__class__.__name__,
 696                         self.server_name,
 697                         self.server_port))
 698
 699            def get_request(self):
 700                # override this to wrap socket with SSL
 701                sock, addr = self.socket.accept()
 702                sslconn = ssl.wrap_socket(sock, server_side=True,
 703                                          certfile=self.certfile)
 704                return sslconn, addr
 705
 706        class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
 707            # need to override translate_path to get a known root,
 708            # instead of using os.curdir, since the test could be
 709            # run from anywhere
 710
 711            server_version = "TestHTTPS/1.0"
 712
 713            root = None
 714
 715            def translate_path(self, path):
 716                """Translate a /-separated PATH to the local filename syntax.
 717
 718                Components that mean special things to the local file system
 719                (e.g. drive or directory names) are ignored.  (XXX They should
 720                probably be diagnosed.)
 721
 722                """
 723                # abandon query parameters
 724                path = urlparse.urlparse(path)[2]
 725                path = os.path.normpath(urllib.unquote(path))
 726                words = path.split('/')
 727                words = filter(None, words)
 728                path = self.root
 729                for word in words:
 730                    drive, word = os.path.splitdrive(word)
 731                    head, word = os.path.split(word)
 732                    if word in self.root: continue
 733                    path = os.path.join(path, word)
 734                return path
 735
 736            def log_message(self, format, *args):
 737
 738                # we override this to suppress logging unless "verbose"
 739
 740                if test_support.verbose:
 741                    sys.stdout.write(" server (%s:%d %s):\n   [%s] %s\n" %
 742                                     (self.server.server_address,
 743                                      self.server.server_port,
 744                                      self.request.cipher(),
 745                                      self.log_date_time_string(),
 746                                      format%args))
 747
 748
 749        def __init__(self, certfile):
 750            self.flag = None
 751            self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
 752            self.server = self.HTTPSServer(
 753                (HOST, 0), self.RootedHTTPRequestHandler, certfile)
 754            self.port = self.server.server_port
 755            threading.Thread.__init__(self)
 756            self.daemon = True
 757
 758        def __str__(self):
 759            return "<%s %s>" % (self.__class__.__name__, self.server)
 760
 761        def start(self, flag=None):
 762            self.flag = flag
 763            threading.Thread.start(self)
 764
 765        def run(self):
 766            if self.flag:
 767                self.flag.set()
 768            self.server.serve_forever(0.05)
 769
 770        def stop(self):
 771            self.server.shutdown()
 772
 773
 774    def bad_cert_test(certfile):
 775        """
 776        Launch a server with CERT_REQUIRED, and check that trying to
 777        connect to it with the given client certificate fails.
 778        """
 779        server = ThreadedEchoServer(CERTFILE,
 780                                    certreqs=ssl.CERT_REQUIRED,
 781                                    cacerts=CERTFILE, chatty=False)
 782        with server:
 783            try:
 784                s = ssl.wrap_socket(socket.socket(),
 785                                    certfile=certfile,
 786                                    ssl_version=ssl.PROTOCOL_TLSv1)
 787                s.connect((HOST, server.port))
 788            except ssl.SSLError, x:
 789                if test_support.verbose:
 790                    sys.stdout.write("\nSSLError is %s\n" % x[1])
 791            except socket.error, x:
 792                if test_support.verbose:
 793                    sys.stdout.write("\nsocket.error is %s\n" % x[1])
 794            else:
 795                raise AssertionError("Use of invalid cert should have failed!")
 796
 797    def server_params_test(certfile, protocol, certreqs, cacertsfile,
 798                           client_certfile, client_protocol=None, indata="FOO\n",
 799                           ciphers=None, chatty=True, connectionchatty=False,
 800                           wrap_accepting_socket=False):
 801        """
 802        Launch a server, connect a client to it and try various reads
 803        and writes.
 804        """
 805        server = ThreadedEchoServer(certfile,
 806                                    certreqs=certreqs,
 807                                    ssl_version=protocol,
 808                                    cacerts=cacertsfile,
 809                                    ciphers=ciphers,
 810                                    chatty=chatty,
 811                                    connectionchatty=connectionchatty,
 812                                    wrap_accepting_socket=wrap_accepting_socket)
 813        with server:
 814            # try to connect
 815            if client_protocol is None:
 816                client_protocol = protocol
 817            s = ssl.wrap_socket(socket.socket(),
 818                                certfile=client_certfile,
 819                                ca_certs=cacertsfile,
 820                                ciphers=ciphers,
 821                                cert_reqs=certreqs,
 822                                ssl_version=client_protocol)
 823            s.connect((HOST, server.port))
 824            for arg in [indata, bytearray(indata), memoryview(indata)]:
 825                if connectionchatty:
 826                    if test_support.verbose:
 827                        sys.stdout.write(
 828                            " client:  sending %s...\n" % (repr(arg)))
 829                s.write(arg)
 830                outdata = s.read()
 831                if connectionchatty:
 832                    if test_support.verbose:
 833                        sys.stdout.write(" client:  read %s\n" % repr(outdata))
 834                if outdata != indata.lower():
 835                    raise AssertionError(
 836                        "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
 837                        % (outdata[:min(len(outdata),20)], len(outdata),
 838                           indata[:min(len(indata),20)].lower(), len(indata)))
 839            s.write("over\n")
 840            if connectionchatty:
 841                if test_support.verbose:
 842                    sys.stdout.write(" client:  closing connection.\n")
 843            s.close()
 844
 845    def try_protocol_combo(server_protocol,
 846                           client_protocol,
 847                           expect_success,
 848                           certsreqs=None):
 849        if certsreqs is None:
 850            certsreqs = ssl.CERT_NONE
 851        certtype = {
 852            ssl.CERT_NONE: "CERT_NONE",
 853            ssl.CERT_OPTIONAL: "CERT_OPTIONAL",
 854            ssl.CERT_REQUIRED: "CERT_REQUIRED",
 855        }[certsreqs]
 856        if test_support.verbose:
 857            formatstr = (expect_success and " %s->%s %s\n") or " {%s->%s} %s\n"
 858            sys.stdout.write(formatstr %
 859                             (ssl.get_protocol_name(client_protocol),
 860                              ssl.get_protocol_name(server_protocol),
 861                              certtype))
 862        try:
 863            # NOTE: we must enable "ALL" ciphers, otherwise an SSLv23 client
 864            # will send an SSLv3 hello (rather than SSLv2) starting from
 865            # OpenSSL 1.0.0 (see issue #8322).
 866            server_params_test(CERTFILE, server_protocol, certsreqs,
 867                               CERTFILE, CERTFILE, client_protocol,
 868                               ciphers="ALL", chatty=False)
 869        # Protocol mismatch can result in either an SSLError, or a
 870        # "Connection reset by peer" error.
 871        except ssl.SSLError:
 872            if expect_success:
 873                raise
 874        except socket.error as e:
 875            if expect_success or e.errno != errno.ECONNRESET:
 876                raise
 877        else:
 878            if not expect_success:
 879                raise AssertionError(
 880                    "Client protocol %s succeeded with server protocol %s!"
 881                    % (ssl.get_protocol_name(client_protocol),
 882                       ssl.get_protocol_name(server_protocol)))
 883
 884
 885    class ThreadedTests(unittest.TestCase):
 886
 887        def test_rude_shutdown(self):
 888            """A brutal shutdown of an SSL server should raise an IOError
 889            in the client when attempting handshake.
 890            """
 891            listener_ready = threading.Event()
 892            listener_gone = threading.Event()
 893
 894            s = socket.socket()
 895            port = test_support.bind_port(s, HOST)
 896
 897            # `listener` runs in a thread.  It sits in an accept() until
 898            # the main thread connects.  Then it rudely closes the socket,
 899            # and sets Event `listener_gone` to let the main thread know
 900            # the socket is gone.
 901            def listener():
 902                s.listen(5)
 903                listener_ready.set()
 904                s.accept()
 905                s.close()
 906                listener_gone.set()
 907
 908            def connector():
 909                listener_ready.wait()
 910                c = socket.socket()
 911                c.connect((HOST, port))
 912                listener_gone.wait()
 913                try:
 914                    ssl_sock = ssl.wrap_socket(c)
 915                except IOError:
 916                    pass
 917                else:
 918                    self.fail('connecting to closed SSL socket should have failed')
 919
 920            t = threading.Thread(target=listener)
 921            t.start()
 922            try:
 923                connector()
 924            finally:
 925                t.join()
 926
 927        @skip_if_broken_ubuntu_ssl
 928        def test_echo(self):
 929            """Basic test of an SSL client connecting to a server"""
 930            if test_support.verbose:
 931                sys.stdout.write("\n")
 932            server_params_test(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
 933                               CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
 934                               chatty=True, connectionchatty=True)
 935
 936        def test_getpeercert(self):
 937            if test_support.verbose:
 938                sys.stdout.write("\n")
 939            s2 = socket.socket()
 940            server = ThreadedEchoServer(CERTFILE,
 941                                        certreqs=ssl.CERT_NONE,
 942                                        ssl_version=ssl.PROTOCOL_SSLv23,
 943                                        cacerts=CERTFILE,
 944                                        chatty=False)
 945            with server:
 946                s = ssl.wrap_socket(socket.socket(),
 947                                    certfile=CERTFILE,
 948                                    ca_certs=CERTFILE,
 949                                    cert_reqs=ssl.CERT_REQUIRED,
 950                                    ssl_version=ssl.PROTOCOL_SSLv23)
 951                s.connect((HOST, server.port))
 952                cert = s.getpeercert()
 953                self.assertTrue(cert, "Can't get peer certificate.")
 954                cipher = s.cipher()
 955                if test_support.verbose:
 956                    sys.stdout.write(pprint.pformat(cert) + '\n')
 957                    sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
 958                if 'subject' not in cert:
 959                    self.fail("No subject field in certificate: %s." %
 960                              pprint.pformat(cert))
 961                if ((('organizationName', 'Python Software Foundation'),)
 962                    not in cert['subject']):
 963                    self.fail(
 964                        "Missing or invalid 'organizationName' field in certificate subject; "
 965                        "should be 'Python Software Foundation'.")
 966                s.close()
 967
 968        def test_empty_cert(self):
 969            """Connecting with an empty cert file"""
 970            bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
 971                                      "nullcert.pem"))
 972        def test_malformed_cert(self):
 973            """Connecting with a badly formatted certificate (syntax error)"""
 974            bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
 975                                       "badcert.pem"))
 976        def test_nonexisting_cert(self):
 977            """Connecting with a non-existing cert file"""
 978            bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
 979                                       "wrongcert.pem"))
 980        def test_malformed_key(self):
 981            """Connecting with a badly formatted key (syntax error)"""
 982            bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
 983                                       "badkey.pem"))
 984
 985        @skip_if_broken_ubuntu_ssl
 986        def test_protocol_sslv2(self):
 987            """Connecting to an SSLv2 server with various client options"""
 988            if test_support.verbose:
 989                sys.stdout.write("\n")
 990            if not hasattr(ssl, 'PROTOCOL_SSLv2'):
 991                self.skipTest("PROTOCOL_SSLv2 needed")
 992            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
 993            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
 994            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
 995            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
 996            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
 997            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
 998
 999        @skip_if_broken_ubuntu_ssl
1000        def test_protocol_sslv23(self):
1001            """Connecting to an SSLv23 server with various client options"""
1002            if test_support.verbose:
1003                sys.stdout.write("\n")
1004            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
1005            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
1006            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
1007
1008            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
1009            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
1010            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
1011
1012            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
1013            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
1014            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
1015
1016        @skip_if_broken_ubuntu_ssl
1017        def test_protocol_sslv3(self):
1018            """Connecting to an SSLv3 server with various client options"""
1019            if test_support.verbose:
1020                sys.stdout.write("\n")
1021            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
1022            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
1023            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
1024            if hasattr(ssl, 'PROTOCOL_SSLv2'):
1025                try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
1026            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
1027
1028        @skip_if_broken_ubuntu_ssl
1029        def test_protocol_tlsv1(self):
1030            """Connecting to a TLSv1 server with various client options"""
1031            if test_support.verbose:
1032                sys.stdout.write("\n")
1033            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
1034            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
1035            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
1036            if hasattr(ssl, 'PROTOCOL_SSLv2'):
1037                try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
1038            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
1039
1040        def test_starttls(self):
1041            """Switching from clear text to encrypted and back again."""
1042            msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
1043
1044            server = ThreadedEchoServer(CERTFILE,
1045                                        ssl_version=ssl.PROTOCOL_TLSv1,
1046                                        starttls_server=True,
1047                                        chatty=True,
1048                                        connectionchatty=True)
1049            wrapped = False
1050            with server:
1051                s = socket.socket()
1052                s.setblocking(1)
1053                s.connect((HOST, server.port))
1054                if test_support.verbose:
1055                    sys.stdout.write("\n")
1056                for indata in msgs:
1057                    if test_support.verbose:
1058                        sys.stdout.write(
1059                            " client:  sending %s...\n" % repr(indata))
1060                    if wrapped:
1061                        conn.write(indata)
1062                        outdata = conn.read()
1063                    else:
1064                        s.send(indata)
1065                        outdata = s.recv(1024)
1066                    if (indata == "STARTTLS" and
1067                        outdata.strip().lower().startswith("ok")):
1068                        # STARTTLS ok, switch to secure mode
1069                        if test_support.verbose:
1070                            sys.stdout.write(
1071                                " client:  read %s from server, starting TLS...\n"
1072                                % repr(outdata))
1073                        conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
1074                        wrapped = True
1075                    elif (indata == "ENDTLS" and
1076                        outdata.strip().lower().startswith("ok")):
1077                        # ENDTLS ok, switch back to clear text
1078                        if test_support.verbose:
1079                            sys.stdout.write(
1080                                " client:  read %s from server, ending TLS...\n"
1081                                % repr(outdata))
1082                        s = conn.unwrap()
1083                        wrapped = False
1084                    else:
1085                        if test_support.verbose:
1086                            sys.stdout.write(
1087                                " client:  read %s from server\n" % repr(outdata))
1088                if test_support.verbose:
1089                    sys.stdout.write(" client:  closing connection.\n")
1090                if wrapped:
1091                    conn.write("over\n")
1092                else:
1093                    s.send("over\n")
1094                s.close()
1095
1096        def test_socketserver(self):
1097            """Using a SocketServer to create and manage SSL connections."""
1098            server = SocketServerHTTPSServer(CERTFILE)
1099            flag = threading.Event()
1100            server.start(flag)
1101            # wait for it to start
1102            flag.wait()
1103            # try to connect
1104            try:
1105                if test_support.verbose:
1106                    sys.stdout.write('\n')
1107                with open(CERTFILE, 'rb') as f:
1108                    d1 = f.read()
1109                d2 = ''
1110                # now fetch the same data from the HTTPS server
1111                url = 'https://127.0.0.1:%d/%s' % (
1112                    server.port, os.path.split(CERTFILE)[1])
1113                with test_support.check_py3k_warnings():
1114                    f = urllib.urlopen(url)
1115                dlen = f.info().getheader("content-length")
1116                if dlen and (int(dlen) > 0):
1117                    d2 = f.read(int(dlen))
1118                    if test_support.verbose:
1119                        sys.stdout.write(
1120                            " client: read %d bytes from remote server '%s'\n"
1121                            % (len(d2), server))
1122                f.close()
1123                self.assertEqual(d1, d2)
1124            finally:
1125                server.stop()
1126                server.join()
1127
1128        def test_wrapped_accept(self):
1129            """Check the accept() method on SSL sockets."""
1130            if test_support.verbose:
1131                sys.stdout.write("\n")
1132            server_params_test(CERTFILE, ssl.PROTOCOL_SSLv23, ssl.CERT_REQUIRED,
1133                               CERTFILE, CERTFILE, ssl.PROTOCOL_SSLv23,
1134                               chatty=True, connectionchatty=True,
1135                               wrap_accepting_socket=True)
1136
1137        def test_asyncore_server(self):
1138            """Check the example asyncore integration."""
1139            indata = "TEST MESSAGE of mixed case\n"
1140
1141            if test_support.verbose:
1142                sys.stdout.write("\n")
1143            server = AsyncoreEchoServer(CERTFILE)
1144            with server:
1145                s = ssl.wrap_socket(socket.socket())
1146                s.connect(('127.0.0.1', server.port))
1147                if test_support.verbose:
1148                    sys.stdout.write(
1149                        " client:  sending %s...\n" % (repr(indata)))
1150                s.write(indata)
1151                outdata = s.read()
1152                if test_support.verbose:
1153                    sys.stdout.write(" client:  read %s\n" % repr(outdata))
1154                if outdata != indata.lower():
1155                    self.fail(
1156                        "bad data <<%s>> …

Large files files are truncated, but you can click here to view the full file