blob: cef8ef66e000c54119a9b3fd921c7b0ea2c0adef [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 errno
Thomas Woutersed03b412007-08-28 21:37:11 +00009import subprocess
10import time
Antoine Pitrou3b9b9ba2010-04-23 23:33:50 +000011import gc
Thomas Woutersed03b412007-08-28 21:37:11 +000012import os
Antoine Pitrou3b9b9ba2010-04-23 23:33:50 +000013import errno
Thomas Woutersed03b412007-08-28 21:37:11 +000014import pprint
Jeremy Hylton1afc1692008-06-18 20:49:58 +000015import urllib.parse, urllib.request
Thomas Woutersed03b412007-08-28 21:37:11 +000016import shutil
17import traceback
Bill Janssen54cc54c2007-12-14 22:08:56 +000018import asyncore
Antoine Pitrou78f4a9a2010-04-23 23:12:22 +000019import weakref
Thomas Woutersed03b412007-08-28 21:37:11 +000020
Georg Brandl24420152008-05-26 16:32:26 +000021from http.server import HTTPServer, SimpleHTTPRequestHandler
Thomas Wouters1b7f8912007-09-19 03:06:30 +000022
Thomas Woutersed03b412007-08-28 21:37:11 +000023# Optionally test SSL support, if we have it in the tested platform
24skip_expected = False
25try:
26 import ssl
27except ImportError:
28 skip_expected = True
29
Benjamin Petersonee8712c2008-05-20 21:35:26 +000030HOST = support.HOST
Thomas Woutersed03b412007-08-28 21:37:11 +000031CERTFILE = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +000032SVN_PYTHON_ORG_ROOT_CERT = None
Thomas Woutersed03b412007-08-28 21:37:11 +000033
Thomas Woutersed03b412007-08-28 21:37:11 +000034def handle_error(prefix):
35 exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +000036 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000037 sys.stdout.write(prefix + exc_format)
Thomas Woutersed03b412007-08-28 21:37:11 +000038
39
40class BasicTests(unittest.TestCase):
41
Antoine Pitrou91382d82010-04-28 21:39:56 +000042 def test_constants(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +000043 ssl.PROTOCOL_SSLv2
44 ssl.PROTOCOL_SSLv23
45 ssl.PROTOCOL_SSLv3
46 ssl.PROTOCOL_TLSv1
47 ssl.CERT_NONE
48 ssl.CERT_OPTIONAL
49 ssl.CERT_REQUIRED
Thomas Woutersed03b412007-08-28 21:37:11 +000050
Antoine Pitrou91382d82010-04-28 21:39:56 +000051 def test_random(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +000052 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +000053 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000054 sys.stdout.write("\n RAND_status is %d (%s)\n"
55 % (v, (v and "sufficient randomness") or
56 "insufficient randomness"))
Thomas Woutersed03b412007-08-28 21:37:11 +000057 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000058 ssl.RAND_egd(1)
59 except TypeError:
60 pass
Thomas Woutersed03b412007-08-28 21:37:11 +000061 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000062 print("didn't raise TypeError")
63 ssl.RAND_add("this is a random string", 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +000064
Antoine Pitrou91382d82010-04-28 21:39:56 +000065 def test_parse_cert(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +000066 # note that this uses an 'unofficial' function in _ssl.c,
67 # provided solely for this test, to exercise the certificate
68 # parsing code
69 p = ssl._ssl._test_decode_cert(CERTFILE, False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +000070 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000071 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Thomas Woutersed03b412007-08-28 21:37:11 +000072
Antoine Pitrou91382d82010-04-28 21:39:56 +000073 def test_DER_to_PEM(self):
74 with open(SVN_PYTHON_ORG_ROOT_CERT, 'r') as f:
75 pem = f.read()
Thomas Wouters1b7f8912007-09-19 03:06:30 +000076 d1 = ssl.PEM_cert_to_DER_cert(pem)
77 p2 = ssl.DER_cert_to_PEM_cert(d1)
78 d2 = ssl.PEM_cert_to_DER_cert(p2)
Antoine Pitrou66ffb262010-04-27 11:05:15 +000079 self.assertEqual(d1, d2)
Antoine Pitrou00f905e2010-04-27 22:09:05 +000080 if not p2.startswith(ssl.PEM_HEADER + '\n'):
81 self.fail("DER-to-PEM didn't include correct header:\n%r\n" % p2)
82 if not p2.endswith('\n' + ssl.PEM_FOOTER + '\n'):
83 self.fail("DER-to-PEM didn't include correct footer:\n%r\n" % p2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +000084
Antoine Pitrou78f4a9a2010-04-23 23:12:22 +000085 @support.cpython_only
86 def test_refcycle(self):
87 # Issue #7943: an SSL object doesn't create reference cycles with
88 # itself.
89 s = socket.socket(socket.AF_INET)
90 ss = ssl.wrap_socket(s)
91 wr = weakref.ref(ss)
92 del ss
93 self.assertEqual(wr(), None)
94
Antoine Pitrouc2203f92010-04-24 22:07:51 +000095 def test_timeout(self):
96 # Issue #8524: when creating an SSL socket, the timeout of the
97 # original socket should be retained.
98 for timeout in (None, 0.0, 5.0):
99 s = socket.socket(socket.AF_INET)
100 s.settimeout(timeout)
101 ss = ssl.wrap_socket(s)
102 self.assertEqual(timeout, ss.gettimeout())
103
Antoine Pitrou3b9b9ba2010-04-23 23:33:50 +0000104
Bill Janssen6e027db2007-11-15 22:23:56 +0000105class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000106
Antoine Pitrou91382d82010-04-28 21:39:56 +0000107 def test_connect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000108 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
109 cert_reqs=ssl.CERT_NONE)
110 s.connect(("svn.python.org", 443))
111 c = s.getpeercert()
112 if c:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000113 self.fail("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000114 s.close()
115
116 # this should fail because we have no verification certs
117 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
118 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000119 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000120 s.connect(("svn.python.org", 443))
121 except ssl.SSLError:
122 pass
123 finally:
124 s.close()
125
126 # this should succeed because we specify the root cert
127 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
128 cert_reqs=ssl.CERT_REQUIRED,
129 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
130 try:
131 s.connect(("svn.python.org", 443))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000132 finally:
133 s.close()
134
Antoine Pitroufe0f1172010-04-24 11:17:37 +0000135 @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
136 def test_makefile_close(self):
137 # Issue #5238: creating a file-like object with makefile() shouldn't
138 # delay closing the underlying "real socket" (here tested with its
139 # file descriptor, hence skipping the test under Windows).
140 ss = ssl.wrap_socket(socket.socket(socket.AF_INET))
141 ss.connect(("svn.python.org", 443))
142 fd = ss.fileno()
143 f = ss.makefile()
144 f.close()
145 # The fd is still open
146 os.read(fd, 0)
147 # Closing the SSL socket should close the fd too
148 ss.close()
149 gc.collect()
150 try:
151 os.read(fd, 0)
152 except OSError as e:
153 self.assertEqual(e.errno, errno.EBADF)
154 else:
155 self.fail("OSError wasn't raised")
156
Antoine Pitrou91382d82010-04-28 21:39:56 +0000157 def test_non_blocking_handshake(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000158 s = socket.socket(socket.AF_INET)
159 s.connect(("svn.python.org", 443))
160 s.setblocking(False)
161 s = ssl.wrap_socket(s,
162 cert_reqs=ssl.CERT_NONE,
163 do_handshake_on_connect=False)
164 count = 0
165 while True:
166 try:
167 count += 1
168 s.do_handshake()
169 break
170 except ssl.SSLError as err:
171 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
172 select.select([s], [], [])
173 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
174 select.select([], [s], [])
175 else:
176 raise
177 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000178 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000179 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000180
Antoine Pitrou91382d82010-04-28 21:39:56 +0000181 def test_get_server_certificate(self):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000182 pem = ssl.get_server_certificate(("svn.python.org", 443))
183 if not pem:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000184 self.fail("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000185
186 return
187
188 try:
189 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
190 except ssl.SSLError as x:
191 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000192 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000193 sys.stdout.write("%s\n" % x)
194 else:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000195 self.fail("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000196
197 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
198 if not pem:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000199 self.fail("No server certificate on svn.python.org:443!")
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000200 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000201 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
202
Antoine Pitrou754b98c2010-04-22 18:47:06 +0000203 # Test disabled: OPENSSL_VERSION* not available in Python 3.1
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000204 def test_algorithms(self):
Antoine Pitrouae92a722010-04-22 18:46:16 +0000205 if support.verbose:
206 sys.stdout.write("test_algorithms disabled, "
207 "as it fails on some old OpenSSL versions")
208 return
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000209 # Issue #8484: all algorithms should be available when verifying a
210 # certificate.
Antoine Pitrouae92a722010-04-22 18:46:16 +0000211 # SHA256 was added in OpenSSL 0.9.8
212 if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
213 self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000214 # NOTE: https://sha256.tbs-internet.com is another possible test host
215 remote = ("sha2.hboeck.de", 443)
216 sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
217 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
218 cert_reqs=ssl.CERT_REQUIRED,
219 ca_certs=sha256_cert,)
220 with support.transient_internet():
221 try:
222 s.connect(remote)
223 if support.verbose:
224 sys.stdout.write("\nCipher with %r is %r\n" %
225 (remote, s.cipher()))
226 sys.stdout.write("Certificate is:\n%s\n" %
227 pprint.pformat(s.getpeercert()))
228 finally:
229 s.close()
230
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000231
232try:
233 import threading
234except ImportError:
235 _have_threads = False
236else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000237 _have_threads = True
238
239 class ThreadedEchoServer(threading.Thread):
240
241 class ConnectionHandler(threading.Thread):
242
243 """A mildly complicated class, because we want it to work both
244 with and without the SSL wrapper around the socket connection, so
245 that we can test the STARTTLS functionality."""
246
Bill Janssen6e027db2007-11-15 22:23:56 +0000247 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000248 self.server = server
249 self.running = False
250 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000251 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000252 self.sock.setblocking(1)
253 self.sslconn = None
254 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000255 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000256
Antoine Pitrou91382d82010-04-28 21:39:56 +0000257 def wrap_conn(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000258 try:
259 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
260 certfile=self.server.certificate,
261 ssl_version=self.server.protocol,
262 ca_certs=self.server.cacerts,
263 cert_reqs=self.server.certreqs)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000264 except ssl.SSLError:
265 # XXX Various errors can have happened here, for example
266 # a mismatching protocol version, an invalid certificate,
267 # or a low-level bug. This should be made more discriminating.
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000268 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000269 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000270 self.running = False
271 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000272 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000273 return False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000274 else:
275 if self.server.certreqs == ssl.CERT_REQUIRED:
276 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000277 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000278 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
279 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000280 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000281 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
282 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000283 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000284 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
285 return True
286
287 def read(self):
288 if self.sslconn:
289 return self.sslconn.read()
290 else:
291 return self.sock.recv(1024)
292
293 def write(self, bytes):
294 if self.sslconn:
295 return self.sslconn.write(bytes)
296 else:
297 return self.sock.send(bytes)
298
299 def close(self):
300 if self.sslconn:
301 self.sslconn.close()
302 else:
303 self.sock.close()
304
Antoine Pitrou91382d82010-04-28 21:39:56 +0000305 def run(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000306 self.running = True
307 if not self.server.starttls_server:
308 if not self.wrap_conn():
309 return
310 while self.running:
311 try:
312 msg = self.read()
Antoine Pitrou91382d82010-04-28 21:39:56 +0000313 stripped = msg.strip()
314 if not stripped:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000315 # eof, so quit this handler
316 self.running = False
317 self.close()
Antoine Pitrou91382d82010-04-28 21:39:56 +0000318 elif stripped == b'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000319 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000320 sys.stdout.write(" server: client closed connection\n")
321 self.close()
322 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000323 elif (self.server.starttls_server and
Antoine Pitroub1997962010-04-28 22:58:16 +0000324 stripped == b'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000325 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000326 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Antoine Pitrou91382d82010-04-28 21:39:56 +0000327 self.write(b"OK\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000328 if not self.wrap_conn():
329 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000330 elif (self.server.starttls_server and self.sslconn
Antoine Pitroub1997962010-04-28 22:58:16 +0000331 and stripped == b'ENDTLS'):
Bill Janssen40a0f662008-08-12 16:56:25 +0000332 if support.verbose and self.server.connectionchatty:
333 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
Antoine Pitrou91382d82010-04-28 21:39:56 +0000334 self.write(b"OK\n")
Bill Janssen40a0f662008-08-12 16:56:25 +0000335 self.sock = self.sslconn.unwrap()
336 self.sslconn = None
337 if support.verbose and self.server.connectionchatty:
338 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000339 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000340 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000341 self.server.connectionchatty):
342 ctype = (self.sslconn and "encrypted") or "unencrypted"
Antoine Pitrou91382d82010-04-28 21:39:56 +0000343 sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n"
344 % (msg, ctype, msg.lower(), ctype))
345 self.write(msg.lower())
Bill Janssen6e027db2007-11-15 22:23:56 +0000346 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000347 if self.server.chatty:
348 handle_error("Test server failure:\n")
349 self.close()
350 self.running = False
351 # normally, we'd just stop here, but for the test
352 # harness, we want to stop the server
353 self.server.stop()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000354
Trent Nelson78520002008-04-10 20:54:35 +0000355 def __init__(self, certificate, ssl_version=None,
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000356 certreqs=None, cacerts=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000357 chatty=True, connectionchatty=False, starttls_server=False):
358 if ssl_version is None:
359 ssl_version = ssl.PROTOCOL_TLSv1
360 if certreqs is None:
361 certreqs = ssl.CERT_NONE
362 self.certificate = certificate
363 self.protocol = ssl_version
364 self.certreqs = certreqs
365 self.cacerts = cacerts
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000366 self.chatty = chatty
367 self.connectionchatty = connectionchatty
368 self.starttls_server = starttls_server
369 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000370 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000371 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000372 self.active = False
373 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000374 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000375
Antoine Pitrou91382d82010-04-28 21:39:56 +0000376 def start(self, flag=None):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000377 self.flag = flag
378 threading.Thread.start(self)
379
Antoine Pitrou91382d82010-04-28 21:39:56 +0000380 def run(self):
Antoine Pitroube168132010-04-27 10:41:37 +0000381 self.sock.settimeout(0.05)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000382 self.sock.listen(5)
383 self.active = True
384 if self.flag:
385 # signal an event
386 self.flag.set()
387 while self.active:
388 try:
389 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000390 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000391 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000392 + repr(connaddr) + '\n')
393 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000394 handler.start()
395 except socket.timeout:
396 pass
397 except KeyboardInterrupt:
398 self.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000399 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000400
Antoine Pitrou91382d82010-04-28 21:39:56 +0000401 def stop(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000402 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000403
Bill Janssen54cc54c2007-12-14 22:08:56 +0000404 class OurHTTPSServer(threading.Thread):
405
406 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000407
408 class HTTPSServer(HTTPServer):
409
410 def __init__(self, server_address, RequestHandlerClass, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000411 HTTPServer.__init__(self, server_address, RequestHandlerClass)
412 # we assume the certfile contains both private key and certificate
413 self.certfile = certfile
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000414 self.allow_reuse_address = True
415
Bill Janssen6e027db2007-11-15 22:23:56 +0000416 def __str__(self):
417 return ('<%s %s:%s>' %
418 (self.__class__.__name__,
419 self.server_name,
420 self.server_port))
421
Antoine Pitrou91382d82010-04-28 21:39:56 +0000422 def get_request(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000423 # override this to wrap socket with SSL
424 sock, addr = self.socket.accept()
425 sslconn = ssl.wrap_socket(sock, server_side=True,
426 certfile=self.certfile)
427 return sslconn, addr
428
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000429 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000430 # need to override translate_path to get a known root,
431 # instead of using os.curdir, since the test could be
432 # run from anywhere
433
434 server_version = "TestHTTPS/1.0"
435
436 root = None
437
438 def translate_path(self, path):
439 """Translate a /-separated PATH to the local filename syntax.
440
441 Components that mean special things to the local file system
442 (e.g. drive or directory names) are ignored. (XXX They should
443 probably be diagnosed.)
444
445 """
446 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000447 path = urllib.parse.urlparse(path)[2]
448 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000449 words = path.split('/')
450 words = filter(None, words)
451 path = self.root
452 for word in words:
453 drive, word = os.path.splitdrive(word)
454 head, word = os.path.split(word)
455 if word in self.root: continue
456 path = os.path.join(path, word)
457 return path
458
459 def log_message(self, format, *args):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000460 # we override this to suppress logging unless "verbose"
461
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000462 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000463 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
464 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000465 self.server.server_port,
466 self.request.cipher(),
467 self.log_date_time_string(),
468 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000469
470
Trent Nelson78520002008-04-10 20:54:35 +0000471 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000472 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000473 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
474 self.server = self.HTTPSServer(
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000475 (HOST, 0), self.RootedHTTPRequestHandler, certfile)
476 self.port = self.server.server_port
Thomas Woutersed03b412007-08-28 21:37:11 +0000477 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000478 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000479
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000480 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000481 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000482
Antoine Pitrou91382d82010-04-28 21:39:56 +0000483 def start(self, flag=None):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000484 self.flag = flag
485 threading.Thread.start(self)
486
Antoine Pitrou91382d82010-04-28 21:39:56 +0000487 def run(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000488 if self.flag:
489 self.flag.set()
Antoine Pitroube168132010-04-27 10:41:37 +0000490 self.server.serve_forever(0.05)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000491
Antoine Pitrou91382d82010-04-28 21:39:56 +0000492 def stop(self):
Antoine Pitroube168132010-04-27 10:41:37 +0000493 self.server.shutdown()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000494
495
Bill Janssen54cc54c2007-12-14 22:08:56 +0000496 class AsyncoreEchoServer(threading.Thread):
497
498 # this one's based on asyncore.dispatcher
499
500 class EchoServer (asyncore.dispatcher):
501
502 class ConnectionHandler (asyncore.dispatcher_with_send):
503
504 def __init__(self, conn, certfile):
505 self.socket = ssl.wrap_socket(conn, server_side=True,
506 certfile=certfile,
507 do_handshake_on_connect=False)
508 asyncore.dispatcher_with_send.__init__(self, self.socket)
Antoine Pitrouec146182010-04-24 21:30:20 +0000509 self._ssl_accepting = True
510 self._do_ssl_handshake()
Bill Janssen54cc54c2007-12-14 22:08:56 +0000511
512 def readable(self):
513 if isinstance(self.socket, ssl.SSLSocket):
514 while self.socket.pending() > 0:
515 self.handle_read_event()
516 return True
517
Antoine Pitrouec146182010-04-24 21:30:20 +0000518 def _do_ssl_handshake(self):
519 try:
520 self.socket.do_handshake()
521 except ssl.SSLError as err:
522 if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
523 ssl.SSL_ERROR_WANT_WRITE):
524 return
525 elif err.args[0] == ssl.SSL_ERROR_EOF:
526 return self.handle_close()
527 raise
528 except socket.error as err:
529 if err.args[0] == errno.ECONNABORTED:
530 return self.handle_close()
Bill Janssen54cc54c2007-12-14 22:08:56 +0000531 else:
Antoine Pitrouec146182010-04-24 21:30:20 +0000532 self._ssl_accepting = False
533
534 def handle_read(self):
535 if self._ssl_accepting:
536 self._do_ssl_handshake()
537 else:
538 data = self.recv(1024)
539 if support.verbose:
540 sys.stdout.write(" server: read %s from client\n" % repr(data))
541 if not data:
542 self.close()
543 else:
Antoine Pitrou91382d82010-04-28 21:39:56 +0000544 self.send(data.lower())
Bill Janssen54cc54c2007-12-14 22:08:56 +0000545
546 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000547 self.close()
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000548 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000549 sys.stdout.write(" server: closed connection %s\n" % self.socket)
550
551 def handle_error(self):
552 raise
553
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000554 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000555 self.certfile = certfile
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000556 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
557 self.port = support.bind_port(sock, '')
558 asyncore.dispatcher.__init__(self, sock)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000559 self.listen(5)
560
561 def handle_accept(self):
562 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000563 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000564 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
565 self.ConnectionHandler(sock_obj, self.certfile)
566
567 def handle_error(self):
568 raise
569
Trent Nelson78520002008-04-10 20:54:35 +0000570 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000571 self.flag = None
572 self.active = False
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000573 self.server = self.EchoServer(certfile)
574 self.port = self.server.port
Bill Janssen54cc54c2007-12-14 22:08:56 +0000575 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000576 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000577
578 def __str__(self):
579 return "<%s %s>" % (self.__class__.__name__, self.server)
580
581 def start (self, flag=None):
582 self.flag = flag
583 threading.Thread.start(self)
584
Antoine Pitrou91382d82010-04-28 21:39:56 +0000585 def run(self):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000586 self.active = True
587 if self.flag:
588 self.flag.set()
589 while self.active:
590 try:
591 asyncore.loop(1)
592 except:
593 pass
594
Antoine Pitrou91382d82010-04-28 21:39:56 +0000595 def stop(self):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000596 self.active = False
597 self.server.close()
598
Antoine Pitrou91382d82010-04-28 21:39:56 +0000599 def bad_cert_test(certfile):
600 """
601 Launch a server with CERT_REQUIRED, and check that trying to
602 connect to it with the given client certificate fails.
603 """
Trent Nelson78520002008-04-10 20:54:35 +0000604 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000605 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000606 cacerts=CERTFILE, chatty=False,
607 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000608 flag = threading.Event()
609 server.start(flag)
610 # wait for it to start
611 flag.wait()
612 # try to connect
613 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000614 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000615 s = ssl.wrap_socket(socket.socket(),
616 certfile=certfile,
617 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000618 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000619 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000620 if support.verbose:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000621 sys.stdout.write("\nSSLError is %s\n" % x.args[1])
Antoine Pitrou537bed62010-04-27 13:16:06 +0000622 except socket.error as x:
Antoine Pitrou91382d82010-04-28 21:39:56 +0000623 if support.verbose:
Antoine Pitrou537bed62010-04-27 13:16:06 +0000624 sys.stdout.write("\nsocket.error is %s\n" % x[1])
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000625 else:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000626 self.fail("Use of invalid cert should have failed!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000627 finally:
628 server.stop()
629 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000630
Antoine Pitrou91382d82010-04-28 21:39:56 +0000631 def server_params_test(certfile, protocol, certreqs, cacertsfile,
632 client_certfile, client_protocol=None, indata=b"FOO\n",
633 chatty=True, connectionchatty=False):
634 """
635 Launch a server, connect a client to it and try various reads
636 and writes.
637 """
Trent Nelson78520002008-04-10 20:54:35 +0000638 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000639 certreqs=certreqs,
640 ssl_version=protocol,
641 cacerts=cacertsfile,
642 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000643 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000644 flag = threading.Event()
645 server.start(flag)
646 # wait for it to start
647 flag.wait()
648 # try to connect
649 if client_protocol is None:
650 client_protocol = protocol
651 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000652 s = ssl.wrap_socket(socket.socket(),
653 certfile=client_certfile,
654 ca_certs=cacertsfile,
655 cert_reqs=certreqs,
656 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000657 s.connect((HOST, server.port))
Antoine Pitrou91382d82010-04-28 21:39:56 +0000658 arg = indata
Bill Janssen6e027db2007-11-15 22:23:56 +0000659 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000660 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000661 sys.stdout.write(
Antoine Pitrou91382d82010-04-28 21:39:56 +0000662 " client: sending %r...\n" % indata)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000663 s.write(arg)
Bill Janssen6e027db2007-11-15 22:23:56 +0000664 outdata = s.read()
665 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000666 if support.verbose:
Antoine Pitrou91382d82010-04-28 21:39:56 +0000667 sys.stdout.write(" client: read %r\n" % outdata)
Bill Janssen6e027db2007-11-15 22:23:56 +0000668 if outdata != indata.lower():
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000669 self.fail(
Antoine Pitrou91382d82010-04-28 21:39:56 +0000670 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
671 % (outdata[:20], len(outdata),
672 indata[:20].lower(), len(indata)))
673 s.write(b"over\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000674 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000675 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000676 sys.stdout.write(" client: closing connection.\n")
677 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000678 finally:
679 server.stop()
680 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000681
Antoine Pitrou91382d82010-04-28 21:39:56 +0000682 def try_protocol_combo(server_protocol,
683 client_protocol,
684 expect_success,
685 certsreqs=None):
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000686 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000687 certsreqs = ssl.CERT_NONE
Antoine Pitrou91382d82010-04-28 21:39:56 +0000688 certtype = {
689 ssl.CERT_NONE: "CERT_NONE",
690 ssl.CERT_OPTIONAL: "CERT_OPTIONAL",
691 ssl.CERT_REQUIRED: "CERT_REQUIRED",
692 }[certsreqs]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000693 if support.verbose:
Antoine Pitrou91382d82010-04-28 21:39:56 +0000694 formatstr = (expect_success and " %s->%s %s\n") or " {%s->%s} %s\n"
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000695 sys.stdout.write(formatstr %
696 (ssl.get_protocol_name(client_protocol),
697 ssl.get_protocol_name(server_protocol),
698 certtype))
699 try:
Antoine Pitrou91382d82010-04-28 21:39:56 +0000700 server_params_test(CERTFILE, server_protocol, certsreqs,
701 CERTFILE, CERTFILE, client_protocol,
702 chatty=False,
703 connectionchatty=False)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000704 # Protocol mismatch can result in either an SSLError, or a
705 # "Connection reset by peer" error.
706 except ssl.SSLError:
Antoine Pitrou91382d82010-04-28 21:39:56 +0000707 if expect_success:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000708 raise
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000709 except socket.error as e:
Antoine Pitrou91382d82010-04-28 21:39:56 +0000710 if expect_success or e.errno != errno.ECONNRESET:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000711 raise
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000712 else:
Antoine Pitrou91382d82010-04-28 21:39:56 +0000713 if not expect_success:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000714 self.fail(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000715 "Client protocol %s succeeded with server protocol %s!"
716 % (ssl.get_protocol_name(client_protocol),
717 ssl.get_protocol_name(server_protocol)))
718
719
Bill Janssen6e027db2007-11-15 22:23:56 +0000720 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000721
Antoine Pitrou91382d82010-04-28 21:39:56 +0000722 def test_echo(self):
723 """Basic test of an SSL client connecting to a server"""
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000724 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000725 sys.stdout.write("\n")
Antoine Pitrou91382d82010-04-28 21:39:56 +0000726 server_params_test(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
727 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
728 chatty=True, connectionchatty=True)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000729
Antoine Pitrou91382d82010-04-28 21:39:56 +0000730 def test_getpeercert(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000731 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000732 sys.stdout.write("\n")
733 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000734 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000735 certreqs=ssl.CERT_NONE,
736 ssl_version=ssl.PROTOCOL_SSLv23,
737 cacerts=CERTFILE,
738 chatty=False)
739 flag = threading.Event()
740 server.start(flag)
741 # wait for it to start
742 flag.wait()
743 # try to connect
744 try:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000745 s = ssl.wrap_socket(socket.socket(),
746 certfile=CERTFILE,
747 ca_certs=CERTFILE,
748 cert_reqs=ssl.CERT_REQUIRED,
749 ssl_version=ssl.PROTOCOL_SSLv23)
750 s.connect((HOST, server.port))
751 cert = s.getpeercert()
752 self.assertTrue(cert, "Can't get peer certificate.")
753 cipher = s.cipher()
754 if support.verbose:
755 sys.stdout.write(pprint.pformat(cert) + '\n')
756 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
757 if 'subject' not in cert:
758 self.fail("No subject field in certificate: %s." %
759 pprint.pformat(cert))
760 if ((('organizationName', 'Python Software Foundation'),)
761 not in cert['subject']):
762 self.fail(
763 "Missing or invalid 'organizationName' field in certificate subject; "
764 "should be 'Python Software Foundation'.")
765 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000766 finally:
767 server.stop()
768 server.join()
769
Antoine Pitrou91382d82010-04-28 21:39:56 +0000770 def test_empty_cert(self):
771 """Connecting with an empty cert file"""
772 bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
773 "nullcert.pem"))
774 def test_malformed_cert(self):
775 """Connecting with a badly formatted certificate (syntax error)"""
776 bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
777 "badcert.pem"))
778 def test_nonexisting_cert(self):
779 """Connecting with a non-existing cert file"""
780 bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
781 "wrongcert.pem"))
782 def test_malformed_key(self):
783 """Connecting with a badly formatted key (syntax error)"""
784 bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
785 "badkey.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000786
Antoine Pitrou91382d82010-04-28 21:39:56 +0000787 def test_rude_shutdown(self):
788 """A brutal shutdown of an SSL server should raise an IOError
789 in the client when attempting handshake.
790 """
Trent Nelson6b240cd2008-04-10 20:12:06 +0000791 listener_ready = threading.Event()
792 listener_gone = threading.Event()
Antoine Pitrou91382d82010-04-28 21:39:56 +0000793
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000794 s = socket.socket()
795 port = support.bind_port(s, HOST)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000796
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000797 # `listener` runs in a thread. It sits in an accept() until
798 # the main thread connects. Then it rudely closes the socket,
799 # and sets Event `listener_gone` to let the main thread know
800 # the socket is gone.
Trent Nelson6b240cd2008-04-10 20:12:06 +0000801 def listener():
Trent Nelson6b240cd2008-04-10 20:12:06 +0000802 s.listen(5)
803 listener_ready.set()
804 s.accept()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000805 s.close()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000806 listener_gone.set()
807
808 def connector():
809 listener_ready.wait()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000810 c = socket.socket()
811 c.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000812 listener_gone.wait()
813 try:
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000814 ssl_sock = ssl.wrap_socket(c)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000815 except IOError:
816 pass
817 else:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000818 self.fail('connecting to closed SSL socket should have failed')
Trent Nelson6b240cd2008-04-10 20:12:06 +0000819
820 t = threading.Thread(target=listener)
821 t.start()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000822 try:
823 connector()
824 finally:
825 t.join()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000826
Antoine Pitrou91382d82010-04-28 21:39:56 +0000827 def test_protocol_sslv2(self):
828 """Connecting to an SSLv2 server with various client options"""
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000829 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000830 sys.stdout.write("\n")
Antoine Pitrou91382d82010-04-28 21:39:56 +0000831 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
832 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
833 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
834 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
835 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
836 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000837
Antoine Pitrou91382d82010-04-28 21:39:56 +0000838 def test_protocol_sslv23(self):
839 """Connecting to an SSLv23 server with various client options"""
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000840 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000841 sys.stdout.write("\n")
842 try:
Antoine Pitrou91382d82010-04-28 21:39:56 +0000843 try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000844 except (ssl.SSLError, socket.error) as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000845 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000846 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000847 sys.stdout.write(
848 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
849 % str(x))
Antoine Pitrou91382d82010-04-28 21:39:56 +0000850 try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
851 try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
852 try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000853
Antoine Pitrou91382d82010-04-28 21:39:56 +0000854 try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
855 try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
856 try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000857
Antoine Pitrou91382d82010-04-28 21:39:56 +0000858 try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
859 try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
860 try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000861
Antoine Pitrou91382d82010-04-28 21:39:56 +0000862 def test_protocol_sslv3(self):
863 """Connecting to an SSLv3 server with various client options"""
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000864 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000865 sys.stdout.write("\n")
Antoine Pitrou91382d82010-04-28 21:39:56 +0000866 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
867 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
868 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
869 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
870 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
871 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000872
Antoine Pitrou91382d82010-04-28 21:39:56 +0000873 def test_protocol_tlsv1(self):
874 """Connecting to a TLSv1 server with various client options"""
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000875 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000876 sys.stdout.write("\n")
Antoine Pitrou91382d82010-04-28 21:39:56 +0000877 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
878 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
879 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
880 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
881 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
882 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000883
Antoine Pitrou91382d82010-04-28 21:39:56 +0000884 def test_starttls(self):
885 """Switching from clear text to encrypted and back again."""
886 msgs = (b"msg 1", b"MSG 2", b"STARTTLS", b"MSG 3", b"msg 4", b"ENDTLS", b"msg 5", b"msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000887
Trent Nelson78520002008-04-10 20:54:35 +0000888 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000889 ssl_version=ssl.PROTOCOL_TLSv1,
890 starttls_server=True,
891 chatty=True,
892 connectionchatty=True)
893 flag = threading.Event()
894 server.start(flag)
895 # wait for it to start
896 flag.wait()
897 # try to connect
898 wrapped = False
899 try:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000900 s = socket.socket()
901 s.setblocking(1)
902 s.connect((HOST, server.port))
903 if support.verbose:
904 sys.stdout.write("\n")
905 for indata in msgs:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000906 if support.verbose:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000907 sys.stdout.write(
Antoine Pitrou91382d82010-04-28 21:39:56 +0000908 " client: sending %r...\n" % indata)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000909 if wrapped:
Antoine Pitrou91382d82010-04-28 21:39:56 +0000910 conn.write(indata)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000911 outdata = conn.read()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000912 else:
Antoine Pitrou91382d82010-04-28 21:39:56 +0000913 s.send(indata)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000914 outdata = s.recv(1024)
Antoine Pitrou91382d82010-04-28 21:39:56 +0000915 msg = outdata.strip().lower()
916 if indata == b"STARTTLS" and msg.startswith(b"ok"):
917 # STARTTLS ok, switch to secure mode
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000918 if support.verbose:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000919 sys.stdout.write(
Antoine Pitrou91382d82010-04-28 21:39:56 +0000920 " client: read %r from server, starting TLS...\n"
921 % msg)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000922 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
923 wrapped = True
Antoine Pitrou91382d82010-04-28 21:39:56 +0000924 elif indata == b"ENDTLS" and msg.startswith(b"ok"):
925 # ENDTLS ok, switch back to clear text
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000926 if support.verbose:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000927 sys.stdout.write(
Antoine Pitrou91382d82010-04-28 21:39:56 +0000928 " client: read %r from server, ending TLS...\n"
929 % msg)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000930 s = conn.unwrap()
931 wrapped = False
932 else:
933 if support.verbose:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000934 sys.stdout.write(
Antoine Pitrou91382d82010-04-28 21:39:56 +0000935 " client: read %r from server\n" % msg)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000936 if support.verbose:
937 sys.stdout.write(" client: closing connection.\n")
938 if wrapped:
Antoine Pitrou91382d82010-04-28 21:39:56 +0000939 conn.write(b"over\n")
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000940 else:
Antoine Pitrou91382d82010-04-28 21:39:56 +0000941 s.send(b"over\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000942 if wrapped:
943 conn.close()
944 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000945 s.close()
946 finally:
947 server.stop()
948 server.join()
949
Antoine Pitrou91382d82010-04-28 21:39:56 +0000950 def test_socketserver(self):
951 """Using a SocketServer to create and manage SSL connections."""
Trent Nelson78520002008-04-10 20:54:35 +0000952 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000953 flag = threading.Event()
954 server.start(flag)
955 # wait for it to start
956 flag.wait()
957 # try to connect
958 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000959 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000960 sys.stdout.write('\n')
Antoine Pitrou91382d82010-04-28 21:39:56 +0000961 with open(CERTFILE, 'rb') as f:
962 d1 = f.read()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000963 d2 = ''
964 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +0000965 url = 'https://%s:%d/%s' % (
966 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000967 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +0000968 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000969 if dlen and (int(dlen) > 0):
970 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000971 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000972 sys.stdout.write(
973 " client: read %d bytes from remote server '%s'\n"
974 % (len(d2), server))
975 f.close()
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000976 self.assertEqual(d1, d2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000977 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000978 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000979 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000980 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000981 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000982 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000983 server.join()
984
Antoine Pitrou91382d82010-04-28 21:39:56 +0000985 def test_asyncore_server(self):
986 """Check the example asyncore integration."""
987 indata = "TEST MESSAGE of mixed case\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000988
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000989 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +0000990 sys.stdout.write("\n")
991
Antoine Pitrou91382d82010-04-28 21:39:56 +0000992 indata = b"FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +0000993 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000994 flag = threading.Event()
995 server.start(flag)
996 # wait for it to start
997 flag.wait()
998 # try to connect
999 try:
1000 s = ssl.wrap_socket(socket.socket())
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001001 s.connect(('127.0.0.1', server.port))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001002 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001003 sys.stdout.write(
Antoine Pitrou91382d82010-04-28 21:39:56 +00001004 " client: sending %r...\n" % indata)
1005 s.write(indata)
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001006 outdata = s.read()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001007 if support.verbose:
Antoine Pitrou91382d82010-04-28 21:39:56 +00001008 sys.stdout.write(" client: read %r\n" % outdata)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001009 if outdata != indata.lower():
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001010 self.fail(
Antoine Pitrou91382d82010-04-28 21:39:56 +00001011 "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
1012 % (outdata[:20], len(outdata),
1013 indata[:20].lower(), len(indata)))
1014 s.write(b"over\n")
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001015 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001016 sys.stdout.write(" client: closing connection.\n")
1017 s.close()
1018 finally:
1019 server.stop()
1020 server.join()
1021
Antoine Pitrou91382d82010-04-28 21:39:56 +00001022 def test_recv_send(self):
1023 """Test recv(), send() and friends."""
Bill Janssen58afe4c2008-09-08 16:45:19 +00001024 if support.verbose:
1025 sys.stdout.write("\n")
1026
1027 server = ThreadedEchoServer(CERTFILE,
1028 certreqs=ssl.CERT_NONE,
1029 ssl_version=ssl.PROTOCOL_TLSv1,
1030 cacerts=CERTFILE,
1031 chatty=True,
1032 connectionchatty=False)
1033 flag = threading.Event()
1034 server.start(flag)
1035 # wait for it to start
1036 flag.wait()
1037 # try to connect
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001038 s = ssl.wrap_socket(socket.socket(),
1039 server_side=False,
1040 certfile=CERTFILE,
1041 ca_certs=CERTFILE,
1042 cert_reqs=ssl.CERT_NONE,
1043 ssl_version=ssl.PROTOCOL_TLSv1)
1044 s.connect((HOST, server.port))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001045 try:
Bill Janssen58afe4c2008-09-08 16:45:19 +00001046 # helper methods for standardising recv* method signatures
1047 def _recv_into():
1048 b = bytearray(b"\0"*100)
1049 count = s.recv_into(b)
1050 return b[:count]
1051
1052 def _recvfrom_into():
1053 b = bytearray(b"\0"*100)
1054 count, addr = s.recvfrom_into(b)
1055 return b[:count]
1056
1057 # (name, method, whether to expect success, *args)
1058 send_methods = [
1059 ('send', s.send, True, []),
1060 ('sendto', s.sendto, False, ["some.address"]),
1061 ('sendall', s.sendall, True, []),
1062 ]
1063 recv_methods = [
1064 ('recv', s.recv, True, []),
1065 ('recvfrom', s.recvfrom, False, ["some.address"]),
1066 ('recv_into', _recv_into, True, []),
1067 ('recvfrom_into', _recvfrom_into, False, []),
1068 ]
1069 data_prefix = "PREFIX_"
1070
1071 for meth_name, send_meth, expect_success, args in send_methods:
Antoine Pitrou91382d82010-04-28 21:39:56 +00001072 indata = (data_prefix + meth_name).encode('ascii')
Bill Janssen58afe4c2008-09-08 16:45:19 +00001073 try:
Antoine Pitrou91382d82010-04-28 21:39:56 +00001074 send_meth(indata, *args)
Bill Janssen58afe4c2008-09-08 16:45:19 +00001075 outdata = s.read()
Bill Janssen58afe4c2008-09-08 16:45:19 +00001076 if outdata != indata.lower():
1077 raise support.TestFailed(
1078 "While sending with <<{name:s}>> bad data "
Antoine Pitrou91382d82010-04-28 21:39:56 +00001079 "<<{outdata:r}>> ({nout:d}) received; "
1080 "expected <<{indata:r}>> ({nin:d})\n".format(
1081 name=meth_name, outdata=outdata[:20],
Bill Janssen58afe4c2008-09-08 16:45:19 +00001082 nout=len(outdata),
Antoine Pitrou91382d82010-04-28 21:39:56 +00001083 indata=indata[:20], nin=len(indata)
Bill Janssen58afe4c2008-09-08 16:45:19 +00001084 )
1085 )
1086 except ValueError as e:
1087 if expect_success:
1088 raise support.TestFailed(
1089 "Failed to send with method <<{name:s}>>; "
1090 "expected to succeed.\n".format(name=meth_name)
1091 )
1092 if not str(e).startswith(meth_name):
1093 raise support.TestFailed(
1094 "Method <<{name:s}>> failed with unexpected "
1095 "exception message: {exp:s}\n".format(
1096 name=meth_name, exp=e
1097 )
1098 )
1099
1100 for meth_name, recv_meth, expect_success, args in recv_methods:
Antoine Pitrou91382d82010-04-28 21:39:56 +00001101 indata = (data_prefix + meth_name).encode('ascii')
Bill Janssen58afe4c2008-09-08 16:45:19 +00001102 try:
Antoine Pitrou91382d82010-04-28 21:39:56 +00001103 s.send(indata)
Bill Janssen58afe4c2008-09-08 16:45:19 +00001104 outdata = recv_meth(*args)
Bill Janssen58afe4c2008-09-08 16:45:19 +00001105 if outdata != indata.lower():
1106 raise support.TestFailed(
1107 "While receiving with <<{name:s}>> bad data "
Antoine Pitrou91382d82010-04-28 21:39:56 +00001108 "<<{outdata:r}>> ({nout:d}) received; "
1109 "expected <<{indata:r}>> ({nin:d})\n".format(
1110 name=meth_name, outdata=outdata[:20],
Bill Janssen58afe4c2008-09-08 16:45:19 +00001111 nout=len(outdata),
Antoine Pitrou91382d82010-04-28 21:39:56 +00001112 indata=indata[:20], nin=len(indata)
Bill Janssen58afe4c2008-09-08 16:45:19 +00001113 )
1114 )
1115 except ValueError as e:
1116 if expect_success:
1117 raise support.TestFailed(
1118 "Failed to receive with method <<{name:s}>>; "
1119 "expected to succeed.\n".format(name=meth_name)
1120 )
1121 if not str(e).startswith(meth_name):
1122 raise support.TestFailed(
1123 "Method <<{name:s}>> failed with unexpected "
1124 "exception message: {exp:s}\n".format(
1125 name=meth_name, exp=e
1126 )
1127 )
1128 # consume data
1129 s.read()
1130
Antoine Pitrou91382d82010-04-28 21:39:56 +00001131 s.write(b"over\n")
Bill Janssen58afe4c2008-09-08 16:45:19 +00001132 s.close()
1133 finally:
1134 server.stop()
1135 server.join()
1136
Antoine Pitrouec146182010-04-24 21:30:20 +00001137 def test_handshake_timeout(self):
1138 # Issue #5103: SSL handshake must respect the socket timeout
1139 server = socket.socket(socket.AF_INET)
1140 host = "127.0.0.1"
1141 port = support.bind_port(server)
1142 started = threading.Event()
1143 finish = False
1144
1145 def serve():
1146 server.listen(5)
1147 started.set()
1148 conns = []
1149 while not finish:
1150 r, w, e = select.select([server], [], [], 0.1)
1151 if server in r:
1152 # Let the socket hang around rather than having
1153 # it closed by garbage collection.
1154 conns.append(server.accept()[0])
1155
1156 t = threading.Thread(target=serve)
1157 t.start()
1158 started.wait()
1159
1160 try:
Antoine Pitrouc2203f92010-04-24 22:07:51 +00001161 try:
1162 c = socket.socket(socket.AF_INET)
1163 c.settimeout(0.2)
1164 c.connect((host, port))
1165 # Will attempt handshake and time out
1166 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1167 ssl.wrap_socket, c)
1168 finally:
1169 c.close()
Antoine Pitrouec146182010-04-24 21:30:20 +00001170 try:
1171 c = socket.socket(socket.AF_INET)
1172 c = ssl.wrap_socket(c)
1173 c.settimeout(0.2)
1174 # Will attempt handshake and time out
1175 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1176 c.connect, (host, port))
1177 finally:
1178 c.close()
1179 finally:
1180 finish = True
1181 t.join()
1182 server.close()
1183
Bill Janssen58afe4c2008-09-08 16:45:19 +00001184
Thomas Woutersed03b412007-08-28 21:37:11 +00001185def test_main(verbose=False):
1186 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001187 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001188
Trent Nelson78520002008-04-10 20:54:35 +00001189 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001190 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1191 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001192 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1193 os.path.dirname(__file__) or os.curdir,
1194 "https_svn_python_org_root.pem")
1195
1196 if (not os.path.exists(CERTFILE) or
1197 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001198 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001199
Thomas Woutersed03b412007-08-28 21:37:11 +00001200 tests = [BasicTests]
1201
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001202 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001203 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001204
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001205 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001206 thread_info = support.threading_setup()
1207 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001208 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001209
Antoine Pitrou91382d82010-04-28 21:39:56 +00001210 try:
1211 support.run_unittest(*tests)
1212 finally:
1213 if _have_threads:
1214 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001215
1216if __name__ == "__main__":
1217 test_main()