blob: f00478cf412d278f9984e7d14c552b9259cd0d15 [file] [log] [blame]
Thomas Woutersed03b412007-08-28 21:37:11 +00001# Test the support for SSL and sockets
2
3import sys
4import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00005from test import support
Thomas Woutersed03b412007-08-28 21:37:11 +00006import socket
Bill Janssen6e027db2007-11-15 22:23:56 +00007import select
Thomas Woutersed03b412007-08-28 21:37:11 +00008import time
9import os
10import pprint
Jeremy Hylton1afc1692008-06-18 20:49:58 +000011import urllib.parse, urllib.request
Thomas Woutersed03b412007-08-28 21:37:11 +000012import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000013import asyncore
Antoine Pitrou9d543662010-04-23 23:10:32 +000014import weakref
Thomas Woutersed03b412007-08-28 21:37:11 +000015
Georg Brandl24420152008-05-26 16:32:26 +000016from http.server import HTTPServer, SimpleHTTPRequestHandler
Thomas Wouters1b7f8912007-09-19 03:06:30 +000017
Thomas Woutersed03b412007-08-28 21:37:11 +000018# Optionally test SSL support, if we have it in the tested platform
19skip_expected = False
20try:
21 import ssl
22except ImportError:
23 skip_expected = True
24
Benjamin Petersonee8712c2008-05-20 21:35:26 +000025HOST = support.HOST
Thomas Woutersed03b412007-08-28 21:37:11 +000026CERTFILE = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +000027SVN_PYTHON_ORG_ROOT_CERT = None
Thomas Woutersed03b412007-08-28 21:37:11 +000028
Thomas Woutersed03b412007-08-28 21:37:11 +000029def handle_error(prefix):
30 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +000031 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000032 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +000033
34
35class BasicTests(unittest.TestCase):
36
Georg Brandlfceab5a2008-01-19 20:08:23 +000037 def testSSLconnect(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000038 if not support.is_resource_enabled('network'):
Georg Brandlfceab5a2008-01-19 20:08:23 +000039 return
40 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
41 cert_reqs=ssl.CERT_NONE)
42 s.connect(("svn.python.org", 443))
43 c = s.getpeercert()
44 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +000045 raise support.TestFailed("Peer cert %s shouldn't be here!")
Georg Brandlfceab5a2008-01-19 20:08:23 +000046 s.close()
47
48 # this should fail because we have no verification certs
49 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
50 cert_reqs=ssl.CERT_REQUIRED)
51 try:
52 s.connect(("svn.python.org", 443))
53 except ssl.SSLError:
54 pass
55 finally:
56 s.close()
57
Thomas Wouters1b7f8912007-09-19 03:06:30 +000058 def testCrucialConstants(self):
59 ssl.PROTOCOL_SSLv2
60 ssl.PROTOCOL_SSLv23
61 ssl.PROTOCOL_SSLv3
62 ssl.PROTOCOL_TLSv1
63 ssl.CERT_NONE
64 ssl.CERT_OPTIONAL
65 ssl.CERT_REQUIRED
Thomas Woutersed03b412007-08-28 21:37:11 +000066
Thomas Wouters1b7f8912007-09-19 03:06:30 +000067 def testRAND(self):
68 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +000069 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000070 sys.stdout.write("\n RAND_status is %d (%s)\n"
71 % (v, (v and "sufficient randomness") or
72 "insufficient randomness"))
Thomas Woutersed03b412007-08-28 21:37:11 +000073 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000074 ssl.RAND_egd(1)
75 except TypeError:
76 pass
Thomas Woutersed03b412007-08-28 21:37:11 +000077 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000078 print("didn't raise TypeError")
79 ssl.RAND_add("this is a random string", 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +000080
Thomas Wouters1b7f8912007-09-19 03:06:30 +000081 def testParseCert(self):
82 # note that this uses an 'unofficial' function in _ssl.c,
83 # provided solely for this test, to exercise the certificate
84 # parsing code
85 p = ssl._ssl._test_decode_cert(CERTFILE, False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +000086 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000087 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Thomas Woutersed03b412007-08-28 21:37:11 +000088
Thomas Wouters1b7f8912007-09-19 03:06:30 +000089 def testDERtoPEM(self):
90
91 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
92 d1 = ssl.PEM_cert_to_DER_cert(pem)
93 p2 = ssl.DER_cert_to_PEM_cert(d1)
94 d2 = ssl.PEM_cert_to_DER_cert(p2)
95 if (d1 != d2):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000096 raise support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
Thomas Wouters1b7f8912007-09-19 03:06:30 +000097
Antoine Pitrou04f6a322010-04-05 21:40:07 +000098 def test_openssl_version(self):
99 n = ssl.OPENSSL_VERSION_NUMBER
100 t = ssl.OPENSSL_VERSION_INFO
101 s = ssl.OPENSSL_VERSION
102 self.assertIsInstance(n, int)
103 self.assertIsInstance(t, tuple)
104 self.assertIsInstance(s, str)
105 # Some sanity checks follow
106 # >= 0.9
107 self.assertGreaterEqual(n, 0x900000)
108 # < 2.0
109 self.assertLess(n, 0x20000000)
110 major, minor, fix, patch, status = t
111 self.assertGreaterEqual(major, 0)
112 self.assertLess(major, 2)
113 self.assertGreaterEqual(minor, 0)
114 self.assertLess(minor, 256)
115 self.assertGreaterEqual(fix, 0)
116 self.assertLess(fix, 256)
117 self.assertGreaterEqual(patch, 0)
118 self.assertLessEqual(patch, 26)
119 self.assertGreaterEqual(status, 0)
120 self.assertLessEqual(status, 15)
121 # Version string as returned by OpenSSL, the format might change
122 self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)),
123 (s, t))
124
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000125 def test_ciphers(self):
126 if not support.is_resource_enabled('network'):
127 return
128 remote = ("svn.python.org", 443)
129 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
130 cert_reqs=ssl.CERT_NONE, ciphers="ALL")
131 s.connect(remote)
132 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
133 cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT")
134 s.connect(remote)
135 # Error checking occurs when connecting, because the SSL context
136 # isn't created before.
137 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
138 cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
139 with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"):
140 s.connect(remote)
141
Antoine Pitrou9d543662010-04-23 23:10:32 +0000142 @support.cpython_only
143 def test_refcycle(self):
144 # Issue #7943: an SSL object doesn't create reference cycles with
145 # itself.
146 s = socket.socket(socket.AF_INET)
147 ss = ssl.wrap_socket(s)
148 wr = weakref.ref(ss)
149 del ss
150 self.assertEqual(wr(), None)
151
Antoine Pitrou04f6a322010-04-05 21:40:07 +0000152
Bill Janssen6e027db2007-11-15 22:23:56 +0000153class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000154
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000155 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000156 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
157 cert_reqs=ssl.CERT_NONE)
158 s.connect(("svn.python.org", 443))
159 c = s.getpeercert()
160 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000161 raise support.TestFailed("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000162 s.close()
163
164 # this should fail because we have no verification certs
165 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
166 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000167 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000168 s.connect(("svn.python.org", 443))
169 except ssl.SSLError:
170 pass
171 finally:
172 s.close()
173
174 # this should succeed because we specify the root cert
175 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
176 cert_reqs=ssl.CERT_REQUIRED,
177 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
178 try:
179 s.connect(("svn.python.org", 443))
180 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000181 raise support.TestFailed("Unexpected exception %s" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000182 finally:
183 s.close()
184
Bill Janssen6e027db2007-11-15 22:23:56 +0000185 def testNonBlockingHandshake(self):
186 s = socket.socket(socket.AF_INET)
187 s.connect(("svn.python.org", 443))
188 s.setblocking(False)
189 s = ssl.wrap_socket(s,
190 cert_reqs=ssl.CERT_NONE,
191 do_handshake_on_connect=False)
192 count = 0
193 while True:
194 try:
195 count += 1
196 s.do_handshake()
197 break
198 except ssl.SSLError as err:
199 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
200 select.select([s], [], [])
201 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
202 select.select([], [s], [])
203 else:
204 raise
205 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000206 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000207 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000208
Bill Janssen54cc54c2007-12-14 22:08:56 +0000209 def testFetchServerCert(self):
210
211 pem = ssl.get_server_certificate(("svn.python.org", 443))
212 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000213 raise support.TestFailed("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000214
215 return
216
217 try:
218 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
219 except ssl.SSLError as x:
220 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000221 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000222 sys.stdout.write("%s\n" % x)
223 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000224 raise support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000225
226 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
227 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000228 raise support.TestFailed("No server certificate on svn.python.org:443!")
229 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000230 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
231
Antoine Pitroufec12ff2010-04-21 19:46:23 +0000232 def test_algorithms(self):
233 # Issue #8484: all algorithms should be available when verifying a
234 # certificate.
Antoine Pitrou29619b22010-04-22 18:43:31 +0000235 # SHA256 was added in OpenSSL 0.9.8
236 if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
237 self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
Antoine Pitroufec12ff2010-04-21 19:46:23 +0000238 # NOTE: https://sha256.tbs-internet.com is another possible test host
239 remote = ("sha2.hboeck.de", 443)
240 sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
241 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
242 cert_reqs=ssl.CERT_REQUIRED,
243 ca_certs=sha256_cert,)
244 with support.transient_internet():
245 try:
246 s.connect(remote)
247 if support.verbose:
248 sys.stdout.write("\nCipher with %r is %r\n" %
249 (remote, s.cipher()))
250 sys.stdout.write("Certificate is:\n%s\n" %
251 pprint.pformat(s.getpeercert()))
252 finally:
253 s.close()
254
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000255
256try:
257 import threading
258except ImportError:
259 _have_threads = False
260else:
261
262 _have_threads = True
263
264 class ThreadedEchoServer(threading.Thread):
265
266 class ConnectionHandler(threading.Thread):
267
268 """A mildly complicated class, because we want it to work both
269 with and without the SSL wrapper around the socket connection, so
270 that we can test the STARTTLS functionality."""
271
Bill Janssen6e027db2007-11-15 22:23:56 +0000272 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000273 self.server = server
274 self.running = False
275 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000276 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000277 self.sock.setblocking(1)
278 self.sslconn = None
279 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000280 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000281
282 def wrap_conn (self):
283 try:
284 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
285 certfile=self.server.certificate,
286 ssl_version=self.server.protocol,
287 ca_certs=self.server.cacerts,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000288 cert_reqs=self.server.certreqs,
289 ciphers=self.server.ciphers)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000290 except:
291 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000292 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000293 if not self.server.expect_bad_connects:
294 # here, we want to stop the server, because this shouldn't
295 # happen in the context of our test case
296 self.running = False
297 # normally, we'd just stop here, but for the test
298 # harness, we want to stop the server
299 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000300 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000301 return False
302
303 else:
304 if self.server.certreqs == ssl.CERT_REQUIRED:
305 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000306 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000307 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
308 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000309 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000310 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
311 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000312 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000313 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
314 return True
315
316 def read(self):
317 if self.sslconn:
318 return self.sslconn.read()
319 else:
320 return self.sock.recv(1024)
321
322 def write(self, bytes):
323 if self.sslconn:
324 return self.sslconn.write(bytes)
325 else:
326 return self.sock.send(bytes)
327
328 def close(self):
329 if self.sslconn:
330 self.sslconn.close()
331 else:
332 self.sock.close()
333
334 def run (self):
335 self.running = True
336 if not self.server.starttls_server:
337 if not self.wrap_conn():
338 return
339 while self.running:
340 try:
341 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000342 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000343 if not msg:
344 # eof, so quit this handler
345 self.running = False
346 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000347 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000348 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000349 sys.stdout.write(" server: client closed connection\n")
350 self.close()
351 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000352 elif (self.server.starttls_server and
353 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000354 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000355 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000356 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000357 if not self.wrap_conn():
358 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000359 elif (self.server.starttls_server and self.sslconn
360 and amsg.strip() == 'ENDTLS'):
361 if support.verbose and self.server.connectionchatty:
362 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
363 self.write("OK\n".encode("ASCII", "strict"))
364 self.sock = self.sslconn.unwrap()
365 self.sslconn = None
366 if support.verbose and self.server.connectionchatty:
367 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000368 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000369 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000370 self.server.connectionchatty):
371 ctype = (self.sslconn and "encrypted") or "unencrypted"
372 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
373 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000374 self.write(amsg.lower().encode('ASCII', 'strict'))
375 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000376 if self.server.chatty:
377 handle_error("Test server failure:\n")
378 self.close()
379 self.running = False
380 # normally, we'd just stop here, but for the test
381 # harness, we want to stop the server
382 self.server.stop()
383 except:
384 handle_error('')
385
Trent Nelson78520002008-04-10 20:54:35 +0000386 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000387 certreqs=None, cacerts=None, expect_bad_connects=False,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000388 chatty=True, connectionchatty=False, starttls_server=False,
389 ciphers=None):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000390 if ssl_version is None:
391 ssl_version = ssl.PROTOCOL_TLSv1
392 if certreqs is None:
393 certreqs = ssl.CERT_NONE
394 self.certificate = certificate
395 self.protocol = ssl_version
396 self.certreqs = certreqs
397 self.cacerts = cacerts
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000398 self.ciphers = ciphers
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000399 self.expect_bad_connects = expect_bad_connects
400 self.chatty = chatty
401 self.connectionchatty = connectionchatty
402 self.starttls_server = starttls_server
403 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000404 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000405 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000406 self.active = False
407 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000408 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000409
410 def start (self, flag=None):
411 self.flag = flag
412 threading.Thread.start(self)
413
414 def run (self):
415 self.sock.settimeout(0.5)
416 self.sock.listen(5)
417 self.active = True
418 if self.flag:
419 # signal an event
420 self.flag.set()
421 while self.active:
422 try:
423 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000424 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000425 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000426 + repr(connaddr) + '\n')
427 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000428 handler.start()
429 except socket.timeout:
430 pass
431 except KeyboardInterrupt:
432 self.stop()
433 except:
434 if self.chatty:
435 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000436 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000437
438 def stop (self):
439 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000440
Bill Janssen54cc54c2007-12-14 22:08:56 +0000441 class OurHTTPSServer(threading.Thread):
442
443 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000444
445 class HTTPSServer(HTTPServer):
446
447 def __init__(self, server_address, RequestHandlerClass, certfile):
448
449 HTTPServer.__init__(self, server_address, RequestHandlerClass)
450 # we assume the certfile contains both private key and certificate
451 self.certfile = certfile
452 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000453 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000454 self.allow_reuse_address = True
455
Bill Janssen6e027db2007-11-15 22:23:56 +0000456 def __str__(self):
457 return ('<%s %s:%s>' %
458 (self.__class__.__name__,
459 self.server_name,
460 self.server_port))
461
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000462 def get_request (self):
463 # override this to wrap socket with SSL
464 sock, addr = self.socket.accept()
465 sslconn = ssl.wrap_socket(sock, server_side=True,
466 certfile=self.certfile)
467 return sslconn, addr
468
469 # The methods overridden below this are mainly so that we
470 # can run it in a thread and be able to stop it from another
471 # You probably wouldn't need them in other uses.
472
473 def server_activate(self):
474 # We want to run this in a thread for testing purposes,
475 # so we override this to set timeout, so that we get
476 # a chance to stop the server
477 self.socket.settimeout(0.5)
478 HTTPServer.server_activate(self)
479
480 def serve_forever(self):
481 # We want this to run in a thread, so we use a slightly
482 # modified version of "forever".
483 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000484 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000485 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000486 # We need to lock while handling the request.
487 # Another thread can close the socket after self.active
488 # has been checked and before the request is handled.
489 # This causes an exception when using the closed socket.
490 with self.active_lock:
491 if not self.active:
492 break
493 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000494 except socket.timeout:
495 pass
496 except KeyboardInterrupt:
497 self.server_close()
498 return
499 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000500 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
501 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000502 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000503
504 def server_close(self):
505 # Again, we want this to run in a thread, so we need to override
506 # close to clear the "active" flag, so that serve_forever() will
507 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000508 with self.active_lock:
509 HTTPServer.server_close(self)
510 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000511
512 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
513
514 # need to override translate_path to get a known root,
515 # instead of using os.curdir, since the test could be
516 # run from anywhere
517
518 server_version = "TestHTTPS/1.0"
519
520 root = None
521
522 def translate_path(self, path):
523 """Translate a /-separated PATH to the local filename syntax.
524
525 Components that mean special things to the local file system
526 (e.g. drive or directory names) are ignored. (XXX They should
527 probably be diagnosed.)
528
529 """
530 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000531 path = urllib.parse.urlparse(path)[2]
532 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000533 words = path.split('/')
534 words = filter(None, words)
535 path = self.root
536 for word in words:
537 drive, word = os.path.splitdrive(word)
538 head, word = os.path.split(word)
539 if word in self.root: continue
540 path = os.path.join(path, word)
541 return path
542
543 def log_message(self, format, *args):
544
545 # we override this to suppress logging unless "verbose"
546
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000547 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000548 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
549 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000550 self.server.server_port,
551 self.request.cipher(),
552 self.log_date_time_string(),
553 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000554
555
Trent Nelson78520002008-04-10 20:54:35 +0000556 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000557 self.flag = None
558 self.active = False
559 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000560 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000561 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000562 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000563 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000564 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000565
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000566 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000567 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000568
569 def start (self, flag=None):
570 self.flag = flag
571 threading.Thread.start(self)
572
Thomas Woutersed03b412007-08-28 21:37:11 +0000573 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000574 self.active = True
575 if self.flag:
576 self.flag.set()
577 self.server.serve_forever()
578 self.active = False
579
580 def stop (self):
581 self.active = False
582 self.server.server_close()
583
584
Bill Janssen54cc54c2007-12-14 22:08:56 +0000585 class AsyncoreEchoServer(threading.Thread):
586
587 # this one's based on asyncore.dispatcher
588
589 class EchoServer (asyncore.dispatcher):
590
591 class ConnectionHandler (asyncore.dispatcher_with_send):
592
593 def __init__(self, conn, certfile):
594 self.socket = ssl.wrap_socket(conn, server_side=True,
595 certfile=certfile,
596 do_handshake_on_connect=False)
597 asyncore.dispatcher_with_send.__init__(self, self.socket)
598 # now we have to do the handshake
599 # we'll just do it the easy way, and block the connection
600 # till it's finished. If we were doing it right, we'd
601 # do this in multiple calls to handle_read...
602 self.do_handshake(block=True)
603
604 def readable(self):
605 if isinstance(self.socket, ssl.SSLSocket):
606 while self.socket.pending() > 0:
607 self.handle_read_event()
608 return True
609
610 def handle_read(self):
611 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000612 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000613 sys.stdout.write(" server: read %s from client\n" % repr(data))
614 if not data:
615 self.close()
616 else:
617 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
618
619 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000620 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000621 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000622 sys.stdout.write(" server: closed connection %s\n" % self.socket)
623
624 def handle_error(self):
625 raise
626
627 def __init__(self, port, certfile):
628 self.port = port
629 self.certfile = certfile
630 asyncore.dispatcher.__init__(self)
631 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
632 self.bind(('', port))
633 self.listen(5)
634
635 def handle_accept(self):
636 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000637 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000638 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
639 self.ConnectionHandler(sock_obj, self.certfile)
640
641 def handle_error(self):
642 raise
643
Trent Nelson78520002008-04-10 20:54:35 +0000644 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000645 self.flag = None
646 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000647 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000648 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000649 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000650 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000651
652 def __str__(self):
653 return "<%s %s>" % (self.__class__.__name__, self.server)
654
655 def start (self, flag=None):
656 self.flag = flag
657 threading.Thread.start(self)
658
659 def run (self):
660 self.active = True
661 if self.flag:
662 self.flag.set()
663 while self.active:
664 try:
665 asyncore.loop(1)
666 except:
667 pass
668
669 def stop (self):
670 self.active = False
671 self.server.close()
672
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000673 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000674 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000675 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000676 cacerts=CERTFILE, chatty=False,
677 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000678 flag = threading.Event()
679 server.start(flag)
680 # wait for it to start
681 flag.wait()
682 # try to connect
683 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000684 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000685 s = ssl.wrap_socket(socket.socket(),
686 certfile=certfile,
687 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000688 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000689 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000690 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000691 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000692 except socket.error as x:
693 if support.verbose:
694 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000695 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000696 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000697 "Use of invalid cert should have failed!")
698 finally:
699 server.stop()
700 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000701
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000702 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000703 client_certfile, client_protocol=None,
704 indata="FOO\n",
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000705 ciphers=None, chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000706
Trent Nelson78520002008-04-10 20:54:35 +0000707 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000708 certreqs=certreqs,
709 ssl_version=protocol,
710 cacerts=cacertsfile,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000711 ciphers=ciphers,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000712 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000713 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000714 flag = threading.Event()
715 server.start(flag)
716 # wait for it to start
717 flag.wait()
718 # try to connect
719 if client_protocol is None:
720 client_protocol = protocol
721 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000722 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000723 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000724 certfile=client_certfile,
725 ca_certs=cacertsfile,
726 cert_reqs=certreqs,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000727 ciphers=ciphers,
Bill Janssen6e027db2007-11-15 22:23:56 +0000728 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000729 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000730 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000731 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000732 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000733 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000734 else:
Antoine Pitrou7d7aede2009-11-25 18:55:32 +0000735 bindata = indata.encode('ASCII', 'strict')
736 for arg in [bindata, bytearray(bindata), memoryview(bindata)]:
737 if connectionchatty:
738 if support.verbose:
739 sys.stdout.write(
740 " client: sending %s...\n" % (repr(indata)))
741 s.write(arg)
742 outdata = s.read()
743 if connectionchatty:
744 if support.verbose:
745 sys.stdout.write(" client: read %s\n" % repr(outdata))
746 outdata = str(outdata, 'ASCII', 'strict')
747 if outdata != indata.lower():
748 raise support.TestFailed(
749 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
750 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
751 repr(indata[:min(len(indata),20)].lower()), len(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000752 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000753 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000754 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000755 sys.stdout.write(" client: closing connection.\n")
756 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000757 finally:
758 server.stop()
759 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000760
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000761 def tryProtocolCombo (server_protocol,
762 client_protocol,
763 expectedToWork,
764 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000765
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000766 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000767 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000768
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000769 if certsreqs == ssl.CERT_NONE:
770 certtype = "CERT_NONE"
771 elif certsreqs == ssl.CERT_OPTIONAL:
772 certtype = "CERT_OPTIONAL"
773 elif certsreqs == ssl.CERT_REQUIRED:
774 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000775 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000776 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
777 sys.stdout.write(formatstr %
778 (ssl.get_protocol_name(client_protocol),
779 ssl.get_protocol_name(server_protocol),
780 certtype))
781 try:
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000782 # NOTE: we must enable "ALL" ciphers, otherwise an SSLv23 client
783 # will send an SSLv3 hello (rather than SSLv2) starting from
784 # OpenSSL 1.0.0 (see issue #8322).
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000785 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000786 CERTFILE, CERTFILE, client_protocol,
Antoine Pitrou2d9cb9c2010-04-17 17:40:45 +0000787 ciphers="ALL",
Bill Janssen6e027db2007-11-15 22:23:56 +0000788 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000789 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000790 if expectedToWork:
791 raise
792 else:
793 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000794 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000795 "Client protocol %s succeeded with server protocol %s!"
796 % (ssl.get_protocol_name(client_protocol),
797 ssl.get_protocol_name(server_protocol)))
798
799
Bill Janssen6e027db2007-11-15 22:23:56 +0000800 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000801
Trent Nelson6b240cd2008-04-10 20:12:06 +0000802 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000803
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000804 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000805 sys.stdout.write("\n")
806 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
807 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
808 chatty=True, connectionchatty=True)
809
810 def testReadCert(self):
811
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000812 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000813 sys.stdout.write("\n")
814 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000815 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000816 certreqs=ssl.CERT_NONE,
817 ssl_version=ssl.PROTOCOL_SSLv23,
818 cacerts=CERTFILE,
819 chatty=False)
820 flag = threading.Event()
821 server.start(flag)
822 # wait for it to start
823 flag.wait()
824 # try to connect
825 try:
826 try:
827 s = ssl.wrap_socket(socket.socket(),
828 certfile=CERTFILE,
829 ca_certs=CERTFILE,
830 cert_reqs=ssl.CERT_REQUIRED,
831 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000832 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000833 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000834 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000835 "Unexpected SSL error: " + str(x))
836 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000837 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000838 "Unexpected exception: " + str(x))
839 else:
840 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000841 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000842 "Can't SSL-handshake with test server")
843 cert = s.getpeercert()
844 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000845 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000846 "Can't get peer certificate.")
847 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000848 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000849 sys.stdout.write(pprint.pformat(cert) + '\n')
850 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000851 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000852 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000853 "No subject field in certificate: %s." %
854 pprint.pformat(cert))
855 if ((('organizationName', 'Python Software Foundation'),)
856 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000857 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000858 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000859 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000860 s.close()
861 finally:
862 server.stop()
863 server.join()
864
865 def testNULLcert(self):
866 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
867 "nullcert.pem"))
868 def testMalformedCert(self):
869 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
870 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000871 def testWrongCert(self):
872 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
873 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000874 def testMalformedKey(self):
875 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
876 "badkey.pem"))
877
Trent Nelson6b240cd2008-04-10 20:12:06 +0000878 def testRudeShutdown(self):
879
880 listener_ready = threading.Event()
881 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000882 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000883
884 # `listener` runs in a thread. It opens a socket listening on
885 # PORT, and sits in an accept() until the main thread connects.
886 # Then it rudely closes the socket, and sets Event `listener_gone`
887 # to let the main thread know the socket is gone.
888 def listener():
889 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000890 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000891 s.listen(5)
892 listener_ready.set()
893 s.accept()
894 s = None # reclaim the socket object, which also closes it
895 listener_gone.set()
896
897 def connector():
898 listener_ready.wait()
899 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000900 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000901 listener_gone.wait()
902 try:
903 ssl_sock = ssl.wrap_socket(s)
904 except IOError:
905 pass
906 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000907 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000908 'connecting to closed SSL socket should have failed')
909
910 t = threading.Thread(target=listener)
911 t.start()
912 connector()
913 t.join()
914
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000915 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000916 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000917 sys.stdout.write("\n")
918 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
919 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
920 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
921 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
922 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
923 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
924
925 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000926 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000927 sys.stdout.write("\n")
928 try:
929 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000930 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000931 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000932 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000933 sys.stdout.write(
934 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
935 % str(x))
936 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
937 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
938 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
939
940 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
941 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
942 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
943
944 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
945 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
946 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
947
948 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000949 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000950 sys.stdout.write("\n")
951 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
952 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
953 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
954 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
955 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
956 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
957
958 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000959 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000960 sys.stdout.write("\n")
961 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
962 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
963 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
964 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
965 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
966 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
967
968 def testSTARTTLS (self):
969
Bill Janssen40a0f662008-08-12 16:56:25 +0000970 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000971
Trent Nelson78520002008-04-10 20:54:35 +0000972 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000973 ssl_version=ssl.PROTOCOL_TLSv1,
974 starttls_server=True,
975 chatty=True,
976 connectionchatty=True)
977 flag = threading.Event()
978 server.start(flag)
979 # wait for it to start
980 flag.wait()
981 # try to connect
982 wrapped = False
983 try:
984 try:
985 s = socket.socket()
986 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000987 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000988 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000989 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000990 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000991 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000992 sys.stdout.write("\n")
993 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000994 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000995 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000996 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000997 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000998 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000999 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001000 outdata = conn.read()
1001 else:
Bill Janssen6e027db2007-11-15 22:23:56 +00001002 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001003 outdata = s.recv(1024)
1004 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +00001005 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001006 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +00001007 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001008 sys.stdout.write(
1009 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +00001010 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001011 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001012 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +00001013 elif (indata == "ENDTLS" and
1014 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
1015 if support.verbose:
1016 msg = str(outdata, 'ASCII', 'replace')
1017 sys.stdout.write(
1018 " client: read %s from server, ending TLS...\n"
1019 % repr(msg))
1020 s = conn.unwrap()
1021 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001022 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001023 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +00001024 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001025 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +00001026 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001027 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001028 sys.stdout.write(" client: closing connection.\n")
1029 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +00001030 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001031 else:
Bill Janssen40a0f662008-08-12 16:56:25 +00001032 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +00001033 if wrapped:
1034 conn.close()
1035 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001036 s.close()
1037 finally:
1038 server.stop()
1039 server.join()
1040
Bill Janssen54cc54c2007-12-14 22:08:56 +00001041 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +00001042
Trent Nelson78520002008-04-10 20:54:35 +00001043 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001044 flag = threading.Event()
1045 server.start(flag)
1046 # wait for it to start
1047 flag.wait()
1048 # try to connect
1049 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001050 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001051 sys.stdout.write('\n')
1052 d1 = open(CERTFILE, 'rb').read()
1053 d2 = ''
1054 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +00001055 url = 'https://%s:%d/%s' % (
1056 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001057 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +00001058 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001059 if dlen and (int(dlen) > 0):
1060 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001061 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001062 sys.stdout.write(
1063 " client: read %d bytes from remote server '%s'\n"
1064 % (len(d2), server))
1065 f.close()
1066 except:
1067 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001068 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001069 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001070 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001071 else:
1072 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +00001073 print("d1 is", len(d1), repr(d1))
1074 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001075 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001076 "Couldn't fetch data from HTTPS server")
1077 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001078 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001079 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001080 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001081 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001082 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001083 server.join()
1084
Trent Nelson6b240cd2008-04-10 20:12:06 +00001085 def testAsyncoreServer(self):
1086
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001087 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001088 sys.stdout.write("\n")
1089
1090 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001091 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001092 flag = threading.Event()
1093 server.start(flag)
1094 # wait for it to start
1095 flag.wait()
1096 # try to connect
1097 try:
1098 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001099 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001100 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001101 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001102 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001103 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001104 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001105 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001106 sys.stdout.write(
1107 " client: sending %s...\n" % (repr(indata)))
1108 s.sendall(indata.encode('ASCII', 'strict'))
1109 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001110 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001111 sys.stdout.write(" client: read %s\n" % repr(outdata))
1112 outdata = str(outdata, 'ASCII', 'strict')
1113 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001114 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001115 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1116 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1117 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1118 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001119 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001120 sys.stdout.write(" client: closing connection.\n")
1121 s.close()
1122 finally:
1123 server.stop()
1124 server.join()
1125
Bill Janssen58afe4c2008-09-08 16:45:19 +00001126 def testAllRecvAndSendMethods(self):
1127
1128 if support.verbose:
1129 sys.stdout.write("\n")
1130
1131 server = ThreadedEchoServer(CERTFILE,
1132 certreqs=ssl.CERT_NONE,
1133 ssl_version=ssl.PROTOCOL_TLSv1,
1134 cacerts=CERTFILE,
1135 chatty=True,
1136 connectionchatty=False)
1137 flag = threading.Event()
1138 server.start(flag)
1139 # wait for it to start
1140 flag.wait()
1141 # try to connect
1142 try:
1143 s = ssl.wrap_socket(socket.socket(),
1144 server_side=False,
1145 certfile=CERTFILE,
1146 ca_certs=CERTFILE,
1147 cert_reqs=ssl.CERT_NONE,
1148 ssl_version=ssl.PROTOCOL_TLSv1)
1149 s.connect((HOST, server.port))
1150 except ssl.SSLError as x:
Georg Brandl89fad142010-03-14 10:23:39 +00001151 self.fail("Unexpected SSL error: " + str(x))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001152 except Exception as x:
Georg Brandl89fad142010-03-14 10:23:39 +00001153 self.fail("Unexpected exception: " + str(x))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001154 else:
1155 # helper methods for standardising recv* method signatures
1156 def _recv_into():
1157 b = bytearray(b"\0"*100)
1158 count = s.recv_into(b)
1159 return b[:count]
1160
1161 def _recvfrom_into():
1162 b = bytearray(b"\0"*100)
1163 count, addr = s.recvfrom_into(b)
1164 return b[:count]
1165
1166 # (name, method, whether to expect success, *args)
1167 send_methods = [
1168 ('send', s.send, True, []),
1169 ('sendto', s.sendto, False, ["some.address"]),
1170 ('sendall', s.sendall, True, []),
1171 ]
1172 recv_methods = [
1173 ('recv', s.recv, True, []),
1174 ('recvfrom', s.recvfrom, False, ["some.address"]),
1175 ('recv_into', _recv_into, True, []),
1176 ('recvfrom_into', _recvfrom_into, False, []),
1177 ]
1178 data_prefix = "PREFIX_"
1179
1180 for meth_name, send_meth, expect_success, args in send_methods:
1181 indata = data_prefix + meth_name
1182 try:
1183 send_meth(indata.encode('ASCII', 'strict'), *args)
1184 outdata = s.read()
1185 outdata = str(outdata, 'ASCII', 'strict')
1186 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001187 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001188 "While sending with <<{name:s}>> bad data "
1189 "<<{outdata:s}>> ({nout:d}) received; "
1190 "expected <<{indata:s}>> ({nin:d})\n".format(
1191 name=meth_name, outdata=repr(outdata[:20]),
1192 nout=len(outdata),
1193 indata=repr(indata[:20]), nin=len(indata)
1194 )
1195 )
1196 except ValueError as e:
1197 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001198 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001199 "Failed to send with method <<{name:s}>>; "
1200 "expected to succeed.\n".format(name=meth_name)
1201 )
1202 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001203 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001204 "Method <<{name:s}>> failed with unexpected "
1205 "exception message: {exp:s}\n".format(
1206 name=meth_name, exp=e
1207 )
1208 )
1209
1210 for meth_name, recv_meth, expect_success, args in recv_methods:
1211 indata = data_prefix + meth_name
1212 try:
1213 s.send(indata.encode('ASCII', 'strict'))
1214 outdata = recv_meth(*args)
1215 outdata = str(outdata, 'ASCII', 'strict')
1216 if outdata != indata.lower():
Georg Brandl89fad142010-03-14 10:23:39 +00001217 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001218 "While receiving with <<{name:s}>> bad data "
1219 "<<{outdata:s}>> ({nout:d}) received; "
1220 "expected <<{indata:s}>> ({nin:d})\n".format(
1221 name=meth_name, outdata=repr(outdata[:20]),
1222 nout=len(outdata),
1223 indata=repr(indata[:20]), nin=len(indata)
1224 )
1225 )
1226 except ValueError as e:
1227 if expect_success:
Georg Brandl89fad142010-03-14 10:23:39 +00001228 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001229 "Failed to receive with method <<{name:s}>>; "
1230 "expected to succeed.\n".format(name=meth_name)
1231 )
1232 if not str(e).startswith(meth_name):
Georg Brandl89fad142010-03-14 10:23:39 +00001233 self.fail(
Bill Janssen58afe4c2008-09-08 16:45:19 +00001234 "Method <<{name:s}>> failed with unexpected "
1235 "exception message: {exp:s}\n".format(
1236 name=meth_name, exp=e
1237 )
1238 )
1239 # consume data
1240 s.read()
1241
1242 s.write("over\n".encode("ASCII", "strict"))
1243 s.close()
1244 finally:
1245 server.stop()
1246 server.join()
1247
1248
Thomas Woutersed03b412007-08-28 21:37:11 +00001249def test_main(verbose=False):
1250 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001251 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001252
Trent Nelson78520002008-04-10 20:54:35 +00001253 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001254 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1255 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001256 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1257 os.path.dirname(__file__) or os.curdir,
1258 "https_svn_python_org_root.pem")
1259
1260 if (not os.path.exists(CERTFILE) or
1261 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001262 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001263
Thomas Woutersed03b412007-08-28 21:37:11 +00001264 tests = [BasicTests]
1265
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001266 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001267 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001268
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001269 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001270 thread_info = support.threading_setup()
1271 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001272 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001273
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001274 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001275
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001276 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001277 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001278
1279if __name__ == "__main__":
1280 test_main()