blob: fdde562eadeadd7bf3256b756c56984e151881d1 [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:
Antoine Pitrou66ffb262010-04-27 11:05:15 +000050 self.fail("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)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000100 self.assertEqual(d1, d2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000101
Antoine Pitrou78f4a9a2010-04-23 23:12:22 +0000102 @support.cpython_only
103 def test_refcycle(self):
104 # Issue #7943: an SSL object doesn't create reference cycles with
105 # itself.
106 s = socket.socket(socket.AF_INET)
107 ss = ssl.wrap_socket(s)
108 wr = weakref.ref(ss)
109 del ss
110 self.assertEqual(wr(), None)
111
Antoine Pitrouc2203f92010-04-24 22:07:51 +0000112 def test_timeout(self):
113 # Issue #8524: when creating an SSL socket, the timeout of the
114 # original socket should be retained.
115 for timeout in (None, 0.0, 5.0):
116 s = socket.socket(socket.AF_INET)
117 s.settimeout(timeout)
118 ss = ssl.wrap_socket(s)
119 self.assertEqual(timeout, ss.gettimeout())
120
Antoine Pitrou3b9b9ba2010-04-23 23:33:50 +0000121
Bill Janssen6e027db2007-11-15 22:23:56 +0000122class NetworkedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000123
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000124 def testConnect(self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000125 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
126 cert_reqs=ssl.CERT_NONE)
127 s.connect(("svn.python.org", 443))
128 c = s.getpeercert()
129 if c:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000130 self.fail("Peer cert %s shouldn't be here!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000131 s.close()
132
133 # this should fail because we have no verification certs
134 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
135 cert_reqs=ssl.CERT_REQUIRED)
Thomas Woutersed03b412007-08-28 21:37:11 +0000136 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000137 s.connect(("svn.python.org", 443))
138 except ssl.SSLError:
139 pass
140 finally:
141 s.close()
142
143 # this should succeed because we specify the root cert
144 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
145 cert_reqs=ssl.CERT_REQUIRED,
146 ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
147 try:
148 s.connect(("svn.python.org", 443))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000149 finally:
150 s.close()
151
Antoine Pitroufe0f1172010-04-24 11:17:37 +0000152 @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
153 def test_makefile_close(self):
154 # Issue #5238: creating a file-like object with makefile() shouldn't
155 # delay closing the underlying "real socket" (here tested with its
156 # file descriptor, hence skipping the test under Windows).
157 ss = ssl.wrap_socket(socket.socket(socket.AF_INET))
158 ss.connect(("svn.python.org", 443))
159 fd = ss.fileno()
160 f = ss.makefile()
161 f.close()
162 # The fd is still open
163 os.read(fd, 0)
164 # Closing the SSL socket should close the fd too
165 ss.close()
166 gc.collect()
167 try:
168 os.read(fd, 0)
169 except OSError as e:
170 self.assertEqual(e.errno, errno.EBADF)
171 else:
172 self.fail("OSError wasn't raised")
173
Bill Janssen6e027db2007-11-15 22:23:56 +0000174 def testNonBlockingHandshake(self):
175 s = socket.socket(socket.AF_INET)
176 s.connect(("svn.python.org", 443))
177 s.setblocking(False)
178 s = ssl.wrap_socket(s,
179 cert_reqs=ssl.CERT_NONE,
180 do_handshake_on_connect=False)
181 count = 0
182 while True:
183 try:
184 count += 1
185 s.do_handshake()
186 break
187 except ssl.SSLError as err:
188 if err.args[0] == ssl.SSL_ERROR_WANT_READ:
189 select.select([s], [], [])
190 elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
191 select.select([], [s], [])
192 else:
193 raise
194 s.close()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000195 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000196 sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000197
Bill Janssen54cc54c2007-12-14 22:08:56 +0000198 def testFetchServerCert(self):
199
200 pem = ssl.get_server_certificate(("svn.python.org", 443))
201 if not pem:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000202 self.fail("No server certificate on svn.python.org:443!")
Bill Janssen54cc54c2007-12-14 22:08:56 +0000203
204 return
205
206 try:
207 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
208 except ssl.SSLError as x:
209 #should fail
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000210 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000211 sys.stdout.write("%s\n" % x)
212 else:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000213 self.fail("Got server certificate %s for svn.python.org!" % pem)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000214
215 pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
216 if not pem:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000217 self.fail("No server certificate on svn.python.org:443!")
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000218 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000219 sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
220
Antoine Pitrou754b98c2010-04-22 18:47:06 +0000221 # Test disabled: OPENSSL_VERSION* not available in Python 3.1
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000222 def test_algorithms(self):
Antoine Pitrouae92a722010-04-22 18:46:16 +0000223 if support.verbose:
224 sys.stdout.write("test_algorithms disabled, "
225 "as it fails on some old OpenSSL versions")
226 return
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000227 # Issue #8484: all algorithms should be available when verifying a
228 # certificate.
Antoine Pitrouae92a722010-04-22 18:46:16 +0000229 # SHA256 was added in OpenSSL 0.9.8
230 if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
231 self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
Antoine Pitrouda6902c2010-04-21 19:52:52 +0000232 # NOTE: https://sha256.tbs-internet.com is another possible test host
233 remote = ("sha2.hboeck.de", 443)
234 sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
235 s = ssl.wrap_socket(socket.socket(socket.AF_INET),
236 cert_reqs=ssl.CERT_REQUIRED,
237 ca_certs=sha256_cert,)
238 with support.transient_internet():
239 try:
240 s.connect(remote)
241 if support.verbose:
242 sys.stdout.write("\nCipher with %r is %r\n" %
243 (remote, s.cipher()))
244 sys.stdout.write("Certificate is:\n%s\n" %
245 pprint.pformat(s.getpeercert()))
246 finally:
247 s.close()
248
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000249
250try:
251 import threading
252except ImportError:
253 _have_threads = False
254else:
255
256 _have_threads = True
257
258 class ThreadedEchoServer(threading.Thread):
259
260 class ConnectionHandler(threading.Thread):
261
262 """A mildly complicated class, because we want it to work both
263 with and without the SSL wrapper around the socket connection, so
264 that we can test the STARTTLS functionality."""
265
Bill Janssen6e027db2007-11-15 22:23:56 +0000266 def __init__(self, server, connsock, addr):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000267 self.server = server
268 self.running = False
269 self.sock = connsock
Bill Janssen6e027db2007-11-15 22:23:56 +0000270 self.addr = addr
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000271 self.sock.setblocking(1)
272 self.sslconn = None
273 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000274 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000275
276 def wrap_conn (self):
277 try:
278 self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
279 certfile=self.server.certificate,
280 ssl_version=self.server.protocol,
281 ca_certs=self.server.cacerts,
282 cert_reqs=self.server.certreqs)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000283 except ssl.SSLError:
284 # XXX Various errors can have happened here, for example
285 # a mismatching protocol version, an invalid certificate,
286 # or a low-level bug. This should be made more discriminating.
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000287 if self.server.chatty:
Bill Janssen6e027db2007-11-15 22:23:56 +0000288 handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n")
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000289 self.running = False
290 self.server.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000291 self.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000292 return False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000293 else:
294 if self.server.certreqs == ssl.CERT_REQUIRED:
295 cert = self.sslconn.getpeercert()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000296 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000297 sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
298 cert_binary = self.sslconn.getpeercert(True)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000299 if support.verbose and self.server.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000300 sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
301 cipher = self.sslconn.cipher()
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(" server: connection cipher is now " + str(cipher) + "\n")
304 return True
305
306 def read(self):
307 if self.sslconn:
308 return self.sslconn.read()
309 else:
310 return self.sock.recv(1024)
311
312 def write(self, bytes):
313 if self.sslconn:
314 return self.sslconn.write(bytes)
315 else:
316 return self.sock.send(bytes)
317
318 def close(self):
319 if self.sslconn:
320 self.sslconn.close()
321 else:
322 self.sock.close()
323
324 def run (self):
325 self.running = True
326 if not self.server.starttls_server:
327 if not self.wrap_conn():
328 return
329 while self.running:
330 try:
331 msg = self.read()
Bill Janssen6e027db2007-11-15 22:23:56 +0000332 amsg = (msg and str(msg, 'ASCII', 'strict')) or ''
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000333 if not msg:
334 # eof, so quit this handler
335 self.running = False
336 self.close()
Bill Janssen6e027db2007-11-15 22:23:56 +0000337 elif amsg.strip() == 'over':
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000338 if support.verbose and self.server.connectionchatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000339 sys.stdout.write(" server: client closed connection\n")
340 self.close()
341 return
Bill Janssen6e027db2007-11-15 22:23:56 +0000342 elif (self.server.starttls_server and
343 amsg.strip() == 'STARTTLS'):
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: read STARTTLS from client, sending OK...\n")
Bill Janssen6e027db2007-11-15 22:23:56 +0000346 self.write("OK\n".encode("ASCII", "strict"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000347 if not self.wrap_conn():
348 return
Bill Janssen40a0f662008-08-12 16:56:25 +0000349 elif (self.server.starttls_server and self.sslconn
350 and amsg.strip() == 'ENDTLS'):
351 if support.verbose and self.server.connectionchatty:
352 sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
353 self.write("OK\n".encode("ASCII", "strict"))
354 self.sock = self.sslconn.unwrap()
355 self.sslconn = None
356 if support.verbose and self.server.connectionchatty:
357 sys.stdout.write(" server: connection is now unencrypted...\n")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000358 else:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000359 if (support.verbose and
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000360 self.server.connectionchatty):
361 ctype = (self.sslconn and "encrypted") or "unencrypted"
362 sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
363 % (repr(msg), ctype, repr(msg.lower()), ctype))
Bill Janssen6e027db2007-11-15 22:23:56 +0000364 self.write(amsg.lower().encode('ASCII', 'strict'))
365 except socket.error:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000366 if self.server.chatty:
367 handle_error("Test server failure:\n")
368 self.close()
369 self.running = False
370 # normally, we'd just stop here, but for the test
371 # harness, we want to stop the server
372 self.server.stop()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000373
Trent Nelson78520002008-04-10 20:54:35 +0000374 def __init__(self, certificate, ssl_version=None,
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000375 certreqs=None, cacerts=None,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000376 chatty=True, connectionchatty=False, starttls_server=False):
377 if ssl_version is None:
378 ssl_version = ssl.PROTOCOL_TLSv1
379 if certreqs is None:
380 certreqs = ssl.CERT_NONE
381 self.certificate = certificate
382 self.protocol = ssl_version
383 self.certreqs = certreqs
384 self.cacerts = cacerts
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000385 self.chatty = chatty
386 self.connectionchatty = connectionchatty
387 self.starttls_server = starttls_server
388 self.sock = socket.socket()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000389 self.port = support.bind_port(self.sock)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000390 self.flag = None
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000391 self.active = False
392 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000393 self.daemon = True
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000394
395 def start (self, flag=None):
396 self.flag = flag
397 threading.Thread.start(self)
398
399 def run (self):
Antoine Pitroube168132010-04-27 10:41:37 +0000400 self.sock.settimeout(0.05)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000401 self.sock.listen(5)
402 self.active = True
403 if self.flag:
404 # signal an event
405 self.flag.set()
406 while self.active:
407 try:
408 newconn, connaddr = self.sock.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000409 if support.verbose and self.chatty:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000410 sys.stdout.write(' server: new connection from '
Bill Janssen6e027db2007-11-15 22:23:56 +0000411 + repr(connaddr) + '\n')
412 handler = self.ConnectionHandler(self, newconn, connaddr)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000413 handler.start()
414 except socket.timeout:
415 pass
416 except KeyboardInterrupt:
417 self.stop()
Bill Janssen6e027db2007-11-15 22:23:56 +0000418 self.sock.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000419
420 def stop (self):
421 self.active = False
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000422
Bill Janssen54cc54c2007-12-14 22:08:56 +0000423 class OurHTTPSServer(threading.Thread):
424
425 # This one's based on HTTPServer, which is based on SocketServer
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000426
427 class HTTPSServer(HTTPServer):
428
429 def __init__(self, server_address, RequestHandlerClass, certfile):
430
431 HTTPServer.__init__(self, server_address, RequestHandlerClass)
432 # we assume the certfile contains both private key and certificate
433 self.certfile = certfile
434 self.active = False
Christian Heimesdd15f6c2008-03-16 00:07:10 +0000435 self.active_lock = threading.Lock()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000436 self.allow_reuse_address = True
437
Bill Janssen6e027db2007-11-15 22:23:56 +0000438 def __str__(self):
439 return ('<%s %s:%s>' %
440 (self.__class__.__name__,
441 self.server_name,
442 self.server_port))
443
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000444 def get_request (self):
445 # override this to wrap socket with SSL
446 sock, addr = self.socket.accept()
447 sslconn = ssl.wrap_socket(sock, server_side=True,
448 certfile=self.certfile)
449 return sslconn, addr
450
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000451 class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
452
453 # need to override translate_path to get a known root,
454 # instead of using os.curdir, since the test could be
455 # run from anywhere
456
457 server_version = "TestHTTPS/1.0"
458
459 root = None
460
461 def translate_path(self, path):
462 """Translate a /-separated PATH to the local filename syntax.
463
464 Components that mean special things to the local file system
465 (e.g. drive or directory names) are ignored. (XXX They should
466 probably be diagnosed.)
467
468 """
469 # abandon query parameters
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000470 path = urllib.parse.urlparse(path)[2]
471 path = os.path.normpath(urllib.parse.unquote(path))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000472 words = path.split('/')
473 words = filter(None, words)
474 path = self.root
475 for word in words:
476 drive, word = os.path.splitdrive(word)
477 head, word = os.path.split(word)
478 if word in self.root: continue
479 path = os.path.join(path, word)
480 return path
481
482 def log_message(self, format, *args):
483
484 # we override this to suppress logging unless "verbose"
485
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000486 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000487 sys.stdout.write(" server (%s:%d %s):\n [%s] %s\n" %
488 (self.server.server_address,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000489 self.server.server_port,
490 self.request.cipher(),
491 self.log_date_time_string(),
492 format%args))
Thomas Woutersed03b412007-08-28 21:37:11 +0000493
494
Trent Nelson78520002008-04-10 20:54:35 +0000495 def __init__(self, certfile):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000496 self.flag = None
497 self.active = False
498 self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
499 self.server = self.HTTPSServer(
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000500 (HOST, 0), self.RootedHTTPRequestHandler, certfile)
501 self.port = self.server.server_port
Thomas Woutersed03b412007-08-28 21:37:11 +0000502 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000503 self.daemon = True
Thomas Woutersed03b412007-08-28 21:37:11 +0000504
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000505 def __str__(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000506 return "<%s %s>" % (self.__class__.__name__, self.server)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000507
508 def start (self, flag=None):
509 self.flag = flag
510 threading.Thread.start(self)
511
Thomas Woutersed03b412007-08-28 21:37:11 +0000512 def run (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000513 self.active = True
514 if self.flag:
515 self.flag.set()
Antoine Pitroube168132010-04-27 10:41:37 +0000516 self.server.serve_forever(0.05)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000517 self.active = False
518
519 def stop (self):
520 self.active = False
Antoine Pitroube168132010-04-27 10:41:37 +0000521 self.server.shutdown()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000522
523
Bill Janssen54cc54c2007-12-14 22:08:56 +0000524 class AsyncoreEchoServer(threading.Thread):
525
526 # this one's based on asyncore.dispatcher
527
528 class EchoServer (asyncore.dispatcher):
529
530 class ConnectionHandler (asyncore.dispatcher_with_send):
531
532 def __init__(self, conn, certfile):
533 self.socket = ssl.wrap_socket(conn, server_side=True,
534 certfile=certfile,
535 do_handshake_on_connect=False)
536 asyncore.dispatcher_with_send.__init__(self, self.socket)
Antoine Pitrouec146182010-04-24 21:30:20 +0000537 self._ssl_accepting = True
538 self._do_ssl_handshake()
Bill Janssen54cc54c2007-12-14 22:08:56 +0000539
540 def readable(self):
541 if isinstance(self.socket, ssl.SSLSocket):
542 while self.socket.pending() > 0:
543 self.handle_read_event()
544 return True
545
Antoine Pitrouec146182010-04-24 21:30:20 +0000546 def _do_ssl_handshake(self):
547 try:
548 self.socket.do_handshake()
549 except ssl.SSLError as err:
550 if err.args[0] in (ssl.SSL_ERROR_WANT_READ,
551 ssl.SSL_ERROR_WANT_WRITE):
552 return
553 elif err.args[0] == ssl.SSL_ERROR_EOF:
554 return self.handle_close()
555 raise
556 except socket.error as err:
557 if err.args[0] == errno.ECONNABORTED:
558 return self.handle_close()
Bill Janssen54cc54c2007-12-14 22:08:56 +0000559 else:
Antoine Pitrouec146182010-04-24 21:30:20 +0000560 self._ssl_accepting = False
561
562 def handle_read(self):
563 if self._ssl_accepting:
564 self._do_ssl_handshake()
565 else:
566 data = self.recv(1024)
567 if support.verbose:
568 sys.stdout.write(" server: read %s from client\n" % repr(data))
569 if not data:
570 self.close()
571 else:
572 self.send(str(data, 'ASCII', 'strict').lower().encode('ASCII', 'strict'))
Bill Janssen54cc54c2007-12-14 22:08:56 +0000573
574 def handle_close(self):
Bill Janssen2f5799b2008-06-29 00:08:12 +0000575 self.close()
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000576 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000577 sys.stdout.write(" server: closed connection %s\n" % self.socket)
578
579 def handle_error(self):
580 raise
581
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000582 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000583 self.certfile = certfile
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000584 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
585 self.port = support.bind_port(sock, '')
586 asyncore.dispatcher.__init__(self, sock)
Bill Janssen54cc54c2007-12-14 22:08:56 +0000587 self.listen(5)
588
589 def handle_accept(self):
590 sock_obj, addr = self.accept()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000591 if support.verbose:
Bill Janssen54cc54c2007-12-14 22:08:56 +0000592 sys.stdout.write(" server: new connection from %s:%s\n" %addr)
593 self.ConnectionHandler(sock_obj, self.certfile)
594
595 def handle_error(self):
596 raise
597
Trent Nelson78520002008-04-10 20:54:35 +0000598 def __init__(self, certfile):
Bill Janssen54cc54c2007-12-14 22:08:56 +0000599 self.flag = None
600 self.active = False
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000601 self.server = self.EchoServer(certfile)
602 self.port = self.server.port
Bill Janssen54cc54c2007-12-14 22:08:56 +0000603 threading.Thread.__init__(self)
Benjamin Peterson4171da52008-08-18 21:11:09 +0000604 self.daemon = True
Bill Janssen54cc54c2007-12-14 22:08:56 +0000605
606 def __str__(self):
607 return "<%s %s>" % (self.__class__.__name__, self.server)
608
609 def start (self, flag=None):
610 self.flag = flag
611 threading.Thread.start(self)
612
613 def run (self):
614 self.active = True
615 if self.flag:
616 self.flag.set()
617 while self.active:
618 try:
619 asyncore.loop(1)
620 except:
621 pass
622
623 def stop (self):
624 self.active = False
625 self.server.close()
626
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000627 def badCertTest (certfile):
Trent Nelson78520002008-04-10 20:54:35 +0000628 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000629 certreqs=ssl.CERT_REQUIRED,
Bill Janssen6e027db2007-11-15 22:23:56 +0000630 cacerts=CERTFILE, chatty=False,
631 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000632 flag = threading.Event()
633 server.start(flag)
634 # wait for it to start
635 flag.wait()
636 # try to connect
637 try:
Thomas Woutersed03b412007-08-28 21:37:11 +0000638 try:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000639 s = ssl.wrap_socket(socket.socket(),
640 certfile=certfile,
641 ssl_version=ssl.PROTOCOL_TLSv1)
Trent Nelson78520002008-04-10 20:54:35 +0000642 s.connect((HOST, server.port))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000643 except ssl.SSLError as x:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000644 if support.verbose:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000645 sys.stdout.write("\nSSLError is %s\n" % x.args[1])
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000646 else:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000647 self.fail("Use of invalid cert should have failed!")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000648 finally:
649 server.stop()
650 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000651
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000652 def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
Bill Janssen6e027db2007-11-15 22:23:56 +0000653 client_certfile, client_protocol=None,
654 indata="FOO\n",
655 chatty=False, connectionchatty=False):
Thomas Woutersed03b412007-08-28 21:37:11 +0000656
Trent Nelson78520002008-04-10 20:54:35 +0000657 server = ThreadedEchoServer(certfile,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000658 certreqs=certreqs,
659 ssl_version=protocol,
660 cacerts=cacertsfile,
661 chatty=chatty,
Bill Janssen6e027db2007-11-15 22:23:56 +0000662 connectionchatty=False)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000663 flag = threading.Event()
664 server.start(flag)
665 # wait for it to start
666 flag.wait()
667 # try to connect
668 if client_protocol is None:
669 client_protocol = protocol
670 try:
Bill Janssen6e027db2007-11-15 22:23:56 +0000671 s = ssl.wrap_socket(socket.socket(),
672 certfile=client_certfile,
673 ca_certs=cacertsfile,
674 cert_reqs=certreqs,
675 ssl_version=client_protocol)
Trent Nelson78520002008-04-10 20:54:35 +0000676 s.connect((HOST, server.port))
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000677 arg = indata.encode('ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000678 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000679 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000680 sys.stdout.write(
681 " client: sending %s...\n" % (repr(indata)))
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000682 s.write(arg)
Bill Janssen6e027db2007-11-15 22:23:56 +0000683 outdata = s.read()
684 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000685 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000686 sys.stdout.write(" client: read %s\n" % repr(outdata))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000687 outdata = str(outdata, 'ASCII', 'strict')
Bill Janssen6e027db2007-11-15 22:23:56 +0000688 if outdata != indata.lower():
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000689 self.fail(
Bill Janssen6e027db2007-11-15 22:23:56 +0000690 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Trent Nelson6b240cd2008-04-10 20:12:06 +0000691 % (repr(outdata[:min(len(outdata),20)]), len(outdata),
692 repr(indata[:min(len(indata),20)].lower()), len(indata)))
693 s.write("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000694 if connectionchatty:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000695 if support.verbose:
Bill Janssen6e027db2007-11-15 22:23:56 +0000696 sys.stdout.write(" client: closing connection.\n")
697 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000698 finally:
699 server.stop()
700 server.join()
Thomas Woutersed03b412007-08-28 21:37:11 +0000701
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000702 def tryProtocolCombo (server_protocol,
703 client_protocol,
704 expectedToWork,
705 certsreqs=None):
Thomas Woutersed03b412007-08-28 21:37:11 +0000706
Benjamin Peterson2a691a82008-03-31 01:51:45 +0000707 if certsreqs is None:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000708 certsreqs = ssl.CERT_NONE
Thomas Woutersed03b412007-08-28 21:37:11 +0000709
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000710 if certsreqs == ssl.CERT_NONE:
711 certtype = "CERT_NONE"
712 elif certsreqs == ssl.CERT_OPTIONAL:
713 certtype = "CERT_OPTIONAL"
714 elif certsreqs == ssl.CERT_REQUIRED:
715 certtype = "CERT_REQUIRED"
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000716 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000717 formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
718 sys.stdout.write(formatstr %
719 (ssl.get_protocol_name(client_protocol),
720 ssl.get_protocol_name(server_protocol),
721 certtype))
722 try:
723 serverParamsTest(CERTFILE, server_protocol, certsreqs,
Bill Janssen6e027db2007-11-15 22:23:56 +0000724 CERTFILE, CERTFILE, client_protocol,
725 chatty=False, connectionchatty=False)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000726 # Protocol mismatch can result in either an SSLError, or a
727 # "Connection reset by peer" error.
728 except ssl.SSLError:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000729 if expectedToWork:
730 raise
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000731 except socket.error as e:
732 if expectedToWork or e.errno != errno.ECONNRESET:
733 raise
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000734 else:
735 if not expectedToWork:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000736 self.fail(
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000737 "Client protocol %s succeeded with server protocol %s!"
738 % (ssl.get_protocol_name(client_protocol),
739 ssl.get_protocol_name(server_protocol)))
740
741
Bill Janssen6e027db2007-11-15 22:23:56 +0000742 class ThreadedTests(unittest.TestCase):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000743
Trent Nelson6b240cd2008-04-10 20:12:06 +0000744 def testEcho (self):
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000745
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000746 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000747 sys.stdout.write("\n")
748 serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
749 CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
750 chatty=True, connectionchatty=True)
751
752 def testReadCert(self):
753
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000754 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000755 sys.stdout.write("\n")
756 s2 = socket.socket()
Trent Nelson78520002008-04-10 20:54:35 +0000757 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000758 certreqs=ssl.CERT_NONE,
759 ssl_version=ssl.PROTOCOL_SSLv23,
760 cacerts=CERTFILE,
761 chatty=False)
762 flag = threading.Event()
763 server.start(flag)
764 # wait for it to start
765 flag.wait()
766 # try to connect
767 try:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000768 s = ssl.wrap_socket(socket.socket(),
769 certfile=CERTFILE,
770 ca_certs=CERTFILE,
771 cert_reqs=ssl.CERT_REQUIRED,
772 ssl_version=ssl.PROTOCOL_SSLv23)
773 s.connect((HOST, server.port))
774 cert = s.getpeercert()
775 self.assertTrue(cert, "Can't get peer certificate.")
776 cipher = s.cipher()
777 if support.verbose:
778 sys.stdout.write(pprint.pformat(cert) + '\n')
779 sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
780 if 'subject' not in cert:
781 self.fail("No subject field in certificate: %s." %
782 pprint.pformat(cert))
783 if ((('organizationName', 'Python Software Foundation'),)
784 not in cert['subject']):
785 self.fail(
786 "Missing or invalid 'organizationName' field in certificate subject; "
787 "should be 'Python Software Foundation'.")
788 s.close()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000789 finally:
790 server.stop()
791 server.join()
792
793 def testNULLcert(self):
794 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
795 "nullcert.pem"))
796 def testMalformedCert(self):
797 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
798 "badcert.pem"))
Bill Janssen58afe4c2008-09-08 16:45:19 +0000799 def testWrongCert(self):
800 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
801 "wrongcert.pem"))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000802 def testMalformedKey(self):
803 badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
804 "badkey.pem"))
805
Trent Nelson6b240cd2008-04-10 20:12:06 +0000806 def testRudeShutdown(self):
807
808 listener_ready = threading.Event()
809 listener_gone = threading.Event()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000810 s = socket.socket()
811 port = support.bind_port(s, HOST)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000812
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000813 # `listener` runs in a thread. It sits in an accept() until
814 # the main thread connects. Then it rudely closes the socket,
815 # and sets Event `listener_gone` to let the main thread know
816 # the socket is gone.
Trent Nelson6b240cd2008-04-10 20:12:06 +0000817 def listener():
Trent Nelson6b240cd2008-04-10 20:12:06 +0000818 s.listen(5)
819 listener_ready.set()
820 s.accept()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000821 s.close()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000822 listener_gone.set()
823
824 def connector():
825 listener_ready.wait()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000826 c = socket.socket()
827 c.connect((HOST, port))
Trent Nelson6b240cd2008-04-10 20:12:06 +0000828 listener_gone.wait()
829 try:
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000830 ssl_sock = ssl.wrap_socket(c)
Trent Nelson6b240cd2008-04-10 20:12:06 +0000831 except IOError:
832 pass
833 else:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000834 self.fail('connecting to closed SSL socket should have failed')
Trent Nelson6b240cd2008-04-10 20:12:06 +0000835
836 t = threading.Thread(target=listener)
837 t.start()
Antoine Pitrou0fb2e542010-04-27 08:58:38 +0000838 try:
839 connector()
840 finally:
841 t.join()
Trent Nelson6b240cd2008-04-10 20:12:06 +0000842
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000843 def testProtocolSSL2(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000844 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000845 sys.stdout.write("\n")
846 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
847 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
848 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
849 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
850 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
851 tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
852
853 def testProtocolSSL23(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000854 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000855 sys.stdout.write("\n")
856 try:
857 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000858 except (ssl.SSLError, socket.error) as x:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000859 # this fails on some older versions of OpenSSL (0.9.7l, for instance)
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000860 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000861 sys.stdout.write(
862 " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
863 % str(x))
864 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
865 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
866 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
867
868 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
869 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
870 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
871
872 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
873 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
874 tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
875
876 def testProtocolSSL3(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000877 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000878 sys.stdout.write("\n")
879 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
880 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
881 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
882 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
883 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
884 tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
885
886 def testProtocolTLS1(self):
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000887 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000888 sys.stdout.write("\n")
889 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
890 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
891 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
892 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
893 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
894 tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
895
896 def testSTARTTLS (self):
897
Bill Janssen40a0f662008-08-12 16:56:25 +0000898 msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000899
Trent Nelson78520002008-04-10 20:54:35 +0000900 server = ThreadedEchoServer(CERTFILE,
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000901 ssl_version=ssl.PROTOCOL_TLSv1,
902 starttls_server=True,
903 chatty=True,
904 connectionchatty=True)
905 flag = threading.Event()
906 server.start(flag)
907 # wait for it to start
908 flag.wait()
909 # try to connect
910 wrapped = False
911 try:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000912 s = socket.socket()
913 s.setblocking(1)
914 s.connect((HOST, server.port))
915 if support.verbose:
916 sys.stdout.write("\n")
917 for indata in msgs:
918 msg = indata.encode('ASCII', 'replace')
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000919 if support.verbose:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000920 sys.stdout.write(
921 " client: sending %s...\n" % repr(msg))
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000922 if wrapped:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000923 conn.write(msg)
924 outdata = conn.read()
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000925 else:
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000926 s.send(msg)
927 outdata = s.recv(1024)
928 if (indata == "STARTTLS" and
929 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
930 if support.verbose:
931 msg = str(outdata, 'ASCII', 'replace')
932 sys.stdout.write(
933 " client: read %s from server, starting TLS...\n"
934 % repr(msg))
935 conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
936 wrapped = True
937 elif (indata == "ENDTLS" and
938 str(outdata, 'ASCII', 'replace').strip().lower().startswith("ok")):
939 if support.verbose:
940 msg = str(outdata, 'ASCII', 'replace')
941 sys.stdout.write(
942 " client: read %s from server, ending TLS...\n"
943 % repr(msg))
944 s = conn.unwrap()
945 wrapped = False
946 else:
947 if support.verbose:
948 msg = str(outdata, 'ASCII', 'replace')
949 sys.stdout.write(
950 " client: read %s from server\n" % repr(msg))
951 if support.verbose:
952 sys.stdout.write(" client: closing connection.\n")
953 if wrapped:
954 conn.write("over\n".encode("ASCII", "strict"))
955 else:
956 s.send("over\n".encode("ASCII", "strict"))
Bill Janssen6e027db2007-11-15 22:23:56 +0000957 if wrapped:
958 conn.close()
959 else:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000960 s.close()
961 finally:
962 server.stop()
963 server.join()
964
Bill Janssen54cc54c2007-12-14 22:08:56 +0000965 def testSocketServer(self):
Bill Janssen6e027db2007-11-15 22:23:56 +0000966
Trent Nelson78520002008-04-10 20:54:35 +0000967 server = OurHTTPSServer(CERTFILE)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000968 flag = threading.Event()
969 server.start(flag)
970 # wait for it to start
971 flag.wait()
972 # try to connect
973 try:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000974 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000975 sys.stdout.write('\n')
976 d1 = open(CERTFILE, 'rb').read()
977 d2 = ''
978 # now fetch the same data from the HTTPS server
Trent Nelson78520002008-04-10 20:54:35 +0000979 url = 'https://%s:%d/%s' % (
980 HOST, server.port, os.path.split(CERTFILE)[1])
Jeremy Hylton1afc1692008-06-18 20:49:58 +0000981 f = urllib.request.urlopen(url)
Barry Warsaw820c1202008-06-12 04:06:45 +0000982 dlen = f.info().get("content-length")
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000983 if dlen and (int(dlen) > 0):
984 d2 = f.read(int(dlen))
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000985 if support.verbose:
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000986 sys.stdout.write(
987 " client: read %d bytes from remote server '%s'\n"
988 % (len(d2), server))
989 f.close()
Antoine Pitrou66ffb262010-04-27 11:05:15 +0000990 self.assertEqual(d1, d2)
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000991 finally:
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000992 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000993 sys.stdout.write('stopping server\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000994 server.stop()
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000995 if support.verbose:
Neal Norwitzf9ff5f02008-03-31 05:39:26 +0000996 sys.stdout.write('joining thread\n')
Thomas Wouters1b7f8912007-09-19 03:06:30 +0000997 server.join()
998
Trent Nelson6b240cd2008-04-10 20:12:06 +0000999 def testAsyncoreServer(self):
1000
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001001 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001002 sys.stdout.write("\n")
1003
1004 indata="FOO\n"
Trent Nelson78520002008-04-10 20:54:35 +00001005 server = AsyncoreEchoServer(CERTFILE)
Trent Nelson6b240cd2008-04-10 20:12:06 +00001006 flag = threading.Event()
1007 server.start(flag)
1008 # wait for it to start
1009 flag.wait()
1010 # try to connect
1011 try:
1012 s = ssl.wrap_socket(socket.socket())
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001013 s.connect(('127.0.0.1', server.port))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001014 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001015 sys.stdout.write(
1016 " client: sending %s...\n" % (repr(indata)))
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001017 s.write(indata.encode('ASCII', 'strict'))
1018 outdata = s.read()
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001019 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001020 sys.stdout.write(" client: read %s\n" % repr(outdata))
1021 outdata = str(outdata, 'ASCII', 'strict')
1022 if outdata != indata.lower():
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001023 self.fail(
Trent Nelson6b240cd2008-04-10 20:12:06 +00001024 "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001025 % (outdata[:min(len(outdata),20)], len(outdata),
1026 indata[:min(len(indata),20)].lower(), len(indata)))
Trent Nelson6b240cd2008-04-10 20:12:06 +00001027 s.write("over\n".encode("ASCII", "strict"))
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001028 if support.verbose:
Trent Nelson6b240cd2008-04-10 20:12:06 +00001029 sys.stdout.write(" client: closing connection.\n")
1030 s.close()
1031 finally:
1032 server.stop()
1033 server.join()
1034
Bill Janssen58afe4c2008-09-08 16:45:19 +00001035 def testAllRecvAndSendMethods(self):
1036
1037 if support.verbose:
1038 sys.stdout.write("\n")
1039
1040 server = ThreadedEchoServer(CERTFILE,
1041 certreqs=ssl.CERT_NONE,
1042 ssl_version=ssl.PROTOCOL_TLSv1,
1043 cacerts=CERTFILE,
1044 chatty=True,
1045 connectionchatty=False)
1046 flag = threading.Event()
1047 server.start(flag)
1048 # wait for it to start
1049 flag.wait()
1050 # try to connect
Antoine Pitrou66ffb262010-04-27 11:05:15 +00001051 s = ssl.wrap_socket(socket.socket(),
1052 server_side=False,
1053 certfile=CERTFILE,
1054 ca_certs=CERTFILE,
1055 cert_reqs=ssl.CERT_NONE,
1056 ssl_version=ssl.PROTOCOL_TLSv1)
1057 s.connect((HOST, server.port))
Bill Janssen58afe4c2008-09-08 16:45:19 +00001058 try:
Bill Janssen58afe4c2008-09-08 16:45:19 +00001059 # helper methods for standardising recv* method signatures
1060 def _recv_into():
1061 b = bytearray(b"\0"*100)
1062 count = s.recv_into(b)
1063 return b[:count]
1064
1065 def _recvfrom_into():
1066 b = bytearray(b"\0"*100)
1067 count, addr = s.recvfrom_into(b)
1068 return b[:count]
1069
1070 # (name, method, whether to expect success, *args)
1071 send_methods = [
1072 ('send', s.send, True, []),
1073 ('sendto', s.sendto, False, ["some.address"]),
1074 ('sendall', s.sendall, True, []),
1075 ]
1076 recv_methods = [
1077 ('recv', s.recv, True, []),
1078 ('recvfrom', s.recvfrom, False, ["some.address"]),
1079 ('recv_into', _recv_into, True, []),
1080 ('recvfrom_into', _recvfrom_into, False, []),
1081 ]
1082 data_prefix = "PREFIX_"
1083
1084 for meth_name, send_meth, expect_success, args in send_methods:
1085 indata = data_prefix + meth_name
1086 try:
1087 send_meth(indata.encode('ASCII', 'strict'), *args)
1088 outdata = s.read()
1089 outdata = str(outdata, 'ASCII', 'strict')
1090 if outdata != indata.lower():
1091 raise support.TestFailed(
1092 "While sending with <<{name:s}>> bad data "
1093 "<<{outdata:s}>> ({nout:d}) received; "
1094 "expected <<{indata:s}>> ({nin:d})\n".format(
1095 name=meth_name, outdata=repr(outdata[:20]),
1096 nout=len(outdata),
1097 indata=repr(indata[:20]), nin=len(indata)
1098 )
1099 )
1100 except ValueError as e:
1101 if expect_success:
1102 raise support.TestFailed(
1103 "Failed to send with method <<{name:s}>>; "
1104 "expected to succeed.\n".format(name=meth_name)
1105 )
1106 if not str(e).startswith(meth_name):
1107 raise support.TestFailed(
1108 "Method <<{name:s}>> failed with unexpected "
1109 "exception message: {exp:s}\n".format(
1110 name=meth_name, exp=e
1111 )
1112 )
1113
1114 for meth_name, recv_meth, expect_success, args in recv_methods:
1115 indata = data_prefix + meth_name
1116 try:
1117 s.send(indata.encode('ASCII', 'strict'))
1118 outdata = recv_meth(*args)
1119 outdata = str(outdata, 'ASCII', 'strict')
1120 if outdata != indata.lower():
1121 raise support.TestFailed(
1122 "While receiving with <<{name:s}>> bad data "
1123 "<<{outdata:s}>> ({nout:d}) received; "
1124 "expected <<{indata:s}>> ({nin:d})\n".format(
1125 name=meth_name, outdata=repr(outdata[:20]),
1126 nout=len(outdata),
1127 indata=repr(indata[:20]), nin=len(indata)
1128 )
1129 )
1130 except ValueError as e:
1131 if expect_success:
1132 raise support.TestFailed(
1133 "Failed to receive with method <<{name:s}>>; "
1134 "expected to succeed.\n".format(name=meth_name)
1135 )
1136 if not str(e).startswith(meth_name):
1137 raise support.TestFailed(
1138 "Method <<{name:s}>> failed with unexpected "
1139 "exception message: {exp:s}\n".format(
1140 name=meth_name, exp=e
1141 )
1142 )
1143 # consume data
1144 s.read()
1145
1146 s.write("over\n".encode("ASCII", "strict"))
1147 s.close()
1148 finally:
1149 server.stop()
1150 server.join()
1151
Antoine Pitrouec146182010-04-24 21:30:20 +00001152 def test_handshake_timeout(self):
1153 # Issue #5103: SSL handshake must respect the socket timeout
1154 server = socket.socket(socket.AF_INET)
1155 host = "127.0.0.1"
1156 port = support.bind_port(server)
1157 started = threading.Event()
1158 finish = False
1159
1160 def serve():
1161 server.listen(5)
1162 started.set()
1163 conns = []
1164 while not finish:
1165 r, w, e = select.select([server], [], [], 0.1)
1166 if server in r:
1167 # Let the socket hang around rather than having
1168 # it closed by garbage collection.
1169 conns.append(server.accept()[0])
1170
1171 t = threading.Thread(target=serve)
1172 t.start()
1173 started.wait()
1174
1175 try:
Antoine Pitrouc2203f92010-04-24 22:07:51 +00001176 try:
1177 c = socket.socket(socket.AF_INET)
1178 c.settimeout(0.2)
1179 c.connect((host, port))
1180 # Will attempt handshake and time out
1181 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1182 ssl.wrap_socket, c)
1183 finally:
1184 c.close()
Antoine Pitrouec146182010-04-24 21:30:20 +00001185 try:
1186 c = socket.socket(socket.AF_INET)
1187 c = ssl.wrap_socket(c)
1188 c.settimeout(0.2)
1189 # Will attempt handshake and time out
1190 self.assertRaisesRegexp(ssl.SSLError, "timed out",
1191 c.connect, (host, port))
1192 finally:
1193 c.close()
1194 finally:
1195 finish = True
1196 t.join()
1197 server.close()
1198
Bill Janssen58afe4c2008-09-08 16:45:19 +00001199
Thomas Woutersed03b412007-08-28 21:37:11 +00001200def test_main(verbose=False):
1201 if skip_expected:
Benjamin Petersone549ead2009-03-28 21:42:05 +00001202 raise unittest.SkipTest("No SSL support")
Thomas Woutersed03b412007-08-28 21:37:11 +00001203
Trent Nelson78520002008-04-10 20:54:35 +00001204 global CERTFILE, SVN_PYTHON_ORG_ROOT_CERT
Thomas Woutersed03b412007-08-28 21:37:11 +00001205 CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
1206 "keycert.pem")
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001207 SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
1208 os.path.dirname(__file__) or os.curdir,
1209 "https_svn_python_org_root.pem")
1210
1211 if (not os.path.exists(CERTFILE) or
1212 not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001213 raise support.TestFailed("Can't read certificate files!")
Bill Janssen6e027db2007-11-15 22:23:56 +00001214
Thomas Woutersed03b412007-08-28 21:37:11 +00001215 tests = [BasicTests]
1216
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001217 if support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001218 tests.append(NetworkedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001219
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001220 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001221 thread_info = support.threading_setup()
1222 if thread_info and support.is_resource_enabled('network'):
Bill Janssen6e027db2007-11-15 22:23:56 +00001223 tests.append(ThreadedTests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001224
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001225 support.run_unittest(*tests)
Thomas Woutersed03b412007-08-28 21:37:11 +00001226
Thomas Wouters1b7f8912007-09-19 03:06:30 +00001227 if _have_threads:
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001228 support.threading_cleanup(*thread_info)
Thomas Woutersed03b412007-08-28 21:37:11 +00001229
1230if __name__ == "__main__":
1231 test_main()