blob: 19e7cb849c9cdf1b9f803afc39ecefe8edac25a2 [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 def test_makefile_close(self):
114 # Issue #5238: creating a file-like object with makefile() shouldn't
115 # leak the underlying file descriptor.
116 ss = ssl.wrap_socket(socket.socket(socket.AF_INET))
117 fd = ss.fileno()
118 f = ss.makefile()
119 f.close()
120 # The fd is still open
121 os.read(fd, 0)
122 # Closing the SSL socket should close the fd too
123 ss.close()
124 gc.collect()
125 try:
126 os.read(fd, 0)
127 except OSError as e:
128 self.assertEqual(e.errno, errno.EBADF)
129 else:
130 self.fail("OSError wasn't raised")
131
Bill Janssen6e027db2007-11-15 22:23:56 +0000132class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000133
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000134 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000135 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
136 cert_reqs=ssl.CERT_NONE)
137 s.connect(("svn.python.org", 443))
138 c = s.getpeercert()
139 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000140 raise support.TestFailed("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000141 s.close()
142
143 # this should fail because we have no verification certs
144 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
145 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000146 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000147 s.connect(("svn.python.org", 443))
148 except ssl.SSLError:
149 pass
150 finally:
151 s.close()
152
153 # this should succeed because we specify the root cert
154 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
155 cert_reqs=ssl.CERT_REQUIRED,
156 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
157 try:
158 s.connect(("svn.python.org", 443))
159 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000160 raise support.TestFailed("Unexpected exception %s" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000161 finally:
162 s.close()
163
Bill Janssen6e027db2007-11-15 22:23:56 +0000164 def testNonBlockingHandshake(self):
165 s = socket.socket(socket.AF_INET)
166 s.connect(("svn.python.org", 443))
167 s.setblocking(False)
168 s = ssl.wrap_socket(s,
169 cert_reqs=ssl.CERT_NONE,
170 do_handshake_on_connect=False)
171 count = 0
172 while True:
173 try:
174 count += 1
175 s.do_handshake()
176 break
177 except ssl.SSLError as err:
178 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
179 select.select([s], [], [])
180 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
181 select.select([], [s], [])
182 else:
183 raise
184 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000185 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000186 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000187
Bill Janssen54cc54c2007-12-14 22:08:56 +0000188 def testFetchServerCert(self):
189
190 pem = ssl.get_server_certificate(("svn.python.org", 443))
191 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000192 raise support.TestFailed("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000193
194 return
195
196 try:
197 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
198 except ssl.SSLError as x:
199 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000200 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000201 sys.stdout.write("%s\n" % x)
202 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000203 raise support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000204
205 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
206 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000207 raise support.TestFailed("No server certificate on svn.python.org:443!")
208 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000209 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
210
Antoine Pitrou754b98c2010-04-22 18:47:06 +0000211 # Test disabled: OPENSSL_VERSION* not available in Python 3.1
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000212 def test_algorithms(self):
Antoine Pitrouae92a722010-04-22 18:46:16 +0000213 if support.verbose:
214 sys.stdout.write("test_algorithms disabled, "
215 "as it fails on some old OpenSSL versions")
216 return
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000217 # Issue #8484: all algorithms should be available when verifying a
218 # certificate.
Antoine Pitrouae92a722010-04-22 18:46:16 +0000219 # SHA256 was added in OpenSSL 0.9.8
220 if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
221 self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000222 # NOTE: https://sha256.tbs-internet.com is another possible test host
223 remote = ("sha2.hboeck.de", 443)
224 sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
225 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
226 cert_reqs=ssl.CERT_REQUIRED,
227 ca_certs=sha256_cert,)
228 with support.transient_internet():
229 try:
230 s.connect(remote)
231 if support.verbose:
232 sys.stdout.write("\nCipher with %r is %r\n" %
233 (remote, s.cipher()))
234 sys.stdout.write("Certificate is:\n%s\n" %
235 pprint.pformat(s.getpeercert()))
236 finally:
237 s.close()
238
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000239
240try:
241 import threading
242except ImportError:
243 _have_threads = False
244else:
245
246 _have_threads = True
247
248 class ThreadedEchoServer(threading.Thread):
249
250 class ConnectionHandler(threading.Thread):
251
252 """A mildly complicated class, because we want it to work both
253 with and without the SSL wrapper around the socket connection, so
254 that we can test the STARTTLS functionality."""
255
Bill Janssen6e027db2007-11-15 22:23:56 +0000256 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000257 self.server = server
258 self.running = False
259 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000260 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000261 self.sock.setblocking(1)
262 self.sslconn = None
263 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000264 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000265
266 def wrap_conn (self):
267 try:
268 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
269 certfile=self.server.certificate,
270 ssl_version=self.server.protocol,
271 ca_certs=self.server.cacerts,
272 cert_reqs=self.server.certreqs)
273 except:
274 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000275 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000276 if not self.server.expect_bad_connects:
277 # here, we want to stop the server, because this shouldn't
278 # happen in the context of our test case
279 self.running = False
280 # normally, we'd just stop here, but for the test
281 # harness, we want to stop the server
282 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000283 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000284 return False
285
286 else:
287 if self.server.certreqs == ssl.CERT_REQUIRED:
288 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000289 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000290 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
291 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000292 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000293 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
294 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000295 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000296 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
297 return True
298
299 def read(self):
300 if self.sslconn:
301 return self.sslconn.read()
302 else:
303 return self.sock.recv(1024)
304
305 def write(self, bytes):
306 if self.sslconn:
307 return self.sslconn.write(bytes)
308 else:
309 return self.sock.send(bytes)
310
311 def close(self):
312 if self.sslconn:
313 self.sslconn.close()
314 else:
315 self.sock.close()
316
317 def run (self):
318 self.running = True
319 if not self.server.starttls_server:
320 if not self.wrap_conn():
321 return
322 while self.running:
323 try:
324 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000325 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000326 if not msg:
327 # eof, so quit this handler
328 self.running = False
329 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000330 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000331 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000332 sys.stdout.write(" server: client closed connection\n")
333 self.close()
334 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000335 elif (self.server.starttls_server and
336 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000337 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000338 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000339 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000340 if not self.wrap_conn():
341 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000342 elif (self.server.starttls_server and self.sslconn
343 and amsg.strip() == 'ENDTLS'):
344 if support.verbose and self.server.connectionchatty:
345 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
346 self.write("OK\n".encode("ASCII", "strict"))
347 self.sock = self.sslconn.unwrap()
348 self.sslconn = None
349 if support.verbose and self.server.connectionchatty:
350 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000351 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000352 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000353 self.server.connectionchatty):
354 ctype = (self.sslconn and "encrypted") or "unencrypted"
355 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
356 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000357 self.write(amsg.lower().encode('ASCII', 'strict'))
358 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000359 if self.server.chatty:
360 handle_error("Test server failure:\n")
361 self.close()
362 self.running = False
363 # normally, we'd just stop here, but for the test
364 # harness, we want to stop the server
365 self.server.stop()
366 except:
367 handle_error('')
368
Trent Nelson78520002008-04-10 20:54:35 +0000369 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000370 certreqs=None, cacerts=None, expect_bad_connects=False,
371 chatty=True, connectionchatty=False, starttls_server=False):
372 if ssl_version is None:
373 ssl_version = ssl.PROTOCOL_TLSv1
374 if certreqs is None:
375 certreqs = ssl.CERT_NONE
376 self.certificate = certificate
377 self.protocol = ssl_version
378 self.certreqs = certreqs
379 self.cacerts = cacerts
380 self.expect_bad_connects = expect_bad_connects
381 self.chatty = chatty
382 self.connectionchatty = connectionchatty
383 self.starttls_server = starttls_server
384 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000385 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000386 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000387 self.active = False
388 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000389 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000390
391 def start (self, flag=None):
392 self.flag = flag
393 threading.Thread.start(self)
394
395 def run (self):
396 self.sock.settimeout(0.5)
397 self.sock.listen(5)
398 self.active = True
399 if self.flag:
400 # signal an event
401 self.flag.set()
402 while self.active:
403 try:
404 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000405 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000406 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000407 + repr(connaddr) + '\n')
408 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000409 handler.start()
410 except socket.timeout:
411 pass
412 except KeyboardInterrupt:
413 self.stop()
414 except:
415 if self.chatty:
416 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000417 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000418
419 def stop (self):
420 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000421
Bill Janssen54cc54c2007-12-14 22:08:56 +0000422 class OurHTTPSServer(threading.Thread):
423
424 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000425
426 class HTTPSServer(HTTPServer):
427
428 def __init__(self, server_address, RequestHandlerClass, certfile):
429
430 HTTPServer.__init__(self, server_address, RequestHandlerClass)
431 # we assume the certfile contains both private key and certificate
432 self.certfile = certfile
433 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000434 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000435 self.allow_reuse_address = True
436
Bill Janssen6e027db2007-11-15 22:23:56 +0000437 def __str__(self):
438 return ('<%s %s:%s>' %
439 (self.__class__.__name__,
440 self.server_name,
441 self.server_port))
442
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000443 def get_request (self):
444 # override this to wrap socket with SSL
445 sock, addr = self.socket.accept()
446 sslconn = ssl.wrap_socket(sock, server_side=True,
447 certfile=self.certfile)
448 return sslconn, addr
449
450 # The methods overridden below this are mainly so that we
451 # can run it in a thread and be able to stop it from another
452 # You probably wouldn't need them in other uses.
453
454 def server_activate(self):
455 # We want to run this in a thread for testing purposes,
456 # so we override this to set timeout, so that we get
457 # a chance to stop the server
458 self.socket.settimeout(0.5)
459 HTTPServer.server_activate(self)
460
461 def serve_forever(self):
462 # We want this to run in a thread, so we use a slightly
463 # modified version of "forever".
464 self.active = True
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000465 while 1:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000466 try:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000467 # We need to lock while handling the request.
468 # Another thread can close the socket after self.active
469 # has been checked and before the request is handled.
470 # This causes an exception when using the closed socket.
471 with self.active_lock:
472 if not self.active:
473 break
474 self.handle_request()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000475 except socket.timeout:
476 pass
477 except KeyboardInterrupt:
478 self.server_close()
479 return
480 except:
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000481 sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
482 break
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000483 time.sleep(0.1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000484
485 def server_close(self):
486 # Again, we want this to run in a thread, so we need to override
487 # close to clear the "active" flag, so that serve_forever() will
488 # terminate.
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000489 with self.active_lock:
490 HTTPServer.server_close(self)
491 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000492
493 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
494
495 # need to override translate_path to get a known root,
496 # instead of using os.curdir, since the test could be
497 # run from anywhere
498
499 server_version = "TestHTTPS/1.0"
500
501 root = None
502
503 def translate_path(self, path):
504 """Translate a /-separated PATH to the local filename syntax.
505
506 Components that mean special things to the local file system
507 (e.g. drive or directory names) are ignored. (XXX They should
508 probably be diagnosed.)
509
510 """
511 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000512 path = urllib.parse.urlparse(path)[2]
513 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000514 words = path.split('/')
515 words = filter(None, words)
516 path = self.root
517 for word in words:
518 drive, word = os.path.splitdrive(word)
519 head, word = os.path.split(word)
520 if word in self.root: continue
521 path = os.path.join(path, word)
522 return path
523
524 def log_message(self, format, *args):
525
526 # we override this to suppress logging unless "verbose"
527
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000528 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000529 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
530 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000531 self.server.server_port,
532 self.request.cipher(),
533 self.log_date_time_string(),
534 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000535
536
Trent Nelson78520002008-04-10 20:54:35 +0000537 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000538 self.flag = None
539 self.active = False
540 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000541 self.port = support.find_unused_port()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000542 self.server = self.HTTPSServer(
Trent Nelson78520002008-04-10 20:54:35 +0000543 (HOST, self.port), self.RootedHTTPRequestHandler, certfile)
Thomas Woutersed03b412007-08-28 21:37:11 +0000544 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000545 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000546
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000547 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000548 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000549
550 def start (self, flag=None):
551 self.flag = flag
552 threading.Thread.start(self)
553
Thomas Woutersed03b412007-08-28 21:37:11 +0000554 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000555 self.active = True
556 if self.flag:
557 self.flag.set()
558 self.server.serve_forever()
559 self.active = False
560
561 def stop (self):
562 self.active = False
563 self.server.server_close()
564
565
Bill Janssen54cc54c2007-12-14 22:08:56 +0000566 class AsyncoreEchoServer(threading.Thread):
567
568 # this one's based on asyncore.dispatcher
569
570 class EchoServer (asyncore.dispatcher):
571
572 class ConnectionHandler (asyncore.dispatcher_with_send):
573
574 def __init__(self, conn, certfile):
575 self.socket = ssl.wrap_socket(conn, server_side=True,
576 certfile=certfile,
577 do_handshake_on_connect=False)
578 asyncore.dispatcher_with_send.__init__(self, self.socket)
579 # now we have to do the handshake
580 # we'll just do it the easy way, and block the connection
581 # till it's finished. If we were doing it right, we'd
582 # do this in multiple calls to handle_read...
583 self.do_handshake(block=True)
584
585 def readable(self):
586 if isinstance(self.socket, ssl.SSLSocket):
587 while self.socket.pending() > 0:
588 self.handle_read_event()
589 return True
590
591 def handle_read(self):
592 data = self.recv(1024)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000593 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000594 sys.stdout.write(" server: read %s from client\n" % repr(data))
595 if not data:
596 self.close()
597 else:
598 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
599
600 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000601 self.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000602 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000603 sys.stdout.write(" server: closed connection %s\n" % self.socket)
604
605 def handle_error(self):
606 raise
607
608 def __init__(self, port, certfile):
609 self.port = port
610 self.certfile = certfile
611 asyncore.dispatcher.__init__(self)
612 self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
613 self.bind(('', port))
614 self.listen(5)
615
616 def handle_accept(self):
617 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000618 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000619 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
620 self.ConnectionHandler(sock_obj, self.certfile)
621
622 def handle_error(self):
623 raise
624
Trent Nelson78520002008-04-10 20:54:35 +0000625 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000626 self.flag = None
627 self.active = False
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000628 self.port = support.find_unused_port()
Trent Nelson78520002008-04-10 20:54:35 +0000629 self.server = self.EchoServer(self.port, certfile)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000630 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000631 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000632
633 def __str__(self):
634 return "<%s %s>" % (self.__class__.__name__, self.server)
635
636 def start (self, flag=None):
637 self.flag = flag
638 threading.Thread.start(self)
639
640 def run (self):
641 self.active = True
642 if self.flag:
643 self.flag.set()
644 while self.active:
645 try:
646 asyncore.loop(1)
647 except:
648 pass
649
650 def stop (self):
651 self.active = False
652 self.server.close()
653
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000654 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000655 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000656 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000657 cacerts=CERTFILE, chatty=False,
658 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000659 flag = threading.Event()
660 server.start(flag)
661 # wait for it to start
662 flag.wait()
663 # try to connect
664 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000665 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000666 s = ssl.wrap_socket(socket.socket(),
667 certfile=certfile,
668 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000669 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000670 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000671 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000672 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000673 except socket.error as x:
674 if support.verbose:
675 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000676 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000677 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000678 "Use of invalid cert should have failed!")
679 finally:
680 server.stop()
681 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000682
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000683 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000684 client_certfile, client_protocol=None,
685 indata="FOO\n",
686 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000687
Trent Nelson78520002008-04-10 20:54:35 +0000688 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000689 certreqs=certreqs,
690 ssl_version=protocol,
691 cacerts=cacertsfile,
692 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000693 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000694 flag = threading.Event()
695 server.start(flag)
696 # wait for it to start
697 flag.wait()
698 # try to connect
699 if client_protocol is None:
700 client_protocol = protocol
701 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000702 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000703 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000704 certfile=client_certfile,
705 ca_certs=cacertsfile,
706 cert_reqs=certreqs,
707 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000708 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000709 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000710 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000711 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000712 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000713 else:
714 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000715 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000716 sys.stdout.write(
717 " client: sending %s...\n" % (repr(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000718 s.write(indata.encode('ASCII', 'strict'))
Bill Janssen6e027db2007-11-15 22:23:56 +0000719 outdata = s.read()
720 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000721 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000722 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000723 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000724 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000725 raise support.TestFailed(
Bill Janssen6e027db2007-11-15 22:23:56 +0000726 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000727 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
728 repr(indata[:min(len(indata),20)].lower()), len(indata)))
729 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000730 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000731 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000732 sys.stdout.write(" client: closing connection.\n")
733 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000734 finally:
735 server.stop()
736 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000737
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000738 def tryProtocolCombo (server_protocol,
739 client_protocol,
740 expectedToWork,
741 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000742
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000743 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000744 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000745
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000746 if certsreqs == ssl.CERT_NONE:
747 certtype = "CERT_NONE"
748 elif certsreqs == ssl.CERT_OPTIONAL:
749 certtype = "CERT_OPTIONAL"
750 elif certsreqs == ssl.CERT_REQUIRED:
751 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000752 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000753 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
754 sys.stdout.write(formatstr %
755 (ssl.get_protocol_name(client_protocol),
756 ssl.get_protocol_name(server_protocol),
757 certtype))
758 try:
759 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000760 CERTFILE, CERTFILE, client_protocol,
761 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000762 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000763 if expectedToWork:
764 raise
765 else:
766 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000767 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000768 "Client protocol %s succeeded with server protocol %s!"
769 % (ssl.get_protocol_name(client_protocol),
770 ssl.get_protocol_name(server_protocol)))
771
772
Bill Janssen6e027db2007-11-15 22:23:56 +0000773 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000774
Trent Nelson6b240cd2008-04-10 20:12:06 +0000775 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000776
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000777 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000778 sys.stdout.write("\n")
779 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
780 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
781 chatty=True, connectionchatty=True)
782
783 def testReadCert(self):
784
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000785 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000786 sys.stdout.write("\n")
787 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000788 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000789 certreqs=ssl.CERT_NONE,
790 ssl_version=ssl.PROTOCOL_SSLv23,
791 cacerts=CERTFILE,
792 chatty=False)
793 flag = threading.Event()
794 server.start(flag)
795 # wait for it to start
796 flag.wait()
797 # try to connect
798 try:
799 try:
800 s = ssl.wrap_socket(socket.socket(),
801 certfile=CERTFILE,
802 ca_certs=CERTFILE,
803 cert_reqs=ssl.CERT_REQUIRED,
804 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000805 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000806 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000807 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000808 "Unexpected SSL error: " + str(x))
809 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000810 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000811 "Unexpected exception: " + str(x))
812 else:
813 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000814 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000815 "Can't SSL-handshake with test server")
816 cert = s.getpeercert()
817 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000818 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000819 "Can't get peer certificate.")
820 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000821 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000822 sys.stdout.write(pprint.pformat(cert) + '\n')
823 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000824 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000825 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000826 "No subject field in certificate: %s." %
827 pprint.pformat(cert))
828 if ((('organizationName', 'Python Software Foundation'),)
829 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000830 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000831 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000832 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000833 s.close()
834 finally:
835 server.stop()
836 server.join()
837
838 def testNULLcert(self):
839 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
840 "nullcert.pem"))
841 def testMalformedCert(self):
842 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
843 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000844 def testWrongCert(self):
845 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
846 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000847 def testMalformedKey(self):
848 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
849 "badkey.pem"))
850
Trent Nelson6b240cd2008-04-10 20:12:06 +0000851 def testRudeShutdown(self):
852
853 listener_ready = threading.Event()
854 listener_gone = threading.Event()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000855 port = support.find_unused_port()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000856
857 # `listener` runs in a thread. It opens a socket listening on
858 # PORT, and sits in an accept() until the main thread connects.
859 # Then it rudely closes the socket, and sets Event `listener_gone`
860 # to let the main thread know the socket is gone.
861 def listener():
862 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000863 s.bind((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000864 s.listen(5)
865 listener_ready.set()
866 s.accept()
867 s = None # reclaim the socket object, which also closes it
868 listener_gone.set()
869
870 def connector():
871 listener_ready.wait()
872 s = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000873 s.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000874 listener_gone.wait()
875 try:
876 ssl_sock = ssl.wrap_socket(s)
877 except IOError:
878 pass
879 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000880 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000881 'connecting to closed SSL socket should have failed')
882
883 t = threading.Thread(target=listener)
884 t.start()
885 connector()
886 t.join()
887
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000888 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000889 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000890 sys.stdout.write("\n")
891 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
892 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
893 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
894 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
895 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
896 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
897
898 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000899 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000900 sys.stdout.write("\n")
901 try:
902 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000903 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000904 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000905 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000906 sys.stdout.write(
907 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
908 % str(x))
909 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
910 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
911 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
912
913 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
914 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
915 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
916
917 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
918 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
919 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
920
921 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000922 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000923 sys.stdout.write("\n")
924 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
925 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
926 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
927 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
928 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
929 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
930
931 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000932 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000933 sys.stdout.write("\n")
934 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
935 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
936 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
937 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
938 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
939 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
940
941 def testSTARTTLS (self):
942
Bill Janssen40a0f662008-08-12 16:56:25 +0000943 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000944
Trent Nelson78520002008-04-10 20:54:35 +0000945 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000946 ssl_version=ssl.PROTOCOL_TLSv1,
947 starttls_server=True,
948 chatty=True,
949 connectionchatty=True)
950 flag = threading.Event()
951 server.start(flag)
952 # wait for it to start
953 flag.wait()
954 # try to connect
955 wrapped = False
956 try:
957 try:
958 s = socket.socket()
959 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000960 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000961 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000962 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000963 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000964 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000965 sys.stdout.write("\n")
966 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000967 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000968 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000969 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000970 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000971 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000972 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000973 outdata = conn.read()
974 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000975 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000976 outdata = s.recv(1024)
977 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000978 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000979 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000980 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000981 sys.stdout.write(
982 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000983 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000984 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000985 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +0000986 elif (indata == "ENDTLS" and
987 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
988 if support.verbose:
989 msg = str(outdata, 'ASCII', 'replace')
990 sys.stdout.write(
991 " client: read %s from server, ending TLS...\n"
992 % repr(msg))
993 s = conn.unwrap()
994 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000995 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000996 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000997 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000998 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000999 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001000 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001001 sys.stdout.write(" client: closing connection.\n")
1002 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +00001003 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001004 else:
Bill Janssen40a0f662008-08-12 16:56:25 +00001005 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +00001006 if wrapped:
1007 conn.close()
1008 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001009 s.close()
1010 finally:
1011 server.stop()
1012 server.join()
1013
Bill Janssen54cc54c2007-12-14 22:08:56 +00001014 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +00001015
Trent Nelson78520002008-04-10 20:54:35 +00001016 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001017 flag = threading.Event()
1018 server.start(flag)
1019 # wait for it to start
1020 flag.wait()
1021 # try to connect
1022 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001023 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001024 sys.stdout.write('\n')
1025 d1 = open(CERTFILE, 'rb').read()
1026 d2 = ''
1027 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +00001028 url = 'https://%s:%d/%s' % (
1029 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001030 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +00001031 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001032 if dlen and (int(dlen) > 0):
1033 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001034 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001035 sys.stdout.write(
1036 " client: read %d bytes from remote server '%s'\n"
1037 % (len(d2), server))
1038 f.close()
1039 except:
1040 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001041 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001042 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001043 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001044 else:
1045 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +00001046 print("d1 is", len(d1), repr(d1))
1047 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001048 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001049 "Couldn't fetch data from HTTPS server")
1050 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001051 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001052 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001053 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001054 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001055 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001056 server.join()
1057
Trent Nelson6b240cd2008-04-10 20:12:06 +00001058 def testAsyncoreServer(self):
1059
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001060 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001061 sys.stdout.write("\n")
1062
1063 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001064 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001065 flag = threading.Event()
1066 server.start(flag)
1067 # wait for it to start
1068 flag.wait()
1069 # try to connect
1070 try:
1071 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001072 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001073 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001074 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001075 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001076 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001077 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001078 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001079 sys.stdout.write(
1080 " client: sending %s...\n" % (repr(indata)))
1081 s.sendall(indata.encode('ASCII', 'strict'))
1082 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001083 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001084 sys.stdout.write(" client: read %s\n" % repr(outdata))
1085 outdata = str(outdata, 'ASCII', 'strict')
1086 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001087 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001088 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1089 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1090 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1091 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001092 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001093 sys.stdout.write(" client: closing connection.\n")
1094 s.close()
1095 finally:
1096 server.stop()
1097 server.join()
1098
Bill Janssen58afe4c2008-09-08 16:45:19 +00001099 def testAllRecvAndSendMethods(self):
1100
1101 if support.verbose:
1102 sys.stdout.write("\n")
1103
1104 server = ThreadedEchoServer(CERTFILE,
1105 certreqs=ssl.CERT_NONE,
1106 ssl_version=ssl.PROTOCOL_TLSv1,
1107 cacerts=CERTFILE,
1108 chatty=True,
1109 connectionchatty=False)
1110 flag = threading.Event()
1111 server.start(flag)
1112 # wait for it to start
1113 flag.wait()
1114 # try to connect
1115 try:
1116 s = ssl.wrap_socket(socket.socket(),
1117 server_side=False,
1118 certfile=CERTFILE,
1119 ca_certs=CERTFILE,
1120 cert_reqs=ssl.CERT_NONE,
1121 ssl_version=ssl.PROTOCOL_TLSv1)
1122 s.connect((HOST, server.port))
1123 except ssl.SSLError as x:
1124 raise support.TestFailed("Unexpected SSL error: " + str(x))
1125 except Exception as x:
1126 raise support.TestFailed("Unexpected exception: " + str(x))
1127 else:
1128 # helper methods for standardising recv* method signatures
1129 def _recv_into():
1130 b = bytearray(b"\0"*100)
1131 count = s.recv_into(b)
1132 return b[:count]
1133
1134 def _recvfrom_into():
1135 b = bytearray(b"\0"*100)
1136 count, addr = s.recvfrom_into(b)
1137 return b[:count]
1138
1139 # (name, method, whether to expect success, *args)
1140 send_methods = [
1141 ('send', s.send, True, []),
1142 ('sendto', s.sendto, False, ["some.address"]),
1143 ('sendall', s.sendall, True, []),
1144 ]
1145 recv_methods = [
1146 ('recv', s.recv, True, []),
1147 ('recvfrom', s.recvfrom, False, ["some.address"]),
1148 ('recv_into', _recv_into, True, []),
1149 ('recvfrom_into', _recvfrom_into, False, []),
1150 ]
1151 data_prefix = "PREFIX_"
1152
1153 for meth_name, send_meth, expect_success, args in send_methods:
1154 indata = data_prefix + meth_name
1155 try:
1156 send_meth(indata.encode('ASCII', 'strict'), *args)
1157 outdata = s.read()
1158 outdata = str(outdata, 'ASCII', 'strict')
1159 if outdata != indata.lower():
1160 raise support.TestFailed(
1161 "While sending with <<{name:s}>> bad data "
1162 "<<{outdata:s}>> ({nout:d}) received; "
1163 "expected <<{indata:s}>> ({nin:d})\n".format(
1164 name=meth_name, outdata=repr(outdata[:20]),
1165 nout=len(outdata),
1166 indata=repr(indata[:20]), nin=len(indata)
1167 )
1168 )
1169 except ValueError as e:
1170 if expect_success:
1171 raise support.TestFailed(
1172 "Failed to send with method <<{name:s}>>; "
1173 "expected to succeed.\n".format(name=meth_name)
1174 )
1175 if not str(e).startswith(meth_name):
1176 raise support.TestFailed(
1177 "Method <<{name:s}>> failed with unexpected "
1178 "exception message: {exp:s}\n".format(
1179 name=meth_name, exp=e
1180 )
1181 )
1182
1183 for meth_name, recv_meth, expect_success, args in recv_methods:
1184 indata = data_prefix + meth_name
1185 try:
1186 s.send(indata.encode('ASCII', 'strict'))
1187 outdata = recv_meth(*args)
1188 outdata = str(outdata, 'ASCII', 'strict')
1189 if outdata != indata.lower():
1190 raise support.TestFailed(
1191 "While receiving with <<{name:s}>> bad data "
1192 "<<{outdata:s}>> ({nout:d}) received; "
1193 "expected <<{indata:s}>> ({nin:d})\n".format(
1194 name=meth_name, outdata=repr(outdata[:20]),
1195 nout=len(outdata),
1196 indata=repr(indata[:20]), nin=len(indata)
1197 )
1198 )
1199 except ValueError as e:
1200 if expect_success:
1201 raise support.TestFailed(
1202 "Failed to receive with method <<{name:s}>>; "
1203 "expected to succeed.\n".format(name=meth_name)
1204 )
1205 if not str(e).startswith(meth_name):
1206 raise support.TestFailed(
1207 "Method <<{name:s}>> failed with unexpected "
1208 "exception message: {exp:s}\n".format(
1209 name=meth_name, exp=e
1210 )
1211 )
1212 # consume data
1213 s.read()
1214
1215 s.write("over\n".encode("ASCII", "strict"))
1216 s.close()
1217 finally:
1218 server.stop()
1219 server.join()
1220
1221
Thomas Woutersed03b412007-08-28 21:37:11 +00001222def test_main(verbose=False):
1223 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001224 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001225
Trent Nelson78520002008-04-10 20:54:35 +00001226 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001227 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1228 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001229 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1230 os.path.dirname(__file__) or os.curdir,
1231 "https_svn_python_org_root.pem")
1232
1233 if (not os.path.exists(CERTFILE) or
1234 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001235 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001236
Thomas Woutersed03b412007-08-28 21:37:11 +00001237 tests = [BasicTests]
1238
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001239 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001240 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001241
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001242 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001243 thread_info = support.threading_setup()
1244 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001245 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001246
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001247 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001248
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001249 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001250 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001251
1252if __name__ == "__main__":
1253 test_main()