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