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