PageRenderTime 4ms CodeModel.GetById 4ms app.highlight 73ms RepoModel.GetById 1ms app.codeStats 1ms

/lib-python/2.7/test/test_ssl.py

https://bitbucket.org/nbtaylor/pypy
Python | 1369 lines | 1177 code | 102 blank | 90 comment | 137 complexity | 11e90867cfb9c3da63c1c8d7c526f31b 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                # XXX why is it necessary?
 914                test_support.gc_collect()
 915                try:
 916                    ssl_sock = ssl.wrap_socket(c)
 917                except IOError:
 918                    pass
 919                else:
 920                    self.fail('connecting to closed SSL socket should have failed')
 921
 922            t = threading.Thread(target=listener)
 923            t.start()
 924            try:
 925                connector()
 926            finally:
 927                t.join()
 928
 929        @skip_if_broken_ubuntu_ssl
 930        def test_echo(self):
 931            """Basic test of an SSL client connecting to a server"""
 932            if test_support.verbose:
 933                sys.stdout.write("\n")
 934            server_params_test(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
 935                               CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
 936                               chatty=True, connectionchatty=True)
 937
 938        def test_getpeercert(self):
 939            if test_support.verbose:
 940                sys.stdout.write("\n")
 941            s2 = socket.socket()
 942            server = ThreadedEchoServer(CERTFILE,
 943                                        certreqs=ssl.CERT_NONE,
 944                                        ssl_version=ssl.PROTOCOL_SSLv23,
 945                                        cacerts=CERTFILE,
 946                                        chatty=False)
 947            with server:
 948                s = ssl.wrap_socket(socket.socket(),
 949                                    certfile=CERTFILE,
 950                                    ca_certs=CERTFILE,
 951                                    cert_reqs=ssl.CERT_REQUIRED,
 952                                    ssl_version=ssl.PROTOCOL_SSLv23)
 953                s.connect((HOST, server.port))
 954                cert = s.getpeercert()
 955                self.assertTrue(cert, "Can't get peer certificate.")
 956                cipher = s.cipher()
 957                if test_support.verbose:
 958                    sys.stdout.write(pprint.pformat(cert) + '\n')
 959                    sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
 960                if 'subject' not in cert:
 961                    self.fail("No subject field in certificate: %s." %
 962                              pprint.pformat(cert))
 963                if ((('organizationName', 'Python Software Foundation'),)
 964                    not in cert['subject']):
 965                    self.fail(
 966                        "Missing or invalid 'organizationName' field in certificate subject; "
 967                        "should be 'Python Software Foundation'.")
 968                s.close()
 969
 970        def test_empty_cert(self):
 971            """Connecting with an empty cert file"""
 972            bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
 973                                      "nullcert.pem"))
 974        def test_malformed_cert(self):
 975            """Connecting with a badly formatted certificate (syntax error)"""
 976            bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
 977                                       "badcert.pem"))
 978        def test_nonexisting_cert(self):
 979            """Connecting with a non-existing cert file"""
 980            bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
 981                                       "wrongcert.pem"))
 982        def test_malformed_key(self):
 983            """Connecting with a badly formatted key (syntax error)"""
 984            bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
 985                                       "badkey.pem"))
 986
 987        @skip_if_broken_ubuntu_ssl
 988        def test_protocol_sslv2(self):
 989            """Connecting to an SSLv2 server with various client options"""
 990            if test_support.verbose:
 991                sys.stdout.write("\n")
 992            if not hasattr(ssl, 'PROTOCOL_SSLv2'):
 993                self.skipTest("PROTOCOL_SSLv2 needed")
 994            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
 995            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
 996            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
 997            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
 998            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
 999            try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
1000
1001        @skip_if_broken_ubuntu_ssl
1002        def test_protocol_sslv23(self):
1003            """Connecting to an SSLv23 server with various client options"""
1004            if test_support.verbose:
1005                sys.stdout.write("\n")
1006            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
1007            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
1008            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
1009
1010            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
1011            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
1012            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
1013
1014            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
1015            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
1016            try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
1017
1018        @skip_if_broken_ubuntu_ssl
1019        def test_protocol_sslv3(self):
1020            """Connecting to an SSLv3 server with various client options"""
1021            if test_support.verbose:
1022                sys.stdout.write("\n")
1023            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
1024            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
1025            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
1026            if hasattr(ssl, 'PROTOCOL_SSLv2'):
1027                try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
1028            try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
1029
1030        @skip_if_broken_ubuntu_ssl
1031        def test_protocol_tlsv1(self):
1032            """Connecting to a TLSv1 server with various client options"""
1033            if test_support.verbose:
1034                sys.stdout.write("\n")
1035            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
1036            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
1037            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
1038            if hasattr(ssl, 'PROTOCOL_SSLv2'):
1039                try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
1040            try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
1041
1042        def test_starttls(self):
1043            """Switching from clear text to encrypted and back again."""
1044            msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
1045
1046            server = ThreadedEchoServer(CERTFILE,
1047                                        ssl_version=ssl.PROTOCOL_TLSv1,
1048                                        starttls_server=True,
1049                                        chatty=True,
1050                                        connectionchatty=True)
1051            wrapped = False
1052            with server:
1053                s = socket.socket()
1054                s.setblocking(1)
1055                s.connect((HOST, server.port))
1056                if test_support.verbose:
1057                    sys.stdout.write("\n")
1058                for indata in msgs:
1059                    if test_support.verbose:
1060                        sys.stdout.write(
1061                            " client:  sending %s...\n" % repr(indata))
1062                    if wrapped:
1063                        conn.write(indata)
1064                        outdata = conn.read()
1065                    else:
1066                        s.send(indata)
1067                        outdata = s.recv(1024)
1068                    if (indata == "STARTTLS" and
1069                        outdata.strip().lower().startswith("ok")):
1070                        # STARTTLS ok, switch to secure mode
1071                        if test_support.verbose:
1072                            sys.stdout.write(
1073                                " client:  read %s from server, starting TLS...\n"
1074                                % repr(outdata))
1075                        conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
1076                        wrapped = True
1077                    elif (indata == "ENDTLS" and
1078                        outdata.strip().lower().startswith("ok")):
1079                        # ENDTLS ok, switch back to clear text
1080                        if test_support.verbose:
1081                            sys.stdout.write(
1082                                " client:  read %s from server, ending TLS...\n"
1083                                % repr(outdata))
1084                        s = conn.unwrap()
1085                        wrapped = False
1086                    else:
1087                        if test_support.verbose:
1088                            sys.stdout.write(
1089                                " client:  read %s from server\n" % repr(outdata))
1090                if test_support.verbose:
1091                    sys.stdout.write(" client:  closing connection.\n")
1092                if wrapped:
1093                    conn.write("over\n")
1094                else:
1095                    s.send("over\n")
1096                s.close()
1097
1098        def test_socketserver(self):
1099            """Using a SocketServer to create and manage SSL connections."""
1100            server = SocketServerHTTPSServer(CERTFILE)
1101            flag = threading.Event()
1102            server.start(flag)
1103            # wait for it to start
1104            flag.wait()
1105            # try to connect
1106            try:
1107                if test_support.verbose:
1108                    sys.stdout.write('\n')
1109                with open(CERTFILE, 'rb') as f:
1110                    d1 = f.read()
1111                d2 = ''
1112                # now fetch the same data from the HTTPS server
1113                url = 'https://127.0.0.1:%d/%s' % (
1114                    server.port, os.path.split(CERTFILE)[1])
1115                with test_support.check_py3k_warnings():
1116                    f = urllib.urlopen(url)
1117                dlen = f.info().getheader("content-length")
1118                if dlen and (int(dlen) > 0):
1119                    d2 = f.read(int(dlen))
1120                    if test_support.verbose:
1121                        sys.stdout.write(
1122                            " client: read %d bytes from remote server '%s'\n"
1123                            % (len(d2), server))
1124                f.close()
1125                self.assertEqual(d1, d2)
1126            finally:
1127                server.stop()
1128                server.join()
1129
1130        def test_wrapped_accept(self):
1131            """Check the accept() method on SSL sockets."""
1132            if test_support.verbose:
1133                sys.stdout.write("\n")
1134            server_params_test(CERTFILE, ssl.PROTOCOL_SSLv23, ssl.CERT_REQUIRED,
1135                               CERTFILE, CERTFILE, ssl.PROTOCOL_SSLv23,
1136                               chatty=True, connectionchatty=True,
1137                               wrap_accepting_socket=True)
1138
1139        def test_asyncore_server(self):
1140            """Check the example asyncore integration."""
1141            indata = "TEST MESSAGE of mixed case\n"
1142
1143            if test_support.verbose:
1144                sys.stdout.write("\n")
1145            server = AsyncoreEchoServer(CERTFILE)
1146            with server:
1147                s = ssl.wrap_socket(socket.socket())
1148                s.connect(('127.0.0.1', server.port))
1149                if test_support.verbose:
1150                    sys.stdout.write(
1151                        " client:  sending %s...\n" % (repr(indata)))
1152                s.write(indata)
1153                outdata = s.read()
1154                if test_support.verbose:
1155                    sys.stdout.write(" client:  read %s\n" % repr(outdata))
1156                if outdata != ind

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