blob: d9892b95b7e54cb5d7dc1af1981b295476941a16 [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 Pitrouc2203f92010-04-24 22:07:51 +0000113 def test_timeout(self):
114 # Issue #8524: when creating an SSL socket, the timeout of the
115 # original socket should be retained.
116 for timeout in (None, 0.0, 5.0):
117 s = socket.socket(socket.AF_INET)
118 s.settimeout(timeout)
119 ss = ssl.wrap_socket(s)
120 self.assertEqual(timeout, ss.gettimeout())
121
Antoine Pitrou3b9b9ba2010-04-23 23:33:50 +0000122
Bill Janssen6e027db2007-11-15 22:23:56 +0000123class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000124
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000125 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000126 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
127 cert_reqs=ssl.CERT_NONE)
128 s.connect(("svn.python.org", 443))
129 c = s.getpeercert()
130 if c:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000131 raise support.TestFailed("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000132 s.close()
133
134 # this should fail because we have no verification certs
135 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
136 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000137 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000138 s.connect(("svn.python.org", 443))
139 except ssl.SSLError:
140 pass
141 finally:
142 s.close()
143
144 # this should succeed because we specify the root cert
145 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
146 cert_reqs=ssl.CERT_REQUIRED,
147 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
148 try:
149 s.connect(("svn.python.org", 443))
150 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000151 raise support.TestFailed("Unexpected exception %s" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000152 finally:
153 s.close()
154
Antoine Pitroufe0f1172010-04-24 11:17:37 +0000155 @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
156 def test_makefile_close(self):
157 # Issue #5238: creating a file-like object with makefile() shouldn't
158 # delay closing the underlying "real socket" (here tested with its
159 # file descriptor, hence skipping the test under Windows).
160 ss = ssl.wrap_socket(socket.socket(socket.AF_INET))
161 ss.connect(("svn.python.org", 443))
162 fd = ss.fileno()
163 f = ss.makefile()
164 f.close()
165 # The fd is still open
166 os.read(fd, 0)
167 # Closing the SSL socket should close the fd too
168 ss.close()
169 gc.collect()
170 try:
171 os.read(fd, 0)
172 except OSError as e:
173 self.assertEqual(e.errno, errno.EBADF)
174 else:
175 self.fail("OSError wasn't raised")
176
Bill Janssen6e027db2007-11-15 22:23:56 +0000177 def testNonBlockingHandshake(self):
178 s = socket.socket(socket.AF_INET)
179 s.connect(("svn.python.org", 443))
180 s.setblocking(False)
181 s = ssl.wrap_socket(s,
182 cert_reqs=ssl.CERT_NONE,
183 do_handshake_on_connect=False)
184 count = 0
185 while True:
186 try:
187 count += 1
188 s.do_handshake()
189 break
190 except ssl.SSLError as err:
191 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
192 select.select([s], [], [])
193 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
194 select.select([], [s], [])
195 else:
196 raise
197 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000198 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000199 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000200
Bill Janssen54cc54c2007-12-14 22:08:56 +0000201 def testFetchServerCert(self):
202
203 pem = ssl.get_server_certificate(("svn.python.org", 443))
204 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000205 raise support.TestFailed("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000206
207 return
208
209 try:
210 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
211 except ssl.SSLError as x:
212 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000213 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000214 sys.stdout.write("%s\n" % x)
215 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000216 raise support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000217
218 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
219 if not pem:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000220 raise support.TestFailed("No server certificate on svn.python.org:443!")
221 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000222 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
223
Antoine Pitrou754b98c2010-04-22 18:47:06 +0000224 # Test disabled: OPENSSL_VERSION* not available in Python 3.1
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000225 def test_algorithms(self):
Antoine Pitrouae92a722010-04-22 18:46:16 +0000226 if support.verbose:
227 sys.stdout.write("test_algorithms disabled, "
228 "as it fails on some old OpenSSL versions")
229 return
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000230 # Issue #8484: all algorithms should be available when verifying a
231 # certificate.
Antoine Pitrouae92a722010-04-22 18:46:16 +0000232 # SHA256 was added in OpenSSL 0.9.8
233 if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
234 self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000235 # NOTE: https://sha256.tbs-internet.com is another possible test host
236 remote = ("sha2.hboeck.de", 443)
237 sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
238 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
239 cert_reqs=ssl.CERT_REQUIRED,
240 ca_certs=sha256_cert,)
241 with support.transient_internet():
242 try:
243 s.connect(remote)
244 if support.verbose:
245 sys.stdout.write("\nCipher with %r is %r\n" %
246 (remote, s.cipher()))
247 sys.stdout.write("Certificate is:\n%s\n" %
248 pprint.pformat(s.getpeercert()))
249 finally:
250 s.close()
251
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000252
253try:
254 import threading
255except ImportError:
256 _have_threads = False
257else:
258
259 _have_threads = True
260
261 class ThreadedEchoServer(threading.Thread):
262
263 class ConnectionHandler(threading.Thread):
264
265 """A mildly complicated class, because we want it to work both
266 with and without the SSL wrapper around the socket connection, so
267 that we can test the STARTTLS functionality."""
268
Bill Janssen6e027db2007-11-15 22:23:56 +0000269 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000270 self.server = server
271 self.running = False
272 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000273 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000274 self.sock.setblocking(1)
275 self.sslconn = None
276 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000277 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000278
279 def wrap_conn (self):
280 try:
281 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
282 certfile=self.server.certificate,
283 ssl_version=self.server.protocol,
284 ca_certs=self.server.cacerts,
285 cert_reqs=self.server.certreqs)
286 except:
287 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000288 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000289 if not self.server.expect_bad_connects:
290 # here, we want to stop the server, because this shouldn't
291 # happen in the context of our test case
292 self.running = False
293 # normally, we'd just stop here, but for the test
294 # harness, we want to stop the server
295 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000296 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000297 return False
298
299 else:
300 if self.server.certreqs == ssl.CERT_REQUIRED:
301 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000302 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000303 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
304 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000305 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000306 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
307 cipher = self.sslconn.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000308 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000309 sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
310 return True
311
312 def read(self):
313 if self.sslconn:
314 return self.sslconn.read()
315 else:
316 return self.sock.recv(1024)
317
318 def write(self, bytes):
319 if self.sslconn:
320 return self.sslconn.write(bytes)
321 else:
322 return self.sock.send(bytes)
323
324 def close(self):
325 if self.sslconn:
326 self.sslconn.close()
327 else:
328 self.sock.close()
329
330 def run (self):
331 self.running = True
332 if not self.server.starttls_server:
333 if not self.wrap_conn():
334 return
335 while self.running:
336 try:
337 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000338 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000339 if not msg:
340 # eof, so quit this handler
341 self.running = False
342 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000343 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000344 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000345 sys.stdout.write(" server: client closed connection\n")
346 self.close()
347 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000348 elif (self.server.starttls_server and
349 amsg.strip() == 'STARTTLS'):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000350 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000351 sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000352 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000353 if not self.wrap_conn():
354 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000355 elif (self.server.starttls_server and self.sslconn
356 and amsg.strip() == 'ENDTLS'):
357 if support.verbose and self.server.connectionchatty:
358 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
359 self.write("OK\n".encode("ASCII", "strict"))
360 self.sock = self.sslconn.unwrap()
361 self.sslconn = None
362 if support.verbose and self.server.connectionchatty:
363 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000364 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000365 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000366 self.server.connectionchatty):
367 ctype = (self.sslconn and "encrypted") or "unencrypted"
368 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
369 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000370 self.write(amsg.lower().encode('ASCII', 'strict'))
371 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000372 if self.server.chatty:
373 handle_error("Test server failure:\n")
374 self.close()
375 self.running = False
376 # normally, we'd just stop here, but for the test
377 # harness, we want to stop the server
378 self.server.stop()
379 except:
380 handle_error('')
381
Trent Nelson78520002008-04-10 20:54:35 +0000382 def __init__(self, certificate, ssl_version=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000383 certreqs=None, cacerts=None, expect_bad_connects=False,
384 chatty=True, connectionchatty=False, starttls_server=False):
385 if ssl_version is None:
386 ssl_version = ssl.PROTOCOL_TLSv1
387 if certreqs is None:
388 certreqs = ssl.CERT_NONE
389 self.certificate = certificate
390 self.protocol = ssl_version
391 self.certreqs = certreqs
392 self.cacerts = cacerts
393 self.expect_bad_connects = expect_bad_connects
394 self.chatty = chatty
395 self.connectionchatty = connectionchatty
396 self.starttls_server = starttls_server
397 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000398 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000399 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000400 self.active = False
401 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000402 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000403
404 def start (self, flag=None):
405 self.flag = flag
406 threading.Thread.start(self)
407
408 def run (self):
Antoine Pitroube168132010-04-27 10:41:37 +0000409 self.sock.settimeout(0.05)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000410 self.sock.listen(5)
411 self.active = True
412 if self.flag:
413 # signal an event
414 self.flag.set()
415 while self.active:
416 try:
417 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000418 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000419 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000420 + repr(connaddr) + '\n')
421 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000422 handler.start()
423 except socket.timeout:
424 pass
425 except KeyboardInterrupt:
426 self.stop()
427 except:
428 if self.chatty:
429 handle_error("Test server failure:\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000430 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000431
432 def stop (self):
433 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000434
Bill Janssen54cc54c2007-12-14 22:08:56 +0000435 class OurHTTPSServer(threading.Thread):
436
437 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000438
439 class HTTPSServer(HTTPServer):
440
441 def __init__(self, server_address, RequestHandlerClass, certfile):
442
443 HTTPServer.__init__(self, server_address, RequestHandlerClass)
444 # we assume the certfile contains both private key and certificate
445 self.certfile = certfile
446 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000447 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000448 self.allow_reuse_address = True
449
Bill Janssen6e027db2007-11-15 22:23:56 +0000450 def __str__(self):
451 return ('<%s %s:%s>' %
452 (self.__class__.__name__,
453 self.server_name,
454 self.server_port))
455
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000456 def get_request (self):
457 # override this to wrap socket with SSL
458 sock, addr = self.socket.accept()
459 sslconn = ssl.wrap_socket(sock, server_side=True,
460 certfile=self.certfile)
461 return sslconn, addr
462
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000463 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
464
465 # need to override translate_path to get a known root,
466 # instead of using os.curdir, since the test could be
467 # run from anywhere
468
469 server_version = "TestHTTPS/1.0"
470
471 root = None
472
473 def translate_path(self, path):
474 """Translate a /-separated PATH to the local filename syntax.
475
476 Components that mean special things to the local file system
477 (e.g. drive or directory names) are ignored. (XXX They should
478 probably be diagnosed.)
479
480 """
481 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000482 path = urllib.parse.urlparse(path)[2]
483 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000484 words = path.split('/')
485 words = filter(None, words)
486 path = self.root
487 for word in words:
488 drive, word = os.path.splitdrive(word)
489 head, word = os.path.split(word)
490 if word in self.root: continue
491 path = os.path.join(path, word)
492 return path
493
494 def log_message(self, format, *args):
495
496 # we override this to suppress logging unless "verbose"
497
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000498 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000499 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
500 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000501 self.server.server_port,
502 self.request.cipher(),
503 self.log_date_time_string(),
504 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000505
506
Trent Nelson78520002008-04-10 20:54:35 +0000507 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000508 self.flag = None
509 self.active = False
510 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
511 self.server = self.HTTPSServer(
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000512 (HOST, 0), self.RootedHTTPRequestHandler, certfile)
513 self.port = self.server.server_port
Thomas Woutersed03b412007-08-28 21:37:11 +0000514 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000515 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000516
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000517 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000518 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000519
520 def start (self, flag=None):
521 self.flag = flag
522 threading.Thread.start(self)
523
Thomas Woutersed03b412007-08-28 21:37:11 +0000524 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000525 self.active = True
526 if self.flag:
527 self.flag.set()
Antoine Pitroube168132010-04-27 10:41:37 +0000528 self.server.serve_forever(0.05)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000529 self.active = False
530
531 def stop (self):
532 self.active = False
Antoine Pitroube168132010-04-27 10:41:37 +0000533 self.server.shutdown()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000534
535
Bill Janssen54cc54c2007-12-14 22:08:56 +0000536 class AsyncoreEchoServer(threading.Thread):
537
538 # this one's based on asyncore.dispatcher
539
540 class EchoServer (asyncore.dispatcher):
541
542 class ConnectionHandler (asyncore.dispatcher_with_send):
543
544 def __init__(self, conn, certfile):
545 self.socket = ssl.wrap_socket(conn, server_side=True,
546 certfile=certfile,
547 do_handshake_on_connect=False)
548 asyncore.dispatcher_with_send.__init__(self, self.socket)
Antoine Pitrouec146182010-04-24 21:30:20 +0000549 self._ssl_accepting = True
550 self._do_ssl_handshake()
Bill Janssen54cc54c2007-12-14 22:08:56 +0000551
552 def readable(self):
553 if isinstance(self.socket, ssl.SSLSocket):
554 while self.socket.pending() > 0:
555 self.handle_read_event()
556 return True
557
Antoine Pitrouec146182010-04-24 21:30:20 +0000558 def _do_ssl_handshake(self):
559 try:
560 self.socket.do_handshake()
561 except ssl.SSLError as err:
562 if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
563 ssl.SSL_ERROR_WANT_WRITE):
564 return
565 elif err.args[0] == ssl.SSL_ERROR_EOF:
566 return self.handle_close()
567 raise
568 except socket.error as err:
569 if err.args[0] == errno.ECONNABORTED:
570 return self.handle_close()
Bill Janssen54cc54c2007-12-14 22:08:56 +0000571 else:
Antoine Pitrouec146182010-04-24 21:30:20 +0000572 self._ssl_accepting = False
573
574 def handle_read(self):
575 if self._ssl_accepting:
576 self._do_ssl_handshake()
577 else:
578 data = self.recv(1024)
579 if support.verbose:
580 sys.stdout.write(" server: read %s from client\n" % repr(data))
581 if not data:
582 self.close()
583 else:
584 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
Bill Janssen54cc54c2007-12-14 22:08:56 +0000585
586 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000587 self.close()
Antoine Pitrouec146182010-04-24 21:30:20 +0000588 if test_support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000589 sys.stdout.write(" server: closed connection %s\n" % self.socket)
590
591 def handle_error(self):
592 raise
593
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000594 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000595 self.certfile = certfile
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000596 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
597 self.port = support.bind_port(sock, '')
598 asyncore.dispatcher.__init__(self, sock)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000599 self.listen(5)
600
601 def handle_accept(self):
602 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000603 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000604 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
605 self.ConnectionHandler(sock_obj, self.certfile)
606
607 def handle_error(self):
608 raise
609
Trent Nelson78520002008-04-10 20:54:35 +0000610 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000611 self.flag = None
612 self.active = False
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000613 self.server = self.EchoServer(certfile)
614 self.port = self.server.port
Bill Janssen54cc54c2007-12-14 22:08:56 +0000615 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000616 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000617
618 def __str__(self):
619 return "<%s %s>" % (self.__class__.__name__, self.server)
620
621 def start (self, flag=None):
622 self.flag = flag
623 threading.Thread.start(self)
624
625 def run (self):
626 self.active = True
627 if self.flag:
628 self.flag.set()
629 while self.active:
630 try:
631 asyncore.loop(1)
632 except:
633 pass
634
635 def stop (self):
636 self.active = False
637 self.server.close()
638
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000639 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000640 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000641 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000642 cacerts=CERTFILE, chatty=False,
643 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000644 flag = threading.Event()
645 server.start(flag)
646 # wait for it to start
647 flag.wait()
648 # try to connect
649 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000650 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000651 s = ssl.wrap_socket(socket.socket(),
652 certfile=certfile,
653 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000654 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000655 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000656 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000657 sys.stdout.write("\nSSLError is %s\n" % x)
Bill Janssenddc56692008-07-17 18:17:20 +0000658 except socket.error as x:
659 if support.verbose:
660 sys.stdout.write("\nsocket.error is %s\n" % x)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000661 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000662 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000663 "Use of invalid cert should have failed!")
664 finally:
665 server.stop()
666 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000667
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000668 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000669 client_certfile, client_protocol=None,
670 indata="FOO\n",
671 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000672
Trent Nelson78520002008-04-10 20:54:35 +0000673 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000674 certreqs=certreqs,
675 ssl_version=protocol,
676 cacerts=cacertsfile,
677 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000678 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000679 flag = threading.Event()
680 server.start(flag)
681 # wait for it to start
682 flag.wait()
683 # try to connect
684 if client_protocol is None:
685 client_protocol = protocol
686 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000687 s = ssl.wrap_socket(socket.socket(),
Trent Nelson6b240cd2008-04-10 20:12:06 +0000688 server_side=False,
Bill Janssen6e027db2007-11-15 22:23:56 +0000689 certfile=client_certfile,
690 ca_certs=cacertsfile,
691 cert_reqs=certreqs,
692 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000693 s.connect((HOST, server.port))
Bill Janssen6e027db2007-11-15 22:23:56 +0000694 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000695 raise support.TestFailed("Unexpected SSL error: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000696 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000697 raise support.TestFailed("Unexpected exception: " + str(x))
Bill Janssen6e027db2007-11-15 22:23:56 +0000698 else:
699 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000700 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000701 sys.stdout.write(
702 " client: sending %s...\n" % (repr(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000703 s.write(indata.encode('ASCII', 'strict'))
Bill Janssen6e027db2007-11-15 22:23:56 +0000704 outdata = s.read()
705 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000706 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000707 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000708 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000709 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000710 raise support.TestFailed(
Bill Janssen6e027db2007-11-15 22:23:56 +0000711 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000712 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
713 repr(indata[:min(len(indata),20)].lower()), len(indata)))
714 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000715 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000716 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000717 sys.stdout.write(" client: closing connection.\n")
718 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000719 finally:
720 server.stop()
721 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000722
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000723 def tryProtocolCombo (server_protocol,
724 client_protocol,
725 expectedToWork,
726 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000727
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000728 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000729 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000730
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000731 if certsreqs == ssl.CERT_NONE:
732 certtype = "CERT_NONE"
733 elif certsreqs == ssl.CERT_OPTIONAL:
734 certtype = "CERT_OPTIONAL"
735 elif certsreqs == ssl.CERT_REQUIRED:
736 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000737 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000738 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
739 sys.stdout.write(formatstr %
740 (ssl.get_protocol_name(client_protocol),
741 ssl.get_protocol_name(server_protocol),
742 certtype))
743 try:
744 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000745 CERTFILE, CERTFILE, client_protocol,
746 chatty=False, connectionchatty=False)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000747 except support.TestFailed:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000748 if expectedToWork:
749 raise
750 else:
751 if not expectedToWork:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000752 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000753 "Client protocol %s succeeded with server protocol %s!"
754 % (ssl.get_protocol_name(client_protocol),
755 ssl.get_protocol_name(server_protocol)))
756
757
Bill Janssen6e027db2007-11-15 22:23:56 +0000758 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000759
Trent Nelson6b240cd2008-04-10 20:12:06 +0000760 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000761
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000762 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000763 sys.stdout.write("\n")
764 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
765 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
766 chatty=True, connectionchatty=True)
767
768 def testReadCert(self):
769
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000770 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000771 sys.stdout.write("\n")
772 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000773 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000774 certreqs=ssl.CERT_NONE,
775 ssl_version=ssl.PROTOCOL_SSLv23,
776 cacerts=CERTFILE,
777 chatty=False)
778 flag = threading.Event()
779 server.start(flag)
780 # wait for it to start
781 flag.wait()
782 # try to connect
783 try:
784 try:
785 s = ssl.wrap_socket(socket.socket(),
786 certfile=CERTFILE,
787 ca_certs=CERTFILE,
788 cert_reqs=ssl.CERT_REQUIRED,
789 ssl_version=ssl.PROTOCOL_SSLv23)
Trent Nelson78520002008-04-10 20:54:35 +0000790 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000791 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000792 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000793 "Unexpected SSL error: " + str(x))
794 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000795 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000796 "Unexpected exception: " + str(x))
797 else:
798 if not s:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000799 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000800 "Can't SSL-handshake with test server")
801 cert = s.getpeercert()
802 if not cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000803 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000804 "Can't get peer certificate.")
805 cipher = s.cipher()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000806 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000807 sys.stdout.write(pprint.pformat(cert) + '\n')
808 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
Bill Janssen6e027db2007-11-15 22:23:56 +0000809 if 'subject' not in cert:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000810 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000811 "No subject field in certificate: %s." %
812 pprint.pformat(cert))
813 if ((('organizationName', 'Python Software Foundation'),)
814 not in cert['subject']):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000815 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000816 "Missing or invalid 'organizationName' field in certificate subject; "
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000817 "should be 'Python Software Foundation'.")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000818 s.close()
819 finally:
820 server.stop()
821 server.join()
822
823 def testNULLcert(self):
824 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
825 "nullcert.pem"))
826 def testMalformedCert(self):
827 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
828 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000829 def testWrongCert(self):
830 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
831 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000832 def testMalformedKey(self):
833 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
834 "badkey.pem"))
835
Trent Nelson6b240cd2008-04-10 20:12:06 +0000836 def testRudeShutdown(self):
837
838 listener_ready = threading.Event()
839 listener_gone = threading.Event()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000840 s = socket.socket()
841 port = support.bind_port(s, HOST)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000842
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000843 # `listener` runs in a thread. It sits in an accept() until
844 # the main thread connects. Then it rudely closes the socket,
845 # and sets Event `listener_gone` to let the main thread know
846 # the socket is gone.
Trent Nelson6b240cd2008-04-10 20:12:06 +0000847 def listener():
Trent Nelson6b240cd2008-04-10 20:12:06 +0000848 s.listen(5)
849 listener_ready.set()
850 s.accept()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000851 s.close()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000852 listener_gone.set()
853
854 def connector():
855 listener_ready.wait()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000856 c = socket.socket()
857 c.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000858 listener_gone.wait()
859 try:
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000860 ssl_sock = ssl.wrap_socket(c)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000861 except IOError:
862 pass
863 else:
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000864 raise test_support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +0000865 'connecting to closed SSL socket should have failed')
866
867 t = threading.Thread(target=listener)
868 t.start()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000869 try:
870 connector()
871 finally:
872 t.join()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000873
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000874 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000875 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000876 sys.stdout.write("\n")
877 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
878 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
879 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
880 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
881 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
882 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
883
884 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000885 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000886 sys.stdout.write("\n")
887 try:
888 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000889 except support.TestFailed as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000890 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000891 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000892 sys.stdout.write(
893 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
894 % str(x))
895 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
896 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
897 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
898
899 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
900 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
901 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
902
903 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
904 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
905 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
906
907 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000908 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000909 sys.stdout.write("\n")
910 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
911 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
912 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
913 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
914 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
915 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
916
917 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000918 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000919 sys.stdout.write("\n")
920 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
921 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
922 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
923 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
924 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
925 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
926
927 def testSTARTTLS (self):
928
Bill Janssen40a0f662008-08-12 16:56:25 +0000929 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000930
Trent Nelson78520002008-04-10 20:54:35 +0000931 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000932 ssl_version=ssl.PROTOCOL_TLSv1,
933 starttls_server=True,
934 chatty=True,
935 connectionchatty=True)
936 flag = threading.Event()
937 server.start(flag)
938 # wait for it to start
939 flag.wait()
940 # try to connect
941 wrapped = False
942 try:
943 try:
944 s = socket.socket()
945 s.setblocking(1)
Trent Nelson78520002008-04-10 20:54:35 +0000946 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000947 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000948 raise support.TestFailed("Unexpected exception: " + str(x))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000949 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000950 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000951 sys.stdout.write("\n")
952 for indata in msgs:
Bill Janssen6e027db2007-11-15 22:23:56 +0000953 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000954 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000955 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000956 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000957 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000958 conn.write(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000959 outdata = conn.read()
960 else:
Bill Janssen6e027db2007-11-15 22:23:56 +0000961 s.send(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000962 outdata = s.recv(1024)
963 if (indata == "STARTTLS" and
Bill Janssen6e027db2007-11-15 22:23:56 +0000964 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000965 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000966 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000967 sys.stdout.write(
968 " client: read %s from server, starting TLS...\n"
Bill Janssen6e027db2007-11-15 22:23:56 +0000969 % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000970 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000971 wrapped = True
Bill Janssen40a0f662008-08-12 16:56:25 +0000972 elif (indata == "ENDTLS" and
973 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
974 if support.verbose:
975 msg = str(outdata, 'ASCII', 'replace')
976 sys.stdout.write(
977 " client: read %s from server, ending TLS...\n"
978 % repr(msg))
979 s = conn.unwrap()
980 wrapped = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000981 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000982 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000983 msg = str(outdata, 'ASCII', 'replace')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000984 sys.stdout.write(
Bill Janssen6e027db2007-11-15 22:23:56 +0000985 " client: read %s from server\n" % repr(msg))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000986 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000987 sys.stdout.write(" client: closing connection.\n")
988 if wrapped:
Bill Janssen6e027db2007-11-15 22:23:56 +0000989 conn.write("over\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000990 else:
Bill Janssen40a0f662008-08-12 16:56:25 +0000991 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000992 if wrapped:
993 conn.close()
994 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000995 s.close()
996 finally:
997 server.stop()
998 server.join()
999
Bill Janssen54cc54c2007-12-14 22:08:56 +00001000 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +00001001
Trent Nelson78520002008-04-10 20:54:35 +00001002 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001003 flag = threading.Event()
1004 server.start(flag)
1005 # wait for it to start
1006 flag.wait()
1007 # try to connect
1008 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001009 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001010 sys.stdout.write('\n')
1011 d1 = open(CERTFILE, 'rb').read()
1012 d2 = ''
1013 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +00001014 url = 'https://%s:%d/%s' % (
1015 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001016 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +00001017 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001018 if dlen and (int(dlen) > 0):
1019 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001020 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001021 sys.stdout.write(
1022 " client: read %d bytes from remote server '%s'\n"
1023 % (len(d2), server))
1024 f.close()
1025 except:
1026 msg = ''.join(traceback.format_exception(*sys.exc_info()))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001027 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001028 sys.stdout.write('\n' + msg)
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001029 raise support.TestFailed(msg)
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001030 else:
1031 if not (d1 == d2):
Bill Janssen6e027db2007-11-15 22:23:56 +00001032 print("d1 is", len(d1), repr(d1))
1033 print("d2 is", len(d2), repr(d2))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001034 raise support.TestFailed(
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001035 "Couldn't fetch data from HTTPS server")
1036 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001037 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001038 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001039 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001040 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +00001041 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001042 server.join()
1043
Trent Nelson6b240cd2008-04-10 20:12:06 +00001044 def testAsyncoreServer(self):
1045
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001046 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001047 sys.stdout.write("\n")
1048
1049 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001050 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001051 flag = threading.Event()
1052 server.start(flag)
1053 # wait for it to start
1054 flag.wait()
1055 # try to connect
1056 try:
1057 s = ssl.wrap_socket(socket.socket())
Trent Nelson78520002008-04-10 20:54:35 +00001058 s.connect((HOST, server.port))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001059 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001060 raise support.TestFailed("Unexpected SSL error: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001061 except Exception as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001062 raise support.TestFailed("Unexpected exception: " + str(x))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001063 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001064 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001065 sys.stdout.write(
1066 " client: sending %s...\n" % (repr(indata)))
1067 s.sendall(indata.encode('ASCII', 'strict'))
1068 outdata = s.recv()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001069 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001070 sys.stdout.write(" client: read %s\n" % repr(outdata))
1071 outdata = str(outdata, 'ASCII', 'strict')
1072 if outdata != indata.lower():
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001073 raise support.TestFailed(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001074 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
1075 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
1076 repr(indata[:min(len(indata),20)].lower()), len(indata)))
1077 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001078 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001079 sys.stdout.write(" client: closing connection.\n")
1080 s.close()
1081 finally:
1082 server.stop()
1083 server.join()
1084
Bill Janssen58afe4c2008-09-08 16:45:19 +00001085 def testAllRecvAndSendMethods(self):
1086
1087 if support.verbose:
1088 sys.stdout.write("\n")
1089
1090 server = ThreadedEchoServer(CERTFILE,
1091 certreqs=ssl.CERT_NONE,
1092 ssl_version=ssl.PROTOCOL_TLSv1,
1093 cacerts=CERTFILE,
1094 chatty=True,
1095 connectionchatty=False)
1096 flag = threading.Event()
1097 server.start(flag)
1098 # wait for it to start
1099 flag.wait()
1100 # try to connect
1101 try:
1102 s = ssl.wrap_socket(socket.socket(),
1103 server_side=False,
1104 certfile=CERTFILE,
1105 ca_certs=CERTFILE,
1106 cert_reqs=ssl.CERT_NONE,
1107 ssl_version=ssl.PROTOCOL_TLSv1)
1108 s.connect((HOST, server.port))
1109 except ssl.SSLError as x:
1110 raise support.TestFailed("Unexpected SSL error: " + str(x))
1111 except Exception as x:
1112 raise support.TestFailed("Unexpected exception: " + str(x))
1113 else:
1114 # helper methods for standardising recv* method signatures
1115 def _recv_into():
1116 b = bytearray(b"\0"*100)
1117 count = s.recv_into(b)
1118 return b[:count]
1119
1120 def _recvfrom_into():
1121 b = bytearray(b"\0"*100)
1122 count, addr = s.recvfrom_into(b)
1123 return b[:count]
1124
1125 # (name, method, whether to expect success, *args)
1126 send_methods = [
1127 ('send', s.send, True, []),
1128 ('sendto', s.sendto, False, ["some.address"]),
1129 ('sendall', s.sendall, True, []),
1130 ]
1131 recv_methods = [
1132 ('recv', s.recv, True, []),
1133 ('recvfrom', s.recvfrom, False, ["some.address"]),
1134 ('recv_into', _recv_into, True, []),
1135 ('recvfrom_into', _recvfrom_into, False, []),
1136 ]
1137 data_prefix = "PREFIX_"
1138
1139 for meth_name, send_meth, expect_success, args in send_methods:
1140 indata = data_prefix + meth_name
1141 try:
1142 send_meth(indata.encode('ASCII', 'strict'), *args)
1143 outdata = s.read()
1144 outdata = str(outdata, 'ASCII', 'strict')
1145 if outdata != indata.lower():
1146 raise support.TestFailed(
1147 "While sending with <<{name:s}>> bad data "
1148 "<<{outdata:s}>> ({nout:d}) received; "
1149 "expected <<{indata:s}>> ({nin:d})\n".format(
1150 name=meth_name, outdata=repr(outdata[:20]),
1151 nout=len(outdata),
1152 indata=repr(indata[:20]), nin=len(indata)
1153 )
1154 )
1155 except ValueError as e:
1156 if expect_success:
1157 raise support.TestFailed(
1158 "Failed to send with method <<{name:s}>>; "
1159 "expected to succeed.\n".format(name=meth_name)
1160 )
1161 if not str(e).startswith(meth_name):
1162 raise support.TestFailed(
1163 "Method <<{name:s}>> failed with unexpected "
1164 "exception message: {exp:s}\n".format(
1165 name=meth_name, exp=e
1166 )
1167 )
1168
1169 for meth_name, recv_meth, expect_success, args in recv_methods:
1170 indata = data_prefix + meth_name
1171 try:
1172 s.send(indata.encode('ASCII', 'strict'))
1173 outdata = recv_meth(*args)
1174 outdata = str(outdata, 'ASCII', 'strict')
1175 if outdata != indata.lower():
1176 raise support.TestFailed(
1177 "While receiving with <<{name:s}>> bad data "
1178 "<<{outdata:s}>> ({nout:d}) received; "
1179 "expected <<{indata:s}>> ({nin:d})\n".format(
1180 name=meth_name, outdata=repr(outdata[:20]),
1181 nout=len(outdata),
1182 indata=repr(indata[:20]), nin=len(indata)
1183 )
1184 )
1185 except ValueError as e:
1186 if expect_success:
1187 raise support.TestFailed(
1188 "Failed to receive with method <<{name:s}>>; "
1189 "expected to succeed.\n".format(name=meth_name)
1190 )
1191 if not str(e).startswith(meth_name):
1192 raise support.TestFailed(
1193 "Method <<{name:s}>> failed with unexpected "
1194 "exception message: {exp:s}\n".format(
1195 name=meth_name, exp=e
1196 )
1197 )
1198 # consume data
1199 s.read()
1200
1201 s.write("over\n".encode("ASCII", "strict"))
1202 s.close()
1203 finally:
1204 server.stop()
1205 server.join()
1206
Antoine Pitrouec146182010-04-24 21:30:20 +00001207 def test_handshake_timeout(self):
1208 # Issue #5103: SSL handshake must respect the socket timeout
1209 server = socket.socket(socket.AF_INET)
1210 host = "127.0.0.1"
1211 port = support.bind_port(server)
1212 started = threading.Event()
1213 finish = False
1214
1215 def serve():
1216 server.listen(5)
1217 started.set()
1218 conns = []
1219 while not finish:
1220 r, w, e = select.select([server], [], [], 0.1)
1221 if server in r:
1222 # Let the socket hang around rather than having
1223 # it closed by garbage collection.
1224 conns.append(server.accept()[0])
1225
1226 t = threading.Thread(target=serve)
1227 t.start()
1228 started.wait()
1229
1230 try:
Antoine Pitrouc2203f92010-04-24 22:07:51 +00001231 try:
1232 c = socket.socket(socket.AF_INET)
1233 c.settimeout(0.2)
1234 c.connect((host, port))
1235 # Will attempt handshake and time out
1236 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1237 ssl.wrap_socket, c)
1238 finally:
1239 c.close()
Antoine Pitrouec146182010-04-24 21:30:20 +00001240 try:
1241 c = socket.socket(socket.AF_INET)
1242 c = ssl.wrap_socket(c)
1243 c.settimeout(0.2)
1244 # Will attempt handshake and time out
1245 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1246 c.connect, (host, port))
1247 finally:
1248 c.close()
1249 finally:
1250 finish = True
1251 t.join()
1252 server.close()
1253
Bill Janssen58afe4c2008-09-08 16:45:19 +00001254
Thomas Woutersed03b412007-08-28 21:37:11 +00001255def test_main(verbose=False):
1256 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001257 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001258
Trent Nelson78520002008-04-10 20:54:35 +00001259 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001260 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1261 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001262 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1263 os.path.dirname(__file__) or os.curdir,
1264 "https_svn_python_org_root.pem")
1265
1266 if (not os.path.exists(CERTFILE) or
1267 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001268 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001269
Thomas Woutersed03b412007-08-28 21:37:11 +00001270 tests = [BasicTests]
1271
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001272 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001273 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001274
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001275 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001276 thread_info = support.threading_setup()
1277 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001278 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001279
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001280 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001281
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001282 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001283 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001284
1285if __name__ == "__main__":
1286 test_main()