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