blob: 30923e7a8c6413dacb8a6fada029f52e5b5c6f13 [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
Georg Brandlfceab5a2008-01-19 20:08:23 +000042 def testSSLconnect(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +000043 if not support.is_resource_enabled('network'):
Georg Brandlfceab5a2008-01-19 20:08:23 +000044 return
45 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
46 cert_reqs=ssl.CERT_NONE)
47 s.connect(("svn.python.org", 443))
48 c = s.getpeercert()
49 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +000050 raise support.TestFailed("Peer cert %s shouldn't be here!")
Georg Brandlfceab5a2008-01-19 20:08:23 +000051 s.close()
52
53 # this should fail because we have no verification certs
54 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
55 cert_reqs=ssl.CERT_REQUIRED)
56 try:
57 s.connect(("svn.python.org", 443))
58 except ssl.SSLError:
59 pass
60 finally:
61 s.close()
62
Thomas Wouters1b7f8912007-09-19 03:06:30 +000063 def testCrucialConstants(self):
64 ssl.PROTOCOL_SSLv2
65 ssl.PROTOCOL_SSLv23
66 ssl.PROTOCOL_SSLv3
67 ssl.PROTOCOL_TLSv1
68 ssl.CERT_NONE
69 ssl.CERT_OPTIONAL
70 ssl.CERT_REQUIRED
Thomas Woutersed03b412007-08-28 21:37:11 +000071
Thomas Wouters1b7f8912007-09-19 03:06:30 +000072 def testRAND(self):
73 v = ssl.RAND_status()
Benjamin Petersonee8712c2008-05-20 21:35:26 +000074 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000075 sys.stdout.write("\n RAND_status is %d (%s)\n"
76 % (v, (v and "sufficient randomness") or
77 "insufficient randomness"))
Thomas Woutersed03b412007-08-28 21:37:11 +000078 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000079 ssl.RAND_egd(1)
80 except TypeError:
81 pass
Thomas Woutersed03b412007-08-28 21:37:11 +000082 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000083 print("didn't raise TypeError")
84 ssl.RAND_add("this is a random string", 75.0)
Thomas Woutersed03b412007-08-28 21:37:11 +000085
Thomas Wouters1b7f8912007-09-19 03:06:30 +000086 def testParseCert(self):
87 # note that this uses an 'unofficial' function in _ssl.c,
88 # provided solely for this test, to exercise the certificate
89 # parsing code
90 p = ssl._ssl._test_decode_cert(CERTFILE, False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +000091 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +000092 sys.stdout.write("\n" + pprint.pformat(p) + "\n")
Thomas Woutersed03b412007-08-28 21:37:11 +000093
Thomas Wouters1b7f8912007-09-19 03:06:30 +000094 def testDERtoPEM(self):
95
96 pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
97 d1 = ssl.PEM_cert_to_DER_cert(pem)
98 p2 = ssl.DER_cert_to_PEM_cert(d1)
99 d2 = ssl.PEM_cert_to_DER_cert(p2)
100 if (d1 != d2):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000101 raise support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000102
Antoine Pitrou78f4a9a2010-04-23 23:12:22 +0000103 @support.cpython_only
104 def test_refcycle(self):
105 # Issue #7943: an SSL object doesn't create reference cycles with
106 # itself.
107 s = socket.socket(socket.AF_INET)
108 ss = ssl.wrap_socket(s)
109 wr = weakref.ref(ss)
110 del ss
111 self.assertEqual(wr(), None)
112
Antoine Pitrou3b9b9ba2010-04-23 23:33:50 +0000113
Bill Janssen6e027db2007-11-15 22:23:56 +0000114class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000115
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000116 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000117 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
118 cert_reqs=ssl.CERT_NONE)
119 s.connect(("svn.python.org", 443))
120 c = s.getpeercert()
121 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000122 raise support.TestFailed("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000123 s.close()
124
125 # this should fail because we have no verification certs
126 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
127 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000128 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000129 s.connect(("svn.python.org", 443))
130 except ssl.SSLError:
131 pass
132 finally:
133 s.close()
134
135 # this should succeed because we specify the root cert
136 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
137 cert_reqs=ssl.CERT_REQUIRED,
138 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
139 try:
140 s.connect(("svn.python.org", 443))
141 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000142 raise support.TestFailed("Unexpected exception %s" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000143 finally:
144 s.close()
145
Antoine Pitroufe0f1172010-04-24 11:17:37 +0000146 @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
147 def test_makefile_close(self):
148 # Issue #5238: creating a file-like object with makefile() shouldn't
149 # delay closing the underlying "real socket" (here tested with its
150 # file descriptor, hence skipping the test under Windows).
151 ss = ssl.wrap_socket(socket.socket(socket.AF_INET))
152 ss.connect(("svn.python.org", 443))
153 fd = ss.fileno()
154 f = ss.makefile()
155 f.close()
156 # The fd is still open
157 os.read(fd, 0)
158 # Closing the SSL socket should close the fd too
159 ss.close()
160 gc.collect()
161 try:
162 os.read(fd, 0)
163 except OSError as e:
164 self.assertEqual(e.errno, errno.EBADF)
165 else:
166 self.fail("OSError wasn't raised")
167
Bill Janssen6e027db2007-11-15 22:23:56 +0000168 def testNonBlockingHandshake(self):
169 s = socket.socket(socket.AF_INET)
170 s.connect(("svn.python.org", 443))
171 s.setblocking(False)
172 s = ssl.wrap_socket(s,
173 cert_reqs=ssl.CERT_NONE,
174 do_handshake_on_connect=False)
175 count = 0
176 while True:
177 try:
178 count += 1
179 s.do_handshake()
180 break
181 except ssl.SSLError as err:
182 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
183 select.select([s], [], [])
184 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
185 select.select([], [s], [])
186 else:
187 raise
188 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000189 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000190 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000191
Bill Janssen54cc54c2007-12-14 22:08:56 +0000192 def testFetchServerCert(self):
193
194 pem = ssl.get_server_certificate(("svn.python.org", 443))
195 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000196 raise support.TestFailed("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000197
198 return
199
200 try:
201 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
202 except ssl.SSLError as x:
203 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000204 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000205 sys.stdout.write("%s\n" % x)
206 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000207 raise support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000208
209 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
210 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000211 raise support.TestFailed("No server certificate on svn.python.org:443!")
212 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000213 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
214
Antoine Pitrou754b98c2010-04-22 18:47:06 +0000215 # Test disabled: OPENSSL_VERSION* not available in Python 3.1
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000216 def test_algorithms(self):
Antoine Pitrouae92a722010-04-22 18:46:16 +0000217 if support.verbose:
218 sys.stdout.write("test_algorithms disabled, "
219 "as it fails on some old OpenSSL versions")
220 return
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000221 # Issue #8484: all algorithms should be available when verifying a
222 # certificate.
Antoine Pitrouae92a722010-04-22 18:46:16 +0000223 # SHA256 was added in OpenSSL 0.9.8
224 if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
225 self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000226 # NOTE: https://sha256.tbs-internet.com is another possible test host
227 remote = ("sha2.hboeck.de", 443)
228 sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
229 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
230 cert_reqs=ssl.CERT_REQUIRED,
231 ca_certs=sha256_cert,)
232 with support.transient_internet():
233 try:
234 s.connect(remote)
235 if support.verbose:
236 sys.stdout.write("\nCipher with %r is %r\n" %
237 (remote, s.cipher()))
238 sys.stdout.write("Certificate is:\n%s\n" %
239 pprint.pformat(s.getpeercert()))
240 finally:
241 s.close()
242
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000243
244try:
245 import threading
246except ImportError:
247 _have_threads = False
248else:
249
250 _have_threads = True
251
252 class ThreadedEchoServer(threading.Thread):
253
254 class ConnectionHandler(threading.Thread):
255
256 """A mildly complicated class, because we want it to work both
257 with and without the SSL wrapper around the socket connection, so
258 that we can test the STARTTLS functionality."""
259
Bill Janssen6e027db2007-11-15 22:23:56 +0000260 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000261 self.server = server
262 self.running = False
263 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000264 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000265 self.sock.setblocking(1)
266 self.sslconn = None
267 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000268 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000269
270 def wrap_conn (self):
271 try:
272 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
273 certfile=self.server.certificate,
274 ssl_version=self.server.protocol,
275 ca_certs=self.server.cacerts,
276 cert_reqs=self.server.certreqs)
277 except:
278 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000279 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000280 if not self.server.expect_bad_connects:
281 # here, we want to stop the server, because this shouldn't
282 # happen in the context of our test case
283 self.running = False
284 # normally, we'd just stop here, but for the test
285 # harness, we want to stop the server
286 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000287 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000288 return False
289
290 else:
291 if self.server.certreqs == ssl.CERT_REQUIRED:
292 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000293 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000294 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
295 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000296 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000297 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
298 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000299 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000300 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
301 return True
302
303 def read(self):
304 if self.sslconn:
305 return self.sslconn.read()
306 else:
307 return self.sock.recv(1024)
308
309 def write(self, bytes):
310 if self.sslconn:
311 return self.sslconn.write(bytes)
312 else:
313 return self.sock.send(bytes)
314
315 def close(self):
316 if self.sslconn:
317 self.sslconn.close()
318 else:
319 self.sock.close()
320
321 def run (self):
322 self.running = True
323 if not self.server.starttls_server:
324 if not self.wrap_conn():
325 return
326 while self.running:
327 try:
328 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000329 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000330 if not msg:
331 # eof, so quit this handler
332 self.running = False
333 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000334 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000335 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000336 sys.stdout.write(" server: client closed connection\n")
337 self.close()
338 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000339 elif (self.server.starttls_server and
340 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000341 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000342 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000343 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000344 if not self.wrap_conn():
345 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000346 elif (self.server.starttls_server and self.sslconn
347 and amsg.strip() == 'ENDTLS'):
348 if support.verbose and self.server.connectionchatty:
349 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
350 self.write("OK\n".encode("ASCII", "strict"))
351 self.sock = self.sslconn.unwrap()
352 self.sslconn = None
353 if support.verbose and self.server.connectionchatty:
354 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000355 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000356 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000357 self.server.connectionchatty):
358 ctype = (self.sslconn and "encrypted") or "unencrypted"
359 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
360 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000361 self.write(amsg.lower().encode('ASCII', 'strict'))
362 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000363 if self.server.chatty:
364 handle_error("Test server failure:\n")
365 self.close()
366 self.running = False
367 # normally, we'd just stop here, but for the test
368 # harness, we want to stop the server
369 self.server.stop()
370 except:
371 handle_error('')
372
Trent Nelson78520002008-04-10 20:54:35 +0000373 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000374 certreqs=None, cacerts=None, expect_bad_connects=False,
375 chatty=True, connectionchatty=False, starttls_server=False):
376 if ssl_version is None:
377 ssl_version = ssl.PROTOCOL_TLSv1
378 if certreqs is None:
379 certreqs = ssl.CERT_NONE
380 self.certificate = certificate
381 self.protocol = ssl_version
382 self.certreqs = certreqs
383 self.cacerts = cacerts
384 self.expect_bad_connects = expect_bad_connects
385 self.chatty = chatty
386 self.connectionchatty = connectionchatty
387 self.starttls_server = starttls_server
388 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000389 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000390 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000391 self.active = False
392 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000393 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000394
395 def start (self, flag=None):
396 self.flag = flag
397 threading.Thread.start(self)
398
399 def run (self):
400 self.sock.settimeout(0.5)
401 self.sock.listen(5)
402 self.active = True
403 if self.flag:
404 # signal an event
405 self.flag.set()
406 while self.active:
407 try:
408 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000409 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000410 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000411 + repr(connaddr) + '\n')
412 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000413 handler.start()
414 except socket.timeout:
415 pass
416 except KeyboardInterrupt:
417 self.stop()
418 except:
419 if self.chatty:
420 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000421 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000422
423 def stop (self):
424 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000425
Bill Janssen54cc54c2007-12-14 22:08:56 +0000426 class OurHTTPSServer(threading.Thread):
427
428 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000429
430 class HTTPSServer(HTTPServer):
431
432 def __init__(self, server_address, RequestHandlerClass, certfile):
433
434 HTTPServer.__init__(self, server_address, RequestHandlerClass)
435 # we assume the certfile contains both private key and certificate
436 self.certfile = certfile
437 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000438 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000439 self.allow_reuse_address = True
440
Bill Janssen6e027db2007-11-15 22:23:56 +0000441 def __str__(self):
442 return ('<%s %s:%s>' %
443 (self.__class__.__name__,
444 self.server_name,
445 self.server_port))
446
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000447 def get_request (self):
448 # override this to wrap socket with SSL
449 sock, addr = self.socket.accept()
450 sslconn = ssl.wrap_socket(sock, server_side=True,
451 certfile=self.certfile)
452 return sslconn, addr
453
454 # The methods overridden below this are mainly so that we
455 # can run it in a thread and be able to stop it from another
456 # You probably wouldn't need them in other uses.
457
458 def server_activate(self):
459 # We want to run this in a thread for testing purposes,
460 # so we override this to set timeout, so that we get
461 # a chance to stop the server
462 self.socket.settimeout(0.5)
463 HTTPServer.server_activate(self)
464
465 def serve_forever(self):
466 # We want this to run in a thread, so we use a slightly
467 # modified version of "forever".
468 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000469 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000470 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000471 # We need to lock while handling the request.
472 # Another thread can close the socket after self.active
473 # has been checked and before the request is handled.
474 # This causes an exception when using the closed socket.
475 with self.active_lock:
476 if not self.active:
477 break
478 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000479 except socket.timeout:
480 pass
481 except KeyboardInterrupt:
482 self.server_close()
483 return
484 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000485 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
486 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000487 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000488
489 def server_close(self):
490 # Again, we want this to run in a thread, so we need to override
491 # close to clear the "active" flag, so that serve_forever() will
492 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000493 with self.active_lock:
494 HTTPServer.server_close(self)
495 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000496
497 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
498
499 # need to override translate_path to get a known root,
500 # instead of using os.curdir, since the test could be
501 # run from anywhere
502
503 server_version = "TestHTTPS/1.0"
504
505 root = None
506
507 def translate_path(self, path):
508 """Translate a /-separated PATH to the local filename syntax.
509
510 Components that mean special things to the local file system
511 (e.g. drive or directory names) are ignored. (XXX They should
512 probably be diagnosed.)
513
514 """
515 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000516 path = urllib.parse.urlparse(path)[2]
517 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000518 words = path.split('/')
519 words = filter(None, words)
520 path = self.root
521 for word in words:
522 drive, word = os.path.splitdrive(word)
523 head, word = os.path.split(word)
524 if word in self.root: continue
525 path = os.path.join(path, word)
526 return path
527
528 def log_message(self, format, *args):
529
530 # we override this to suppress logging unless "verbose"
531
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000532 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000533 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
534 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000535 self.server.server_port,
536 self.request.cipher(),
537 self.log_date_time_string(),
538 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000539
540
Trent Nelson78520002008-04-10 20:54:35 +0000541 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000542 self.flag = None
543 self.active = False
544 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000545 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000546 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000547 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000548 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000549 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000550
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000551 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000552 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000553
554 def start (self, flag=None):
555 self.flag = flag
556 threading.Thread.start(self)
557
Thomas Woutersed03b412007-08-28 21:37:11 +0000558 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000559 self.active = True
560 if self.flag:
561 self.flag.set()
562 self.server.serve_forever()
563 self.active = False
564
565 def stop (self):
566 self.active = False
567 self.server.server_close()
568
569
Bill Janssen54cc54c2007-12-14 22:08:56 +0000570 class AsyncoreEchoServer(threading.Thread):
571
572 # this one's based on asyncore.dispatcher
573
574 class EchoServer (asyncore.dispatcher):
575
576 class ConnectionHandler (asyncore.dispatcher_with_send):
577
578 def __init__(self, conn, certfile):
579 self.socket = ssl.wrap_socket(conn, server_side=True,
580 certfile=certfile,
581 do_handshake_on_connect=False)
582 asyncore.dispatcher_with_send.__init__(self, self.socket)
583 # now we have to do the handshake
584 # we'll just do it the easy way, and block the connection
585 # till it's finished. If we were doing it right, we'd
586 # do this in multiple calls to handle_read...
587 self.do_handshake(block=True)
588
589 def readable(self):
590 if isinstance(self.socket, ssl.SSLSocket):
591 while self.socket.pending() > 0:
592 self.handle_read_event()
593 return True
594
595 def handle_read(self):
596 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000597 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000598 sys.stdout.write(" server: read %s from client\n" % repr(data))
599 if not data:
600 self.close()
601 else:
602 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
603
604 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000605 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000606 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000607 sys.stdout.write(" server: closed connection %s\n" % self.socket)
608
609 def handle_error(self):
610 raise
611
612 def __init__(self, port, certfile):
613 self.port = port
614 self.certfile = certfile
615 asyncore.dispatcher.__init__(self)
616 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
617 self.bind(('', port))
618 self.listen(5)
619
620 def handle_accept(self):
621 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000622 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000623 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
624 self.ConnectionHandler(sock_obj, self.certfile)
625
626 def handle_error(self):
627 raise
628
Trent Nelson78520002008-04-10 20:54:35 +0000629 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000630 self.flag = None
631 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000632 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000633 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000634 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000635 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000636
637 def __str__(self):
638 return "<%s %s>" % (self.__class__.__name__, self.server)
639
640 def start (self, flag=None):
641 self.flag = flag
642 threading.Thread.start(self)
643
644 def run (self):
645 self.active = True
646 if self.flag:
647 self.flag.set()
648 while self.active:
649 try:
650 asyncore.loop(1)
651 except:
652 pass
653
654 def stop (self):
655 self.active = False
656 self.server.close()
657
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000658 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000659 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000660 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000661 cacerts=CERTFILE, chatty=False,
662 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000663 flag = threading.Event()
664 server.start(flag)
665 # wait for it to start
666 flag.wait()
667 # try to connect
668 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000669 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000670 s = ssl.wrap_socket(socket.socket(),
671 certfile=certfile,
672 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000673 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000674 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000675 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000676 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000677 except socket.error as x:
678 if support.verbose:
679 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000680 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000681 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000682 "Use of invalid cert should have failed!")
683 finally:
684 server.stop()
685 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000686
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000687 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000688 client_certfile, client_protocol=None,
689 indata="FOO\n",
690 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000691
Trent Nelson78520002008-04-10 20:54:35 +0000692 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000693 certreqs=certreqs,
694 ssl_version=protocol,
695 cacerts=cacertsfile,
696 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000697 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000698 flag = threading.Event()
699 server.start(flag)
700 # wait for it to start
701 flag.wait()
702 # try to connect
703 if client_protocol is None:
704 client_protocol = protocol
705 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000706 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000707 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000708 certfile=client_certfile,
709 ca_certs=cacertsfile,
710 cert_reqs=certreqs,
711 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000712 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000713 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000714 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000715 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000716 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000717 else:
718 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000719 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000720 sys.stdout.write(
721 " client: sending %s...\n" % (repr(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000722 s.write(indata.encode('ASCII', 'strict'))
Bill Janssen6e027db2007-11-15 22:23:56 +0000723 outdata = s.read()
724 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000725 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000726 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000727 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000728 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000729 raise support.TestFailed(
Bill Janssen6e027db2007-11-15 22:23:56 +0000730 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000731 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
732 repr(indata[:min(len(indata),20)].lower()), len(indata)))
733 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000734 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000735 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000736 sys.stdout.write(" client: closing connection.\n")
737 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000738 finally:
739 server.stop()
740 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000741
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000742 def tryProtocolCombo (server_protocol,
743 client_protocol,
744 expectedToWork,
745 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000746
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000747 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000748 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000749
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000750 if certsreqs == ssl.CERT_NONE:
751 certtype = "CERT_NONE"
752 elif certsreqs == ssl.CERT_OPTIONAL:
753 certtype = "CERT_OPTIONAL"
754 elif certsreqs == ssl.CERT_REQUIRED:
755 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000756 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000757 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
758 sys.stdout.write(formatstr %
759 (ssl.get_protocol_name(client_protocol),
760 ssl.get_protocol_name(server_protocol),
761 certtype))
762 try:
763 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000764 CERTFILE, CERTFILE, client_protocol,
765 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000766 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000767 if expectedToWork:
768 raise
769 else:
770 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000771 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000772 "Client protocol %s succeeded with server protocol %s!"
773 % (ssl.get_protocol_name(client_protocol),
774 ssl.get_protocol_name(server_protocol)))
775
776
Bill Janssen6e027db2007-11-15 22:23:56 +0000777 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000778
Trent Nelson6b240cd2008-04-10 20:12:06 +0000779 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000780
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000781 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000782 sys.stdout.write("\n")
783 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
784 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
785 chatty=True, connectionchatty=True)
786
787 def testReadCert(self):
788
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000789 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000790 sys.stdout.write("\n")
791 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000792 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000793 certreqs=ssl.CERT_NONE,
794 ssl_version=ssl.PROTOCOL_SSLv23,
795 cacerts=CERTFILE,
796 chatty=False)
797 flag = threading.Event()
798 server.start(flag)
799 # wait for it to start
800 flag.wait()
801 # try to connect
802 try:
803 try:
804 s = ssl.wrap_socket(socket.socket(),
805 certfile=CERTFILE,
806 ca_certs=CERTFILE,
807 cert_reqs=ssl.CERT_REQUIRED,
808 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000809 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000810 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000811 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000812 "Unexpected SSL error: " + str(x))
813 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000814 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000815 "Unexpected exception: " + str(x))
816 else:
817 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000818 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000819 "Can't SSL-handshake with test server")
820 cert = s.getpeercert()
821 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000822 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000823 "Can't get peer certificate.")
824 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000825 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000826 sys.stdout.write(pprint.pformat(cert) + '\n')
827 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000828 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000829 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000830 "No subject field in certificate: %s." %
831 pprint.pformat(cert))
832 if ((('organizationName', 'Python Software Foundation'),)
833 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000834 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000835 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000836 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000837 s.close()
838 finally:
839 server.stop()
840 server.join()
841
842 def testNULLcert(self):
843 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
844 "nullcert.pem"))
845 def testMalformedCert(self):
846 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
847 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000848 def testWrongCert(self):
849 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
850 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000851 def testMalformedKey(self):
852 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
853 "badkey.pem"))
854
Trent Nelson6b240cd2008-04-10 20:12:06 +0000855 def testRudeShutdown(self):
856
857 listener_ready = threading.Event()
858 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000859 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000860
861 # `listener` runs in a thread. It opens a socket listening on
862 # PORT, and sits in an accept() until the main thread connects.
863 # Then it rudely closes the socket, and sets Event `listener_gone`
864 # to let the main thread know the socket is gone.
865 def listener():
866 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000867 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000868 s.listen(5)
869 listener_ready.set()
870 s.accept()
871 s = None # reclaim the socket object, which also closes it
872 listener_gone.set()
873
874 def connector():
875 listener_ready.wait()
876 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000877 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000878 listener_gone.wait()
879 try:
880 ssl_sock = ssl.wrap_socket(s)
881 except IOError:
882 pass
883 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000884 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000885 'connecting to closed SSL socket should have failed')
886
887 t = threading.Thread(target=listener)
888 t.start()
889 connector()
890 t.join()
891
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000892 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000893 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000894 sys.stdout.write("\n")
895 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
896 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
897 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
898 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
899 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
900 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
901
902 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000903 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000904 sys.stdout.write("\n")
905 try:
906 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000907 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000908 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000909 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000910 sys.stdout.write(
911 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
912 % str(x))
913 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
914 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
915 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
916
917 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
918 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
919 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
920
921 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
922 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
923 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
924
925 def testProtocolSSL3(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 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
929 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
930 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
931 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
932 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
933 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
934
935 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000936 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000937 sys.stdout.write("\n")
938 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
939 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
940 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
941 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
942 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
943 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
944
945 def testSTARTTLS (self):
946
Bill Janssen40a0f662008-08-12 16:56:25 +0000947 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000948
Trent Nelson78520002008-04-10 20:54:35 +0000949 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000950 ssl_version=ssl.PROTOCOL_TLSv1,
951 starttls_server=True,
952 chatty=True,
953 connectionchatty=True)
954 flag = threading.Event()
955 server.start(flag)
956 # wait for it to start
957 flag.wait()
958 # try to connect
959 wrapped = False
960 try:
961 try:
962 s = socket.socket()
963 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000964 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000965 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000966 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000967 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000968 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000969 sys.stdout.write("\n")
970 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000971 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000972 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000973 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000974 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000975 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000976 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000977 outdata = conn.read()
978 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000979 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000980 outdata = s.recv(1024)
981 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000982 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000983 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000984 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000985 sys.stdout.write(
986 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000987 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000988 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000989 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +0000990 elif (indata == "ENDTLS" and
991 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
992 if support.verbose:
993 msg = str(outdata, 'ASCII', 'replace')
994 sys.stdout.write(
995 " client: read %s from server, ending TLS...\n"
996 % repr(msg))
997 s = conn.unwrap()
998 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000999 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001000 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +00001001 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001002 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +00001003 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001004 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001005 sys.stdout.write(" client: closing connection.\n")
1006 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +00001007 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001008 else:
Bill Janssen40a0f662008-08-12 16:56:25 +00001009 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +00001010 if wrapped:
1011 conn.close()
1012 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001013 s.close()
1014 finally:
1015 server.stop()
1016 server.join()
1017
Bill Janssen54cc54c2007-12-14 22:08:56 +00001018 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +00001019
Trent Nelson78520002008-04-10 20:54:35 +00001020 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001021 flag = threading.Event()
1022 server.start(flag)
1023 # wait for it to start
1024 flag.wait()
1025 # try to connect
1026 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001027 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001028 sys.stdout.write('\n')
1029 d1 = open(CERTFILE, 'rb').read()
1030 d2 = ''
1031 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +00001032 url = 'https://%s:%d/%s' % (
1033 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001034 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +00001035 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001036 if dlen and (int(dlen) > 0):
1037 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001038 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001039 sys.stdout.write(
1040 " client: read %d bytes from remote server '%s'\n"
1041 % (len(d2), server))
1042 f.close()
1043 except:
1044 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001045 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001046 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001047 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001048 else:
1049 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +00001050 print("d1 is", len(d1), repr(d1))
1051 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001052 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001053 "Couldn't fetch data from HTTPS server")
1054 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001055 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001056 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001057 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001058 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001059 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001060 server.join()
1061
Trent Nelson6b240cd2008-04-10 20:12:06 +00001062 def testAsyncoreServer(self):
1063
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001064 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001065 sys.stdout.write("\n")
1066
1067 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001068 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001069 flag = threading.Event()
1070 server.start(flag)
1071 # wait for it to start
1072 flag.wait()
1073 # try to connect
1074 try:
1075 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001076 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001077 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001078 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001079 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001080 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001081 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001082 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001083 sys.stdout.write(
1084 " client: sending %s...\n" % (repr(indata)))
1085 s.sendall(indata.encode('ASCII', 'strict'))
1086 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001087 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001088 sys.stdout.write(" client: read %s\n" % repr(outdata))
1089 outdata = str(outdata, 'ASCII', 'strict')
1090 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001091 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001092 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1093 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1094 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1095 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001096 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001097 sys.stdout.write(" client: closing connection.\n")
1098 s.close()
1099 finally:
1100 server.stop()
1101 server.join()
1102
Bill Janssen58afe4c2008-09-08 16:45:19 +00001103 def testAllRecvAndSendMethods(self):
1104
1105 if support.verbose:
1106 sys.stdout.write("\n")
1107
1108 server = ThreadedEchoServer(CERTFILE,
1109 certreqs=ssl.CERT_NONE,
1110 ssl_version=ssl.PROTOCOL_TLSv1,
1111 cacerts=CERTFILE,
1112 chatty=True,
1113 connectionchatty=False)
1114 flag = threading.Event()
1115 server.start(flag)
1116 # wait for it to start
1117 flag.wait()
1118 # try to connect
1119 try:
1120 s = ssl.wrap_socket(socket.socket(),
1121 server_side=False,
1122 certfile=CERTFILE,
1123 ca_certs=CERTFILE,
1124 cert_reqs=ssl.CERT_NONE,
1125 ssl_version=ssl.PROTOCOL_TLSv1)
1126 s.connect((HOST, server.port))
1127 except ssl.SSLError as x:
1128 raise support.TestFailed("Unexpected SSL error: " + str(x))
1129 except Exception as x:
1130 raise support.TestFailed("Unexpected exception: " + str(x))
1131 else:
1132 # helper methods for standardising recv* method signatures
1133 def _recv_into():
1134 b = bytearray(b"\0"*100)
1135 count = s.recv_into(b)
1136 return b[:count]
1137
1138 def _recvfrom_into():
1139 b = bytearray(b"\0"*100)
1140 count, addr = s.recvfrom_into(b)
1141 return b[:count]
1142
1143 # (name, method, whether to expect success, *args)
1144 send_methods = [
1145 ('send', s.send, True, []),
1146 ('sendto', s.sendto, False, ["some.address"]),
1147 ('sendall', s.sendall, True, []),
1148 ]
1149 recv_methods = [
1150 ('recv', s.recv, True, []),
1151 ('recvfrom', s.recvfrom, False, ["some.address"]),
1152 ('recv_into', _recv_into, True, []),
1153 ('recvfrom_into', _recvfrom_into, False, []),
1154 ]
1155 data_prefix = "PREFIX_"
1156
1157 for meth_name, send_meth, expect_success, args in send_methods:
1158 indata = data_prefix + meth_name
1159 try:
1160 send_meth(indata.encode('ASCII', 'strict'), *args)
1161 outdata = s.read()
1162 outdata = str(outdata, 'ASCII', 'strict')
1163 if outdata != indata.lower():
1164 raise support.TestFailed(
1165 "While sending with <<{name:s}>> bad data "
1166 "<<{outdata:s}>> ({nout:d}) received; "
1167 "expected <<{indata:s}>> ({nin:d})\n".format(
1168 name=meth_name, outdata=repr(outdata[:20]),
1169 nout=len(outdata),
1170 indata=repr(indata[:20]), nin=len(indata)
1171 )
1172 )
1173 except ValueError as e:
1174 if expect_success:
1175 raise support.TestFailed(
1176 "Failed to send with method <<{name:s}>>; "
1177 "expected to succeed.\n".format(name=meth_name)
1178 )
1179 if not str(e).startswith(meth_name):
1180 raise support.TestFailed(
1181 "Method <<{name:s}>> failed with unexpected "
1182 "exception message: {exp:s}\n".format(
1183 name=meth_name, exp=e
1184 )
1185 )
1186
1187 for meth_name, recv_meth, expect_success, args in recv_methods:
1188 indata = data_prefix + meth_name
1189 try:
1190 s.send(indata.encode('ASCII', 'strict'))
1191 outdata = recv_meth(*args)
1192 outdata = str(outdata, 'ASCII', 'strict')
1193 if outdata != indata.lower():
1194 raise support.TestFailed(
1195 "While receiving with <<{name:s}>> bad data "
1196 "<<{outdata:s}>> ({nout:d}) received; "
1197 "expected <<{indata:s}>> ({nin:d})\n".format(
1198 name=meth_name, outdata=repr(outdata[:20]),
1199 nout=len(outdata),
1200 indata=repr(indata[:20]), nin=len(indata)
1201 )
1202 )
1203 except ValueError as e:
1204 if expect_success:
1205 raise support.TestFailed(
1206 "Failed to receive with method <<{name:s}>>; "
1207 "expected to succeed.\n".format(name=meth_name)
1208 )
1209 if not str(e).startswith(meth_name):
1210 raise support.TestFailed(
1211 "Method <<{name:s}>> failed with unexpected "
1212 "exception message: {exp:s}\n".format(
1213 name=meth_name, exp=e
1214 )
1215 )
1216 # consume data
1217 s.read()
1218
1219 s.write("over\n".encode("ASCII", "strict"))
1220 s.close()
1221 finally:
1222 server.stop()
1223 server.join()
1224
1225
Thomas Woutersed03b412007-08-28 21:37:11 +00001226def test_main(verbose=False):
1227 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001228 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001229
Trent Nelson78520002008-04-10 20:54:35 +00001230 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001231 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1232 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001233 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1234 os.path.dirname(__file__) or os.curdir,
1235 "https_svn_python_org_root.pem")
1236
1237 if (not os.path.exists(CERTFILE) or
1238 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001239 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001240
Thomas Woutersed03b412007-08-28 21:37:11 +00001241 tests = [BasicTests]
1242
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001243 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001244 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001245
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001246 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001247 thread_info = support.threading_setup()
1248 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001249 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001250
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001251 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001252
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001253 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001254 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001255
1256if __name__ == "__main__":
1257 test_main()